Repository: PDModdingCommunity/PD-Loader Branch: dev Commit: becac44e1683 Files: 336 Total size: 7.5 MB Directory structure: gitextract_k_mgt9p3/ ├── .gitattributes ├── .gitignore ├── .gitmodules ├── READ ME.txt.rtf ├── README.txt ├── appveyor.yml └── source-code/ ├── LICENSE ├── PD-Loader.sln ├── README.md ├── data/ │ ├── Download .NET Framework Runtime.url │ ├── Download QuickSFV.url │ ├── Download Visual C++ Runtime.url │ ├── README - PD Loader.url │ ├── patches/ │ │ └── custom_freeplay_text_example.p │ ├── plugins/ │ │ ├── Novidia Shaders/ │ │ │ └── e6d9187b.vcdiff │ │ └── ShaderPatch.ini │ ├── verify_base_game.sfv │ └── verify_mount_data.sfv ├── dependencies/ │ ├── GPUModel/ │ │ └── GPUModel.h │ ├── PluginConfigApi/ │ │ └── PluginConfigApi.h │ ├── WineVer/ │ │ └── WineVer.h │ ├── detours/ │ │ ├── include/ │ │ │ ├── detours.h │ │ │ ├── detver.h │ │ │ └── syelog.h │ │ └── lib/ │ │ ├── detours.lib │ │ └── syelog.lib │ ├── freeglut/ │ │ ├── include/ │ │ │ └── GL/ │ │ │ ├── freeglut.h │ │ │ ├── freeglut_ext.h │ │ │ ├── freeglut_std.h │ │ │ ├── freeglut_ucall.h │ │ │ └── glut.h │ │ └── lib/ │ │ ├── freeglut.exp │ │ ├── freeglut.lib │ │ ├── freeglutd.exp │ │ └── freeglutd.lib │ ├── simpleini/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── ConvertUTF.c │ │ ├── ConvertUTF.h │ │ ├── LICENCE.txt │ │ ├── Makefile │ │ ├── README.md │ │ ├── SimpleIni.h │ │ ├── other/ │ │ │ ├── package.cmd │ │ │ └── simpleini.doxy │ │ └── vcproj/ │ │ ├── SimpleIni.sln │ │ ├── SimpleIni.vcxproj │ │ └── SimpleIni.vcxproj.filters │ └── xdelta3/ │ ├── LICENSE │ ├── Makefile.am │ ├── README.md │ ├── badcopy.c │ ├── configure.ac │ ├── cpp-btree/ │ │ ├── CMakeLists.txt │ │ ├── COPYING │ │ ├── README │ │ ├── btree.h │ │ ├── btree_bench.cc │ │ ├── btree_container.h │ │ ├── btree_map.h │ │ ├── btree_set.h │ │ ├── btree_test.cc │ │ ├── btree_test.h │ │ ├── btree_test_flags.cc │ │ ├── safe_btree.h │ │ ├── safe_btree_map.h │ │ ├── safe_btree_set.h │ │ └── safe_btree_test.cc │ ├── draft-korn-vcdiff.txt │ ├── examples/ │ │ ├── Makefile │ │ ├── README.md │ │ ├── compare_test.c │ │ ├── encode_decode_test.c │ │ ├── iOS/ │ │ │ └── xdelta3-ios-test/ │ │ │ ├── xdelta3-ios-test/ │ │ │ │ ├── Xd3iOSAppDelegate.h │ │ │ │ ├── Xd3iOSAppDelegate.m │ │ │ │ ├── Xd3iOSViewController.h │ │ │ │ ├── Xd3iOSViewController.m │ │ │ │ ├── en.lproj/ │ │ │ │ │ ├── InfoPlist.strings │ │ │ │ │ ├── MainStoryboard_iPad.storyboard │ │ │ │ │ └── MainStoryboard_iPhone.storyboard │ │ │ │ ├── main.m │ │ │ │ └── xdelta3-ios-test-Info.plist │ │ │ └── xdelta3-ios-test.xcodeproj/ │ │ │ └── project.pbxproj │ │ ├── small_page_test.c │ │ ├── speed_test.c │ │ └── test.h │ ├── generate_build_files.sh │ ├── go/ │ │ └── src/ │ │ ├── regtest.go │ │ └── xdelta/ │ │ ├── rstream.go │ │ ├── run.go │ │ ├── test.go │ │ └── tgroup.go │ ├── linkxd3lib.c │ ├── m4/ │ │ ├── ax_check_aligned_access_required.m4 │ │ ├── ax_pkg_swig.m4 │ │ ├── ax_python_devel.m4 │ │ └── ax_swig_python.m4 │ ├── plot.sh │ ├── rcs_junk.cc │ ├── run_release.sh │ ├── testing/ │ │ ├── Makefile │ │ ├── checksum_test.cc │ │ ├── checksum_test_c.c │ │ ├── cmp.h │ │ ├── delta.h │ │ ├── file.h │ │ ├── modify.h │ │ ├── random.h │ │ ├── regtest.cc │ │ ├── regtest_c.c │ │ ├── run_release.sh │ │ ├── segment.h │ │ ├── sizes.h │ │ ├── test.h │ │ ├── xdelta3-regtest.py │ │ └── xdelta3-test.py │ ├── xdelta3-blkcache.h │ ├── xdelta3-cfgs.h │ ├── xdelta3-decode.h │ ├── xdelta3-djw.h │ ├── xdelta3-fgk.h │ ├── xdelta3-hash.h │ ├── xdelta3-internal.h │ ├── xdelta3-list.h │ ├── xdelta3-lzma.h │ ├── xdelta3-main.h │ ├── xdelta3-merge.h │ ├── xdelta3-second.h │ ├── xdelta3-test.h │ ├── xdelta3.1 │ ├── xdelta3.c │ ├── xdelta3.h │ ├── xdelta3.i │ ├── xdelta3.vcxproj │ ├── xdelta3.wxi │ └── xdelta3.wxs └── source/ ├── PD-Loader/ │ ├── ModuleList.h │ ├── PD-Loader.vcxproj │ ├── PD-Loader.vcxproj.filters │ ├── dllmain.cpp │ ├── exception.hpp │ ├── framework.h │ └── x64.def ├── fakedll/ │ ├── ModuleList.h │ ├── dllmain.cpp │ ├── exception.hpp │ ├── fakedll.vcxproj │ ├── fakedll.vcxproj.filters │ ├── framework.h │ └── x64.def └── plugins/ ├── DSCRemote/ │ ├── DSCRemote.vcxproj │ ├── DSCRemote.vcxproj.filters │ ├── PluginConfigApi.h │ ├── dllmain.cpp │ └── framework.h ├── DivaMovie/ │ ├── DivaMovie.vcxproj │ ├── DivaMovie.vcxproj.filters │ ├── PluginConfigApi.h │ ├── dllmain.cpp │ └── framework.h ├── DivaSound/ │ ├── DivaSound.vcxproj │ ├── DivaSound.vcxproj.filters │ ├── bassasio/ │ │ ├── bassasio.h │ │ └── bassasio.lib │ ├── miniaudio/ │ │ └── miniaudio.h │ └── src/ │ ├── dllmain.cpp │ └── framework.h ├── DivaWig/ │ ├── DivaWig.vcxproj │ ├── DivaWig.vcxproj.filters │ ├── PluginConfigApi.h │ ├── dllmain.cpp │ └── framework.h ├── Launcher/ │ ├── ConfigOption.h │ ├── IniReader.h │ ├── Launcher.filters │ ├── Launcher.vcxproj │ ├── PluginConfig.h │ ├── SkinnedMessageBox.h │ ├── SkinnedMessageBox.resx │ ├── TabPadding.cpp │ ├── TabPadding.h │ ├── composition.h │ ├── dllmain.cpp │ ├── framework.h │ ├── ui.h │ └── ui.resx ├── Novidia/ │ ├── Novidia.vcxproj │ ├── Novidia.vcxproj.filters │ └── src/ │ ├── crc/ │ │ ├── crc.h │ │ ├── crc_32.c │ │ └── sniptype.h │ ├── dllmain.cpp │ ├── framework.h │ └── glStuff.h ├── Patches/ │ ├── PatchApplier.h │ ├── PatchApplier600.h │ ├── PatchApplier710.h │ ├── Patches.vcxproj │ ├── Patches.vcxproj.filters │ ├── databank.cpp │ ├── databank.h │ ├── dllmain.cpp │ ├── framework.h │ ├── storage.h │ └── urlutil.h ├── Render/ │ ├── Render.vcxproj │ ├── Render.vcxproj.filters │ ├── dllmain.cpp │ └── framework.h ├── ShaderPatch/ │ ├── ShaderPatch.vcxproj │ ├── ShaderPatch.vcxproj.filters │ └── src/ │ ├── dllmain.cpp │ └── framework.h └── TLAC/ ├── Components/ │ ├── CameraController.cpp │ ├── CameraController.h │ ├── ComponentsManager.cpp │ ├── ComponentsManager.h │ ├── CustomPlayerData.h │ ├── DebugComponent.cpp │ ├── DebugComponent.h │ ├── EmulatorComponent.cpp │ ├── EmulatorComponent.h │ ├── FastLoader.cpp │ ├── FastLoader.h │ ├── FrameRateManager.cpp │ ├── FrameRateManager.h │ ├── GameState.h │ ├── GameTargets/ │ │ ├── HoldState.h │ │ ├── TargetHitStates.h │ │ ├── TargetInspector.cpp │ │ ├── TargetInspector.h │ │ ├── TargetState.h │ │ └── TargetTypes.h │ ├── Input/ │ │ ├── InputBufferType.h │ │ ├── InputEmulator.cpp │ │ ├── InputEmulator.h │ │ ├── InputState.cpp │ │ ├── InputState.h │ │ ├── JvsButtons.h │ │ ├── TouchPanelEmulator.cpp │ │ ├── TouchPanelEmulator.h │ │ ├── TouchPanelState.h │ │ ├── TouchSliderEmulator.cpp │ │ ├── TouchSliderEmulator.h │ │ ├── TouchSliderState.cpp │ │ └── TouchSliderState.h │ ├── Pause.cpp │ ├── Pause.h │ ├── PlayerData.h │ ├── PlayerDataManager.cpp │ ├── PlayerDataManager.h │ ├── ScaleComponent.cpp │ ├── ScaleComponent.h │ ├── ScoreSaver.cpp │ └── ScoreSaver.h ├── Constants.h ├── FileSystem/ │ ├── ConfigFile.cpp │ ├── ConfigFile.h │ ├── TextFile.cpp │ └── TextFile.h ├── Input/ │ ├── Bindings/ │ │ ├── Binding.cpp │ │ ├── Binding.h │ │ ├── DVLBinding.cpp │ │ ├── DVLBinding.h │ │ ├── Ds4Binding.cpp │ │ ├── Ds4Binding.h │ │ ├── GuBinding.cpp │ │ ├── GuBinding.h │ │ ├── IInputBinding.h │ │ ├── KeyboardBinding.cpp │ │ ├── KeyboardBinding.h │ │ ├── MouseBinding.cpp │ │ ├── MouseBinding.h │ │ ├── XinputBinding.cpp │ │ └── XinputBinding.h │ ├── DirectInput/ │ │ ├── Controller.cpp │ │ ├── Controller.h │ │ ├── DirectInput.cpp │ │ ├── DirectInput.h │ │ ├── DirectInputDevice.cpp │ │ ├── DirectInputDevice.h │ │ ├── DirectInputMouse.cpp │ │ ├── DirectInputMouse.h │ │ ├── Ds4/ │ │ │ ├── Ds4Button.h │ │ │ ├── Ds4State.cpp │ │ │ ├── Ds4State.h │ │ │ ├── DualShock4.cpp │ │ │ └── DualShock4.h │ │ └── GenericUsb/ │ │ ├── GenericUsbInput.cpp │ │ ├── GenericUsbInput.h │ │ ├── GuButton.h │ │ ├── GuState.cpp │ │ └── GuState.h │ ├── Divaller/ │ │ ├── Divaller.cpp │ │ ├── Divaller.h │ │ ├── DivallerButton.h │ │ └── DivallerState.h │ ├── IInputDevice.h │ ├── KeyConfig/ │ │ ├── Config.cpp │ │ ├── Config.h │ │ ├── KeyString.cpp │ │ ├── KeyString.h │ │ ├── KeyStringHash.cpp │ │ └── KeyStringHash.h │ ├── Keyboard/ │ │ ├── Keyboard.cpp │ │ ├── Keyboard.h │ │ ├── KeyboardState.cpp │ │ └── KeyboardState.h │ ├── Mouse/ │ │ ├── Mouse.cpp │ │ ├── Mouse.h │ │ └── MouseState.h │ └── Xinput/ │ ├── Xinput.cpp │ ├── Xinput.h │ ├── XinputState.cpp │ └── XinputState.h ├── TLAC.vcxproj ├── TLAC.vcxproj.filters ├── Utilities/ │ ├── Drawing.cpp │ ├── Drawing.h │ ├── EnumBitwiseOperations.h │ ├── Math.cpp │ ├── Math.h │ ├── Operations.cpp │ ├── Operations.h │ ├── Stopwatch.cpp │ ├── Stopwatch.h │ ├── Vec2.cpp │ ├── Vec2.h │ ├── Vec3.cpp │ └── Vec3.h ├── Utils.cpp ├── Utils.h ├── dllmain.cpp ├── framework.cpp ├── framework.h └── pluginconfig.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * binary ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: .gitignore ================================================ ._* .DS_Store ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- Backup*.rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Exclude data folder !data/* !data/debug/* ================================================ FILE: .gitmodules ================================================ [submodule "source-code/dependencies/MemoryModule"] path = source-code/dependencies/MemoryModule url = https://github.com/fancycode/MemoryModule ================================================ FILE: READ ME.txt.rtf ================================================ {\rtf1\ansi\deff3\adeflang1025 {\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\froman\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset0 Calibri;}{\f6\fnil\fprq2\fcharset0 Arial;}{\f7\fnil\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f8\fnil\fprq2\fcharset0 Calibri;}} {\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;} {\stylesheet{\s0\snext0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1 Normal;} {\*\cs15\snext15\langfe255\cf9\lang255\ul\ulc0 Collegamento Internet;} {\s17\sbasedon0\snext18\dbch\af6\langfe1081\dbch\af7\afs28\ql\nowidctlpar\hyphpar0\sb240\sa120\keepn\ltrpar\cf0\loch\f4\fs28\lang1040\kerning1 Titolo;} {\s18\sbasedon0\snext18\dbch\af6\langfe1081\dbch\af7\afs24\ql\sl276\slmult1\nowidctlpar\hyphpar0\sb0\sa140\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1 Corpo del testo;} {\s19\sbasedon18\snext19\dbch\af6\langfe1081\dbch\af7\afs24\ql\sl276\slmult1\nowidctlpar\hyphpar0\sb0\sa140\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1 Elenco;} {\s20\sbasedon0\snext20\dbch\af6\langfe1081\dbch\af7\afs24\ai\ql\nowidctlpar\hyphpar0\sb120\sa120\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1 Didascalia;} {\s21\sbasedon0\snext21\dbch\af6\langfe1081\dbch\af7\afs24\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1 Indice;} }{\*\generator LibreOffice/6.3.0.4$Windows_X86_64 LibreOffice_project/057fc023c990d676a43019934386b85b21a9ee99}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr2020\mo6\dy2\hr22\min29}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab720 \hyphauto0\viewscale100 {\*\pgdsctbl {\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440\pgdscnxt0 Stile predefinito;}} \formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1800\margr1800\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc {\*\ftnsep\chftnsep}\pgndec\pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl240\slmult1\ql\sb0\sa200{ {\pict{\*\picprop{\sp{\sn wzDescription}{\sv }}{\sp{\sn wzName}{\sv }}}\picscalex1125\picscaley1130\piccropl0\piccropr0\piccropt0\piccropb0\picw73\pich23\picwgoal735\pichgoal225\wmetafile8 010009000003f44e07000000cb4e070000000400000003010800050000000b0200000000050000000c023901fc03030000001e00040000000701040004000000 07010400cb4e0700410b2000cc003901fc03000000003901fc030000000028000000fc030000390100000100180000000000549d0e0000000000000000000000 000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6c6ff00 00ffbdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff6363ff1010ff0000ff0000ff0000ff5252ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6c6ff0000ffc6c6ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffff8484ff1818ff0000ff0000ff0000ff0000ff0000ff0000ff0000ffd6d6ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdff0000ffc6c6ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9494ff1818 ff0000ff0000ff0000ff0000ff0000ff0000ff3939ff0000ff0000ff9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffc6c6ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7373ff0000ff0000ff0000ff0000ff0000ff4a4a ffa5a5ffefefffffffff5252ff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffc6c6ff0000ff9494ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffe7e7ff0000ffa5a5ffffffffffffffffffffffffff0808ff0000ff0000ff0000ff6363ffe7e7ffffffffffffffffffffffffffcece ff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ceceff0000ff7b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84 84ff0000ff5a5afff7f7ffffffffffffffc6c6ff0000ff0000ff4a4affe7e7ffffffffffffffffffffffffffffffffffffffffffff0000ff6363ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeff0000ff5a5affffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeff0000ff0000ff0000ffbdbdffff ffffffffffa5a5ff0000ff3939ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0808ff4a4affffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff3939ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ff0000ff0000ffc6c6ffffffffffffff8484ff0000ffa5 a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2121ff2121ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2121ff2121ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff0808ff0000ffc6c6ffffffffffffff8484ff0000ffd6d6ffffffffffffffffffffff ffffffffffffffffffffffffffffffffff2929ff0000ffdedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff4242ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7ff0000ff0000ff9494ff0000ffc6c6ffffffffffffff8484ff0000ffd6d6ffffffffffffffffffffffffffffffffffffffffffffff ffffffffff5252ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff6363ff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9cff 0000ff0000ff8c8cff0000ffbdbdffffffffffffff8484ff0000ff2929ffb5b5ffffffffffffffffffffffffffffffffffffffffffffffffff7373ff0000ffc6 c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000 ffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9494ff0000ff0000ff4a4affdedeff0000ff c6c6ffffffffffffffa5a5ff0000ff0000ff0000ff2121ff9c9cffffffffa5a5ff4a4aff1818ff0000ff0000ff0000ff0000ffc6c6ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff0000ffe7e7ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1818ff0000ff0000ffa5a5ffdedeff0000ffc6c6ffffffffffffffdedeff 0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5a5ff0000ffd6d6ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffceceff2929ff0000ff0000ff4a4affe7e7ffc6c6ff0000ffc6c6ffffffffffffffffffffc6c6ff4242ff0000ff0000ff 0000ff0000ff0000ff0000ff0000ff0000ff0000ff3939ff4242ffd6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffadadff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ff9494ff0808ff0000ff0000ff1010fff7f7ffffffffc6c6ff0000ff5a5afff7f7ffffffffffffffffffffffffffceceff6363ff4242ff4242ff4242ff5a5aff adadffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffc6c6ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6b6bff0000ff0000ff0000ff0000 ff9c9cffffffffffffffc6c6ff0000ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6 c6ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffefefff3939ff0000ff0000ff0000ff1818ffb5b5ffffffffffffffffffffc6c6 ff0000ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceceff0000ffc6c6ffffffffff ffffffffffffffffffffffffffffffffffceceff1010ff0000ff0000ff0000ff3939ffefefffffffffffffffffffffffffffffffff6b6bff0000ffc6c6ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffffffff ffffadadff0808ff0000ff0000ff0000ff5a5afff7f7ffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffffff8484ff0000ff0000ff0000ff08 08ff9494ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffff6b6bff0000ff0000ff0000ff1010ffc6c6ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffe7e7ff0000ffc6c6ffffffffffffffffffff5a5aff0000ff0000ff0000ff2121ffdedeffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ff f7f7ffa5a5ff1818ff0000ff0000ff0000ff3131fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6 c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffbdbdff2929ff0000ff0000ff0000ff 0000ff5252ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ff3939ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff6b6bffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ff0000ff4242fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7ff0000ff0000ff0000ff0000ff0000ff5252ffceceffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffe7e7ff0000ff0000ff0000ffbdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7e7ff3939ff0000ff3131ff4242ff9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffff7b7bff0000ff0000ff2121fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff4242 ffd6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff 0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff00 00ff3939ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ffc6c6ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff0808ff0000ff0000ff4a4affffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff0000ffc6c6ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff4242ffd6d6ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9cff0000ff0000ff0000ff3131fff7f7ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000ffc6c6ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000ff0000ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4242ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffff8484ff0000ff0000ff7373ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff0808ff0000ffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffff9494ff0000ff0808ffceceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff7373ff0000ff1818ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff 0000ff0000ff2121ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5a5ff0000ff0000ff5a5a ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3131ff0000ff0000ffd6d6ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff0000ff0000ffa5a5ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff1010ff0000ff0000ff3131fff7f7ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff5a5aff0000ff0000ff0000ff3939ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff0000ff0000ff3131fff7f7ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffff4a4aff0000ff0000ff0000ff2929ffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffefffef7bce635ace394abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294a bd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac6 2142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd215ac63984ce63efffe7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefe7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffd6d6ff4242ff0000ff0000ff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff00 00ff0000ff4242fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffefffe74abd294abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd214abd29eff7e7ffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffff7f7f7efe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffa5a5ff0000ff0000ff0000ffadadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0808ff0000ff0000ff7373ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bce634ac6294abd21 4ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142 bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6 294abd214ac62142bd214ac6294abd214ac62142bd214ac6297bce63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffff7f7f7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff8484ff0000ff0000ff1818ffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffc6c6ffa5a5ff 8484ff8484ff8484ff8484ff8484ff8484ff8484ffc6c6ffc6c6fff7f7ff5252ff0000ff0000ff7b7bffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5ac63942bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd215ac639ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefe7e7ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4242ff0000 ff0000ff4a4affffffffffffffffffffffffffffffffffffffffffffffffffefefff9494ff4a4aff0808ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff 0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff2929ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd21 4ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294a bd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac6 2142bd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7e7b573d68c31d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d69431dea55afff7e7ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff1818ff0000ff0000ff9494ffffff ffffffffffffffffffffffffffadadff5252ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff 0000ff0000ff0000ff0000ff2929fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7efd68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68c29f7efd6fffffffffffffffffffffffffffffffffffffff7f7e7b57bd68c 31d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421e7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7de dee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7 dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7 e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7de dee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7 dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7 e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7de dee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7 dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7 e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7de dee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedeffffffdededee7e7e7e7dedee7e7e7 dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7 e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e79494ef0000ff0000ff0808ffadade7e7e7e7cecee77373f71010 ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff3939ff5a5aff6b6bef7373f77373f77373f76b6bef7373f77373f74242ff0000ff0000ff0000ff0000ff 0000ff5252ffefe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff42bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21 4ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142 bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7b573d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21dead63fffffffffffffffffffffffffffffffffff7d68c21efd6adffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c21e7 e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffff6363ff0000ff0000ff1818ff5a5aff0808ff0000ff0000ff0000ff0000ff0000ff1010 ff6b6bffbdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff2929ff0000ff0000ff0808ff0000ff0000ff0000ffdedeffe7e7e7 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffd69439d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421de9431ffffffffffffffffffffffffffffffe7b57befd6adffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffe7e7e7e7dedeffffffffffffffffff1818ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff4a4affadadfff7f7ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff8c8cff0808ff0000ff0000ff0000ff7b7bff9c9cff0000ff0000ff8c8cfff7f7f7efefefffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd214ac62142bd214ac6294abd214ac6 2142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd21 4ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294a bd214ac62142bd214ac6294abd214ac62142bd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21ffffffffffffffffffffffffffffffde9439ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c29e7e7e7ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7ff ffffbdbdff5252ff0000ff0000ff0000ff0000ff0000ff0000ff6363ffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff5a5aff0000ff0000ff0000ff0000ff8484ffffffffffffff5252ff0000ff6363ffffffffefe7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffffffffffffffffffff ffffffffffd68c21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffe7e7e7dededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7dededee7e7ff0000ff0000ff0000ff00 00ff0000ff0000ff0000ff0808ffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5252ff0000ff0000ff0000 ff1010ffadadffffffffffffffffffffbdbdff0000ff1010ffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff42bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6 294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21a5c62184efb54ac6314abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21 4ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421ffb529ffffefd68c9cd68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421ffffffffffffffffffffffffffffffd68c21ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffd68c21e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff9cdeff7b2952ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121212121292929de9c4affffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff217bc62121212929 294a2121ffe79cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9ce7ff21214a7b2121ffffbdffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7e7e7ff0000ff0000ff0000ff3131ffbdbdff6b6bff0000ff00 00ff1010ff8c8cfff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff6363ff0000ff0000ff0000ff4a4affefefffffffffffffffffff ffffffffffffff0808ff0000ffd6d6ffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd21adbd21ffffde84efe74abd2942bd214abd21dee752ffffefeffff773e7de42bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffceefff7b84a5737373cea584ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21f7ad21ffffefd6849cd68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffffffffffffffffffffffffffffffd68c21ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff d68421e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dedeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff9cdeff73214affffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cde9c4affffffff ffffffffff73bdff732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff9c4a73ffffdeffffffbdffff212173de9c4affffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdffde9c4affffffffffff73bdff4a2121ffde9c9cde ff4a214affde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde9c4a21ffffdeffffffffffffffffffffffffffffffffffffff ffffffffff2173bdbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffff ffffffffffffffe7ffff6b7bb56b6b6b6363636b6b6b6363636b6b6b6363636b6b6b6363636b6b6b636363c68c6bffffe7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dedededeff0000ff3939ff9c9cffffffffffffffffffff4a4aff0000ff0000ff0000ff5252ffff ffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000ff0000ff0000ff6363ffffffffffffffffffffffffffffffffffffffffffff4242ff0000 ff8c8cffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a bd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac62963bd21f7f7 94fffff7ffffffffffffffffff84efe74ac6319cbd21deffd642c694adc629d6ffd64ac68c42bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd21 4ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff84addeffd6a5ffffff7ba5d6ffdeadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff6ba5d66b6b6b6b6b6b6b6b6b846b6bffefbdffffffffffff84bdefd6a56bffffffffffffffffff8cbdef6b6b6b6b6b6bbda56b6b8cbde7bd84ffffff84 bdefd6a56bffffffffffffefffff6b8cbdffd6a5ffffffffffffa5d6ff6b6b6b6b6b6ba56b6bffffd6e7ffff6b8cbdffd6a5ffffffffffffbdefffa56b84ffff d6bde7ff6b6b8cffd6a5ffffffffffffffffffffffffd6ffff6b6ba5a56b6bffffd6ffffff84bde76b6b6befbd84ffffffbde7ff6b6b8ca56b6bffffd6a5d6ff 6b6b6b6b6b6bbd8c6b6ba5bd6b6b6bffd6a5bdefff6b6b846b6b6b6b6b6b6b6b6bffd6a5ffffffffffffa5d6ff6b6b6b6b6b6bbd846bffffefd6ffff6b6ba56b 6b6b6b6b6b6b6b6befbd8cffffff8cbdef6b6b6befbd8cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffd68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21f7b521ffffefd68c9cd68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21ffffffffffffffffffffffffffffffd68421ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c29e7e7e7ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff7b2152ffffbd ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff529ce79c4a21ffffe7ffffffffffffbdffff29297bff bd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff9c5229ffffdeffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff297bc6de9c4ae7ffff214a9ce79c52ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffc6ffff212173ffc67bffffffffffffffffffffffffffffffffffffffffffffffff73bdff7b2929ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffd6ffffa56b a5ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffd6ffffa56ba5ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7e7e7e7e7c6c6ff0000ffc6c6ffffffffffffffffffffffffffbdbdff0000ff0000ff0000ff0000ffceceffffffffffffffffffffff ffffffffffffffff5a5aff0000ff0000ff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff5a5affe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd214abd21f7f77bffffffffffffffffffffffffffff ff8cf7ef42bd319cbd21d6ffce4ac68494bd21deffce42bd8c4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7 e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84a5d6ffdeb5ffff ff84b5e7ffd6a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d6d69c63ffffff ffffffa5d6ff846363ffefbdffffff84bdefd69c63ffffffffffffbdefff846384ffefbdffffffa5d6ff636363efbd84ffffff84bdefd69c63ffffffffffffef ffff6384bdffd6a5ffffffa5d6ff846363ffefbdffffffd6ffffe7bdbdefffff6384bdffd6a5ffffffffffffbde7ffa56b84ffffd6bdefff636384ffd6a5ffff ffffffffffffffffffffd6ffff6b6ba59c6363ffffd6ffffff84bdef636363efbd84ffffffbdefff636384a56b6be7ffd66b84bd6363636b6b6b6363636b6b6b 636363ffd6a5bde7ff6b6b846363636b6b6b636363846b6bffe7bdefffff6384bd6b6b6b636363bd846bd6ffe76b6ba56363636b6b6b6363636b6b6be7bd84ff ffff84bde76b6b6be7bd84ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffce949ce7b55aff ffffffffffffffffffffffffffffffffffd6c6ffc68442ce8442c68442ce8c42ce8442ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffceb5d6ce8442c68442ce8c42c68442ce8442ffde9cffffffcec6ffce8442c68442ce8c42dea542ffffffffffffffffffceb5d6ce8442c68442de9442 ceb5b5de9442ffffd6ffffffdeffffce847bc68442ce8c42e7b55acea5b5dea542ffffffffffffdeffffc6847bce8c42c68442de9442ffffd6ffffffdeffffce 847bffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ef8421ffffded6adbdd68c21d68421d68c21f7c621ffffffd6c6d6d68c21 d68421ffef9cffffffffffffefefffd68c21d68421e78c21fff7bdefefffd68421d68c21ffde63ffffffd6849cd68c21d68421d68c21d68421d68c21f7ad21f7 f7efd68463d68c21ffde63efefffd68421f7b521f7ffefd68c9cd68421f7b521ffffefffffffffffffd6b5c6d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21e78421ffffc6ffffffffffffffffffd6cede d68421d68c21f7ad21ffffefffdebdffffffffffffefefffd68421d68c21ffde63efefffd68421d68c21ffde63ffffffffffffffffffd6c6d6d68c21d68421ff ef9cfffffffffffff7deefffffded6adbdd68c21ffde63fffffffffffff7ffffffefbde7deefd68421d68c21d68421d68c21d68421ffce21efefffd68c21d684 21ffef9cdedeefd68c21ffde63efefffd68421d68c21ffde63fffffffffffff7f7ffd68463d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21ffffffffffffffffffffffffffffffd68c21ffffffffffffffffffffffffdec6ffde8c21ffffb5ffffffffffffffffffe7ffffd68c73ffc66bff ffffffffffffffffdec6ffe79421ffffd6fffffffffffffffffffffffff7ffffd6948cffc66bffffffffffffffffffdec6ffde8421ffffb5ffffffffffffffff ffffffffffffffe7ffffd6846bd68c21d68421de8c21ffffb5ffffffffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffffffffffffff84bdef 6363636b6b6b636363efbd84ffffffffffffd6ffff6b6ba56363636b6b6b9c6363ffffd6ffffffd6ffff63639cffd6a5ffffffffffffffffffffffff639cd6d6 a56bffffffffffffffffffffffffffffffe7e7e7dededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cffbd73ffff ffffffff9cdeff73214affffbdffffffbdffff212173212121de9c4affffff9cdeff21214a212121ffbd739cdeff73214a73bdbd2121212121219c4a21ffffde ffffffdeffff214a9c212121212121bd7321ffffff9cdeff21214affbd73bdffff4a2173ffde9cffffffffffffffffff4a9cdebd7321ffffffffffffffffffff ffff2173bdde9c4affffffffffffbdffff4a2173ffde9cffffffffffff2173bd2121212121214a2121ffde9cffffffffffffffffff4a9cde212121732121ffff bd73bdff2121212121219c4a2121739cbd7321ffffff73bdff9c4a214a9cbd2121212121219c4a21ffffdeffffffffffff73bdff2121212121217321214a9c9c 9c4a21ffffdeffffff73bdff2121212121217321219cdebd73214affffbdbdffff212173de9c4affffffffffff4a9cde212121212121212121ffbd73ffffffff ffff73bdff9c4a21ffffdeffffffffffffffffff2173bd212121212121bd73214a9cdebd7321ffffff73bdff9c4a21ffffdeffffffffffffffffff4a9cdebd73 21ffffffffffffdeffff214a9cffbd73ffffff73bdff2121212121219c4a2121739cbd7321ffffff9cdeff21214a212121212121ffbd73ffffffffffff73bdff 2121214a2121ffde9cffffffdeffff214a9cbd7321ffffffffffffffffff4a9cde212121212121732121ffffbddeffff214a9cffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffd6ffff9c639cd6ffd663639c6b6b6b6363 63a56b6bffffd6ffffffbdbde7ffffded6ffffa56ba5ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7 dededec6c6ff0000ffc6c6ffffffffffffffffffffffffffffffffe7e7ff7373ff0000ff0000ff1010f76b6b847b7b7b7373737b7b7b7373841818e70000ff00 00ff0000ff2121ded6ad84ffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff0000ff3939ffdededeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff42bd214ac6294abd214ac62142bd214ac6294abd214ac62142 bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21a5c621ffffcef7ffff52d6c6adc621ffffd68cf7ef4abd294ac62142bd21dee7 4af7fff7f7ffff63ded64ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21 4ac62142bd214ac6294abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdef7ff7384a57b84849c7373fff7ceffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d6d6a56bffffffffffffe7ffff6b8cbdefbd84 ffffff84bde7d6a56bffffffffffffbde7ff8c6b8cffefbdffffffe7ffff6b8cbdefbd84ffffff84bde7d6a56bffffffffffffe7ffff6b8cbdffd6a5efffff6b 84bdefbd8cffffffffffffffffffffffffefffff6b8cbdffd6a5ffffffffffffbdefffa56b84ffffd6ffffffffffffffffffffffffffffffffffffffffffd6ff ff6b6ba5a56b6bffffd6ffffff84bdef6b6b6be7bd84ffffffbdefff6b6b8ca56b6befffd66b84bda56b6bffffd6ffffff6ba5d66b6b6bffd6a5ffffffffffff d6ffff6b6ba56b6b6b846b6bffefbde7ffff6b8cbd846b6bffefbdffffffa5d6ff6b6b6bbd8c6bffffe7ffffffffffffffffffffffff8cbdef6b6b6befbd8cff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdd6efffe7ceffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6949cefb563ffffffffffffffffffffffffff ffffffffffd6c6ffd68c42ffffb5ffffffffffffdedeffc68463e7a54affffffffffffffffffffffffffffffffffffffffffffffffffffffceb5d6d69442ffff d6ffffffffffffffffffffffffd6c6ffce8c42ffc67bffffffffffffcea5bdd69442ffffd6d6deffce8c63ffc67bffffffd6deffce8c63d69442ffffd6deffff ce8c84dea542ffffffffffffcea5bdc68442e7a54affffffefffffc6949cde9c4affffd6ffffffd6deffe7a563ffffffe7ffffc6847bffc684ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421f78c29ffffd6d6b5c6d68421d68c29e78c21ffffc6ffffffd6ceded68c21ffe76bf7f7ffd68c6bd68c21 ffce21d6ced6d68c29f7ad21ffffeffff7efd68c9ce78c21ffffc6fff7efd6ceded68c21d68c21d68421d68c29d68c21f7b521f7f7efd68c6bd68c21ffe76bef efffd68c29f7ad21ffffefd6849cf78c29ffffd6d6ceded68421e78c29f7efbdd68c6bd68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421ffef9cf7f7ffd68c6bd68421ffb529ffffefd6b5c6d68421ffb529ffffef e7e7efd68421e78c29fff7bde7e7efd68421ffe76befefffd68c21ffce21ffffffd68c9cd68c21ef8421ffffded6ced6f7b521ffffefd6b5c6d68c21ffe76bff ffffd6b5c6ffce21ffffffd6adbdd68c29f7ad21ffffefe7deefd68c29d68c21d68c21d68421d68c29ffce21efefffd68421d68c29ffef9ce7e7efd68421ffe7 6befefffd68c21ffce21ffffffd68c9cd68c21f7ad21e7e7ded68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421ffffffffffff ffffffffffffffffffd68c21ffffffffffffffffffffffffdec6ffde8421ffffb5ffffffffffffffffffefffffd68c6bffc673ffffffffffffffffffdec6ffde 9421ffffdeffffffffffffffffffffffffefffffd69c94ffc66bffffffffffffffffffdec6ffde8c29ffffb5fffffffffffffffffffffffff7ffffde9494ffff b5ffffffffffffd6b5d6e79c29ffffd6ffffffffffffffffffffffffd68c21e7e7e7ffffffffffffffffffffffffa5d6ffefbd84ffffffffffffd6ffff6b6ba5 ffd6a5e7ffffa58cbdffffd6ffffffffffff8cbdefbd846bffffefd6ffff6b6ba5ffd6a5ffffffffffffffffffffffff6ba5d6d6a56bffffffffffffffffffff ffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff21529cffbd73ffffffffffff9ce7ff73214affff c6ffffff529ce79c4a21ffffe7ffffffffffff2173bdc67b29ffffffffffff9cdeff292952bd7321ffffffffffff297bc69c4a21ffffe773bdffffc67bffffff e7ffff214a9cffc67b9cdeff212152ffbd73ffffff2173bde79c52ffffffffffffffffff9ce7ff73214affffc6ffffffffffffffffff297bc6de9c4affffffff ffffc6ffff4a2173ffe79cffffff297bc69c4a21ffffe7ffffff9ce7ff4a214affe79cffffffc6ffff212173ffc67bffffffc6ffff212173ffc67bffffff9ce7 ff21214ac67b21ffffff7bc6ff212121e79c52ffffffe7ffff214a9cc67b21ffffffc6ffff212173e79c52ffffffc6ffff2121739c5221ffffde9ce7ff21214a ffc67bffffffc6ffff2121737b2121ffffbdc6ffff212173e79c52ffffff529ce7732121ffffc6ffffffc6ffff212173ffc67bffffff7bc6ff9c4a21ffffe7ff ffffffffff4a9cde7b2121ffffbdffffff73bdff212121bd7321ffffffbdffff52217bffde9cffffffffffffffffff4a9cdec67b29ffffffffffffdeffff2952 9cffbd73c6ffff212173ffc67bffffff9ce7ff21214ac67b29ffffff7b7bc6ffffbdffffff9cdeff7b2152ffffbde7ffff214a9ce79c52ffffffffffffffffff 9ce7ff4a4a4a7b2952ffffbdffffffbdffffc67b7bffffffffffff4a9cdec67b29ffffff529ce7ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffd6ffffa56ba5ffffd6ffffffffffffffffffffffffffffff84bde7a56b 73ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7bdbdff0000ffc6c6ff ffffffffffffffffffffffffffffffffffffffffff3942ff0000ff0000ff2121ef73737b7b7b7b73737b1818ef0000ff0000ff0000ff4231dea5cef7dead7bff ffffffffffffffffffffffffffffffffffffffffffffffffffff1010ff2121ffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd21adbd21ffffdedeffff4abd9ca5bd218cefbd42bd294abd2142bd214abd21a5bd21ffffdedeffff4abd9c42bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d66363636b6b6b6363636b6b6b947b6bf7debdffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d6d69c63ffffffffffffffffff639cd6efbd84ffffff84bdefd69c63ffffff ffffffffffff84bde76b6b6b6363636b6b6b636363efbd84ffffff84bdefd69c63ffffffffffffefffff6384bdffd6a5e7ffff6b84bdffd69cffffffffffffff ffffffffffefffff6384bdffd6a5ffffffffffffbde7ffa56b84ffffd6ffffffffffffffffffffffffffffffffffffffffffd6ffff6b6ba59c6363ffffd6ffff ff84bdef636363efbd84ffffffbdefff636384a56b6bffffd6d6ffff63639c6b6b6b6363636b6b6b636363ffd6a5ffffff6ba5d66363636b6b6b636363ffd6a5 ffffffefffff6384bd846b6bffe7bdffffff84bde76b6b6b6363636b6b6b6363636b6b6b846363ffefbd84bde76b6b6be7bd84ffffffffffffffffffffffffff ffffffffffffffffffffffffffff9cc6ef8c8c8c9c8c84ffe7bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffffce949cefb55affffffffffffffffffffffffffffffffffffd6c6ffce8442ff ffb5ffffffffffffffffffe7ffffc6847bffc67bffffffffffffffffffffffffffffffffffffffffffffffffceb5d6de9442ffffd6ffffffffffffffffffe7ff ffce949cefb55affffffffffffffffffdeffffce8c7bffc67bdedeffce845affde9cffffffffffffceb5d6de9442ffffd6d6c6ffce8442ffffb5ffffffffffff deffffce8c7bdea542ffffffcec6ffce8c42ffd694ffffffffffffffffffffffffffffffdeffffce8c7bffc67bffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21ef8421ffffded6adbdd68c21d68421ffde6bf7ffffffefded6c6d6e78c21fff7bdd6ceded68421d68c21d68421d68c21d68421ffce21 efefffffde6bd6c6d6f7ad21f7f7efffce6bdedeefd68c21d68421d68c21d68421d68c21f7ad21f7ffefd68463d68c21ffde63efefffd68421f7ad21f7ffefd6 8c9cf7c621f7f7ffd68463d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421ef8c21ffffd6d6adbdd68421d68c21d68421ffde6befefffd68c21f7ad21ffffefd6849cd68c21d68421ffce21 f7f7ffd68c6bffde63efefffd68421ffef9cdedeefd68c21d68421d68c21ffde63efefffef8421ffffdeefefffd68c21ef8421ffffded6adbdffde6befefffd6 8c21d68421d68c21ffef9ce7deefd68421d68c21d68421d68c21d68421ffce21efefffd68c21d68421ffef9ce7deefd68c21ffde63efefffd68421ffef9cdede efd68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffffffffffffffffffffffffffffffd68c21 ffffffffffffffffffffffffdec6ffde8c21ffffb5ffffffffffffffffffe7ffffd68c6bffc66bffffffffffffffffffdec6ffe79c21ffffd6ffffffffffffff ffffffffffefffffd69494ffc673ffffffffffffffffffdec6ffde8421ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7deffde84 42ffffb5ffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d6e7bd84ffffffffffffffffff ffffffffffffbde7ffa56b84ffffd6d6ffff63639cffd6a5ffffffffffffffffffffffff639cd6d6a56bffffffffffffffffffffffffffffffe7e7e7e7dedeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cffbd73ffffffffffff9cdeff73214affffbdffffff4a9cde9c4a21ffff deffffffffffff2173bdbd7321ffffffffffff9cdeff73214affffbdffffffffffffbdffff4a2173ffde9cffffffffffffffffff9cdeff21214affbd73ffffff ffffffffffffffffff73bdff732121ffffbdffffffffffffdeffff214a9cde9c4affffffffffffffffff2173bdde9c4affffffffffffbdffff4a2173ffde9c9c deff4a214affde9cffffffffffffffffff4a9cdebd7321ffffffbdffff212173ffbd73ffffffbdffff212173ffbd73ffffffffffff2173bdbd7321ffffff73bd ff9c4a21ffffdeffffffffffff9cdeff73214affffbd9cdeff4a214affde9cffffffffffff4a9cde9c4a21ffffde4a9cde9c4a21ffffdeffffffffffff73bdff 732121ffffbdffffffffffffffffffbdffff212173ffbd73ffffffffffffffffff73bdff9c4a21ffffde73bdff9c4a21ffffdeffffffdeffff214a9cde9c4aff ffffffffffffffff2173bdbd7321ffffffffffff2173bdbd7321ffffffffffffffffff4a9cdebd7321ffffffffffffdeffff214a9cffbd73bdffff212173ffbd 73ffffffffffff2173bdbd7321ffffffffffffffffffffffff4a9cde732121ffffbddeffff214a9cde9c4affffffffffffffffff2173bdde9c4a2173bdde9c4a ffffffffffffffffffffffffdeffff214a9cbd7321ffffff9cdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeff ffffffffffffffffffffffffffffffffffffffffffffffd6ffff9c639cd6ffd663639c6b6b6be7bd84ffffff84b5e76b6b6b6363636b6b6b6363636b6b6b6363 63a56b6bffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dedea5a5ff0000ffc6c6ffffffffffffffffffffffffff ffffffffffffffffff8cb5ff0000ff0000ff0000ff2929d673737b3131e70000ff0000ff0000ff3131ce7373737b7b7bd6ad73ffffffffffffffffffffffffff ffffffffffffffffffffffffffff3939ff2121ffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff4abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294a bd214ac62142bd21adc629ffffd6e7ffff42bd9c4ac6294abd214ac62142bd214ac6294abd21adc621ffffd6e7ffff4abd9c4ac62142bd214ac6294abd214ac6 2142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd21ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff6ba5d66b6b6b8c847b6b737b6b6b6b6b6b6b736b6bffd6a5ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff6ba5d6d6a56bffffffffffffa5d6ff8c6b6bffe7bdffffff84bdefbd8c6bffffe7ffffffffffffffffffffffff ffffffefffff6b8cbdffd6a5ffffff84bdefbd8c6bffffe7ffffffefffff6b8cbdffd6a5ffffff6ba5d6efbd8cffffffffffffffffffffffffe7ffff6b8cbdef bd84ffffffffffffbdefffa56b84ffffd6ffffffffffffffffffffffffffffffffffffffffffd6ffff6b6ba56b6b6bffd6a5efffff6b84bd6b6b6bd6a56bffff ffa5d6ff6b6b6ba56b6bffffd6ffffffffffffffffffffffff6ba5d66b6b6bffd6a5d6ffff6b6ba5a56b6bffffd6ffffffffffffffffffefffff6b8cbd846b6b ffefbdffffffa5d6ff6b6b6bbd8c6bffffefefffff6b84bd8c6b6bffefbd8cbdef6b6b6bbd8c6bffffefffffffffffffffffffffffffffffffffffffffffffa5 ceef8c8c8c8484848c8c8c9c8c8cffe7bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffefffffc6949cefb563ffffffffffffffffffffffffffffffffffffd6c6ffd68c4affffb5ffffffffffffffffffff ffffceb5d6d69442ffffd6ffffffffffffffffffffffffffffffffffffffffffd6b5d6d69442ffffd6ffffffffffffffffffe7ffffc6847bffc684ffffffffff ffffffffefffffc6949cefb563efffffce9c9cdea542ffffffffffffd6b5d6d69442ffffd6ceb5d6de9c4affffd6ffffffffffffffffffc6a5b5e7a542ffffff d6b5d6d69442ffffd6ffffffffffffffffffffffffffffffe7ffffc6847bffc684ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21ef8c 21ffffd6d6b5c6d68c21f7b521ffffefd6cedeffef9cd6cedee78421ffffc6fffffffffffffffffffffffff7f7ffd68c6bffef9cd6cedef7ad21efefefffde6b e7e7f7f7ad21f7ffefd6846bd68c29d68c21d68c21d68421ffb529f7f7efd68c6bd68421ffe76befefffd68c21f7ad21fffff7d68c9cffce21ffffffffffffff ffffffffffffffffd6ceded68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29f7ad21ffffefd6849cd68c29d68c21d68c21ffde6bf7efffd68c21f7b521ffffefd68c9cd68c21d68c21f7ad21fffff7d68c6bffe76befefff d68c29ffef9ce7e7efd68421d68c29d68c21ffe76befefffd68c29d68c21ffce21ffffffffffffffffffd6b5c6ffde6bf7efffd68c21d68c21d68421ffef9ce7 deefd68c21d68421d68c29d68c21d68c21ffce21f7efffd68c21d68c21ffef9ce7e7f7d68c21ffe76befefffd68c29ffef9cffffffffffffffffffffffffffff ffd6849cd68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21ffffffffffffffffffffffffffffffd68421ffffffffffffffffffffffff deceffde8c21ffffb5ffffffffffffffffffefffffd6846bffce73ffffffffffffffffffdeceffde9421ffffd6ffffffffffffffffffffffffefffffd69c94ff c66bffffffffffffffffffdec6ffde8c21ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffefffffd68c6be79c21ffffd6ffffffffffffffff ffffffffd68c29e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffff8cbdef6b6b6bffd6a5ffffffffffffffffffffffffd6ffff6b6ba5bd846b ffffefd6ffff6b6ba5ffd6a5ffffffffffffffffffffffff6ba5d6d6a56bffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffdeffff29529cffbd73ffffffffffff9ce7ff73214affffc6ffffff529ce79c4a21ffffe7ffffffffffff2173bdc67b 21ffffffffffff9cdeff7b2152ffffbdffffffffffffe7ffff214a9cffc67bffffff7bc6ff212121292929de9c4affffffffffffffffffffffffffffffdeffff 29529cffbd73ffffffffffffffffff73bdff9c5221ffffdeffffffffffff217bc6de9c4affffffffffffc6ffff4a2173ffe79c9cdeff7b2152ffffbdffffffff ffffffffff4a9cde9c5229ffffdec6ffff212173ffc67bffffffffffff73bdff292929212121212121212121c67b29ffffff7bc6ff9c4a21ffffe7ffffffffff ffbdffff52297bffde9c9ce7ff4a214affe79cffffffffffff4a9cde9c5229ffffde529ce7bd7321ffffffffffffffffff9cdeff7b2952ffffbdffffffffffff ffffffbdffff52217bffde9cffffffffffffffffff73bdff7b2929ffffbd7bc6ff9c4a21ffffe7ffffffe7ffff214a9cffc67bffffffffffffffffff529ce7bd 7321ffffffffffff9ce7ff73214affffc6ffffffffffff4a9cdec67b21ffffffffffffdeffff21529cffbd73ffffff73bdff212121212121292929212121c67b 21ffffffffffff2173bd2121214a2121ffe79cffffffe7ffff214a9ce79c52ffffffffffffbdffff52297bffde9c7bc6ff9c4a21ffffe7ffffffc6ffff212173 2929299c4a21ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffd6ffffa56ba5ffffd6ffffffffffffffffffffffff8cbdef6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6ba56b6bffffd6ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7a5a5ff0000ffceceffffffffffffffffffffffffffffffffffffffffffffb5e7ff 5252b50000ff0000ff0000ff2921f70000ff0000ff0000ff4242d67b7b7b7b7b7b7b7b7be7bd8cffffffffffffffffffffffffffffffffffffffffffffffffff ffff5a5aff1010ffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21a5bd21ff ffdedeffff4abd9c42bd214abd2142bd214abd2142bd214abd21adbd21ffffdedeffff4abd9c42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffff6ba5d6636363ffd6a5ffffffffffff9cc6ef6b6b7bb57b63ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff6ba5d66363636b6b6b636363a56b6bffffd6ffffffffffff84bdef636363ffd6a5ffffffffffff9cbde7ffefbdffffffbdefff636384ffd6a5 ffffff84bdef636363efbd84ffffffa5d6ff846363ffefbdffffffa5d6ff636363ffd6a5ffffffd6ffffe7bdbdefffff6384bd846b6bffe7bdffffff639cd6bd 846bffffe7bdefff636384ffd6a5ffffffffffffffffffffffffd6ffff6b6ba58463636b84846363636b6b6b84636384a5a56363636b6b6b636363bd846bffff e7bdefff6363846b6b6b6363636b6b6b846363ffefbdd6ffff6b6ba56363636b6b6b636363bd846bd6ffe76b6ba56363636b6b6b636363bd846bd6ffe76b6ba5 6363636b6b6b6363636b6b6bbd8463ffffef84bde76b6b6b8484846b6b6b9c6363ffffd6ffffffffffffffffffffffff9cc6ef8c8c8c8484848c8c8c8484848c 8c8c9c8c84ffe7c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffefffffce949cc68442ce8442c68442d68c42ffffb5ffffffffffffd6c6ffce8442ffffb5ffffffffffffffffffffffffd6deffce8c63ffd694de ffffc6847bce8c42c68442ce8442ffde9cffffffceb5d6de9442ffffd6ffffffffffffffffffdeffffce8c7bffc67bffffffffffffffffffe7ffffce949cefb5 5affffffffffffcea5b5c68442ce8c42c68442de9442ffffd6ceb5d6d69442ffffd6ffffffffffffffffffcea5b5dea542ffffffceb5d6ce8442c68442ce8c42 c68442ce8442ce8442ffde9cdeffffce847bffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ef8421ffffded6adbde78c21fff7 bdefefffd68421ffef9cd6c6d6d68c21ffde63e7deefd68421d68c21ffde63efefffef8421ffffded68494e78c21fff7bdffffefd6adbde78c21fff7bdd6b5c6 d68421d68c21d68421d68c21f7ad21f7f7efd68463d68c21ffde63efefffd68421f7b521f7ffefd68c9cef8421ffffded68494d68c21ef8421ffffded6adbdd6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421f7ad21f7ff efd68c9cd68421d68c21d68421ffde6befefffd68c21f7ad21ffffefefefffd68c21d68421ffef9cefefffd68c21ffde63efefffd68421ffce21f7ffffd68c9c d68421ef8c21ffffd6d6ceded68421ffde6bd6adbdd68c21f7ad21ffffefd6849cf7b521ffffefd6adbdd68421ef8c21ffffd6e7deefd68421d68c21d68421d6 8c21d68421ffce21efefffd68c21d68421ffef9cdedeefd68c21ffde63efefffd68421ffce21efefffd68c21d68421ffce21f7f7ffd68c6bd68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21ffffffffffffffffffffffffffffffd68c21ffffffffffffffffffffffffdec6ffde8c21ffffb5ffffff ffffffffffffe7ffffd68c73ffc66bffffffffffffffffffdec6ffe79421ffffd6fffffffffffffffffffffffff7ffffd6948cffc66bffffffffffffffffffde c6ffd68421d68c21d68421d68c21ffc66bffffffffffffffffffe7ffffd68c73d68421e7a521ffffffffffffffffffffffffffffffffffffd68421e7e7e7ffff ffffffffffffffffffffffffffffffff84bde76b6b6b846363ffefbdffffffffffffffffffd6ffff63639c6b6b6bd69c63ffffffffffffd6ffff63639cffd6a5 ffffffffffffffffffffffff639cd6d6a56bffffffffffffffffffffffffffffffe7e7e7dededeffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffdeffff214a9cde9c4affffffffffff9cdeff73214affffbdffffff4a9cde9c4a21ffffdeffffffffffff2173bdbd7321ffffffffffff9cdeff4a21 4affde9cffffffffffffbdffff212173ffbd739cdeff21214affbd73ffffffffffffffffffffffffffffffffffffffffffffffff4a9cdebd7321ffffffffffff ffffffbdffff4a2173ffde9cffffffffffff2173bdbd7321ffffffffffffbdffff4a2173ffde9c9cdeff4a214affde9cffffffffffffffffff4a9cdebd7321ff ffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffff2173bdde9c4affffff73bdff732121ffffbdffffffffffff9cdeff4a214affde9c9cde ff4a214affde9cffffffffffff4a9cde9c4a21ffffde73bdff9c4a21ffffdeffffffffffff73bdff732121ffffbdffffffffffffffffffbdffff212173ffbd73 ffffffffffffffffff73bdff9c4a21ffffde73bdff732121ffffbdffffffffffff2173bdde9c4affffffffffffffffff2173bdbd7321ffffffffffffdeffff21 4a9cffbd73ffffffffffff4a9cde9c4a21ffffdeffffffdeffff214a9cffbd73ffffffffffffffffffffffffffffff2173bdde9c4affffff4a9cde732121ffff bdffffffffffffffffffdeffff214a9cde9c4affffffffffff4a9cde9c4a21ffffdedeffff214a9cffbd73deffff214a9cbd7321ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffd6 ffff9c639cd6ffd663639c6b6b6be7bd84ffffffffffff8cbde79c636bffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffe7e7e7dededea5a5ff0000ffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000ff0000ff 0000ff0000ff0000ff7b6bdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000ffdededeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff42bd214ac6294abd21 4ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21adc621ffffd6e7ffff4abd9c4ac62142 bd214ac6294abd214ac62142bd21adc629ffffd6e7ffff42bd9c4ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6 294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6b a5d66b6b6bffd6a5ffffffffffffffffff6b9cce7b6b6bffdeb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d6d6a5 6bffffffffffff6ba5d6d6a56bffffffffffff84bde7d6a56b6ba5d66b6b6bffd6a5efffff6b84bd6b6b6b6b6b6bd6a56bffffffffffff84bde7d6a56b84bdef 6b6b6b6b6b6befbd8cffffffffffffffffffbdefff6b6b846b6b6ba56b6bffffd6efffff6b8cbde7d6a56b8cbd6b6b6b6b6b6bffd6a5ffffffbdefff6b6b8cff d6a5ffffffffffffffffffffffffd6ffff6b6ba5a56b6bbde7d66b6b8c6b6b6befbd8ce7ffff6b8cbd6b6b6b8c6b6bffe7bdffffffbdefff6b6b8c6b6b6b6b6b 6b6b6b6bffd6a5ffffffffffffbdefff6b6b8c6b6b6b6b6b6bbd846bd6ffef6b6ba56b6b6b6b6b6b6b6b6bbd846bffffefefffff6b8cbd6b6b6b6b6b6ba56b6b ffffd6ffffff8cbdef6b6b6bd6bd8c6b84bda56b6bffffd6ffffffffffffffffffffffffc6def7b5b5b5bdbdbdbdbdbdbdbdbdb5b5b5c6bdbdf7e7ceffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6949c efb563ffffffffffffceb5d6d68c42ffffb5ffffffd6c6ffd68c42ffffb5ffffffffffffffffffffffffdedeffce8463ffde9cffffffffffffffffffffffffff ffffffffffffffffceb5d6d69442ffffd6ffffffffffffffffffefffffc6949ce7a542ffffffffffffffffffe7ffffc6847bffc684ffffffffffffffffffffff ffffffffceb5d6d69442ffffd6d6deffce8c63ffde9cffffffffffffefffffc6949ce7a54affffffd6c6ffd68442ffffbdffffffffffffd6deffd68c63ffffb5 e7ffffc6847befb563ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffd68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421f78c29ffffd6d6b5c6ffce21ffffffd68c9cd68c21ffef9cd6ce ded68c21d68c21ffef9cfffffffffffff7ffffd6846bffce29f7f7ffd68c6bd68421ffe76bf7f7ffd68c6bd68421ffe76be7deefd68c21d68421d68c29ffce21 ffffffffffffffffffd6ced6ffe76befefffd68c29f7ad21ffffefd6849cd68c29f7ad21ffffefffffffffffffd6ced6d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21f7ad21fffff7d68c9cd68c21d68421d68c 29ffde6befefffd68421ffb529ffffefffce9cfffffffffffff7f7ffd68c6bd68421ffe76befefffd68c21d68421ffce29ffffffffffffffffffe7e7f7d68c21 d68c21e78421ffffc6ffffffffffffe7deefd68c29d68c21ffce21ffffffffffffffffffffffffe7deefd68c29d68c21d68c21d68421ffe76bffffffffffffff ffffd6b5c6ffef9ce7e7efd68421ffe76befefffd68c21d68421ffe76bffffffffffffffffffd68c9cd68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421ffffffffffffffffffffffffffffffd68c21ffffffffffffffffffffffffdec6ffd68421d68c29d68c21d68c21d68421d68c29d68c21 ffc673ffffffffffffffffffdec6ffde9421ffffdeffffffffffffffffffffffffefffffd69c94ffc66bffffffffffffffffffdec6ffde8c29ffffb5ffffffde deffd68c4affc66bffffffdedeffd68c4ade9421ffffd6ffffffffffffffffffffffffffffffffffffffffffd68c21e7e7e7ffffffffffffffffffffffffffff ff6ba5d66b6b6bffd6a5ffffffffffffffffffffffffbdefff6b6b84bd8c6bffffe7ffffffffffffffffffd6ffff6b6ba56b6b6b6b6b6b6b6b6b6b6b6b6b6b6b 6b6b6bd6a56bffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff21529c4a 2121ffe79cffffff217bc69c4a21ffffe7ffffff529ce79c4a21ffffe7ffffffffffff2173bdc67b29ffffffffffff9cdeff2929529c4a21ffffe7ffffff529c e7732121ffffc69cdeff522952ffde9cffffff9cbdffffe79c9cdeff212152ffbd73ffffffffffff9ce7ff4a214affe79cffffffffffffffffff297bc6bd7321 ffffffffffff297bc6212121ffc67bffffff529ce7732121ffffc6ffffff297bc69c4a21ffffe7ffffff9ce7ff21214affc67bffffffc6ffff212173ffc67bff ffffffffff73bdffffc67bffffffc6ffff212173e79c52ffffff7bc6ff212121c67b21ffffffffffff2173bd9c5221ffffde9ce7ff4a214affe79cffffffffff ff4a9cde9c5221ffffdec6ffff212173e79c52ffffffe7ffff214a9c7b2121ffffbdffffffffffffffffffffffff529ce7732121ffffc6ffffffc6ffff212173 e79c52ffffff7bc6ff212121e79c52ffffffffffff73bdff522121ffde9cffffff9cdeff212152bd7321ffffffffffffffffff4a9cde9c5229ffffdeffffff4a 9cde292929de9c4affffff73bdff522929ffde9cffffff73bdffffc67bffffffc6ffff212173e79c52ffffff529ce79c4a21ffffe7ffffff9c9cc6ffffdee7ff ff214a9ce79c52ffffffe7ffff214a9ce79c52ffffffffffff4a9cdec67b21deffff29529cde9c4affffffbdffffe79c9cffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffd6ffffa56ba5ffffd6ffffffff ffffffffffffffffffffffffffffc6bdefffffd6d6ffffa56ba5ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffe7e7e7e7e7e78484ff0000ffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3939ff0000ff0000ff0000ff1010ff7b7384 f7deadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ffe7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21adbd21ffffdedeffff4abd9c42bd214abd2142bd214abd2142bd214a bd21a5bd21ffffdedeffff4abd9c42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d6636363ffd6a5ffffffff ffffd6f7ff7384ad737b7bdead84fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d6d69c63ffffffffffffbdefff9c63 84ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffefffff6384bdffd6a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffefffff6384bd846b6bffe7bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffffce949cefb55affffffffffffefffff c6949cefb563ffffffd6c6ffce8442ffffb5ffffffffffffffffffffffffd6d6ffce8463ffde9cffffffffffffffffffffffffffffffffffffffffffceb5d6de 9442ffffd6ffffffffffffffffffffffffd6c6ffc68442ffc67bffffffffffffc6a5b5de9442ffffd6ffffffceb5d6ffde9cffffffefffffc6949ce7a542ffff ffefffffc6949cde9442ffffd6ffffffceb5d6ce8c42dea542ffffffefffffce949cdea542ffffffffffffcea5b5dea542ffffffdeffffce8c7bce8442ffffb5 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ef8421ffffdeefadbdffffded6c6d6d68c21d68421ffef9cd6c6d6d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21f7ad21f7ffefd68463d68c21 d68421d68c21d68421f7ad21f7ffefd68c9cd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421f7b521f7ffefd68c9cd68421d68c21d68421ffde6befefffd68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21ffde63efefffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffef9ce7deefd68421d68c21d68421d68c21d68421ffce21efefffd68c21d68421d68c21d68421d6 8c21ffde63efefffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffff ffffffffffffffffffffffffffd68c21ffffffffffffffffffffffffdec6ffde8c21ffffb5ffffffffffffffffffe7ffffd68c6bffc66bffffffffffffffffff dec6ffe79c21ffffd6ffffffffffffffffffffffffefffffd69494ffc673ffffffffffffffffffdec6ffde8421ffffb5ffffffffffffd6b5d6e79421efffd6d6 9c94e7a521ffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffffffff9cd6ff846b6bffe7bdffffffffff ffffffffffffffefffff6384bdd6a56bffffffffffffffffffffffffffffffd6ffff63639cffd6a5ffffffffffffffffffffffff639cd6d6a56bffffffffffff ffffffffffffffffffe7e7e7e7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cdebd73214a9c212121212121ff bd73ffffff2173bd212121212121212121bd9c4a214a9c212121212121212121ffbd739cdeff73214a9cdebd21214a2121214a2121ffde9cffffffffffff73bd ff212121212121bd7321ffffff9cdeff21214affbd73ffffffffffffffffff2173bdde9c4affffffffffffffffff9cdeff73214affffbdffffff2173bdde9c4a 2173bd212121212121ffbd73ffffffffffffffffff2173bd212121212121212121ffbd73ffffff9cdeff21214a212121212121732121ffffbdffffff2173bd21 21212121219c4a21ffffdeffffff73bdff9c4a2173bdde212121212121732121ffffbdffffff9cdeff4a214affde9cffffffffffff4a9cde9c4a21ffffdeffff ff9cdeff21214a2121214a21219cbd9c73214affffbdffffffffffffffffffffffffffffff4a9cde212121212121212121de9c4affffffffffff73bdff9c4a21 4a9cbd212121de9c4affffff4a9cde2121212121219c4a214a9cbdbd7321ffffffffffffffffffbdffff4a2173ffde9cffffff4a9cdebd73214a9cde21212121 2121de9c4affffffffffffffffff2173bd2121212121219c4a21ffffdeffffffffffff2173bd212121212121ffbd73bdffff2121732121212121214a2121739c 9c4a2121ffde9cffffffffffff9cdeff4a214affde9cbdffff212173212121732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffd6ffff9c639cd6ffd663639c6b6b6b6363636b6b6b9c6363ff ffd6ffffffffffffd6ffffa56ba5ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dede8484ff0000 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2129ff0000ff0000ff0000ff0000ff1818ef7b737bf7d6adffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000ffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd21 4ac6294abd214ac62142bd214ac6294abd214ac62142bd21adc629ffffd6e7ffff42bd9c4ac6294abd214ac6214abd21cef7734abd94adc621ffffd6e7ffff4a bd9c4ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac6 2142bd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d66b6b6bffd6a5ffffffffffff8caddeffdeadffffff84 addeffdeadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5d6d6a56bffffffffffff84bdefa56b6bffffd6ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7ffff6b8cbdffd6a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffff6ba5d6846b6bffefbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6949cefb563ffffffffffffffffffcea5bddea542ffffffd6c6ff d68c4affffb5ffffffffffffffffffffffffd6c6ffd68442ffffbdffffffffffffffffffffffffffffffffffffffffffd6b5d6d69442ffffd6ffffffffffffff ffffffffffffffffdedeffc68463ce8c42c68442de9c4affffd6ffffffffffffefffffc6949cce8c42c68442de9c4affffd6ffffffffffffefffffc6949cce8c 42c68442efb563c6a5b5e7a542ffffffffffffffffffcea5bdc68442ce8c4ad69442ffffd6ffffffe7ffffc6847be7c684c6847bd68c4affde9cffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21ef8c21ffffd6fffff7efefffd68c21d68421d68c29ffef9cd6ceded68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421ffb529f7f7efd68c6bd68421d68c29d68c21d68c21f7ad21 fffff7d68c9cd68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29f7ad21ffffefd6849cd68c29d68c21d68c21ffde6bf7efffd68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21ffe76befefffd68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421ffef9ce7deefd68c21d68421d68c29d68c21d68c21ffce21f7efffd68c21d68c21d68421d68c29d68c21ffe76befefffd68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21ffffffffffffffffffffffffffff ffd68421ffffffffffffffffffffffffdeceffde8c21ffffb5ffffffffffffffffffefffffd6846bffce73ffffffffffffffffffdeceffde9421ffffd6ffffff ffffffffffffffffffefffffd69c94ffc66bffffffffffffffffffdec6ffde8c21ffffb5ffffffffffffdeb5d6de9421f7ffded69494ffc673ffffffffffffff ffffffffffffffffffffffffffffffffffffffffd68c29e7e7e7ffffffffffffffffffffffffa5d6ffbd846bffffefffffffffffffffffffffffffefffff6b8c bdffd6a5ffffffffffffffffffffffffffffffd6ffff6b6ba5ffd6a5ffffffffffffffffffffffff6ba5d6d6a56bffffffffffffffffffffffffffffffe7e7e7 e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff29529cffbd73ffffffffffffffffffffffffffffffffffff529ce79c 4a21ffffe7ffffffffffff2173bdc67b21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff73bdff9c5221ffffdeffffffffffffe7ffff214a9cffc67bffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffff212173ffc67bffffffffffffffffffffffffffffffffffffffffffffffffff ffff7bc6ff9c4a21ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff217bc6de9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff214a9ce79c52ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffd6ffffa56ba5ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffd6ffffa5 6ba5ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e78484ff0000ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff8c94ff0000ff0000ff0808ff0000ff0000ff0000ff3131d69c7b7bfff7ceffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffff8484ff0000ffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd21d6de42fffff7f7fff763e7d642bd214abd214abd21f7ef73deffff4abd9cced631ffffefd6ffff4abd8c42bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffd6f7ff7384ad737b7bdead84fffff7ffffff7baddeffdeadffffff7baddeffdeadffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff6ba5d66363636b6b6b636363846b6bffe7bdffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff 6384bdffd6a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffefffffce949ce7b55affffffffffffffffffc6a5b5dea542ffffffd6c6ffce8442ffffb5ffffffffffff ffffffefffffc6949cefb563ffffffffffffffffffffffffffffffffffffffffffffffffceb5d6de9442ffffd6ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcea5b5dea5 42ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21ef8421ffffdef7ffffd68c9cd68421d68c21d68421ffef9cd6c6d6d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ef8421ffffded6adbdd68c21ffde63efefffd68421f7b521f7ffefd68c9cd68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421f7ad21f7ffefd68c9cd68421d68c21d68421ffde6befefffd68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffde 63efefffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 ffef94e7deefd68421d68c21d68421d68c21d68421f7b521f7ffefd68c9cd68421ffef9cdedeefd68c21ffde63efefffd68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffffffffffffffffffffffffffffffd68c21ffffffffffffffff ffffffffdec6ffde8c21ffffb5ffffffffffffffffffe7ffffd68c73ffc66bffffffffffffffffffdec6ffe79421ffffd6fffffffffffffffffffffffff7ffff d6948cffc66bffffffffffffffffffdec6ffde8421ffffb5ffffffe7ffffd6846bf7b54affffffdeb5d6de9421ffffd6ffffffe7ffffe7a56bffffffffffffff ffffffffffffffffd68421e7e7e7ffffffffffffffffffffffffd6ffff6b6ba5ffd69cffffffffffffa5bdefffe7bdffffff84bde7bd846bffffe7ffffffd6ff ffd6a5a5ffffffd6ffff63639cffd6a5ffffffffffffffffffffffff639cd6d6a56bffffffffffffffffffffffffffffffe7e7e7dededeffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffdeffff214a9cffbd73ffffffffffffffffffffffffffffffffffff4a9cde9c4a21ffffdeffffffffffff21 73bdbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffbdffff212173ffbd73ffffffffffffffffff4a9cde9c4a21ffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff9c4a21ffffdeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffff73bdff732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cde9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffff ffffffffffffffffffffffffffffffd6ffff63639c6b6b6b6363636b6b6b6363636b6b6b6363636b6b6b6363636b6b6b636363a56b6bffffd6ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7dedede8484ff0000ffffffffffffffffffffffffffffffffffffffffffffffff ffffffffdedeff1818ff0000ff0808ff9cc6ff3939bd0000ff0000ff0000ff7b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffff6363ff0000ffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff42bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6299cbd21 d6ffd642bd849cc629d6ffce4ac68c52bd21f7f77bffffffffffffffffffffffffffffff94f7f742bd294ac6294abd214ac62142bd214ac6294abd214ac62142 bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffff8caddeffdeb5ffffff84b5e7ffdeadffffffceefff737b9c737373c69c7bffffefffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffefffffc6949cefb563ffffffffffffd6c6ffce8c42ffc67bffffffd6c6ffd68c42ffffb5ffffffffffffdedeffc68463e7a54affffff ffffffffffffffffffffffffffffffffffffffffffffffffceb5d6d69442ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6a5b5e7a54affffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffd68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21ffde6bffffffefefffffe76befefffd68c29f7ad21ffffefd6849cd68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421ffe76befefffd68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21ffef9ce7deefd68c29d68c21 d68c21d68421d68c29d68c21ffef9cffffffe7e7f7ffef9ce7e7efd68421ffe76befefffd68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421ffffffffffffffffffffffffffffffd68c21ffffffffffffffffffffffffdec6ffde8421ffff b5ffffffffffffffffffefffffd68c6bffc673dedeffd68c4ad68c21d68c21d68421d68c29d68c21e79c21d6a594d68c29d68c21d68c21d68421d68c29d68c21 ffc673dec6ffd68c29d68c21d68c21d68421efad29ffffffffffffffffffdebdded68c21d68c21de8421ffffb5ffffffffffffffffffffffffffffffd68c21e7 e7e7ffffffffffffffffffffffffffffffd6ffff6b6ba56b6b6b6b6b6befbd84ffffffffffffffffff84bdef6b6b6b6b6b6ba56b6bffffd6ffffffd6ffff6b6b a5ffd6a5ffffffffffffffffffffffff6ba5d6d6a56bffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffdeffff21529cffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff297b c6bd7321ffffffffffffffffff9cdeff522152ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bc6ff9c4a21ffffe7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffc6ffff212173ffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffd6ffff6b6ba58c6b6bffefc6ffffffffffffffffffffffffffffffffffffbdefff6b6b8ca56b6bffffd6ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffe7e7e7e7e7e78484ff0808fffffffffffffffffffffffffffffffffffffffffffffffffff7f7ff2929ff0000ff0000 ff8484ffaddeff7b7b7b3939c60000ff0000ff0000ff5252fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5a5aff0808ff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd219cbd21d6ffce4ac6949cbd21deffd6 42bd8c52bd21efef6bfffffffffffffffffff7ffffa5f7ef42bd424abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 7baddeffdeadffffff7baddeffdeadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ff ffce949cc68442ce8c42c68442ce8442ffc67bffffffffffffd6c6ffc68442ce8c42c68442ce8442ce8442ffde9cffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffceb5d6de9442ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcea5b5dea542ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21ffffffffffffffffffffffffffffffd68c21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffe7ffff6b7bb56b6b6b 6363636b6b6bb57b6bffffe7e7ffff6b84bd6363636b6b6b636363bd846bffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffe7e7e7e7dede8484ff0000fffffffffffffffffffffffffffffffffffffffffffff7f7ff4242ff0000ff0000ff1818ffffffffadd6ff7b7b7b7373 734239de0000ff0000ff0000ff1818ffbdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffff4242ff2121ffe7dedeffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd214ac62142bd214ac6294abd214ac6 2142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac6214abd21efef73fffff7f7ffff84efde4ac6314abd2152c621efef6b e7ffff4abd9c4ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294a bd214ac62142bd214ac6294abd214ac62142bd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff7394b57b7373deb594 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21ffffffffffffffffffffffffffffffd68421ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c29e7e7e7ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff8c73a5ffefbd c6efffa56b8cffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e784 84ff0000ffffffffffffffffffffffffffffffffffffffffffff4a4aff0000ff0000ff0000ffb5b5ffffffffb5deff7b7b7b7b7b7bd6ad844a4aff0000ff0000 ff0000ff0000ff6b6bffffffffffffffffffffffffffffffffffffffffffffffffff1818ff2121ffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd2152bd21bde76b4abd8c42bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffffffffffffffffffff ffffffffffd68c21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffe7e7e7dededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff94c6e76b6b7b736b63e7c694ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7dedede8484ff0000ffffffffffffffff fffffffffffffffff7f7ff4a4aff0000ff0000ff0000ff9c9cffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff0000ff0000ff0000ff3939 fff7f7fffffffffffffffffffffffffffffffff7f7ff0000ff3939ffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff42bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6 294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21 4ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421ffffffffffffffffffffffffffffffd68c21ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffd68c21e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e78484ff0000ffe7e7ffffffffffffffffffffffffff4a4aff00 00ff0000ff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffffffffffffffceceff2929ff0000ff0000ff0000ff3131fff7f7ffffffffffff ffffffffffffffceceff0000ff5a5affe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21ffffffffffffffffffffffffffffffd68c21ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff d68421e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dedeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dede8484ff0000ffc6c6fffffffffffffff7f7ff4a4aff0000ff0000ff0000ff8484ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6b6bff0000ff0000ff0000ff3131fff7f7ffffffffffffffffffff8484ff0000 ff7b7bffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a bd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac6 2142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd21 4ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffde9c42d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c31ffffffffffffffffffffffffffffffd68421ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c29e7e7e7ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7e7e7e7e7a5a5ff0000ff9494ffffffffefefff3939ff0000ff0000ff0000ff6363ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff9c9cff0000ff0000ff0000ff3131fff7f7ffffffffffffff1818ff0000ffadadffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7 e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffdead73d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421deb573ffffffffffffffffffffffffffffffde9c42fff7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffe7e7e7dededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7 dededebdbdff0000ff5a5affceceff1818ff0000ff0000ff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffa5a5ff0000ff0000ff0000ff0808ff5a5aff4a4aff0000ff0000ffd6d6ffe7e7e7ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff42bd214ac6294abd214ac62142bd214ac6294abd214ac62142 bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6 294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd21 4ac62142bd214ac6294abd21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7d68c31d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21 d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c 29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d69431ffefe7ffffffffffff ffffffffffffffffffe7b573efce94ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c21e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffe7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7e7e7dedeff0000ff1818ff 1010ff0000ff0000ff0000ff6b6bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffff9c9cff0000ff0000ff0000ff0000ff0000ff0000ff2121fff7f7f7f7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff4abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd21 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7deb57bde9c4ad68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d69439e7b573f7efe7fffffffffffffffffffffffffffffffffffffffff7 d69439efcea5fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffd68421e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dedeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7e7dedeffffff0000ff0000ff0000ff0000ff0000ff9c9cff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff00 00ff0000ff0000ff0000ff0000ff2929ffd6d6e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff5ac6394ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294a bd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac6 2142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac6215ac639ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefe7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefbd84dea552d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c 21d68421d68c29e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7dedee70808ff0000ff0000ff1010ffadadefe7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7d6d6e73939ff0000ff0000ff00 00ff0000ff3131ffbdbdfff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff84ce6342bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd2184ce6bffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffefefeff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff7b7bff0000ff0000ff0808ffd6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9494ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff94 94ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeff7e752c6294abd21 4ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142 bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6294abd214ac62142bd214ac6 294abd214ac62142bd214ac6294abd214ac62142bd2152c629eff7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffefefeff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffc6c6ff0000ff0000ff0000ff0808ff7b7bfff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff0808ff0000ff0000ff7373ff7373ff0000ff0000ff0000ff3131fff7f7ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f7e784ce6b5ac6394abd2142bd214abd21 42bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214a bd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd214abd2142bd 214abd215ac63984ce6be7f7e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7 e7e7e7e7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7 e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dede dee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7 e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7 e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dede dee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7 e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7 e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedeefe7e7efef efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1818ff0000ff0000 ff0000ff0000ff0000ff1010ff6363ffb5b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffff7b7bff0000ff0000ff4a4affffffffffffffa5a5ff4242ff0000ff0000ff9494ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9494ff0000ff0000ff3939ff2121ff0000ff0000ff0000 ff0000ff0000ff0000ff2929ff4242ff4242ff6363ff8484ffa5a5fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff4242ff 0000ff0000ff2121ffffffffffffffffffffffffffffffff0808ff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3131ff0000ff1010ffe7e7ffe7e7ff7373ff0808ff0000ff0000ff0000ff0000ff0000 ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff3131ff4242ff4242ff0000ff0000ff0000ff0000ff0000ff9c9cffffffff ffffffffffffffffffffffff9494ff0000ff0808ffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffff7f7ff0000ff0000ff9494ffffffffffffffffffffefefff9c9cff5252ff1010ff0000ff0000ff0000ff0000ff0000ff0000 ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff4a4affffffffffffffffffffffffffffffffffffff ffffff0000ff0000ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffdedeff0000ff2121ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdffc6c6ffc6c6ff8c8cff6363ff0808ff0000ff0000ff0000 ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0808ff5252ffb5b5ffffffffffffffffffffffffffffffffffffffffffffffffff3939ff0000ff0000ff c6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ff6363ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff9494ff4a4aff4242ff1010ffadadffffffffc6c6 ffc6c6ffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdff4242ff4242ffd6d6ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff4242ffadadffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffffc6ffffc6ffffc6ffffb5ffff84ff ff84ffff84ffff84ffff84ffff84ffff84ffff84ffffb5ffffc6ffffc6ffffc6ffffceffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffc6ffff8cffff4affff10ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ff ff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff29ffff42ffff73ffff8cffffc6ffffefffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefe7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e794efef6bf7f739ffff39ffff31 ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ff ff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff08ffff39ffff39ffff39ffff39ffff63ffff73f7f773f7f773f7f7 a5efefb5efefe7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffe7dedef7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffff7ffffc6ffffc6ffffc6ffffbdffffc6ffff94ffff5affff10ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 ffff00ffff00ffff00ffff10ffff42ffff42ffff73ffff84ffff84ffff84ffff7bffff84ffff84ffff84ffff7bffff84ffff84ffff7bffff42ffff42ffff39ff ff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff18ffff 42ffff73ffff8cffffc6ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffff7f7f7efe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceffff84ffff42ffff10ffff 00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff31ffff42ffff84ffffbdffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffffb5ff ff84ffff4affff29ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff 00ffff52ffffadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7 efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefe7e7ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffff8cffff42ffff08ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff 00ffff00ffff00ffff00ffff00ffff00ffff4affff9cffffc6ffffc6ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffd6ffffc6ffffbdffffc6ffffc6ffffc6ffff7bffff6bffff42ffff10ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff18ffff 8cfffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffadffff73ffff42ffff18ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff18ffff42ffff42ffff42ffff42ffff73ffff84ffff adfffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffc6ffffa5ffff84ffff52ffff10ffff00ffff00ffff00ffff00ffff00ffff10ffff84fffff7ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5ffff7bffff42ffff08ffff00ffff00ffff00ffff00ff ff00ffff00ffff00ffff00ffff00ffff00ffff39ffff84ffffc6ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5ffff4affff00ffff00ffff00ffff00ffff00ffff10ffff7bfffff7ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffb5ffff63ffff10ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff42ffff84ff ffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffdeffff63ffff00ffff00ffff00ffff00ffff00ffff10ffff84ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffff9cffff21ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff5affffa5ffffbdffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7ffff6bffff08ffff00ffff00ffff00ffff00ffff31fffff7ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7 e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffff29ffff00ffff00ffff00ffff00 ffff00ffff00ffff42ffff8cffffc6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffefffff63ffff00ffff00ffff00ffff00ffff42ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffff63ffff00ffff00ffff00ffff00ffff00ffff4affffa5ffffefffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffdeffff5affff00ffff00ffff00ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffff7ffff31ffff00ffff00ffff00ffff00ffff4affffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84ff ff00ffff00ffff4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff39ffff00ffff00ffff00ffff21ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6bffff00ffff00fffff7ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff94ffff00ffff00ffff00ffff 73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff08ffff00ffffceffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff39ffff00ffff00ffff9cffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5affff00ffff9cffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffff7ffff00ffff00ffff73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffa5ffff00ffff7bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffeff7ffe7e7e7dededef7efe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffbdffff00ffff18fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffd6ffff00ffff5affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdde ff5a73944a4a524242424a4a4a424242735a52d6b58cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffc6efff5a739c5252529c735affefc6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ff94ffff00ffff6bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7effffff7efffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ffff42ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84b5ef424a528c6352cec6a5dededed6de deced6de6b8ca54a4a5ab58452ffffe7ffffffffffffffffffffffffffffffffffffffffffffffff9cd6ff4a4a634242424a4a4a4242429c634affffd6ffffff ffffffffffffd6ffff4a639c4242424a4a4a424242ffb584ffffffffffffffffffffffffffffff9cd6ff424263634a4affd69cffffffffffffffffffffffffff ffffffffffffffffffffffffffff7bb5ff4a4a4a4242424a4a4a7b4242ffffb5ffffffffffffb5ffff4a4a844242424a4a4a7b4242ffffb5ffffffffffff7bb5 ff844a4affffb5ffffffffffff639cd69c6342ffffd6ffffffd6ffff42639cd69c63ffffff9cd6ff634263ffd69cffffffffffff7bb5ff844a4affffb5ffffff ffffff4a84b5b57b42ffffffb5ffff4a4a84ffb57bffffffffffff84b5ff4242424a4a4affb57bb5ffff42427b4a4a4a424242d69c63ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff6ba5e7d69c6bffffff639cd6e7a56bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff427bb54a4a4a 4242424a4a4a4242424a4a4a4242429c634affffd6ffffffffffffffffffffffffffffff427bb54a4a4a4242424a4a4a424242d69c63ffffffffffff9cd6ff63 4a63ffd69cffffffffffffffffff427bb54a4a4a424242b5844a427bb5b5844affffffb5ffff42427bffb584ffffffffffffb5ffff4a4a84ffb57bffffffffff ff9cd6ff4242634a4a4a424242ffb584ffffff84b5ff7b4242ffffb5ffffffffffff7bb5ff844a4affffb5ffffffd6ffff4a639c4242424a4a4a7b4242ffffb5 ffffffffffff427bb54a4a4a4242429c634affffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84ffff00ffffadffffffff ffffffffffffffffffffffffffffffffffffffffffffffffff94c6ef424a6394634affe7c6ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffff639cd64a4a4a9c6342ffffd6ffffffffffffffffffffffffffffffffffffd6ffff4a639cd69c63ffffffffffffffffff9cd6ff4a 4a63b57b42ffffffd6ffff4a639c4242424a4a4a7b4242ffffb5ffffffd6ffff42639cd69c63ffffffffffff9cd6ff4a4a634242424a4a4ab57b42ffffffffff ffb5ffff42427b4a4a4a424242b5b58442427bffb584ffffff84b5ff4242424a4a4a634242ffd69cffffffffffffb5ffff4a4a844242424a4a4a9c6342ffffd6 ffffffd6ffff42639c4a4a4a424242b5844affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff18ffff21ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84bdf74a4252d69c6bfffff7d6ffff42639c634a4affd69cffffffa5cef74a52 73b57b52ffffefffffffffffffffffffffffffffffffffffffffffff639cd64242424a4a4a4242424a4a4a424242844a4affffb5ffffffd6ffff4a639c424242 4a4a4a4242424a4a4a424242ffbd84ffffffffffffffffffffffff9cd6ff4a4a63634242ffd69cffffffffffffffffffffffffffffffffffffffffffffffff42 7bb5634a4affd69cffffffffffffbdffff7b427bffffbdb5ffff4a4a84b57b42ffffffffffff84bdff634242ffd69cffffff84bdff7b4242ffffbdffffffffff ff639cd69c634affffd6ffffffd6ffff4a639cd69c63ffffff9cd6ff634a63ffd69cffffffffffff84bdff7b4242ffffbdffffffffffff427bb5bd844affffff bdffff42427bffbd84ffffffd6ffff42639cbd844affffffffffff7b9cd6ffd69cffffffbdffff42427bffbd84ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ba5e7efad 73ffffff73adefe7a56bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a84bd4242424a4a4a4242424a4a4a424242 4a4a4a9c6342ffffd6ffffffffffffffffffffffffffffff4a84bdb57b42ffffffffffffbdffff42427bd69c63ffffff9cd6ff634263ffd69cffffffffffff7b b5ff634a4affd69cffffff7bb5ff4a4a4ab57b42ffffffb5ffff4a4a84ffb57bffffffffffffbdffff42427bffbd84ffffff9cd6ff424263d69c63ffffffffff ff7b7bb5ffffbd7bb5ff844a4affffb5ffffffffffff84bdff7b4242ffffbdffffff4a84bd7b4242ffffbdffffffbdffff9c637bffffd69cd6ffd69c84ffffff ffffff427bb5bd844affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bffff00ffffdeffffffffffffffffffffffffffffffff ffffffffffffffffffff94ceef6b5263ffd6a5639cce946b52ffefc6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 639cd64242429c634affffd6ffffffffffffffffffffffffffffffffffffd6ffff42639cd69c63ffffffffffffffffff4a84bd7b4242ffffbdffffff4a84bd7b 4242ffffbdffffffbdffff9c637bffffd6d6ffff4a639cd69c63ffffffb5ffff4a4a84b57b42ffffffffffff84bdffd69c63ffffff427bb59c634affffd6ffff ff427bb54a4a4affb57bd6ffff9c7b9cffffd6ffffff84bdff7b4242ffffbdd6ffff4a639c9c6342ffffd6ffffff9cd6ffb57b63ffffff7bb5ffffbd84ffffff d6ffff42639cd69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff39ffff00ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffc6ffff425284ce945affffffffffffd6ffff4a639c634242ffd69cffffffffffff8cc6ff524a5affbd84ffffffffff ffffffffffffffffffffffffffffffff7b9cd6ffd69cffffffffffff9cd6ff4a4a63424242d69c63ffffff84b5ff4242424a4a4affb57bffffff427bb54a4a4a 9c6342ffffd6ffffffffffffffffff9cd6ff424263634a4affd69cffffffffffffffffffffffffffffffffffffffffff7bb5ff634a4affd69cffffffffffffff ffffffffffffffffffffff639cd69c6342ffffd6ffffffffffffffffff4a84b5b57b42ffffff7bb5ff844a4affffb5ffffffffffff639cd69c6342ffffd6ffff ffd6ffff42639cd69c63ffffff9cd6ff634263ffd69cffffffffffff7bb5ff844a4affffb5ffffffffffff4a84b5b57b42ffffffb5ffff4a4a84ffb57bffffff d6ffff4a639cd69c63ffffffffffffffffffffffffffffffd6ffff4a639cd69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff5a6b9c5a5a5a5a4a4affce94ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bb5ff4a4a4a424242ffb584ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffff427bb5b5844affffffffffffffffff639cd69c6342ffffd69cd6ff634a63ffd69cffffffffffff84b5ff7b4242ffffb5ffffffff ffff427bb5b5844affffffb5ffff42427bffb584ffffffffffffb5ffff4a4a84ffb57bffffff427bb5b5844affffffffffffffffffffffffffffff84b5ff7b42 42ffffb5ffffffffffff7bb5ff844a4affffb59cd6ff424263ffb584ffffffffffffffffffffffffffffffffffffffffffffffffffffff639cd69c6342ffffd6 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff94c6ef6b52 63ffd6a5ffffffffffff639cce94634affe7c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff639cd64a4a4a9c6342ffffd6 ffffffffffffffffffffffffffffffffffffd6ffff4a639cd69c63ffffffffffff9cd6ff424263ffb584ffffff9cd6ff424263ffb584ffffffffffffffffffff ffffffffffd6ffff42639cd69c63ffffff639cd67b4242ffffb5ffffffffffffffffffffffffffffff4a84b5b57b42ffffffffffffb5ffff42427bffb584ffff ffffffffffffffffffff9cd6ff634a63ffd69c84b5ff634242ffd69cffffffffffffffffffffffffffffffffffffffffffffffffffffff4a84b5b57b42ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff5affff00fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffff73adef84524affefb5ffffffffffffd6ffff42639c634a4affd69cffffffffffffffffff5284bdad734affffe7ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff427bb54a4a4ab57b42ffffff427bb54a4a4a9c6342ffffd6ffffff9cd6ff424263634a4affd69cffffffffffff ffffff9cd6ff4a4a63634242ffd69cffffffffffffffffffffffffffffffffffffd6ffff4a639cb57b42ffffffffffffffffffffffffffffffffffffffffff42 7bb5bd844affffffffffffffffffffffff639cd69c634affffd684bdff7b4242ffffbdffffffffffff639cd69c634affffd6ffffffd6ffff4a639cd69c63ffff ff9cd6ff634a63ffd69cffffffffffff84bdff7b4242ffffbdffffffffffff427bb5bd844affffffbdffff42427bffbd84ffffffd6ffff42639cd69c63ffffff ffffffffffffffffff639cd64a4a4a634242ffd69cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff639cd64242424a4a4a4242424a4a4a6b524adeb58cffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffff427bb54a4a4a424242d69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffff 4a84bdb57b42ffffffffffffffffff7bb5ff9c634affffd69cd6ff634263ffd69cffffffffffffb5ffff4a4a84d69c63ffffffffffff4a84bdb57b42ffffffb5 ffff4a4a84ffb57bffffffffffffbdffff42427bffbd84d6ffff4a639cd69c63ffffffffffffffffffffffffffffff7bb5ff844a4affffb5ffffffffffff84bd ff7b4242ffffbd7bb5ff844a4affffb5ffffffffffffffffffffffffffffffffffffffffff9cd6ff4a4a63424242d69c63ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffff63ffff10ffffffffffffffffffffffffffffffffffffffffffffff94ceef735263ffdeadffffffffffffffffffffff ff639cce946b52ffefc6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff639cd64242429c634affffd6ffffffffffffffffffffffff ffffffffffffd6ffff42639cd69c63ffffffffffff427bb59c634affffd6ffffff7bb5ff844a4affffb5ffffffffffffffffffffffffffffffd6ffff4a639cd6 9c63ffffff427bb5bd844affffffffffffffffffffffffffffffffffff7bb5ff634a4affd69cffffffb5ffff4a4a84ffb57bffffffffffffd6ffff42639c4a4a 4a9c6342ffffd6639cd69c634affffd6ffffffffffffffffffffffffffffffffffffffffff7bb5ff4a4a4a424242ffbd84ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff7bffff00ffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a7bb5b57b4aff ffffffffffffffffd6ffff4a639c634242ffd69cffffffffffffffffff84b5ff7b424affffb5ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff9cd6ff4a4a63424242d69c63ffffff4a84b5424242b5844affffffffffffb5ffff4a4a84424242ffb584ffffffffffffffffff9cd6ff424263634a4a ffd69cffffffffffffffffffffffffffffffffffffb5ffff42427bffb584ffffffffffffffffffffffffffffffffffffffffff4a84b5b57b42ffffffffffffff ffffffffff639cd69c6342ffffd67bb5ff844a4affffb5ffffffffffff639cd69c6342ffffd6ffffffd6ffff42639cd69c63ffffff9cd6ff634263ffd69cffff ffffffff7bb5ff844a4affffb5ffffffffffff4a84b5b57b42ffffffb5ffff4a4a84ffb57bffffffd6ffff4a639cd69c63ffffffffffff9cd6ff4242634a4a4a ffb57bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffff639cd64a4a4a635a4a4a525a4242424a4a4a4a4242d69c63ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffff639cd64a4a4a424242844a4affffb5ffffffffffffffffffffffffffffffffffffffffff427bb5b5844affffffffffff b5ffff4a4a84d69c63ffffff9cd6ff634a63ffd69cffffffffffffffffffd6ffff4a639c4242424a4a4a424242b5844affffffb5ffff42427bffb584ffffffff ffffb5ffff4a4a84ffb57bd6ffff42639cd69c63ffffffffffffffffffffffffffffff84b5ff7b4242ffffb5ffffffffffff7bb5ff844a4affffb584b5ff4242 424a4a4a4242424a4a4a4242424a4a4affb57bd6ffff42639c4a4a4ab57b42ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffff63ffff21ffffffffffffffffffffffffffffffffffffffff94c6ef7b5263ffe7b5ffffffffffffffffffffffffffffffffffff639cce94634affe7 c6ffffffffffffffffffffffffffffffffffffffffffffffffffffff639cd64a4a4a9c6342ffffd6ffffffffffffffffffffffffffffffffffffd6ffff4a639c d69c63ffffff7bb5ff634a4affd69cffffffffffff84b5ff4242424a4a4a4242424a4a4a4242424a4a4affb57bd6ffff42639cd69c63ffffff4a84b54242424a 4a4a4242424a4a4a424242844a4affffb5ffffff9cd6ff4a4a634242424a4a4a424242ffb584ffffff639cd6424242844a4affffb5ffffffffffff639cd64242 424a4a4a4242424a4a4a424242634a4affd69cb5ffff42427b4a4a4ad69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff8cffff00ffffc6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff42639cd69c63ffffffffffffffffffd6ffff42 639c634a4affd69cffffffffffffffffff9cd6ff634a63ffd69cffffffffffffffffffffffffffffffffffffffffff7bb5ff4a4a4a4242424a4a4a424242bd84 4affffffd6ffff42639c4a4a4ab57b42ffffffffffffbdffff42427b4a4a4affb57bffffffffffffffffff9cd6ff4a4a63634242ffd69cffffffffffffffffff ffffffffffffffffffb5ffff4a4a84ffb57bffffffffffffffffffffffffffffffffffffffffff639cd6844a4affffb5ffffffffffffffffff427bb5bd844aff ffff84bdff634242ffd69cffffffffffff639cd6844a4affffb5ffffffd6ffff4a639cd69c63ffffff9cd6ff4a4a63ffb57bffffffffffff84bdff634242ffd6 9cffffffffffff427bb5bd844affffffbdffff42427bffbd84ffffffd6ffff42639cd69c63ffffffffffff639cd69c634affffd6ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffff639cd6424242d69c63ffffffffffff94c6e74a4a6b734a42fff7b5ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff9cd6ff4a4a63424242844a4affffb5ffffffffffffffffffffffffffffffffffff4a84bd4242424a4a4a4242424a4a4affb57bffffffffffff 9cd6ff424263ffbd84ffffffffffffffffffffffffffffffffffffffffff4a84bdb57b42ffffffb5ffff4a4a84d69c63ffffffffffffbdffff42427bffbd84ff ffff639cd69c6342ffffd6ffffffffffffffffffffffff7bb5ff634a4affd69cffffffffffff84bdff7b4242ffffbd9cd6ff634a63ffd69cffffffffffffbdff ff63427bffd69c9cd6ff634a63ffd69cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63ffff21ffffff ffffffffffffffffffffffffffff94ceef7b5263ffefbdffffffffffffffffffffffffffffffffffffffffffffffff4a7bb5dea56bffffffffffffffffffffff ffffffffffffffffffffffffffffffff639cd64242429c634affffd6ffffffffffffffffffffffffffffffffffffd6ffff42639c4a4a4a4242424a4a4ab57b42 ffffffffffffffffff9cd6ff634a63ffd69cffffffffffffbdffff63427bffd69cd6ffff4a639cd69c63ffffff639cd69c634affffd6ffffffffffff84bdff9c 6342ffffd6ffffffffffffffffffffffffb5ffff4a4a84ffb57bd6ffff42639cd69c63ffffffffffffffffffffffff7bb5ff844a4affffb5ffffffffffff9cd6 ff7b4263ffffbd7bb5ff844a4affffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadffff00ffffa5ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff4a639cd69c63ffffffffffffffffffd6ffff4a639c4242424a4a4a42424263 4a4affd69c9cd6ff634263ffd69cffffffffffffffffffffffffffffffffffffffffff84b5ff4242424a4a4a424242634a4affd69cffffffffffff4a84b54242 42b5844affffffffffffb5ffff4a4a84424242ffb584ffffffffffffffffff9cd6ff424263634a4affd69cffffffffffffffffffffffffffffffffffffd6ffff 42639cd69c63ffffffffffffffffffffffffffffffffffffffffffb5ffff42427bb5844affffffffffff7bb5ff634a4affd69cffffff7bb5ff4a4a4ab57b42ff ffffb5ffff4a4a84424242d69c63ffffff9cd6ff424263ffb584ffffff9cd6ff4242639c634affffd6d6ffff42639c4a4a4ab57b42ffffffb5ffff4a4a84d69c 63ffffffb5ffff4a4a84ffb57bffffffd6ffff4a639cd69c63ffffffffffff84b5ff7b4242ffffb5ffffff9cb5ffffd69cffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffff639cd64a4a4ad69c63ffffffffffffffffff528cc64a4a4aefad73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9cd6 ff4a4a63424242d69c63ffffffffffffffffffffffffffffffffffff427bb5b5844affffffffffff639cd69c634affffd6ffffff9cd6ff4a4a639c6342ffffd6 ffffffffffff7b7bb5ffffb5ffffffb5ffff42427bd69c63ffffffb5ffff42427b634a4affd69cffffff639cd6634a4affd69cffffffb5ffff4a4a84d69c63ff ffffffffff9c9cd6ffffb584b5ff4242429c634affffd6d6ffff42639c9c634affffd6ffffff427bb59c634affffd6ffffff639cd69c634affffd6b5ffff4242 7bffb584ffffffb5ffffd69c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63ffff21ffffffffffffffffffffffffffff9c d6ff7b5a63ffefb5ffffffffffffffffffffffffffffffffffffffffffffffff639ccea5735affffceffffffffffffffffffffffffffffffffffffffffffffff ffffffff639cd64a4a4a9c6342ffffd6ffffffffffffffffffffffffffffffffffffd6ffff4a639cd69c63ffffffffffff84b5ff7b4242ffffb5ffffffffffff 427bb59c634affffd6ffffff639cd69c634affffd6d6ffff42639cd69c63ffffffb5ffff42427bd69c63ffffffd6ffff42639cd69c63ffffffb5ffffb57b7bff ffffffffff84b5ff634242ffd69cffffff4a84b5b57b42ffffffffffff9c9cb5ffffd6d6ffff42639cb5844affffffffffff427bb5b5844affffff9cd6ff6342 63ffd69cffffff9cd6ffffb59cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffff00ffffa5ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7 e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff42639c4a4a4a4242424a4a4a634242ffd69c73adef844a4aff ffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84bdff424242844a4affffb5ffffff639cd64a4a4a9c6342ffffd6ffffff9cd6 ff424263634a4affd69cd6ffff42639c9c634a9cd6d64a4a63634242ffd69cffffffffffffffffffffffffffffffffffffffffff4a84bdb57b42ffffffffffff ffffffffffffffffffffffffffffffffffffd6ffff42639c4a4a4a424242634a4affd69cffffffffffff84bdff7b424284bdbd4242424a4a4a9c6342ffffd642 7bb54a4a4a424242bd844affffffffffff9cd6ff634a639cb59c4a4a63424242844a4affffb5639cd64242424a4a4a9c6342ffffd6ffffffbdffff42427bffbd 849cd6ff4a4a634242424a4a4a424242ffbd84ffffff639cd64242424a4a4ab57b42ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff639cd6424242d69c63ff ffffffffffceffff5a73a5525a52a5735affffceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff42639c4a4a4a9c6342ffff d6ffffffffffffffffffffffffffffff4a84bdb57b42ffffffffffffbdffff42427bffbd84ffffff9cd6ff6342639cbd9c424263844a4affffb5bdffff42427b 4a4a4a424242bd844affffffffffffb5ffff4a4a84d6b57b4a639c4242424a4a4ad69c63ffffffffffffffffffb5ffff4a4a844242424a4a4ad69c63ffffff7b b5ff844a4a9cd6b54a4a63424242634a4affd69cffffffffffffffffff639cd64a4a4a424242844a4affffb5ffffffffffff9cd6ff4242634a4a4a7b4242ffff bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63ffff08ffffffffffffffffffffffffffff5a84bdffce94ffffffffffffff ffffffffffffffffffffffffffffffffff6b9ccead735affffd6ffffffffffffffffffffffffffffffffffffffffff9cd6ff4a4a63d69c63639cd64242429c63 4affffd6ffffffffffffffffffffffffffffffffffffd6ffff42639cd69c63ffffffffffffd6ffff4a639cd69c63ffffffffffffffffff639cd64a4a4a424242 844a4affffb5ffffffd6ffff4a639cd69c63ffffffffffffd6ffff42639c4a4a4a424242bd844affffffffffffffffff84bdff4242424a4a4a424242ffbd84ff ffffffffffd6ffff4a639c4242424a4a4affb57bffffffffffffffffff427bb54a4a4a4242429c634affffd6ffffffffffff84bdff4242424a4a4a9c6342ffff d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff00ffffa5ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffd6ffff4a639c4242424a4a4ab57b52ffffe7ffffffffffffffffffffffffffffffffffffe7ffff4a7badad734afffff7ffffffffffffffffffff ffffffffffffffffb5ffffb58484ffffffffffff9cd6ff4a4a63424242ffb584ffffff84b5ff4242424a4a4affb57bffffff427bb54a4a4a7b4242ffffb5d6ff ff4a639c4242424a4a4a424242634a4affd69cffffffffffffffffffffffffffffffffffffffffff9cd6ff4a4a63ffb57bffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff4a639cd69c 63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff639cd64a4a4ad69c63ffffffffffff73a5e7e7a56bff ffff73a5e7e7a573ffffffffffffffffffffffffffffffffffff9cd6ffb58463ffffffffffffb5ffff4a4a844242429c634affffd6ffffffffffffffffffffff ffffffff427bb5b5844affffffffffffd6ffff4a639cd69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84b5ff7b4242ffffb5ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffff63ffff00ffffefffffffffffffffffffffff6384b5ffd69cffffffffffffffffffffffffffffffffffffff ffff6b9ccea5735affffceffffffffffffffffffffffffffffffffffffffffffffffff9cd6ff4242634a4a4a4242424a4a4a9c6342ffffd6ffffffffffffffff ffffffffffffffffffffd6ffff4a639cd69c63ffffffffffffd6ffff42639cd69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff 42639cd69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffadffff00ffffa5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff42639c 4a4a4a9c6342ffffd6ffffffffffffffffffffffffffffffffffffffffff84bdef634252ffd69cffffffffffffffffffffffffffffffffffffffffffbdffff42 427b4a4a4a4242424a4a4a424242844a4affffb5ffffffffffff4a84bd4242424a4a4a4242424a4a4a424242d69c63ffffffffffffffffff4a84bd4242424a4a 4a634242ffd69cffffffffffffffffffffffffffffffffffffffffffffffff7bb5ff4a4a4affb57bffffffffffffbdffff7b427bffffbdffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff42427bd69c63ffffffd6ffff42639cd69c63ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffceffff5a73a5525a52a5735affffceffffff6ba5e7e7a56bffffff6ba5e7e7a56bffffffff ffffffffffffffffffffffffffff9cd6ff4242634a4a4a4242424a4a4a4242424a4a4affb57bffffffffffffffffffffffffffffffffffff4a84bdb57b42ffff ffffffff84bdff634242ffd69cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bb5ff844a4affffb5ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffff7bffff00ffffceffffffffffffffffffffff637bb5ffd69c427bb54a4a4affb57bffffffffffffffffff73a5cead7363ffffd6ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff42427b4a4a4a4242429c634affffd6ffffffffffffffffffffffffffffffffffffd6ff ff42639cd69c63ffffffffffff7bb5ff4a4a4affb57bffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff4a639cd69c63ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff31ffff00ffffa5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff4a639c8473524a527bbd8c63ffffe7 ffffffffffffffffffffffffffffff7badde4a4a52d69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffff4a84b54242424a4a4a42424284 4a4affffb5ffffffffffffffffffffffff4a84b54242424a4a4a424242d69c63ffffffffffffffffffffffffffffffd6ffff42639c634a4affd69cffffffffff ffffffffffffffffffffffffffffffffffffffffffffb5ffff4a4a844242424a4a4a634242ffd69cffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffb5ffff4a4a84d69c63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff73a5e7efad73ffffff73adefe7a573ffffffc6f7ff52638c524a528c6352fff7c6ffffffffffffffffffffffffffffffff ffffffffff84b5ff4242424a4a4a4242424a4a4affb57bffffffffffffffffffffffffffffffffffffffffff427bb54a4a4a4242424a4a4a424242ffb584ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff84b5ff7b4242ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8cffff 00ffff84ffffffffffffffffffffff6384b5ffd69c4a84b5424242ffb584ffffffffffff6ba5cea57363ffffceffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffff9cd6ff4a4a639c6342ffffd6ffffffffffffffffffffffffffffffffffffd6ffff4a639c4242424a4a4a4242 424a4a4affb57bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff42639cd69c63ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4affff00ffff00ff ffadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffffad94a5ffffdea5d6ff4a52736b524ab5a594e7cebdd6e7e79cadbd 526b8452424acea573fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff6ba5e7e7a56bffffff6ba5e7e7a56bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5ffff00ffff08ffffe7ffffffffff ffffff7badefd69c6bffffffffffffffffffffffff73addead7363ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4affff00ffff00ffff08ffffefffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6f7ff738cb54a4a5a4a4a4a424242524a4a8c6b5af7d6b5ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff5a7bad525252 ad7b5affffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff00ffff00ffff29fffff7ffffffffffefffff739cc64a525a 4242424a4a4a524a42b58c6bffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffff42ffff00ffff00ffff00ffff84ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffff29ffff00ffff00ffff42ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffff4affff00ffff00ffff00ffff63ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffc6ffff00ffff00ffff00ffff9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5ffff73ffff18ffff00 ffff00ffff00ffff6bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff9cffff00ffff00ffff10ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff29ffff00ffff00ffff00ffff00ffff00ffff7bffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63ff ff00ffff00ffff42ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffff9cffff10ffff00ffff00ffff00ffff00ffff00ffff6bffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff18ffff00ffff00ffffadff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffc6ffffc6ffffc6ffffc6ffffc6ffffc6ffffc6ffffc6ffffc6ffff c6ffffc6ffffc6ffffc6fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffff8cffff84ffff84ffff 42ffff39ffff00ffff00ffff00ffff00ffff00ffff39ffff94ffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5ffff00ffff00ffff18ffffefffffffffffffffffffff ffffffffffffffffffffffffffffffffe7ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff 00ffff00ffff29ffff42ffff42ffff42ffff6bffff84ffff8cffffc6ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffa5ffff5affff08ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff 00ffff08ffffadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63ffff00ffff00ffff18ffffa5fffff7ffffffffffffffffffffffffffffffff ffffffffe7ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff 00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff42ffff8cffffc6fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffadffff5affff08ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff52ffffd6ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7ffff10ffff00ffff00ffff00ffff00ffff21ffff42ffff42ffff42ffff42ffff42ffff39ffff00ffff00ff ff00ffff00ffff00ffff31ffff42ffff73ffff84ffff84ffff84ffff7bffff42ffff42ffff42ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff 00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff42ffff42ffff73ffff7bffff9cffffc6ffffc6fffff7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffffa5ffff63ffff10ffff00ff ff00ffff00ffff00ffff00ffff00ffff08ffff4affff84ffffa5ffffbdffffc6ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffadffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffffc6ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffffc6ffffbdffff84ffff84ffff7bffff42ffff08ffff00ffff 00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff39ffff42ffff42ffff73ffff84ffff84ffff84 ffff84ffff84ffff84ffff84ffff84ffff84ffff84ffff42ffff42ffff42ffff21ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff08ffff5aff ffadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffc6ffff5affff18ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff18ffff42ffff42ffffceffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffff7bffff42ffff31ffff00ffff 00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff5affffadffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7 e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffdeffffc6ffffc6ffffc6ffffc6ffffc6ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6ffffb5ffff84ffff 84ffff52ffff42ffff42ffff08ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 ffff00ffff00ffff00ffff00ffff08ffff42ffff73ffffadffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffceffffbdffffc6ffffc6ffffbdffff7bffff84ffff84ffff84ffff7bffff84ffff84ffff84ffff9cffffc6ffffc6ffffc6ffffdeffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeff7f7f7ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7f7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7f7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffff7f7f7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffefefefefefefe7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7f7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2173bd9c4a21ffffdeffffffffffffffffffffffffffffff9cdeff21214affbd73ffffff ffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffdeffff29529c212121212121212121292929212121e79c52ffffffffffffffffffffffffffffffffffffffffffffffff4a9cde292929212121 2121212121219c5229ffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff292929ffbd73ffffffffffffffffffffffffffffff9c deff2929524a2121ffe79cffffffffffffffffffffffff9cdeff292952212121212121212121522929ffde9cffffffffffffffffffffffffffffffffffffffff ff2173bd7b2121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff29297b212121212121212121522929ffde9c ffffffffffff9ce7ff21214a212121212121292929212121212121bd7321ffffff2173bd7b2121ffffbdffffffffffffffffffffffff9ce7ff21214a21212121 2121292929732121ffffc6ffffffffffff4a9cde522121ffde9cffffffffffffffffffbdffff29297b212121e79c52ffffffffffffffffffffffffffffffffff ffffffffffffff4a9cde522929ffde9cffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffc6ffff212173c67b29ffffff ffffff9cdeff2929522121212121212121212929292121219c5221ffffdeffffffffffffffffffffffffffffffbdffff21217b21212129292921212121212121 2121ffc67bffffffffffffffffffffffffffffffffffffffffffffffff2173bd212121212121292929212121c67b21ffffffffffffffffffffffffffffffffff ffffffff7bc6ff2121219c5229ffffdeffffffffffffffffffffffff217bc6212121e79c52ffffffffffffffffffffffff73bdff212121ffbd73ffffffffffff ffffffffffffffffff9cdeff2121524a2121ffe79cffffffffffff2173bd2929292121212121212121212929294a2121ffe79cffffffffffffffffff217bc621 2121292929212121212121bd7321ffffffffffffffffffdeffff29529c732121ffffc6ffffffffffffffffffffffffffffffffffff73bdff212121de9c4affff ff2173bd212121212121292929212121212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff214a9c292929212121 212121212121522929ffde9cffffffffffffffffffffffffffffff9cdeff2929522121212121212121219c5229ffffdeffffffffffffffffffffffffffffffff ffff529ce74a2121ffe79cffffffffffffffffffffffffffffffffffffdeffff21529c9c4a21ffffe7ffffffffffffffffffffffffffffffffffffbdffff2929 7b212121212121212121292929ffbd73ffffffffffffffffffffffffe7ffff214a9c9c5229ffffdeffffffffffffffffffffffffffffff2173bd292929bd7321 ffffffffffff9ce7ff21214ac67b21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde212121212121292929212121c67b21ff ffffffffffdeffff21529cbd7321ffffffffffff7bc6ff4a2121ffe79cffffffffffffffffff529ce7212121212121212121c67b29ffffffffffff4a9cde7b29 29ffffbdffffffffffff529ce7212121522121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7ffff214a9c292929ffbd73ffffffffffffffffffffffff9ce7ff21214a7b2929ffffbdffffffffffffffffffbdffff21217bde9c4affffffffffff529ce773 2121ffffc6ffffffffffff4a9cde2929294a2121ffe79c73bdff522929ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffff217bc69c4a21ffffe7ffffffffffffffffffffffffffffff9ce7ff21214affc67bffffffffffffffffffffffffffffff e7ffff214a9cc67b29ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a 9c9c4a21ffffdeffffffffffffdeffff214a9c4a2121ffde9cffffffffffffffffffffffffbdffff2121734a2121ffde9cffffffffffffffffff2173bd212121 ffbd73ffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121ffbd73ffffffffffffffffffffffffdeffff214a9c2121214a2121ffde9cff ffffffffffffffff2173bd212121de9c4affffffffffffffffff73bdff212121bd7321ffffffffffffffffffffffffffffffffffff2173bd732121ffffbdffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde212121bd7321ffffffffffffffffffdeffff214a9cffbd73ffffff9cdeff21214a de9c4affffffffffffffffffffffffffffffffffff2173bd732121ffffbdffffffffffffffffff2173bd212121de9c4affffffffffffffffffbdffff4a2173ff de9cffffff4a9cde4a2121ffde9cffffffffffffdeffff214a9c212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde4a21 21ffde9cffffffffffffffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffff9cdeff21214ade9c4a ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffffffffffbdffff212173732121ffffbdff ffffffffffffffffffffff9cdeff21214a732121ffffbdffffffffffffdeffff214a9c4a2121ffde9cffffffffffffffffffffffffffffff2173bd2121214a21 21ffde9cffffffffffffffffffbdffff2121732121219c4a21ffffdeffffffffffffffffff73bdff212121ffbd73ffffffffffffffffffffffffdeffff214a9c 2121214a2121ffde9cffffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffffffffff9cdeff21214a732121ffffbdffffffffffffdeffff21 4a9c4a2121ffde9cffffffffffff73bdff212121ffbd73ffffffffffffffffffffffffffffffffffff2173bd732121ffffbdffffff2173bd732121ffffbdffff ffffffffffffff2173bd212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffff73bdff212121 de9c4affffffffffffffffff4a9cde212121de9c4affffffffffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffff4a9cde4a2121ffde9cff ffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffff4a9cde212121bd7321ffffffffffffffffff9cde ff21214a9c4a21ffffdeffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffff73bdff212121212121bd7321ffffffffffff9cdeff21214a bd7321ffffffffffffffffffffffffffffffffffffffffffffffffbdffff2121734a2121ffde9cffffffffffffffffff73bdff9c4a21ffffdedeffff214a9cbd 7321ffffffffffff73bdff4a2121ffde9cffffffffffff2173bd212121ffbd73ffffffffffff73bdffffbd73ffffff4a9cde732121ffffbdffffff73bdff2121 219c4a21ffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff21214a212121bd7321 ffffffffffffffffffffffff4a9cde212121212121ffbd73ffffffffffffffffffbdffff212173de9c4affffffffffff4a9cde732121ffffbdffffff73bdff21 21219c4a21ffffdeffffff73bdff4a2121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff2173bd9c4a21ffffdeffffffffffffffffffffffffffffff9cdeff21214affbd73ffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff21529c9c4a21ffffe7ffffffffff ffffffffffffff4a9cde522121ffde9cffffffffffffe7ffff214a9c7b2929ffffbdffffffffffffffffffffffffffffff4a9cde522929ffde9cffffffffffff ffffffffffffffffffffffffffffff73bdff212121ffbd73ffffffffffffffffffffffff7bc6ff2121215252524a2121ffe79cffffffffffff4a9cde292929ff bd73ffffffffffffffffffffffffffffff9cdeff292952de9c4affffffffffffffffffffffffffffff2173bd7b2929ffffbdffffffffffffffffffffffffffff ffffffffffffffffffffffffff73bdff292929de9c4affffffffffffffffffffffffffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffff ffffffffffffffffff2173bd7b2929ffffbdffffffffffff529ce7212121ffc67bffffffffffffffffffffffffffffffffffffffffffffffff4a9cde522929ff de9cffffffffffff297bc6212121e79c52ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde522121ffde9cffffffffffffffff ffffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffc6ffff212173c67b21ffffffffffff9cdeff212152de9c4affffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffbdffff29297bbd7321ffffffffffffffffffffffffffffff2173bd7b2929ffffbdffffffffffffc6ffff21 21739c5221ffffdeffffffffffffffffffffffffffffff2173bd7b2121ffffbdffffffffffffffffffdeffff29529c4a4a21212152de9c4affffffffffffffff ff73bdff2929294a4a4a7b2121ffffbdffffffffffffffffff73bdff292929ffbd73ffffffffffffffffffffffff7bc6ff2121215252524a2121ffe79cffffff ffffff2173bd7b2121ffffbdffffffffffffffffffffffffffffffbdffff21217b9c4a21ffffe7ffffffffffffffffffffffffffffff217bc6732121ffffc6ff ffffc6ffff212173c67b29ffffffffffffffffffffffffffffffc6ffff212173c67b29ffffffffffff2173bd7b2929ffffbdffffffffffffffffffffffff7bc6 ff212121ffc67bffffffffffffffffffffffffffffffffffffffffffe7ffff214a9c9c5221ffffdeffffffffffffffffff2173bd7b2929ffffbdffffffbdffff 29297bbd7321ffffffffffffffffffffffffe7ffff214a9cc67b29ffffffffffffffffffffffffffffff529ce74a2121ffe79cffffffffffffffffffffffffff ffffffffffdeffff29529c9c4a21ffffe7ffffffffffffffffffffffff73bdff292929de9c4affffffffffffffffffffffffffffffbdffff29297bbd7321ffff ffffffffe7ffff214a9c9c5221ffffdeffffffffffffffffffdeffff29529c4a4a21212152bd7321ffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffe7ffff214a9c7b2121ffffbdffffffffffffffffffffffffffffffffffffffffffdeffff29529cbd7321ffffffffffff7bc6ff4a 2121ffe79cffffff7bc6ff212121ffc67bffffffffffffffffffffffffffffffffffff4a9cde7b2121ffffbd9ce7ff21214a9c5221ffffdeffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bc6ff4a2121215252732121ffffc6ffffffffffffdeffff 29529c4a4a21212152de9c4affffffffffffffffffbdffff29297bde9c4affffffffffff529ce7732121ffffc69cdeff2929529c4a21ffffe7ffffffffffff73 bdff522121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff297bc69c4a21ffff e7ffffffffffffffffffffffffffffff9ce7ff21214affc67bffffffffffffffffffffffffffffffe7ffff214a9cc67b21ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffdeffff214a 9c9c4a21ffffdeffffff73bdff212121ffbd73ffffffffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffffffffffffffffffffffffffff ffffff73bdff212121ffbd73ffffffffffffffffffbdffff212173bd73214a9cde4a2121ffde9cffffffbdffff212173bd7321ffffffffffffffffffffffffff ffffffffffffffff4a9cde732121ffffbdffffffffffffffffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffdeff ff214a9c9c4a21ffffdeffffffffffffffffffffffffffffffffffffffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffffffff2173bd 732121ffffbdffffffbdffff212173bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffff4a9cde212121bd 7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffff9cdeff21214ade9c 4affffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffbdffff212173bd7321ffffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffff4a9cde4a2121ffde9cffffffffffffff ffffffffffffffffffffffbdffff212173de9c4affffffffffffffffff9cdeff21214abd9c4a214a9cbd7321ffffffffffffffffff4a9cde73212173bdbd2121 21ffbd73ffffffffffffffffff73bdff212121ffbd73ffffffffffffffffffbdffff212173bd73214a9cde4a2121ffde9cffffffffffff2173bd732121ffffbd ffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffffbdffff212173de9c4affffffffffff2173bd732121ff ffbdffffffffffffffffffffffff73bdff212121ffbd73ffffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffff2173bd732121ffffbdffff ffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffff4a9cde4a2121ffde9cffffff73bdff212121ffbd73ffffffffffff ffffffffffffffffff4a9cde732121ffffbdffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffffdeffff214a9c9c 4a21ffffdeffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffffffffff73bdff4a2121ffde9cffffffdeffff214a9c9c4a 21ffffdeffffffffffffffffff4a9cde4a2121bdde9c212173bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 73bdff212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffff73bdff4a2121ffde9cffffff4a9cde73 2121ffffbdffffffffffffffffffffffffffffffffffff4a9cde7321219cdebd21214a9c4a21ffffdeffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2173bd73212173bdbd4a2121ffde9cffffffffffffbdffff212173bd9c4a214a9c9c4a21 ffffdeffffffffffffbdffff212173de9c4affffffffffff4a9cde7321219cdebd21214a9c4a21ffffdeffffffffffffffffff73bdff4a2121ffde9cffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2173bd9c4a21ffffdeffffffffffffffffffffff ffffffff9cdeff21214affbd73ffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffdeffff29529c9c4a21ffffe7ffffffffffffffffffffffffffffff7bc6ff4a2121ffe79cffffff297b c6732121ffffc6ffffffffffffffffffffffffffffffffffffffffff529ce7732121ffffc6ffffffffffffffffffffffffffffffffffff73bdff292929ffbd73 ffffffffffffffffff2173bd7b2121ffffbd529ce74a2121ffe79cffffff7bc6ff212121ffc67bffffffffffffffffffffffffffffffffffffffffff9ce7ff21 214affc67bffffffffffffffffffffffff2173bd7b2121ffffbdffffffffffffffffffffffffffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffff ffffffffffffffffffffffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffffffff2173bd7b2121ffffbdffffff73bdff 212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde522121ffde9c7bc6ff2121219c5221ffffdeffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff4a9cde522929ffde9cffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffffffff ffffffffc6ffff212173c67b29ffffffffffff9cdeff292952de9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff 21217bbd7321ffffffffffffffffffffffffffffffffffff529ce7732121ffffc6deffff21529c9c4a21ffffe7ffffffffffffffffffffffffffffffffffffff ffff297bc69c4a21ffffe7ffffffffffff4a9cde522121ffde9c529ce7732121ffffc6ffffffe7ffff214a9c9c5221bdffde29297bbd7321ffffffffffffffff ff73bdff212121ffbd73ffffffffffffffffff2173bd7b2929ffffbd529ce74a2121ffe79cffffffffffff2173bd7b2929ffffbdffffffffffffffffffffffff e7ffff214a9c9c5229ffffdeffffffffffffffffffffffffffffffffffffffffff2173bd9c5221ffffdeffffff73bdff21212121212129292921212121212121 21212929299c4a21ffffe7ffffffffffff2173bd7b2121ffffbdffffffffffffffffffffffffffffff9cdeff212152ffbd73ffffffffffffffffffffffffffff ffffffffe7ffff214a9c9c5229ffffdeffffffffffffffffff2173bd7b2121ffffbdffffff4a9cde522121ffde9cffffffffffffffffffffffffffffff4a9cde 522121ffde9cffffffffffffffffffffffff529ce74a2121ffe79cffffffffffffffffffffffffffffffffffffdeffff21529c9c4a21ffffe7ffffffffffffff ffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffffffffffffffc6ffff212173e79c52ffffffe7ffff214a9c9c5229ffffdeffffffffffff9ce7 ff21214ae79c52bdffff29297bbd7321ffffffffffffe7ffff214a9ce79c52ffffffffffffffffffffffffffffffffffffffffff217bc6732121ffffc6ffffff ffffffffffffffffffffffffffffffffffffffffffdeffff21529cbd7321ffffffffffff7bc6ff4a2121ffe79cffffff217bc6732121ffffc6ffffffffffffff ffffffffffffffffffffff4a9cde2929292121217b2121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffbdffff21217bbd7321c6ffff212173e79c52ffffffffffff73bdff212121ffbd73529ce74a2121ffe79cffffffffffffbdffff 21217bde9c4affffffffffff529ce7212121292929732121ffffc6ffffffffffffffffffffffff73bdff522929ffde9cffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff217bc69c4a21ffffe7ffffffffffffffffffffffffffffff9ce7ff21214affc6 7bffffffffffffffffffffffffffffffe7ffff214a9cc67b29ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffff9cdeff21214ade9c4adeffff214a9c9c4a21ffffdeffffffffff ffffffffffffffffffffffffffffffff73bdff4a2121ffde9cffffffffffffffffffffffffffffffffffff73bdff212121ffbd73ffffffffffff73bdff212121 de9c4affffff4a9cde4a2121ffde9cffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffffffffffbdffff212173de9c4affffffffffffff ffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121ffbd73ffffffffffffffffffffffffffffffffff ffffffffffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffffffff2173bd732121ffffbdffffff4a9cde4a2121ffde9cffffffffffff ffffffffffffffffffffffffffffffffffffffffff4a9cde4a21219cbd9c21214a732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffbdffff212173bd73 21ffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffff ffffffffffffffffffffffff73bdff212121ffbd73bdffff212173bd7321ffffffffffffffffffffffffffffffffffffffffffffffff4a9cde732121ffffbdff ffffdeffff214a9c732121ffffbd73bdff4a2121ffde9cffffff9cdeff21214ade9c4adeffff214a9c9c4a21ffffdeffffffffffff73bdff212121ffbd73ffff ffffffff73bdff212121de9c4affffff4a9cde4a2121ffde9cffffffffffff2173bd732121ffffbdffffffffffffffffffffffffbdffff212173bd7321ffffff ffffffffffffffffffffffffffffffffffffffffff4a9cde732121ffffbdffffffdeffff214a9c9c4a21ffffdeffffffffffff73bdff212121de9c4affffffff ffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a 21ffffdeffffffffffff73bdff212121de9c4affffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffff ffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffff73bdff212121ffbd73ff ffffffffffffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffdeffff214a9c9c4a21ffffdeffffffdeffff214a9c732121ffffbdbdffff2121 73bd7321ffffffffffffbdffff212173de9c4affffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffff ffffffffffffffffffdeffff214a9cbd7321ffffffffffff73bdff4a2121ffde9cffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffff4a 9cde73212173bdbd212121de9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ff73bdff212121de9c4adeffff214a9cbd7321ffffffffffff2173bd732121ffffbd73bdff212121ffbd73ffffffffffffbdffff212173de9c4affffffffffff 4a9cde73212173bdbd212121de9c4affffffffffffffffffffffff73bdff4a2121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffff2173bd9c4a21ffffdeffffffffffffffffffffffffffffff9cdeff21214affbd73ffffffffffffffffffffff ffffffffdeffff214a9cbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde ffff21529c9c4a21ffffe7ffffffffffffffffffffffffffffff9ce7ff21214ae79c52deffff21529c9c4a21ffffe7ffffffffffffffffffffffffffffffffff ffffffff7bc6ff212121ffc67bffffffffffffffffffffffffffffffffffff73bdff212121ffbd73ffffffbdffff21217b9c4a21ffffe7ffffff529ce74a2121 ffe79cffffff529ce74a2121ffe79cffffffffffffffffffffffffffffffffffffffffffc6ffff212173c67b21ffffffffffffffffffffffff2173bd7b2929ff ffbdffffffffffffffffffffffffffffffffffffffffffffffff7bc6ff212121ffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffff9ce7 ff21214ae79c52ffffffffffffffffffffffffffffffffffff2173bd7b2929ffffbdffffff4a9cde522929ffde9cffffffffffffffffffffffffffffffffffff ffffffffffffffffff4a9cde292929212121522121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a 9cde522121ffde9cffffffffffffffffffffffff9ce7ff21214a212121212121292929212121212121212121292929212121c67b21ffffffffffff9cdeff2121 522121212929292121212121214a2121ffe79cffffffffffffffffffffffffffffffffffffbdffff29297bbd7321ffffffffffffffffffffffffffffffffffff 7bc6ff212121ffc67bbdffff29297bbd7321ffffffffffffffffffffffffffffffffffffffffffffffff529ce74a2121ffe79cffffffc6ffff212173c67b29ff ffffc6ffff212173e79c52ffffff7bc6ff4a2121ffe79cffffff529ce74a2121ffe79cffffffffffff73bdff292929ffbd73ffffffbdffff29297b9c4a21ffff e7ffffff529ce74a2121ffe79cffffffffffff2173bd7b2121ffffbdffffffffffffffffffffffffc6ffff212173c67b21ffffffffffffffffffffffffffffff ffffffffffffffffff4a9cde522929ffde9cffffffffffff529ce74a2121ffe79cffffffffffff2173bd522121ffde9cffffffffffffffffff2173bd7b2929ff ffbdffffffffffffffffffffffffffffffbdffff29297bbd7321ffffffffffffffffffffffffffffffffffffe7ffff214a9c2121212121212929292121217b21 21ffffbdffffffffffffffffff4a9cde522929ffde9cffffffffffffffffffffffffffffff4a9cde522929ffde9cffffffffffffffffffffffff529ce74a2121 ffe79cffffffffffffffffffffffffffffffffffffdeffff29529c9c4a21ffffe7ffffffffffffffffff7bc6ff212121ffc67bffffffffffffffffffffffffff ffffffffffffffffe7ffff214a9c9c5221ffffdee7ffff214a9c9c5221ffffdeffffff4a9cde212121ffbd73ffffffbdffff21217bbd7321ffffffffffffc6ff ff212173e79c52ffffffffffffffffffffffffffffffffffffdeffff29529c9c4a21ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffdeffff 29529cbd7321ffffffffffff7bc6ff4a2121ffe79cffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffffffff4a9cde7b2121ffffbd529ce721 2121e79c52ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde522929ffde9cffff ff4a9cde7b2929ffffbde7ffff214a9cc67b29ffffffc6ffff212173c67b29ffffffffffffbdffff29297bde9c4affffffffffff529ce7732121ffffc64a9cde 292929de9c4affffffffffffffffff73bdff522121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffff297bc69c4a21ffffe7ffffffffffffffffffffffffffffff9ce7ff21214affc67bffffffffffffffffffffffffffffffe7ffff214a9cc67b 21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeff ffffffffffffffffffffffffffff9cdeff21214ade9c4adeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffffffffffffffff73bdff4a2121ffde 9cffffffffffffffffffffffffffffffffffff73bdff212121ffbd73ffffff4a9cde4a2121ffde9cffffffffffff4a9cde4a2121ffde9cffffff4a9cde4a2121 ffde9cffffffffffffffffffffffffffffffffffffffffffbdffff212173de9c4affffffffffffffffffffffff2173bd732121ffffbdffffffffffffffffffff ffffffffffffffffffffffffffff73bdff212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff21214ade9c4affffffffff ffffffffffffffffffffffffff2173bd732121ffffbdffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde 4a2121739c9c212121de9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffffff ffffffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffff9cdeff21214ade9c4affffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffffffffffffffffffffffffffff73bdff212121ffbd73bdffff 212173bd7321ffffffffffffffffffffffffffffffffffffffffffffffff4a9cde732121ffffbdffffff73bdff212121ffbd73ffffffffffff2173bd9c4a21ff ffde2173bd732121ffffbdffffff73bdff212121de9c4affffffffffff73bdff212121ffbd73ffffff4a9cde4a2121ffde9cffffffffffff4a9cde4a2121ffde 9cffffffffffff2173bd732121ffffbdffffffffffffffffffffffffbdffff212173bd7321ffffffffffffffffffffffffffffffffffffffffffffffff4a9cde 732121ffffbdffffffffffff9cdeff21214ade9c4affffffbdffff212173bd7321ffffffffffffffffffffffff2173bd732121ffffbdffffffffffffffffffff ffffffffffbdffff212173bd7321ffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffbdffff212173bd7321ffffffffffffffff ff4a9cde4a2121ffde9cffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffff ffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffff73bdff212121ffbd73ffffffffffffffffffffffffffffffffffffffffffdeffff21 4a9cbd7321ffffffdeffff214a9c9c4a21ffffdebdffff212173bd7321ffffffffffffbdffff212173bd7321ffffffffffffbdffff212173de9c4affffffffff ffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffff 73bdff4a2121ffde9cffffffffffff4a9cde212121ffbd73ffffffffffff73bdffffbd73ffffff4a9cde732121ffffbdffffff4a9cde212121de9c4affffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffff9cdeff21214affbd739cde ff21214ade9c4affffffdeffff214a9c732121ffffbdffffffbdffff212173de9c4affffffffffff4a9cde732121ffffbdffffff4a9cde212121de9c4affffff ffffff73bdff4a2121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2173bd9c 4a21ffffdeffffffffffffffffffffffffffffff9cdeff21214affbd73ffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff29529c9c4a21ffffe7ffffffffffffffffffffffffff ffff7bc6ff212121ffc67bffffff297bc6732121ffffc6ffffffffffffffffffffffffffffffffffffffffff529ce7732121ffffc6ffffffffffffffffffffff ffffffffffffff73bdff292929ffbd739ce7ff21214ae79c52ffffffffffffffffff529ce74a2121ffe79cffffff7bc6ff212121ffc67bffffffffffffffffff ffffffffffffffffffffffff9ce7ff21214affc67bffffffffffffffffffffffff2173bd7b2121ffffbdffffffffffffffffffffffffffffffffffffffffffff ffffc6ffff212173e79c52ffffffffffffffffffffffffffffffffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffffff ff2173bd7b2121ffffbdffffff9cdeff212152ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde522121ffde9c529ce7212121 ffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde522929ffde9cffffffffffffffffffffffff9ce7ff21 214ae79c52ffffffffffffffffffffffffffffffc6ffff212173c67b29ffffffffffff9cdeff292952de9c4affffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffbdffff21217bbd7321ffffffffffffffffffffffffffffffffffff529ce74a2121ffe79cdeffff21529c9c4a21ffffe7ffffff ffffffffffffffffffffffffffffffffffff297bc69c4a21ffffe7ffffff297bc64a2121ffe79cffffffffffff4a9cde7b2121deffbd29529cbd7321ffffffff ffffc6ffff212173c67b21ffffffffffff73bdff212121ffbd739ce7ff21214ae79c52ffffffffffffffffff529ce74a2121ffe79cffffffffffff2173bd7b29 29ffffbdffffffffffffffffffffffffe7ffff214a9c9c5229ffffdeffffffffffffffffffffffffffffffffffffffffff2173bd9c5221ffffdeffffffffffff e7ffff214a9c9c5229ffffde7bc6ff212121ffc67bffffffffffffffffffffffff2173bd7b2121ffffbdffffffffffffffffffffffffffffff9cdeff212152de 9c4affffffffffffffffffffffffffffffffffffe7ffff214a9c9c5229ffffdeffffffffffff7bc6ff212121ffc67bffffffffffff4a9cde522121ffde9cffff ffffffffffffffffffffffffff4a9cde522121ffde9cffffffffffffffffffffffff529ce74a2121ffe79cffffffffffffffffffffffffffffffffffffdeffff 21529c9c4a21ffffe7ffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffffffffffffffc6ffff212173e79c52ffffffe7ffff21 4a9c9c5229ffffde217bc6732121ffffc6ffffffffffffbdffff29297bbd7321ffffffffffffc6ffff212173e79c52ffffffffffffffffffffffffffffffffff ffffffff529ce7732121ffffc6ffffffffffffffffffffffffffffffffffffffffffffffffdeffff21529cbd7321ffffffffffff7bc6ff4a2121ffe79cffffff ffffffffffff9ce7ff21214a2121212121219c5229ffffdeffffff4a9cde7b2929ffffbdffffffffffff297bc62121219c5221ffffdeffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffff9ce7ff21214ac67b21ffffffffffffbdffff21217bde9c4a7bc6ff4a2121ffe79cffffffffff ff4a9cde522121ffde9cffffffbdffff21217bde9c4affffffffffff529ce7732121ffffc6ffffffffffff2173bd2929299c4a21ffffe773bdff522929ffde9c ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff217bc69c4a21ffffe7ffffffffffffff ffffffffffffffff9ce7ff21214affc67bffffffffffffffffffffffffffffffe7ffff214a9cc67b29ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffff2173bd732121ffffbdff ffff73bdff212121ffbd73ffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffffffffff73bdff2121 21debd73214a9c732121ffffbdffffffffffffffffff4a9cde4a2121ffde9cffffffbdffff212173bd7321ffffffffffffffffffffffffffffffffffffffffff 4a9cde4a2121ffde9cffffffffffffffffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffff2173bd732121ff ffbdffffffffffffffffffffffffffffffffffffffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffffffff2173bd732121ffffbdffff ffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffff2173bd212121ffbd73ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffff9cdeff21214ade9c4affffffffffffff ffffffffffffffffbdffff212173bd7321ffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffbdffff212173bd7321ffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffff ffffffbdffff212173bd7321ffffffdeffff214a9c9c4a21ffffdeffffffffffff9cdeff21214a9c9c7321214affbd73ffffffffffffdeffff214a9c732121ff ffbdffffff73bdff212121debd73214a9c732121ffffbdffffffffffffffffff4a9cde4a2121ffde9cffffffffffff2173bd732121ffffbdffffffffffffffff ffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffffffffffffffff73bdff4a2121ffde9c 2173bd732121ffffbdffffffffffffffffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffff ffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffbdffff212173de9c4affffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffff ff4a9cde4a2121ffde9cffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffff ffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffffffffff73bdff212121ffbd73ffffffdeffff214a9c9c4a2173bdde212121de 9c4affffffffffffffffffbdffff212173bd7321ffffffffffffbdffff212173de9c4affffffffffffffffffffffffffffffffffffffffff9cdeff21214ade9c 4affffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff4a9cde732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cde 9c4a4a9cdebd7321ffffffffffff73bdff212121ffbd73ffffffffffffffffff2173bd9c4a2121739c9c4a21ffffdeffffffffffff73bdff212121de9c4affff ffffffffffffffffffffffffffffffff4a9cde732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff732121 bdffbd4a2173ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffff2173bd9c4a21ffffdeffffffffffffffffffffffffffffff9cdeff21 214affbd73ffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffdeffff21529c9c4a21ffffe7ffffffffffffffffffffffff73bdff212121ffbd73ffffffffffffffffff2173bd7b2929ff ffbdffffffffffffffffffffffffffffff4a9cde522929ffde9cffffffffffffffffffffffffffffffffffffffffff73bdff2121214a4a4a292929ffbd73ffff ffffffffffffffffffff529ce74a2121ffe79cffffffffffff73bdff292929ffbd73ffffffffffffffffffffffffffffff9cdeff292952de9c4affffffffffff ffffffffffffffffff2173bd7b2929ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff29297bbd7321ffffffffffffffffffff ffffffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffffffff2173bd7b2929ffffbdffffffffffff9ce7ff21214ae79c 52ffffffffffffffffffffffffffffffffffffffffffffffff4a9cde522929ffde9cffffffdeffff29529c4a2121ffe79cffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff4a9cde522121ffde9cffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffc6ffff21 2173c67b21ffffffffffff9cdeff212152de9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff29297bbd7321ffff ffffffffffffffffffffffffff4a9cde522929ffde9cffffffffffffe7ffff214a9c9c5221ffffdeffffffffffffffffffffffffffffff2173bd7b2121ffffbd ffffff9cdeff212152bd7321ffffffffffffffffffdeffff29529c4a4a4a522121ffde9cffffffffffffffffff4a9cde292929ffbd73ffffff73bdff2929294a 4a4a212121ffbd73ffffffffffffffffffffffff529ce74a2121ffe79cffffffffffff2173bd7b2121ffffbdffffffffffffffffffffffffffffffdeffff2152 9c9c4a21ffffe7ffffffffffffffffffffffffffffff217bc6732121ffffc6ffffffffffffffffffffffffbdffff21217b9c9c4a29297bde9c4affffffffffff ffffffffffffffffff2173bd7b2929ffffbdffffffffffffffffffffffff9ce7ff21214ae79c52ffffffffffffffffffffffffffffffffffffffffffe7ffff21 4a9c9c5221ffffdeffffffffffff9ce7ff21214ae79c52ffffffffffff4a9cde522929ffde9cffffffffffffffffffffffffffffff4a9cde522929ffde9cffff ffffffffffffffffffff529ce74a2121ffe79cffffffffffffffffffffffffffffffffffffdeffff29529c9c4a21ffffe7ffffffffffffffffffffffff9cdeff 292952de9c4affffffffffffffffffffffffffffffbdffff29297bbd7321ffffffffffffe7ffff214a9c52522121214a9c5229ffffdeffffffffffffffffffbd ffff21217bbd7321ffffffffffffc6ffff212173e79c52ffffffffffffffffffffffffffffffffffffffffffffffff4a9cde522121ffde9cffffffffffffffff ffffffffffffffffffffffffffdeffff29529cbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff4a9cde7b2121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff29529cde9c4a217bc69c4a21ffffe7ff ffff217bc64a2121ffe79cffffffffffffffffff7bc6ff4a2121215252bd7321ffffffffffffffffffbdffff29297b9c4a21ffffe7ffffffffffffffffffffff ffffffff529ce7732121ffffc6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bc6ff7321219ce7c621214affc67bffffff ffffffffffffffffffffffffffffffbdffff9c527bffffde297bc69c4a21e7ffe7734a9cffffc6ffffff529ce7ffbd739ce7ff21214affc67b73bdffe79c52ff ffff9ce7ffbd734ae7ffff214a9cc67b21bdffff9c527bffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffdeffff214a9c9c4a21ffffdeffffffffffffdeffff214a9c212121ffbd73ffffffffffffffffffffffffdeffff214a9c4a2121ffde9cffffffffffffff ffff2173bd212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121212121bd7321ffffffffffffffffffffffffffffff4a9c de4a2121ffde9cffffffffffffffffff4a9cde212121de9c4affffffffffffffffff73bdff212121bd7321ffffffffffffffffffffffffffffffffffff2173bd 732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff21214a732121ffffbdffffffffffffdeffff214a9cffbd73ff ffff9cdeff21214ade9c4affffffffffffffffffffffffffffffffffff2173bd732121ffffbdffffffffffffffffff73bdff2121219c4a21ffffdeffffffffff ffbdffff4a2173ffde9cffffff4a9cde4a2121ffde9cffffffffffffbdffff212173732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffff ffffff4a9cde4a2121ffde9cffffffffffffffffffffffff9cdeff21214ade9c4affffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffff9c deff21214ade9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173bd7321ffffffffffffffffffbdffff2121 734a2121ffde9cffffffffffffffffffffffffbdffff212173732121ffffbdffffffffffffdeffff214a9c4a2121ffde9cffffffffffff4a9cde212121ffbd73 ffffffffffffffffffffffff2173bd2121219c4a21ffffdeffffffffffffffffff9cdeff21214ade9c4affffff73bdff212121212121bd7321ffffffffffffff ffffffffffffffff4a9cde4a2121ffde9cffffffffffff2173bd732121ffffbdffffffffffffffffffffffffffffffffffffbdffff212173732121ffffbdffff ffffffffdeffff214a9c4a2121ffde9cffffffffffffffffffffffffffffffffffff2173bd2121214a2121ffde9cffffffffffffffffffffffffffffff2173bd 732121ffffbdffffffffffffffffff2173bd212121de9c4affffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffff ffff2173bd4a2121ffde9cffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffff4a9c de4a2121ffde9cffffffffffffffffffffffffffffffffffffdeffff214a9c9c4a21ffffdeffffffffffffffffffffffffffffff73bdff212121bd7321ffffff ffffffffffff9cdeff21214a9c4a21ffffdeffffffffffffdeffff214a9c2121214a2121ffde9cffffffffffffffffffffffffbdffff212173bd7321ffffffff ffffbdffff212173de9c4affffffffffffffffffffffffffffffffffffffffffffffffffffff2173bd212121de9c4affffffffffffffffff73bdff9c4a21ffff dedeffff214a9cbd7321ffffffffffff4a9cde212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde732121ffffbd ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173de9c4a2173bd9c4a21ffffdebdffff2121739c4a21ffffdeff ffffffffffffffff9cdeff21214a212121ffbd73ffffffffffffffffffffffff2173bd732121ffffbd9cdeff21214abd7321ffffffffffff4a9cde732121ffff bdffffffffffffffffffffffffffffffffffff4a9cde212121ffbd73ffffffffffff4a9cde7321219cdebd21214affbd73ffffffffffffffffffffffffffffff ffffffffffff73bdff7321212173734a4a2121214affbd73ffffffffffffdeffff214a9c73734a21214a4a4a4a9c4a21ffffdeffffffffffff4a9cde734a2121 4a734a4a214a214affde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff29529c212121 212121212121292929212121c67b21ffffffffffffffffffffffffffffffffffffffffffffffff73bdff2929292121212121212121219c5229ffffdeffffffff ffffffffffffffffffffffffffffffffffffffffffffff73bdff2929294a2121ffe79cffffffffffffffffffffffffffffff529ce74a2121ffe79cffffffffff ffffffffffffffbdffff29297b212121212121212121522929ffde9cffffffffffffffffff73bdff212121212121292929212121212121212121292929212121 9c5221ffffdeffffffffffffffffffffffffffffffffffffffffffffffff529ce7212121212121212121292929ffbd73ffffffffffff9ce7ff21214ae79c52ff ffffffffffffffffffffffffffffffffff2173bd7b2121ffffbdffffffffffffffffffffffffffffff2173bd2121212121212929294a2121ffe79cffffffffff ff4a9cde522121ffde9cffffffffffffffffff9cdeff2929524a2121ffe79cffffffffffffffffffffffff9cdeff292952212121212121212121292929212121 2121212121217b2929ffffbd9ce7ff21214ae79c52ffffffffffffffffffffffffffffffc6ffff212173c67b29ffffffffffff9cdeff29295221212121212121 2121292929212121e79c52ffffffffffffffffffffffffffffffffffffbdffff21217b212121292929212121212121212121e79c52ffffffffffffffffffffff ffffffffffffffffffffffffff4a9cde212121212121292929212121c67b21ffffffffffffffffffe7ffff214a9c7b2929ffffbdffffffffffffffffffffffff 7bc6ff212121c67b29ffffffffffffffffffffffffbdffff21217b9c4a21ffffe773bdff2121214a2121ffe79cffffffffffffffffffffffffffffff529ce74a 2121ffe79cffffffffffff2173bd7b2929ffffbdffffffffffffffffffffffffffffffffffffffffffffffff529ce7212121292929212121212121bd7321ffff ffffffffffffffffffffffffffffffffffffffffffff9ce7ff21214a9c5221ffffdeffffffffffffffffffffffffffffff2173bd212121212121292929212121 2121219c4a21ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff214a9c2929292121212121212121217b2929ffffbdffffffff ffffffffff4a9cde522121ffde9cffffffffffffffffffffffffffffff4a9cde522121ffde9c9ce7ff21214a2121212121212929292121212121212121212929 29732121529ca5212121292929212121212121212121292929212121212121bd7321ffffffffffffffffffdeffff29529c212121212121212121292929ffbd73 ffffffffffffffffffffffffe7ffff214a9c292929bd7321ffffffffffffffffffffffffffffffbdffff29297bbd7321ffffffffffffc6ffff212173c67b21ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff21217b2121212929292121219c5221ffffdeffffffdeffff21529cbd7321ffff ffffffff529ce7212121ffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde7b2929ffffbdffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffbdffff21217b9c732129529c9c4a21ffffe773bdff292929de9c4affffffffffffffffffffffffe7ffff21 4a9c522929ffde9cffffffffffffffffffffffff529ce7212121ffc67b9cdeff212152bd7321ffffffffffff529ce7732121ffffc6ffffffffffffffffffffff ffffffffffffff4a9cde292929ffbd73ffffffffffff529ce74a21217b9c9c212121ffc67bffffffffffffffffffffffffffffffffffffffffffffffff73bdff 212121212121ffc67bffffffffffffffffffffffffdeffff21529c2121219c5229ffffdeffffffffffffffffffffffff529ce7212121522929ffde9cffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cbd7321ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde732121ffffbdffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cdede9c4affffffffffff ffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffffffffffffff2173bdffbd73ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ff6b6bffdedeffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadadff0000ff8484ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5a5ff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffadadff8484ffdedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffa5a5ff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffe7e7ff2929ff0000ff0000ff8c8cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff9c9cff0000ff8c8cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff3131ff0000 ff4a4affa5a5fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5252ff0000ffb5b5 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff1818ff0000ff4a4affffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff0808ff0808fff7f7ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffa5a5ff2121ff0000ff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6c6ff0000ff4a4affffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffefefff7b7bff1818ff0000ff0000ff4242ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffadadff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff6363ff0808ff0000ff0000ff63 63ffd6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffa5a5ff0000ff6b6bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9494ff1010ff0000ff1010ff7b7bffefefffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000ff9c 9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffd6d6ff3939ff0000ff0000ff7b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3131ff0000ffdedeffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 7b7bff0000ff0000ff3939ffdedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ff2929ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdff1818ff0000ff1010ff9494ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffff9c9cff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ff6363ff0000ff0000ff4a4affefefffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffff6363ff0000ffb5b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffff9c9cff1818ff0000ff1818ffa5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2121ff0000ff f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff4a4a ff0000ff0000ff6363fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeff0000ff3131ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ff7373ff0808ff0000ff1818ffbdbdffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff0000ff7373ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffff9494ff1010ff0000ff0808ff7b7bfff7f7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededededededededededededededededede dedededededededededededededededededededededededededededededededededededededededededededededededededededededeffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffd6d6d6dedededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dedededededededededededededededededeff2121ff0000e7b5b5dedededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededeef9494ff2929ff0000ff0000f74a4ae7c6c6dedededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dedededededededededededededededededededededededededededededededededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdede deffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffbdbdff0000ff3131ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff8484ff2121ff0000ff00 00ff4242ffceceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffbdbdffc6c6ff8484ff8484ff7b7bffb5b5ffbdbdffbdbdffbdbdffc6c6ffbdbdffcece ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6363ff0000ff9c9c ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff5a5aff0000ff0000ff0000ff4242ffbdbdffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffd6d6ff7b7bff4242ff0808ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff2929ff4242 ff6b6bff8484ffbdbdffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0808ff0808fff7f7ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffb5b5ff2929ff0000ff0000ff1010ff6b6bffceceffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9cff0000ff0000ff0000ff10 10ff4242ff4a4aff8484ff7b7bff8484ff7b7bff8484ff7b7bff7373ff3939ff4242ff4242ff4242ff1818ff0000ff0000ff0000ff0000ff0000ff0000ff0000 ff0000ff2929ff4a4aff8484ff8c8cffbdbdffbdbdffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9cff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff 4a4aff0000ff0000ff2929ffa5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ffb5b5ff5252ff0000ff0000ff9494ffdedeffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdffc6c6ff8484ff8484ff4242ff3131ff0000ff0000ff0000 ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff4242ff4242ff5252ff7b7bffb5b5ffe7e7ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffff6363ff0000ffb5b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0808ff0000ff2929ffadadffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffc6c6ff9494ff5a5aff0000ff0000ff0000ff1818ffadadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6c6ffb5b5ff7b7bff6363ff3939ff4242 ff4242ff2929ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff4242ffbdbdffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffff1818ff0000ffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffadadff1818ff0000ff1010ff9c9cffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff5a5aff1010ff0000ff 0000ff0000ff1818ff6363ffa5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffefefffbdbdffc6c6ff8484ff6b6bff1818ff0000ff0000ff3939ff4242ff8484ffbdbdffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceceff0000ff3939ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffbdbdff4242ff0000ff0000ff4a4affefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0808ff0000ff0000ff4242ff8484ffbdbdffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffadadff1818ff0000ff0000ff0000ff0000ff0808ff5252ff7b7bffadadfff7f7ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff8484ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdff4242ff0000 ff0000ff2929ffb5b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffff7f7ff3939ff0000ff0000ff7b7bfff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffd6d6ffbdbdff8c8cff5252ff0808ff0000ff0000ff0000ff1818ffceceffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1818ff0808ffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdff4242ff0000ff0000ff2121ffa5a5ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffff7f7ff4242ff0000ff2929ffceceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffbdbdff8484ff5a5aff0000ff1010ffceceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff8c8cff0000ff6b6bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffff7f7ffa5a5ff2929ff0000ff0000ff3131ffadadffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff0000ff3131 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff8484ff0000ff1010ffceceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff3131ff0000ffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef efff7b7bff1818ff0000ff0000ff3939ffb5b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ff1818ff0000ffd6d6ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484 ff0000ff1010ffa5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff0000ff4242ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff5a5aff0000ff0000ff0000ff5a5affc6 c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5a5ff0000ff5252ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff0808ff0000ffbdbd ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadadff0000ff7373ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7ffa5a5ff6b6bff2121ff0000ff0000ff1010ff7373ffe7e7ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffff5252ff0000ffadadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9494ff0000ff5a5affffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5a5ff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffe7e7ffa5a5ff 7373ff3939ff1010ff0000ff0000ff0000ff0000ff4242ff9c9cffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffff1010ff0808ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ff0808ff0808ffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffff9c9cff0000ff7b7bffffffffffffffffffffffffffceceff7373ff3131ff0000ff0000ff0000ff0000ff0000ff4242ff 7373ffadadffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffff7ffffe7e7efe7e7e7e7e7e7fff7efffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceceff0000ff4242ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff5252ff0000ffa5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffa5a5ff0000ff4242ffceceffb5b5ff5a5aff1818ff0000ff0000ff0000ff2121ff6363ffadadffdedeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffb5efff945a7bf7e7c6ffffffffffffffffffffffffffffffffffffffffffffffffffffff9cd6f72129527b3929ffefbdffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffbdffff212173212121212121732121ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63b5f71010181010101010100808081010101010101010100808081010 10101010181010f7b563ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdede deffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffefffff73a5c6293152212121212121212121312921a5734affefceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffff7efe7e7b56bd69439d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d69439e7b56bffefe7ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff527bbd 3939397b5239ffe7bdffffffffffffffffffe7ffff527bbd3939397b5239ffe7bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7bdbdbda5a5a59c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c 9c9c9ca5a5a5bdbdbdf7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9cff0000ff7b7bffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffadadff0000ff5a5affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9cff0000ff0000 ff1010ff0000ff0000ff0000ff4242ff8c8cffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff4a94de4a2921efc684ffffffffffffffffffffffffffffffffffffffffff9cd6f7213152212121212121de9c4affffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff4a4a94ffde9cffffff ffffff4a94de522121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff3994ded68c39ffffffffffffffffffffffffffffffffffffffffffffffffffffff3994d6de9439ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6f7ff2952944a2921 bd9473efe7d6fffff7e7eff794bdd6294a73522921f7d69cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff f7efe7d68c29d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c29f7efe7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bc6ffbd7b42fffff77bc6f7c67b39ffffff ffffffffffff7bc6ffbd7b42fffff77bc6f7c67b39ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffefefefa5a5a59c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9ca5a5a5 efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff0000ff9494ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffb5e7ff734a73ffe7b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7 f7ff0808ff1010ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff0000ff0000ff0000ff6363ffa5a5ffefef ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceffff29428c944a21 fff7d6ffffffffffffffffffffffffffffffaddef721316b212121212121312121ffc684ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2173b5de9c4a ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffff3994dede9442ffffffffffffffffffffffffffffffffffffffffffffffffffffff4294dede9439ffffffffffffffffffffffffffff ffffffffffffffffffffffffff63b5ff1010106b1010ffffbdffffffffffffffffffffffff0863b5101010de9439ffffff3994de101010b56b10ffffffffffff bdffff10106b101010080808101010b56b10ffffff63b5ff101010101010101010390808ffde94ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff294a9c844a29f7e7bdffffffffffffffffffffffff ffffffe7f7ff4a84c64a2929ffde9cffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffdeffff214a9c212121212121bd 7321ffffffffffff73bdff2121212121214a2121ffde9cffffffffffff94deff212152212121212121bdbd73212173ffbd73ffffffffffff529cde2121212121 21212121ffbd73ffffffffffff73bdff2121212121214a2121ffde94ffffffffffffffffffffffffffffffffffffffffffffffffe7b56bd68c21d68c21d68421 d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421e7b56bffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84ceffce8c4affffff8cceffce844affffffffffffffffff84ceffce8c4a ffffff8cceffce844affffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffffde ffff214a9c212121212121bd73212173bdbd7321ffffffbdffff212173ffbd73ffffff73bdff732121ffffbdffffffffffffffffffffffffffffff9cdeff4a21 4affde94ffffffffffffffffff4a94de212121ffbd73ffffff73bdff212121212121212121de944affffffffffffffffff73bdff2121212121214a2121bdde94 212173ffbd73ffffffffffff529cde21212121212173212173bdbd732121ffffbdffffffffffff2173bd212121212121522121ffde9cffffffffffff2173bd21 2121212121944a21ffffdeffffffffffff73bdff212121212121ffbd73deffff21529c212121212121bd7321ffffffffffffffffffffffffffffffffffffffff ffffffffbdbdbd9c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9cbdbdbdffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffff6b6bff0000ff9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff294a9c2121212121 21212121212121212121212121212121212121212121212121212121212121212121944a29ffffd6ffffffffffffffffffffffffffffffffffffdeffff214a94 732121ffffbdffffffffffffffffff2173bd212121ffbd73ffffffffffffffffff4a94de9c5221ffffdedeffff214a94de9c52ffffffffffff2173bd212121de 9c4a9cdeff4a214affde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4242ff0000ffceceffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff0000ff0000ff5252ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffff4a94d69c5231fff7d6ffffffffffff ffffffb5e7f7213973212121212121312121efbd73fffff7ffffffffffffffffffffffffffffffffffffbdffff212173212121212121732121ffffbdffffffff ffffffffff4a94de212121212121212121ffbd73ffffffffffffffffff4a94de2121214a2121ffde9cffffff73bdff212121212121ffbd739cdeff4a214affde 9cffffff73bdff732121ffffbdffffffffffff73bdff732121ffffbdffffffdeffff214a9c212121212121bd73214a9cdebd7321ffffffffffff2173bd212121 2121219c4a21ffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff39 94ded694393994de080808101010080808101010080808101010d69439ffffff398cd6de9439ffffffffffffffffffffffffffffffffffffffffffffffffffff ff6bbdff0808086b1010ffffb5ffffffffffffffffffffffff106bbd080808de9439ffffff3994de080808bd6b10ffffff94deff080839101010080808101010 080808943910ffffd66bbdff080808101010080808101010390808ffde94ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffff5aa5de632929ffe7adffffffffffff73bdff212121bd7321ffffffffffffe7ffff296bb5 a55a21ffffe7ffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffff73bdffffb573ffffffd6ffff214a9cd6944adeffff947394ff ffdeffffff73bdff732121ffffbdd6ffff214a9cb57321ffffffd6ffff214a9c212121ffbd73ffffff73bdff212121ffbd73ffffffffffff4a73b5ffde9cd6ff ff9c739cffffd6ffffff73b5ff732121ffffb5ffffffffffffffffffffffffffffffffffffffffffd69431d68c21d68421d68c21d68421d68c21d68421d68c21 d68421d68c21d68421d68c21d68421d68c21d68421d68c21d69431ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffe7ffff4a7bc63939317b4a31ffe7c6ffffffffffffffffffe7ffff4a7bc63939317b4a31ffe7c6ffffff ffffffffffffffffffffffffffffffffffffffffffffffffb5ffff212173ffb573ffffffffffffffffffffffffffffffffffff4a9cde732121ffffbdffffff4a 9cde212121bd7321ffffffbdffff212173ffbd73ffffff73bdff732121ffffbdffffffffffffffffffffffffffffff9cdeff4a214affde9cffffffffffffb5ff ff212173b57321ffffff94d6ff21214ad6944affffffffffff4a9cdeffb573ffffff73b5ff212121ffb573ffffffd6ffff4a739c21214affbd73ffffff9cdeff 21214affbd73ffffff9cdeff21214a732121ffffb5ffffff4a94d64a2121ffd694ffffffd6ffff734a9cffffb59cdeffd69473ffffffffffff2173bdb57321ff ffffd6ffff214a9cb57321ffffffffffff73bdffffb573ffffffd6ffff214a9cd6944affffffffffffffffffffffffffffffffffffffffffa5a5a59c9c9c9c9c 9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9ca5a5a5ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffff5252ff0000ffbdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffb5ff ff732173ffffb5ffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffffffffffffff94d6ff21214a4a2121ffde9cffffffffffff d6ffff214a9c212121de9c4affffffffffffffffff4a9cde944a21ffffded6ffff214a9cd6944affffff4a94d6212121ffb573ffffff94d6ff4a214affd694ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff9494ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffff9494ff0000ff5252ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffff4a94ce9c5231fff7d6ffffffd6ffff294a9c212121212121 212121d69c52fffff7ffffffffffffffffffffffffffffffffffffbdffff732173ffffbdffffffffffff73b5ff4a2121ffd694ffffff73b5ff212121ffb573ff ffffffffff4a73bdffd694ffffffb5ffff212173d6944affffffffffffdeffff214a94bd7321ffffffffffff94d6ff4a214affd694ffffff73b5ff732121ffff b5ffffffffffff73bdff732121ffffbdd6ffff214a9c944a21ffffdeffffff4a9cde2121219c4a21ffffd69cdeffd69473ffffffffffff2173bdb57321ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3994dede9442ffffffffffffff ffffffffffffffffffffffffffffffffffffffff4294dede9439ffffffffffffffffffffffffffffffffffffffffffffffffffffff6bb5ff101010630808ffff bdffffffffffffffffffffffff106bb5101010de9439ffffff3994de101010b56308ffffff106bb5101010b56308ffffffffffffffffffffffffffffffffffff ffffffffffffffffff106bb5101010de9439ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffc6ffff213184dea552ffffffffffffffffff73bdff212121bd7321ffffffffffffffffffa5e7ff31215affc67bffffffffffff ffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffff2173bdbd7321ffffffffffffffffffffffff9cdeff4a214aff de94bdffff212173ffbd73ffffffffffff9cdeff21214affbd73deffff214a9cbd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffff9cde ff4a214affde9cffffffffffffffffffffffffffffffffffffffffffd68c21d68421d68c29d68c21d68c21f7ad21fffff7fffffffffffff7f7ffd68c6bd68c21 d68c21d68421d68c29d68c21d68c21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffff73bdff212121bd7321ffffffffffffffffffffffffffffff73bdff212121bd7321ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffff2173bdbd7321ffffffffffffdeffff21529cbd7321ffffffbd ffff212173ffbd73ffffff73bdff732121ffffbdffffffffffffffffffffffffffffff94deff522152ffde9cffffffffffff529cde732121ffffbdffffff2173 bd9c4a21ffffdeffffffffffffffffffffffffffffff2173bdbd7321ffffffffffffffffff9cdeff21214affbd73ffffff73bdff732121ffffbdffffffffffff 4a9cde732121ffffbdbdffff212173de944affffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde9c4a21ffffdedeffff214a9cde9c4aff ffffffffffffffffffffffffffffffffff2173bdbd7321ffffffffffffffffffffffffffffffffffffffffff9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ce7c6 a5fffffffffffff7ffffa5c6e79c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4242ff0000ff bdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffbdffff732173ffffbdffffffffff ffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffffffffffffff529cde734a21214a73de944affffffffffff9cdeff4a214a5273739c4a21 ffffdeffffffffffff4a9cde9c4a21ffffdedeffff214a9cde9c4a73bdff212121ffbd73ffffffffffff9cdeff4a214affde9cffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdff0000ff3131ffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffff7f7ff0808ff0000ffc6c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff4a8cceb56b39fff7deffffffbdefff29397b292121d69c52fffff7ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9cffbd73deffff21529cbd7321ffffffffffffffffffffffffffffffff ffffbdffff212173ffbd73ffffffffffffdeffff214a9cde944affffffffffff9cdeff4a214affde9cffffff73bdff732121ffffbdffffffffffff73bdff7321 21ffffbd9cdeff4a214affde9cffffffffffffdeffff21529c9c4a21ffffdeffffffffffffffffffffffff4a94de9c5221ffffdeffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3994ded68c393994de08080810101008080810101008080810 1010d68c39ffffff3994d6de9439ffffffffffffffffffffffffffffffffffffffffffffffffffffff6bbdff0808086b1010ffffb5ffffffffffffffffffffff ff106bbd080808de9439ffffff3994de080808bd6b10d6ffff103994080808101010080808101010080808101010d68c39ffffff94d6ff101039080808101010 390808ffde94ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ff94d6ff4a2142ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a94de944affffffffffffffffffffffffffffffffffff ffffffbdffff212173ffbd73ffffffffffffffffff73bdff212121212121ffb573ffffffffffffdeffff214a94212121944a21ffffde94d6ff4a214affd694ff ffffffffffbdffff212173ffbd73b5ffff212173ffb573ffffffffffffffffffffffffffffffffffffffffffd6ffff214a9c2121219c4a21ffffd6ffffffffff ffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21d68421f7b521ffffefffffffffffffffffffefefffd68c21d68421d68c21d68421d68c21 d68421ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ff73bdff212121bd7321ffffffffffffffffffffffffffffff73bdff212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff b5ffff212173ffb573ffffffffffffffffffffffffffffffd6ffff214a9cd6944affffffffffffffffff2173b5bd7321ffffffbdffff212173ffbd73ffffff73 bdff732121ffffbdffffffffffffffffffffffffffffff9cdeff4a214affde9cffffffbdffff212173de9c4affffffdeffff214a94de9c4affffffffffffffff ffffffffffffffdeffff214a94de9c4affffffffffffffffffbdffff212173ffbd73ffffff4a9cde944a21ffffdeffffffffffff73b5ff732121ffffb59cdeff 4a214affde9cffffffffffffffffffffffffffffffffffffffffff9cdeff21214a212121d6944affffffd6ffff214a9cd6944affffffffffffffffffffffff73 bdff212121212121ffb573ffffffffffffffffffffffffffffffffffffffffff9c9c9c9c9c9c9c9c9c9c9c9c9c9c9cd69c9cffffefffffffffffffffffffefff ff9c9cd69c9c9c9c9c9c9c9c9c9c9c9c9c9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4242ff0000ffc6c6ffffffffffffffffffff ffffffffffffffffffffffffffffffffffbdffff732173bdffbd212173212121212121732121b5ffb5732173b5ffb5212173212121212121732121bdffbd7321 73ffffbdffffffffffffffffffffffffffffffffffff2173b5bd73214a94d6bd7321ffffffffffff73b5ff9c4a2173b5d6732121ffffb5ffffffffffff4a9cde 944a21ffffded6ffff214a9c4a4a2121214ad6944affffffffffffffffff94d6ff4a214affd694ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffff3131ff0000ff5a5affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffff9494ff0000ff1010ff4a4affdedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffefffff427bbdb5733973b5d6bd734ab5e7e7bd8484ffffe7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffff73b5ff212121ffb573bdffff212173ffbd73ffffffffffffffffffffffffffffffffffffb5ffff212173ffb573ff ffffffffffdeffff214a94de9c4affffffffffff94d6ff4a214affd694ffffff73b5ff732121ffffb5ffffffffffff73bdff732121ffffbd73b5ff732121ffff b5ffffffffffffffffff4a94d69c4a21ffffd6ffffffffffff9cdeff21214a212121d6944affffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff3994dede9442ffffffffffffffffffffffffffffffffffffffffffffffffffffff4294dede 9439ffffffffffffffffffffffffffffffffffffffffffffffffffffff63b5ff101010101010101010080808101010de9439ffffff0863b5101010de9439ffff ff3994de101010b56b10ffffff0863b5101010101010101010080808101010101010ffbd6b94deff101042101010101010390808ffde94ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff732121ffffbdffff ffffffffffffff73bdff212121bd7321ffffffffffffffffffffffff2173bdbd7321ffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73 ffffffbdffff212173212121de9c52ffffffffffffffffff529cde212121732121ffffbdffffffffffff9cdeff4a214affde9cffffffffffffbdffff212173ff bd73bdffff212173212121212121212121212121212121bd7321ffffff4a94de212121732121ffffbdffffffffffffffffffffffffffffffffffffffffffffff ffffffffd68c29d68c21d68c21d68421d68c29e7ad21d68c6bd68421e78c29fff7bdffffffd6849cd68c29d68c21d68c21d68421d68c29ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121bd7321ffff ffffffffffffffffffffffffff73bdff212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173212121212121 2121219c4a21ffffdeffffffdeffff214a9cde9c4affffffffffffffffff2173bdbd7321ffffffbdffff212173ffbd73ffffff73bdff732121ffffbdffffffff ffffffffffffffffffffff9cdeff4a214affde94ffffff2173bd9c4a21ffffdeffffffdeffff214a9c2121212121212121212121212121219c5221deffde214a 9cde944affffffffffffffffffbdffff212173ffbd73ffffff4a94de9c5221ffffdeffffffffffff73bdff732121ffffbd94deff212152212121212121212121 212121212121de9c4adeffff21529c212121bd7321ffffffffffffffffffdeffff214a94de9c52ffffffffffffbdffff212173212121de9c4affffffffffffff ffffffffffffffffffffffffffffffffffffffffa5a5a59c9c9c9c9c9c9c9c9ca5a5a5efd69cffffffd6efffa5a5a5ffe7bdffffff9cd6efa5a5a59c9c9c9c9c 9c9c9c9ca5a5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4242ff0000ffbdbdffffffffffffffffffffffffffffffffffffffffffff ffffffffffbdffff732173ffffbdffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffff ffffffffffffffbdffff212173ffbd739cdeff73214affffbdffffff2173bdbd7321bdffff212173ffbd73ffffffffffff4a94de9c5221ffffdedeffff214a94 5252524a2121ffde9cffffffffffffffffff9cdeff4a214affde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7ff2121ff0000ffadadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484ff0000ff00 00ff5252ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffc6efffdec6b5296bb5212121292121bd7b39ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff deffff214a9c212121bd7321ffffffbdffff212173212121212121212121212121212121bd7321ffffffbdffff212173ffbd73ffffffffffffdeffff21529cde 9c4affffffffffff9cdeff4a214affde9cffffff73bdff732121ffffbdffffffffffff73bdff732121ffffbd73bdff732121ffffbdffffffffffffffffff4a9c de944a21ffffdedeffff214a9c212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff3994ded694393994de080808101010080808101010080808101010d69439ffffff398cd6de9439ffffffffffffffffffff ffffffffffffffffffffffffffffffffff6bbdff080808101010080808101010080808de9439ffffff106bbd080808de9439ffffff3994de080808bd6b10ffff ff3994de080808bd6b10ffffffdeffff08398c391010ffd6946bbdff080808943910ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff732121ffffbdffffffffffffffffff73bdff2121 21bd7321ffffffffffffffffffffffff2173b5bd7321ffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffff73bdff732121ffffbd ffffffffffffffffffdeffff214a94de9c4affffffffffffffffffffffff94d6ff4a214affd694ffffffffffffbdffff212173ffbd73d6ffff214a9cd6944aff ffffffffffffffff2173b5de9c4ad6ffff214a9cd6944affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68421d68c21d684 21d68c21d68421ef8c21ffffd6fffffffffffffffffff7f7ffd68c6bd68421d68c21d68421d68c21d68421ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121bd7321ffffffffffffffffffffffffffff ff73bdff212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5ffff212173ffb573ffffffffffff2173bd944a21ffffde d6ffff214a9cd6944affffffffffffffffff2173b5bd7321ffffffbdffff212173ffbd73ffffff73bdff732121ffffbdffffffffffffffffffffffffffffff9c deff21214a212121212121212121ffb573ffffffffffffffffff2173b5bd7321ffffffffffffffffff4a9cdeb57321ffffff2173b59c4a21ffffd6ffffffffff ff9cdeff21214affbd73ffffff4a9cde944a21ffffdeffffffffffff73b5ff732121ffffb5bdffff212173ffbd73ffffffffffffd6ffff214a9cffb5739cdeff 4a214affde9cffffffffffffffffffffffffd6ffff214a9cd6944affffffffffff73bdff732121ffffbdffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffff9c9c9c9c9c9c9c9c9c9c9c9c9c9c9cefd69cffffff9cd6f79c9c9ce7bd9cfffff7bde7ff9c9c9c9c9c9c9c9c9c9c9c9c9c9c9cffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffff4242ff0000ffbdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff732173bd ffbd212173212121212121732121b5ffb5732173b5ffb5212173212121212121732121bdffbd732173ffffbdffffffffffffffffffffffffffffff73bdff4a21 21ffde9cb5ffff212173ffb573deffff214a94ffbd73d6ffff214a9cb57321ffffffffffff4a9cde944a21ffffded6ffff214a9cd6944a4a9cde4a2121ffde9c ffffffffffff94d6ff4a214affd694ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff adadff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff2121ff0000ffb5b5ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdd6ef7b849c94a58c4a316b8cb5 9421214a212121212121212121ce8c52ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde2121214a2121ffd694ffffff ffffffdeffff214a94de9c4affffffffffffffffff2173bdd6944affffffb5ffff212173ffb573ffffffffffffdeffff214a94de9c4affffffffffff94d6ff4a 214affd694ffffff73b5ff4a2121ffd694ffffffffffff73bdff732121ffffbdb5ffff212173ffb573ffffffffffffffffff2173b59c4a21ffffd69cdeff4a21 4affde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff3994dede9442ffffffffffffffffffffffffffffffffffffffffffffffffffffff4294dede9439ffffffffffffffffffffffffffffffffffffffffffff ffffffffff6bb5ff101010630808ffffbdffffffffffffffffffffffff106bb5101010de9439ffffff3994de101010b56308ffffffb5ffff10106b0808081010 10101010101010943908ffffde94deff1010420808081010101010106b1010ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff392152ffce8cffffffffffffffffff73bdff212121bd7321ffffffffffffffff ffceffff21398cde9c4affffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffff94deff522152ffde9cffffff94deffffbd9cffffff 2173bdbd7321ffffffffffff9c9cbdffffde9cdeff4a214affde9cffffffffffffbdffff212173ffbd73ffffff73bdff4a2121ffde94ffffff9cdeff4a214aff de94ffffff2173bdbd7321ffffffffffff9c9cbdffffdeffffffffffffffffffffffffffffffffffffffffffd68c21d68421d68c29d68c21d68c21ef8421ffff deffffffffffffffffffd6b5c6d68c21d68c21d68421d68c29d68c21d68c21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121bd7321ffffffffffffffffffffffffffffff73bdff212121bd7321ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffffffffbdffff212173ffbd73deffff214a94de9c52ffffff ffffffffffff2173bdbd7321ffffffbdffff212173ffbd73ffffff73bdff732121ffffbdffffffffffffffffffffffffffffff94deff522152ffde9cffffffff ffff2173bdbd7321ffffffffffff9cdeff21214affbd73ffffffbdffff212173ffbd73ffffff9cdeff21214affbd73ffffffdeffff214a9c212121ffbd73ffff ff4a9cde9c4a21ffffdeffffffffffff73bdff732121ffffbdffffff4a9cde732121ffffbdffffff73bdff732121ffffbdbdffff212173ffbd73ffffffbdffff de9c9cffffffdeffff214a9cde9c4affffffffffff9cdeff4a214affde94ffffff9cdeffffbd9cffffffffffffffffffffffffffffffffffffffffff9c9c9c9c 9c9ca5a5a59c9c9c9c9c9cefd69cffffff9cd6ef9c9c9ce7bd9cffffffbde7ff9c9c9c9c9c9ca5a5a59c9c9c9c9c9cffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffff5a5aff0000ffbdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffff ffffbdffff732173ffffbdffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffffffff4a94de9c5221ffffdeffffff2173bdde9c 529cdeff4a214affde94ffffff4a9cde9c4a21ffffdeffffff4a9cde9c4a21ffffdedeffff214a9cde9c4affffff2173bd732121ffffbdffffff9cdeff4a214a ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6c6ff0000ff4242ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadadff0000ff1010ffc6c6ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff529cd6212131212121212121292121de9c5273bde72121392121212121 21292121de9c52fffff7ffffffffffffffffffffffffffffffffffffffffffffffff529cde212121de9c4affffffffffffffffffffffffffffff73bdff4a2121 ffde9cffffff9cdeff4a214affde9cffffffbdffff212173ffbd73ffffffffffffdeffff214a9cde944affffffffffff9cdeff4a214affde9cffffff73bdff21 21219c5221ffffdedeffff214a949c5221ffffdeffffff2173bd732121ffffbdffffff73bdff2121219c4a21ffffdebdffff212173ffbd73ffffffbdffffde9c 9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3994ded68c39ffffff ffffffffffffffffffffffffffffffffffffffffffffffff3994d6de9439ffffffffffffffffffffffffffffffffffffffffffffffffffffff6bbdff0808086b 1010ffffb5ffffffffffffffffffffffff106bbd080808de9439ffffff3994de080808bd6b10ffffffffffffd6ffff103994080808101010943908ffffdeffff ffffffff94d6ff101039080808101010630808ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffd6ffff21398cce8c42fffff7ffffffffffff73bdff212121bd7321ffffffffffffffffff8cceff392139ffd694ffff ffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffffffff73b5ff2121212121219c4a21ffffd6ffffffd6ffff214a9c212121212121 ffb573ffffff94d6ff4a214affd694ffffffffffffbdffff212173ffbd73ffffffffffff94d6ff21214a212121212121ffb573ffffffffffffdeffff214a9421 2121212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffd68421d68c21d68421d68c21d68421ef8c21ffffd6efefffd68421d68c21d684 21d68c21d68421d68c21d68421d68c21d68421ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffff73bdff212121bd7321ffffffffffffd6f7ffc69c94ffffff73bdff212121bd7321ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffb5ffff212173ffb573ffffffffffffdeffff214a94de9c4ad6ffff214a9cd6944affffffffffffffffff2173b5bd7321 ffffffbdffff212173ffbd73ffffff73bdff732121ffffbdffffffffffffffffffffffffffffff9cdeff4a214affde9cffffffffffff94d6ff4a214affd694ff ffffffffffbdffff212173212121212121de9c4affffffffffffffffff9cdeff21214a2121212121219c9c4a212173ffbd73ffffff4a9cde944a21ffffdeffff ffffffff73b5ff732121ffffb5ffffffffffff73bdff2121212121214a2121ffde9cffffffffffff94d6ff21214a212121732121ffffb59cdeff21214a212121 212121212121ffb573ffffff73b5ff2121212121219c4a21ffffd6ffffffffffffffffffffffffffffffffffffffffff9c9c9c9c9c9c9c9c9c9c9c9c9c9c9ce7 bd9cfffff7d6efff9c9c9cffe7bdffffffbde7ff9c9c9c9c9c9c9c9c9c9c9c9c9c9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7b ff0000ffa5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff732173bdffbd212173212121212121732121b5ffb5732173b5ffb521 2173212121212121732121bdffbd732173ffffbdffffffffffffffffffffffffd6ffff214a9cb57321ffffffffffff73bdff944a214a9cbd944a21ffffdeffff ff73bdff4a2121ffde9cffffff4a9cde944a21ffffded6ffff214a9cd6944affffffd6ffff214a9c4a2121ffde9c94d6ff4a214affd694ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ff2929ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff0000ff0000ff7373ffefefffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffff7bc6f7212131212121212121212121212121312121efc67b63adde212131212121212121212121de9c52ffff f7ffffffffffffffffffffffffffffffffffffbdffff212173de9c4affffffffffffffffffffffffffffffffffffffffff9cdeff21214a212121212121ffbd73 ffffff73bdff2121212121212121214a212194b59421214a212121212121212121ffbd7394d6ff4a214affd694ffffff73b5ff73212194d6b521214a2121214a 2121ffd694ffffffffffffffffff2173b52121212121219c4a214a94b59c4a21ffffd6ffffff94d6ff21214a212121732121ffffb5ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3994dede94423994de101010101010101010de9439 ffffffffffffffffffb5efff18296be7a552ffffffffffffffffffffffffffffffffffffffffffffffffffffff63b5ff1010106b1010ffffbdffffffffffffff ffffffffffffffffffffffffffffffffff3994de101010b56b10ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffff73bdef4a2931ffde9cffffffffffff73bdff212121bd7321ffffffffffffdeffff294a94bd7331ffffefffffffffffffffffffffffffffff ffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffd68c29d68c21d68c21d68421d68c29e78c21ffffc6ffffffffffffffffffefefffd68421d68c29d68c21d68c 21d68421d68c29ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffefffff427bc63939317b4231ffefc6d6f7ff29529cbd7321f7ffff4a8cd6212121c68431ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffbdffff212173ffbd73ffffffffffffdeffff214a9cde944affffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73 ffffff73bdff732121ffffbdffffffffffffffffffffffffffffff9cdeff4a214affde94ffffffffffff9cdeff4a214affde9cffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a94de9c52ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5a5a59c9c9c9c9c9c9c9c9ca5a5a5bd9c9cffffe7ffffffffffffff ffffffffff9cbde7a5a5a59c9c9c9c9c9c9c9c9ca5a5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff0000ff8c8cffffffffffff ffffffffffffffffffffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffbd ffff732173ffffbdffffffffffffffffffffffff9cdeff21214affbd73ffffffffffff9cdeff73214a217373bd7321ffffffffffffbdffff212173ffbd73ffff ffffffffffffffffffffdeffff214a94de9c52ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff0000ff4242ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffadadff1818ff0000ff2121ffe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffff3184ce9c4a29f7f7dec6d6e7295a942121216b2121ffefadffffff529cd6212131212121212121312121dead63fffff7ffffffffffffffff ffffffffffffffbdffff212173ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173 ffbd73ffffffffffffdeffff21529cde9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3994ded69439ffffffffffffffffffffffffffffffffffffffffffb5efff18216b d68c39ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6bbdff080808101010080808101010080808943910ffffd6106bbd080808de 9439ffffff3994de080808bd6b10ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff31 73bd522921efce94ffffffffffffffffffffffffffffffceefff29528c733121ffe7b5ffffffffffffffffffffffffffffffffffffffffffffffffbdffff2121 73ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffd68421d68c21d68421d68c21d68421e78c21fff7bdffffffffffffffffffefefffd68c21d68421d68c21d68421d68c21d68421ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bc6ffce8c4afffff78c ceff9c734a295294212121212121212121212121392121ffce8cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5ffff212173ffb5 73ffffffffffff4a9cde4a2121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffff73bdff732121ffffbd ffffffffffffffffffffffffffffff9cdeff4a214affde9cffffffffffff2173b5732121ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff214a9cd6944affffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffff9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9cd69c9cfffff7ffffffffffff9cd6ef9c9c9c9c9c9c9c 9c9c9c9c9c9c9c9c9c9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff0000ff7373ffffffffffffffffffffffffffffffffffff ffffffffffffffffffbdffff732173ffffbdffffffffffffffffffffffffade7ff632163ffe7adffffffffffffffffffffffffbdffff732173ffffbdffffffff ffffffffffffffff73b5ff732121ffffb5ffffffffffffdeffff214a94212121ffb573ffffffffffffdeffff214a94bd7321ffffff4a9cde732121ffffbdd6ff ff214a9cd6944affffffffffffffffffffffffffffff94d6ff21214affb573ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffbdbdff0000ff6363ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffefefff4a4aff0000ff2929ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b8cc6ff efbdffffffffffff63adef2121214a2121ffde9cffffffffffff4a94d6212129212121212121312121e7b56bfffff7ffffffffffffffffffffffffffffff4a94 d6732121ffffb5ffffffd6ffff734a9cffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffb5ffff212173ffb573ffffffffffffdeffff 214a94de9c4affffffffffff94d6ff21214affb573ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff3994dede9442ffffffffffffffffffffffffffffffffffffb5efff18296bd69442ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffff6bb5ff101010080808101010101010101010943908ffffde106bb5101010de9439ffffff3994de101010b5 6308ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f7ff4a84c6292129845a42ce bda5efefdebdcede5a84a5212939844a29f7e7bdffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd68c21d6 8421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84ceffce844affffff84cef7a5845229529c21212121 21212121214a3129efc684ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff2121732121212121212121214a2121ffde 9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff212173ffbd73ffffff73bdff732121ffffbdffffffffffffffffffffffff ffffff94deff212152212121212121212121732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffff9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9cff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffdedeff0000ff3131ffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff 294a94212121212121212121212121212121733921bddebd2139732121212121212121212121212121219c4a29ffffd6ffffffffffffffffffffffff2173bd94 4a21ffffdeffffffffffffffffff529cde732121ffffbdffffffffffffffffff4a9cde732121ffffbd4a9cde732121ffffbddeffff214a9cde9c4affffffffff ffffffffffffffffffff9cdeff21214affbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff9494ff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffff3939ff0000ff7b7bffc6c6fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84ceff21 2131944221ffffd6fffffffffffff7ffff4a94d62121292121212121214a2121ffde9cffffffffffffffffffffffffffffffffffff4a9cde2121212121212121 21ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 9cdeff21214affbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff63b5f7080810101010080808101010080808101010080808181010d68c39ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffadd6e7425a84212931212121212121523129ce a573fff7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd69439d68c21d68421d68c21d68421d6 8c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d69439ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff426bad2121296b4231ffd6a5d6ffff29529cbd7321ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff a5a5a59c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9ca5a5a5ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffff2121ff0808fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7373ff0000ffb5b5 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff0000ff 0000ff0000ff0000ff3131ffadadffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9cd6ff21214a522921f7d694ffffffffffffff ffffffffffefffff4a8cce212129312121efbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7b56bd68c21d68c21d68421d68c29d68c21d68c21d68421d68c29d6 8c21d68c21d68421d68c29d68c21d68c21d68421e7b56bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffffc6a5a5ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdbd9c9c9c9c9c9c9c9c9c a5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9cbdbdbdffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffff5252ff0000ffd6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a4aff0000ffd6d6ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff8484ff6363ff2121ff0000ff 0000ff2121ff7373ff8484ff9494ffdedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcef7ff7b7ba5ad947bf7e7d6ffffffffffffffffffffffffffffffffffffefffff4a 7bbdefbd7bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffff7efe7d68c29d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d68c21d68421d6 8c21d68421d68c29f7efe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefa5a5a59c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c 9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9ca5a5a5efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7b7bff0000ff8c 8cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1010ff1010ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadadff3131ff0000ff0000ff0000ff 0000ff0000ff2929ff6363ff8484ff7b7bff8484ffdedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdede deffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffff7efe7e7b56bd69439d68c21d68421d68c29d68c21d68c21d68421d68c29d68c21d68c21d69439e7b56bffefe7ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7bdbdbda5a5a59c9c9c9c9c9ca5a5a59c9c9c9c9c9c9c9c9ca5a5a59c9c9c 9c9c9ca5a5a5bdbdbdf7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6c6ff0000ff5252ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffd6d6ff0000ff4a4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefffbdbdffbdbdff7b7bff2929ff0000ff0000ff 0000ff0000ff0000ff2929ff5a5aff4242ff4242ff4242ff4242ff4242ff4242ff4242ff4242ff5252ffd6d6ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ff1818ff0000ff9c9cffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffff8c8cff0000ff7b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefffbdbdffc6c6ffbdbdff4a4aff0000ff 0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff8484ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffbdbdff0000ff0000ffb5b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5252ff0000ffc6 c6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceceffbdbdffc6c6ffbdbdffc6c6ff bdbdffc6c6ffbdbdffc6c6ffbdbdffceceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff9494ff0000ff0808ffbdbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff0000ff2929ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffff8484ff0000ff2929ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadadff0000ff7373ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a4aff 0000ff7b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffff8484ff0000ffa5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefff0808ff0000ffb5b5ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffff7f7ff1818ff0000ffd6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff0000ff1010ffbdbdffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff1818ff0000ff5252ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c8cff0000ff0000ff5252ffdedeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7ff8c8cff4a4aff0000ff0000ff6b6bffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffd6d6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffff9c9cff1818ff0000ff0000ff4a4aff9c9cffefefffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffb5b5ff5252ff0000ff0000ff0000ff1010ffa5a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffded6d6ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffff8c8cff2121ff0000ff0000ff0000ff3939ff5252ff9494ffc6c6ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdbdffc6c6ff9494ff8484ff7b7bff8484ff6363ff4242ff1818 ff0000ff0000ff1818ff7373ffc6c6fff7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6d6ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffb5b5ff5a5aff1010ff0000ff0000ff0000ff0000ff0000ff1010ff3939ff5252ffd6d6ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffe7e7ffbdbdffa5a5ff7b7bff6363ff3939ff1010ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff2929ff9c9cffefefffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffbdbdff8c8cff4a4aff2121ff0000ff0000ff0000ff4242ff8484ffa5a5fff7f7ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5b5ff7373ff4242ff0808ff0000ff0000ff0000ff00 00ff0000ff0000ff0000ff1818ff4242ff6363ff7b7bff8484ff8484ffc6c6ffbdbdffd6d6ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffbdbdff0000ff0000ff0000ff0000ff0000ff2121ff9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffc6c6ff3131ff0000ff0000ff0000ff0000ff4242ff5252ff8484ff9494ffbdbdffd6d6ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffe7dedeefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffff7f7f7dededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffceceffbdbdffc6c6ffb5b5ff5a5aff0000ff0000ff1818ff5a5aff8484ffadadffbdbdffc6c6ffdedeffffffffffffffffffffffffffffffffffffffffffff bdbdffc6c6ff8c8cff4a4aff0000ff0000ff2121ff9c9cffdedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefdededede deded6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6 d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dedede d6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6de deded6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6d6dededed6d6 d6dededee7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffbdbdff4a4aff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff 2121ff9c9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffbdbdff7b7bff8484ff4242ff4242ff4242ff1818ff0000ff0000ff0000ff0000ff0000ff2929ff4242ff6b6bff8484ffc6c6ffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefdededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dedededededededededededededededededededededededededededededededededededededededededededededededededee7dedee7e7e7dededee7e7e7e7de dee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7 dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7e7e7ffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffefefefdededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7 e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dedede e7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7de dedee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7 e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dedede e7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefdededee7e7e7dedede e7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7de dedee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7 e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dedede e7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7de dedee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7dededee7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7 e7e7e7efefe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7f7f7f7ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde dedeefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7 f7e7e7e7f7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeefefefffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffff7f7f7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeff7f7f7ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7efefefffffffffff ffffffffffffffffffffffffffffffffffffffffffffefefeff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7efefefffffffffffffffffffffffff ffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffefe7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffff7ffffffefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffff ffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffff ffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff dededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffdeffffce8c84c68442ce8c42e7b573ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7 e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffffc6847bce8c5a c68442ce8c42de9c4affffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffffefce d6fffff7ffffffffffffffffffbdbdd6ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffded6f7c68c63ce8c42f7c67b ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff314a94e7bd73fffff7ffffff4a94 d69c4a29ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5d6c68442de9c42ffffd6ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffdeefffc6c6c6e7cebdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeff ffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffff ffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff21529c312121e7bd734a94d62121299c4a21ffffdeffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeefffce8c7bce8442ffd694ffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffb5c6decebdbdff f7deffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffff ffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffdeffff214a942121212121212121212121219c4a21ffffd6ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ffe7dedee7cebdf7e7defffff7ffffffff ffffffffffffffffffffffffffffffffffffffffefe7efe7d6dee7c6adefe7defff7effffffffffffffffffffffffffffffffffffffffffff7ffffefe7efefde def7e7deffffefffffffffffffffffffffffffffffffc6a5b5ce8442dea54affffffffffffffffffffffffffffffffffffffffffeff7ffefe7dedec6c6efdec6 f7e7deffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcee7f7b5b5b5f7dec6ffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefeff7e7d6dee7ceb5efdedefff7efffffffffffffffffffffffffffffffffffffffff ffffffffefeff7e7d6deefcebdffefe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffefe7e7dec6c6f7e7cefff7e7ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefeff7e7dedee7c6b5efe7d6f7efdeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffff ffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdefff29 427b212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121312921dea5 5afffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5cece8c4ad69442ffffd6ffffff ffffffffffffffffffe7ffffce9c9cc68442efb563ffffffffffffffffffd6bddec68c52ce8c4ac68442ce8c42d6944affdeb5c6a5b5ce8c42dea542ffffffff ffffded6ffc68c63ce8c4ac68442ce8c42c68442ce8c4adead6bffffdeffffffffffffffffffffffffe7f7ffce9c9cc68442ce8c42c68442e7ad4affffffffff ffffffffffffffffffffceadbdc68442d68c4affefadfffffffffffffffffffffffff7ffffcea5adce8c4ac68442ce8c42c68442ce8c4ad6944af7cea5ffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f7ffbdbdd6d6bdb5ffffefffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeffc68463ce8c42ffd694ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffc6a5b5ce8c4ac68442ce8c42c68442ce8c4ace8442ce9452d6a56bf7d6b5fffff7ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63c68442ce8c42c68442ce8c4ac68442ce8c42c68442ce8c4ae7 b563ffffffffffffffffffd6cee7ce947bc68442ce8c4ac68442ce8c42ce8c42e7ad73fff7d6ffffffffffffffffffffffffefffffcea5adce8c4ac68442ce8c 42c68442e7ad63def7d6ce8c7bc68442ffc684ffffffffffffffffffffffffd6bdd6ce8c63c68442ce8c4ac68442ce8c42e7b573e7fff7c6847bce8c42ffc67b ffffffffffffffffffffffffe7e7ffce9c94ce8c4ac68442ce8c4ac68442ce8c42ce944af7ce9cfffff7ffffffffffffd6c6ffc68442d68c42ffffb5ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde21212139312942424239393939 3939212129212121212121212121212121312921393939393939393939424242393939393939393939424242393939212931732121ffffc6ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5d6c68442d69442ffffceffffffffffffffffffffffffefffff c69494ce8442e7ad5affffffffffffd6cef7c6844ace8c42ce8c42d6a573cea57bce8c63ce8c42ce9c7bc68442dea542ffffffffffffcebdffce8c42ce8c4ad6 a573cea57bd6a584c68452ce8442d69c4affffdeffffffffffffffffffceb5cec68442ce8442ce9452d6a584dea55affffffffffffffffffffffffdeefffc684 73ce8c42c68442f7bd73ffffffffffffffffffffffffe7ffffce949cc68442d69c5acea57bd6a584c69473ce844ace8442ffce8cffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffbdd6e7bdbdbdf7e7ceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffd6d6ffce8463ce8442ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffcea5b5c68442ce8442c68442ce8c42c68442ce8442c68442ce8c42c68442d6944af7d6adffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffdedeffc6845ace8442c68442ce8c42c68442ce8442c68442ce8c42c68442efb563ffffffffffffcebde7ce 8452c68442ce8c42ce9c63d6a584ce9c7bce8c4ac68442d6944afff7ceffffffffffffffffffc6a5bdce8c42c68442d6944acea57bce9c84c6844ad6a552c684 6bce8c42ffbd7bffffffffffffffffffcebde7ce8452c68442ce8c42ce9c5ad6a584c68c6bce8c42d6ad63ce847bc68442ffc67bffffffffffffffffffdedeff c68c6bce8442c68442d69c52cea57bd6a584c68c6bce8c4ad69442ffffd6ffffffffffffcebdffce8442ce8442ffffb5ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffffceb5cefff7e7ffffffffffffffffffffffffefff ffbdcee7ffe7ceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffff94c6e77b7b7b9c8484f7debdffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde212121ffbd73ffffffffffffdeffff21529c21212121212121 21212121219c4a21ffffdeffffffffffffffffffffffffffffffffffffffffffdeffff214a94732121ffffbdffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffceb5cece8c42d69442ffffd6ffffffffffffffffffffffffe7ffffce949cc68442efb563ffffff ffffffc6a5b5ce8c4ad69442fff7c6ffffffffffffeff7ffcea5b5c68442ce8c4adea542ffffffffffffdeceffefce94ffffffffffffffffffffffffdedeffc6 8463ce8c4affc684ffffffffffffefffffc6949cce8c42dea54affffffffffffffffffffffffffffffffffffffffffcebdefce8c4ace9c4ace8c63d69442ffff deffffffffffffffffffefffffdeb5adfff7d6ffffffffffffffffffffffffcea5b5ce8c4ade9c42ffffe7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdef7ffb5b5c6e7cebdfffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffdedeffc6845ace8c4affd694ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6a5b5ce8c42dea542ffff ffffffffffffffefe7efe7d6d6cead9cce8c52c68442ce8c4af7c67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffd6d6ffce8c63ce8442ffde9cffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63c68442dea552fff7d6ffffffff ffffffffffdee7f7ce8c7bc68442e7a552ffffe7ffffffdeffffce8c84c68442e7ad5afffff7ffffffffffffdee7ffc68c7bce8c4ac68442ffc67bffffffffff ffdeefffce8c7bc68442de9c4affe7c6ffffffffffffffffffcebdd6ce8c52c68442ce8c4affc67bffffffffffffefffffce9ca5ce8c42ce8c42ffdeadffffff ffffffffffffffffffe7e7f7dead9cffffd6ffffffffffffd6c6ffc68442d68c4affffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeff7ffa5bdd6 8c949c8484848c8c8c9c948cd6bdadffefe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff639cce6b6b6b63 63636b6b6bce9c63ffffffffffffffffffceffff6b6ba5ffce9cffffffffffffd6ffff63639cffd6a5ffffffffffffb5e7ff6b6b84e7b584ffffffffffffa5d6 ff636363ffd6a5ffffffffffffb5e7ff6b6b84636363846b6bb5ceb5846b84ffe7b5ffffffffffff6ba5d6636363a56b6bffffceffffffb5e7ff6b6b84636363 6b6b6bffce9cffffff9cceffa56b6bffffceffffffffffffa5d6ff9c6363ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffff297bc62121212121214a2121ffe79cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff8c9cc68c8484debda5fff7efffffffb5d6ef8c94a59c8484ffefc6ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff639cce6b6b6b6363636b6b6bce9c63ffffffffffffffffffceffff6b6ba5ffce9c ffffffffffffd6ffff63639cffd6a5ffffffbdefff6363846b6b6b636363ffd6a5ffffffffffffe7ffff6b84bd636363bd846bffffe784bdef6363636b6b6bb5 846384bdd6b58463ffffe7e7ffff6b84bde7b584ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffff73bdff292929212121212121de9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffff ffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffffad7ba5ffffdebdefffd6a58cffffffffffffffffffffffffffffffffffffffffff ffffffffffff84bdefb58463ffffe7ffffffffffffffffffffffffffffffbdefff6363846b6b6b636363bd846bffffe7ffffffffffffa5d6ff9c6363ffffd6ff ffffffffffceffff6b6ba5ffce9cffffffe7ffff6b84bd636363ffd6a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffff7bc6ff2121217b2121ffffbdffffffffffffffffffffffffffffff2173bd212121bd7321ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffff4a94d6212121ffb573ffffffffffffdeffff214a942121212121212121212121219c4a21ffffd6ff ffffffffffffffffffffffffffffffffffffffffd6ffff214a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffceb5d6c68442de9442ffffceffffffffffffffffffffffffefffffc69494ce8c42e7ad5affffffffffffcea5b5c68442e7ad52 ffffffffffffffffffffffffdef7ffce8c84c68442dea542ffffffffffffffffffffffffffffffffffffffffffffffffdeffffce8c7bc68442ffc67bffffffff ffffe7ffffce949cc68442f7bd73ffffffffffffffffffffffffffffffffffffefffffce9ca5c68442e7c684c68c8cce8c42ffce8cffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffceb5d6c68442d69442ffffceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff f7ffffbdcee7bdb5b5fff7deffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce 8c63ce8442ffd69cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcea5b5c68442dea542ffffffffffffffffffffffffffff ffffffffdee7ffce9c9cc68442ce8442f7c67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ff c6845ace8c42ffd694fffffffffffffffffffffffffffffffffffffffffff7ffffcea5bdc68442d69442fff7c6ffffffffffffffffffffffffffffffd6cef7ce 8c5ac68442ffd694ffffffdeffffc6847bce8442ffce8cffffffffffffffffffffffffd6ceffc6844ace8442ffbd7bffffffffffffcebddec68442ce8c42ffde 9cffffffffffffffffffffffffffffffceadc6ce8c42c68442ffc67bffffffffffffd6ceffce845ac68442ffce84ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffcebdffce8c42ce8442ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffadcee79c848cdec6b5f7efe7fffffff7ffffe7f7f7 adc6de8c8c9cdebd9cfffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff639ccebd846bffffe7ffffffffffff6b9cd6b58463ff ffe7ffffffd6ffff63639cffd6a5ffffffffffffceffff6b6ba5ffce9cffffffffffff84bde77b7b63bd8484ffffe7ffffff639cce848484e7b584ffffffe7ff ff6b84bdce9c63ffffffe7ffff6b84bd846363ffe7bdffffffbde7ff636384ffd6a5ffffffffffffb5e7ff6b6b84e7b57bffffffffffffa5a5d6ffffce9cd6ff 9c6363ffffd6ffffffffffff9cceffa56b6bffffceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2173bd2121 212121212121212121214a2121ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffff ffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffff84add68484848484848c8c84848c8c848484848484b58484ffffd6ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffff639ccebd846bffffe7ffffffffffff6ba5d6b57b63ffffe7ffffffd6ffff63639cffd69cffffffffffffceffff6b6b9c ffce9cffffff9c9cceffffd6ffffffbde7ff7b637bffe7bdffffffa5d6ff7b6363ffe7bdffffffbde7ff63637bffd69cffffffbde7ff63637bbd846bffffe7e7 ffff637bb5e7bd84ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121212121212121 212121212121de9c4affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffff ffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffd6ffffad84adfff7d6b5deffd6a584ffffffffffffffffffffffffffffffffffffffffffffffffffffff7bb5e7bd846b ffffe7ffffffffffffffffffffffffbde7ff63637be7bd84ffffffffffff7bb5e79c6b6bffffceffffff9cceff9c6b6bffffceffffffffffffd6ffff63639cff d6a5ffffff6b9cd6846363ffe7bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121 732121ffffbdffffffffffffffffffffffffffffff2173bd212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffff529cde212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffdeffff214a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffceb5cece8c4ad69442ffffd6ffffffffffffffffffffffffe7ffffce9c9cc68442efb563ffffffffffffcea5b5ce8c42de9c42ffffefffffffffffffffffff ffffffc6a5b5ce8c42dea542fffffffffffffffffffffffffffffffffffffffffff7ffffd6b5cec6844ace8c42ffc684ffffffffffffefffffc69494ce8c4aff c67bffffffffffffffffffffffffffffffffffffded6ffc6845ad68c42fff7bdceb5d6c68442e7ad52fffff7ffffffffffffffffffffffffffffffffffffffff ffffffffe7e7ffc68c7bce8c42d69c42ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcee7ffbdbdbdefd6bd ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeffc68463ce8c42ffd694ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6a5b5ce8c4adea542ffffffffffffffffffffffffffffffffffffffffffe7f7ffce9c 9cc68442d6944afff7bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63ce8442ffde9cffffff ffffffffffffffffffffffffffffffffffffe7ffffc68c84ce8c4aefb56bffffffffffffffffffffffffffffffffffffefffffc69494ce8c42e7b55affffffde ffffce8c84c68442f7bd73ffffffffffffffffffffffffdeffffce8c7bc68442ffc684ffffffffffffc6a5b5ce8c4ade9c42ffffefffffffffffffffffffffff ffffffffdedeffc68463ce8c42ffc67bffffffffffffceb5d6c68442de944affffc6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff d6c6ffc68442d68c42ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffff7ffff94b5dec6a58cfff7e7e7f7ff9cadce848c8c8c8c8cc6ad94fff7e7e7ffff94adced6b58c fffff7ffffffffffffffffffffffffffffffffffffffffffffffffb5e7ff846b84ffe7b5ffffffffffffffffffceffff846ba5ffe7b5ffffffceffff6b6ba5ff ce9cffffffffffffd6ffff63639cffd6a5ffffffffffff639cced6bd848484b5ffefbdceffff846ba5b5ceb5bd8484ffffe7e7ffff6384b5efbd84ffffffffff ffb5e7ff846b84ffe7b5ffffffb5e7ff846b84ffe7b5ffffffffffff6ba5d6ce9c63ffffffffffffffffffffffffffffff9cceffa56b6bffffceffffffffffff a5d6ff9c6363ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9ce7ff21214a7b2121ffffbdffffff2173bd2121 21bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffff9cceef8484848c8c8c8484848c8c8c8484848c8c8cc69c84ffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffb5e7ff846b84ffe7b5ffffffffffffffffffceffff846ba5ffe7b5ffffffceffff6b6ba5ffce9cffffffffffffd6ffff63639cffd6a5ffffffffffffffffff ffffffceffff6b6ba5ffce9cffffff9cceffa56b6bffffceffffffb5e7ff846b84ffe7b5ffffffffffff84bde7b58463ffffefe7ffff6b84bde7b584ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7 e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff29529c212121ffc67bffffff7bc6ff2121217b2121ffffbd ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffde dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffaddef76b6b7bad7363ffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffff84bde7b58463ffffefffffffffffffffffff ffffff639cced6a56bffffffffffffffffffe7ffff6384b5efbd84ffffffa5d6ff9c6363ffffd6ffffffffffffceffff6b6ba5ffce9c84bde7846363ffefbdff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7 e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bc6ff2121217b2929ffffbdffffffffffff ffffffffffffffffff2173bd292929bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 4a94d6212121ffb573ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff21 4a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5d6c68442d69442ffff ceffffffffffffffffffffffffefffffc69494ce8442e7ad5affffffffffffd6cef7c6844ace8c42dead6bfff7deffffffffffffffffffcea5b5c68442dea542 ffffffffffffffffffffffffffffffeff7ffd6b5c6ce946bc68442ce8442d69442ffffd6ffffffffffffe7ffffce949cc68442ffc67bffffffffffffffffffff ffffffffffffffffc6adc6ce8442dea54affffffd6deffce846bd68c42ffffbdffffffffffffffffffffffffffffffffffffded6efcea59cc6844ace8442c684 42f7c684ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffb5bdd6d6bdbdfff7e7ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8463ce8442ffde9cffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffcea5b5c68442dea542ffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63c68442efb56bffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeffc6845ace8442ffd694ffffffffffffffffffffffffffffff ffffffffffffd6deffce8c63c68442ffce8cffffffffffffffffffffffffffffffffffffffffffcea5b5c68442dea542ffffffffffffc6a5bdce8c42ce8c42ef ce9cffffefffffffffffffdeffffc6847bce8c42ffbd7bffffffe7ffffce949cc68442e7ad52ffffffffffffffffffffffffffffffffffffdeffffce847bc684 42ffc67bffffffffffffc6a5b5ce8c42d69442efe7d6efdedeefe7deefdedeefe7deefdedeefe7deefdedef7e7defffff7ffffffcebdffce8442ce8442ffffb5 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffa5ceefc69c84ffffefe7ffff8ca5ce848484848484848484848484c69c84ffffefe7ffff8ca5cee7c69cffffffffffffffffff ffffffffffffffffffffffffffffff9cd6ff9c6363ffffd6ffffffffffffffffffe7ffff637bb5e7bd84ffffffd6ffff63639cffd69cffffffffffffceffff6b 6b9cffce9cffffffceffff846b9cffe7b56ba5d6e7b57bbde7ffb58484d6ffe77b639cffe7bdffffff84bde79c6363ffffd6ffffffbde7ff7b637bffe7bdffff ffbde7ff7b637bffe7bdffffffe7ffff637bb5e7bd84ffffffffffffffffffffffffffffffa5d6ff9c6363ffffd6ffffffffffff9cceff9c6b6bffffceffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde212121bd7321ffffffffffff73bdff2121219c4a21ffffdeffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadd6ff84 8484848484848484848484848484848484deb584fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5d6ff9c6363ffffd6ffff ffffffffffffffe7ffff6384b5e7bd84ffffffd6ffff63639cffd6a5ffffffffffffceffff6b6ba5ffce9cffffffffffffffffff639cce6b6b6b9c6363ffffd6 ffffff9cd6ff9c6363ffffd6ffffffe7ffff6384b5d6a56bffffffffffff84b5e7bd846bffffe7e7ffff6384b5e7bd84ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff21214a732121ffffbdffffffbdffff2121734a2121ffde9cffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbde7ff6363 84bd846bffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffff84b5e7bd846bffffe7ffffffffffffffffffe7ffff6b84bde7b584ffffff ffffffffffffffffff6ba5d6ce9c63ffffff9cceffa56b6bffffceffffffffffffd6ffff63639c848484636363ffd6a5ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121732121ffffbdffffffffffffffffffffffffffffff2173bd 212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde212121212121212121 212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121732121ffffbdffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5cece8c42d69442ffffd6ffffffffffffffffffffff ffe7ffffce949cc68442efb563ffffffffffffffffffd6bdd6c68452ce8c42c68442ce944ace9452d6ad7bc68c6bce8c4adea542ffffffffffffffffffeff7ff d6b5c6c68452ce8c4ac68442ce8c42dead63ffffdeffffffffffffffffffefffffc69494ce8c42ffc67bffffffffffffffffffffffffffffffdef7ffce8c84ce 8442ffce8cfffffff7ffffc69ca5ce8c4af7bd73ffffffffffffffffffffffffdedef7c69484ce8c4ac68442ce8c42ce944af7cea5ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6def7b5b5b5f7e7ceffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffdedeffc6845ace8c4aefce8cf7e7deefe7def7e7e7fff7e7ffffffffffffffffffffffffffffffff ffffffffffc6a5b5ce8c42dea542fffffffffffffffffffffffffffffffffffffffffffffffff7ffffc69cadce8c42d69c42ffffe7ffffffe7ffffd6a5a5d6ad 84d6a584d6ad84d6a584d6ad84dead84ffffe7ffffffffffffd6d6ffce8c63ce8442ffde9cffffffffffffffffffffffffffffffffffffffffffdedeffc68463 ce8c42ffd694ffffffffffffffffffffffffffffffffffffffffffc6a5b5ce8c4adea542ffffffffffffefffffce9ca5ce8c42c68442ce8c4ace8c52d69c63ce a584ce8c5ac68442ffc67bffffffefffffc69494ce8c42e7b55affffffffffffffffffffffffffffffffffffdeffffc6847bce8c4affc67bffffffffffffcea5 b5c68442ce8c42c68442ce8c4ac68442ce8c42c68442ce8c4ac68442ce8c42d69442ffffd6ffffffd6c6ffc68442d68c4affffb5ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ff ff9c8cb5ffefceffffffb5deff84848c8c8c8c8484848c8c8c8484848c8c8cffd6b5ffffffc6efffbd8ca5ffffdeffffffffffffffffffffffffffffffffffff ffffff84b5e7bd846bffffe7ffffffffffffffffffe7ffff6b84bde7b584ffffffceffff6b6ba5ffce9cffffffffffffd6ffff63639cffd6a5ffffffa5d6ff9c 6363ffffd69cceffd6a56b84b5e7d6a56bffffff6ba5d6e7b584ffffffffffffa5d6ff6363636b6b6b636363846b6bffe7b5ffffffb5e7ff846b84ffe7b5ffff ffe7ffff6b84bde7b584ffffffffffffffffffffffffffffff9cceffa56b6bffffceffffffffffffa5d6ff9c6363ffffd6ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffff529ce72121219c5229ffffdeffffff2173bd292929bd7321ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdef7ff8c94b58484848c8c8c8484848c8c8c84 84848c8c8c8c8484f7deb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84b5e7bd846bffffe7ffffffffffffffffffe7ffff6b84 bde7b584ffffffceffff6b6ba5ffce9cffffffffffffd6ffff63639cffd6a5ffffffa5d6ff636363846b6bffe7b5ffffffffffffffffff9cceffa56b6bffffce ffffffffffffffffff639cce6b6b6b6363636b6b6bb58463ffffe7e7ffff6b84bde7b584ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffff9cdeff2121524a2121ffe79cffffff7bc6ff2121217b2929ffffbdffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8cbde76b6b73846b63ffe7bdffffffffff ffffffffffffffffffffffffffffffffffffffffffff84bdefb58463ffffe7ffffffffffffffffffe7ffff6384b5efbd84ffffffffffffffffffffffff639cce d6a56bffffffa5d6ff9c6363ffffd6ffffffffffffceffff6b6ba5848484a56b6bffffceffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffff7bc6ff2121217b2121ffffbdffffffffffffffffffffffffffffff2173bd212121bd7321ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a94d6212121212121212121393129424242393939393939 393939424242393939393939393939424242393939393939393939424242393939393939393939212931732121ffffbdffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5d6c68442de9442ffffceffffffffffffffffffffffffefffffc69494ce8c42e7ad 5affffffffffffffffffffffffe7e7f7d6adadce9c7bc68c52ce844ac68442ce8c42c68442dea542ffffffffffffefffffce9cadc68442ce8c42ce8c42e7bd8c fff7deffffffffffffffffffffffffffffffe7ffffce949cc68442ffc67bffffffffffffffffffffffffffffffd6bdefc68442d68c42ffffbdffffffffffffd6 bdefc68442de9c42ffffd6ffffffffffffd6cef7c6845ace8c42c68442d6a563f7d6b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffdef7ffbdbdcedec6b5fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffd6d6ffce8c63c68442ce8442c68442ce8c42c68442ce8442d6944affdeadffffffffffffffffffffffffffffffcea5b5c68442de a542ffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5d6c68442d68c42ffffb5ffffffdeffffce8c7bc68442ce8442c68442ce8c42c684 42d69442ffffceffffffffffffd6d6ffc6845ace8c42ffd694ffffffffffffffffffffffffffffffffffffffffffd6efffce8473c68442ffce84ffffffffffff ffffffffffffffffffffffffffffffcea5b5c68442dea542ffffffffffffffffffffffffdeceded6ad9cc6946bce8c5ac68442ce8c42c68442ce8442ffbd7bff fffff7ffffce9cadc68442dea54affffffffffffffffffffffffffffffffffffdeffffce8c7bc68442ffc67bffffffffffffc6a5bdce8442c68442ce945ac68c 52ce945ace8c52ce945ac68c52ce8c52c68442de9442ffffd6ffffffcebdffce8c42ce8442ffefadffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffff9cc6efcead8cffffef9cc6 e7d6ad8484add6848484848484848484848484efce9ceff7ff94add6e7c69cffffffffffffffffffffffffffffffffffffffffffffffff84bde7b57b63ffffe7 ffffffffffffffffffe7ffff6384b5e7bd84ffffffd6ffff63639ce7bd84ffffffffffffceffff6b6ba5ffce9cffffff639cced6a56bffffffbde7ff8463846b 8484ffce9cffffff84b5e7d6a56bffffffffffffffffffffffffffffffbde7ff846384ffe7bdffffffbde7ff846384ffe7bdffffffffffff84b5e7bd846bffff e7ffffffffffffffffffffffff9cd6ff846363ffe7bdffffffffffff9cceffa56b6bffffceffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffff4a9cde212121212121212121212121212121212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6eff78494b58484848484848484848484848484848484848484848484848c8484f7 deb5fffff7ffffffffffffffffffffffffffffffffffffffffffffffff84bde7b58463ffffe7ffffffffffffffffffe7ffff637bb5e7bd84ffffffd6ffff6363 9ce7bd84ffffffffffffceffff6b6b9cffce9cffffff639cced69c6bffffffffffffffffffffffffffffffa5d6ff9c6363ffffd6ffffffffffffffffffffffff ffffffffffff7bb5e7bd846bffffe7e7ffff637bb5d69c6bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ff9cdeff21214a212121212121212121212121212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7 ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84bde76b6b73847b6b6b6b84846b63ffe7b5ffffffffffffffffffffffffffff ffffffffffffffffffff7bb5e76b6b6b6363636b6b6b636363d69c6bffffff6ba5d6b57b63ffffe7ffffffffffffe7ffff6b84bde7b584ffffff9cceff846b6b ffe7b5ffffffffffffd6ffff63639cffd6a5639cce9c6b6bffffceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffff73bdff212121732121ffffbdffffffffffffffffffffffffffffff2173bd212121bd7321ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffff529cde212121212121212121ffbd73ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffceb5cece8c4ad68c42ffffbdffffffffffffffffffffffffe7ffffce9c9cc68442efb563ffffffffffffffffffffff fffffffffffffffffffffffffffffffff7f7ffc69ca5ce8c42dea542ffffffffffffd6d6ffc6845ace8c4ae7b563fffff7ffffffffffffffffffffffffffffff ffffffffffffefffffc69494ce8c4affc67bfffffffffffffffffffffffff7ffffc69ca5ce8c4ae7a54affffffffffffffffffdeefffce8c7bce8442ffde9cff fffff7ffffc69cadce8c4ad68c42ffe7b5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffbdcee7c6bdbdffefdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff dedeffc68463ce8c42ce8c4ace945ace8c52ce8c52c68442ce8c4ace8442efbd73fffff7ffffffffffffffffffc6a5b5ce8c4adea542ffffffffffffffffffff ffffffffffffffffffffffffffffffffffcec6ffce8c4ace8442ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffd6d6ffce8c63ce8442ffde9cffffffffffffffffffffffffffffffffffffffffffe7ffffc68c8cce8c4ae7b563ffffffffffffffffffffffffffffffffffff efffffc69494ce8c42e7ad52ffffffffffffffffffffffffffffffffffffffffffffffffffffffdee7efce8c7bc68442ffc684ffffffffffffceadc6ce8c4ad6 9442ffffd6ffffffffffffffffffffffffffffffdef7ffc68473ce8c42ffc67bffffffffffffd6bdefc68442de944affffc6ffffffffffffffffffffffffffff ffceadc6ce8c4adea542ffffffffffffd6c6ffc68442ce8c42ffc684ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffff94b5decea58cb5dee7c69484bddee7848c948c8c 8c8484848c8c8ce7d6b594adced6b58cfffff7ffffffffffffffffffffffffffffffffffffffffffffffff84b5e7bd846bffffe7ffffffffffffffffffe7ffff 6b84bde7b584ffffffceffff6b6ba5846363ffe7bdffffff84bdef846363ffe7bde7ffff6b84bde7b584ffffffe7ffff6b84bd846363ffe7bdffffffbdefff9c 6384ffffd6b5e7ffefbda5ffffffffffff84b5e7a56b6bffffceffffffb5e7ff846b84ffe7b5ffffffffffffd6ffff63639ce7bd84ffffffffffffb5b5e7ffff d69cceff6b6b6bb58463ffffe7e7ffff6b84bdb58463ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff529ce721 2121c67b212173bd292929212121e79c52ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffdef7ff8c94b58484848c8c8c8484848c8c8c8484848c8c8c8484848c8c8c8484848c8c8c8c8484f7deb5ffffffffffffff ffffffffffffffffffffffffffffffffff84b5e7bd846bffffe7ffffffffffffffffffe7ffff6b84bde7b584ffffffceffff6b6ba5846363ffefbdffffff84bd e7846363ffefbdffffff84bde7b58463ffffefffffffbdbde7ffffceffffff9cceffa56b6bffffceffffffffffffa5bde7ffe7b5ffffffe7ffff6b84bdce9c63 ffffffe7ffff6b84bd846363ffefbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff2929527321217bc6 c62121212929299c4a21ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffff ffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffff84b5e76b6b6bbd8c6bffffe7bde7ff6b7b94846b63f7deb5ffffffffffffffffffffffffffffffffffffffffff84bd e7b58463ffffefffffffffffffffffffffffffb5e7ff6b6b84e7b584ffffffffffff84bde79c6363ffffd6ffffffa5d6ff636363d6a56bffffffffffffceffff 6b6ba5ffce9ce7ffff6384b5bd846bffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7bc6 ff2121217b2929ffffbdffffffffffffffffffffffffffffff2173bd292929bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffff4a94d6212121212121212121ffb573deffff3963a5844242ffffbdffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffd6ffff214a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffceb5d6c68442ce8442f7bd7bffffffffffffffffffffffffdeefffc68473ce8442f7bd73fffffffffffffffffff7f7f7ffffffffffffffffffffff fffffffff7ffffce9cadc68442e7ad52ffffffffffffcebdffce8c42ce8442fff7b5ffffffffffffffffffffffffffffffffffffffffffffffffe7ffffce949c c68442ffc67bffffffffffffffffffffffffd6deffce8c6bc68442ffce8cffffffffffffffffffffffffc6a5b5ce8c42e7ad52ffffffe7ffffce949cc68442e7 b55affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffd6efffb5b5bdefd6bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8463ce8442ffde9c ffffffffffffffffffe7e7f7c69c94ce8442c68442f7c684ffffffffffffffffffcea5b5c68442dea542ffffffffffffffffffffffffffffffffffffffffffff ffffffffffd6c6ffc68442ce8442ffd694ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeffc6845ace8442ffd6 94ffffffffffffffffffffffffffffffffffffffffffffffffceadc6c68442d68c42fff7bdffffffffffffffffffffffffffffffd6cef7ce845ac68442ffce84 fffffffffffff7ffffffffffffffffffffffffffffffffffffffffdeefffc68473ce8c42ffc684ffffffffffffd6d6ffc68452ce8442f7ce8cffffffffffffff ffffffffffffffffcebde7ce844ac68442ffc67bffffffffffffdeefffce8c73c68442ffc684ffffffffffffffffffffffffefffffce9ca5c68442efbd6bffff ffffffffcebdffce8442c68442dea552ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffa5c6e784848c8c848ccead8cefefe784a5c68484848484848c8c8cdebd 9cfffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffff84bde7b58463ffffe7ffffffffffffffffffe7ffff637bb5e7bd84ffffffd6ffff 63639ce7d69c6384b56b6b6b636363e7bd84ffffffbde7ff7b637bffe7bdffffffffffff639ccebd846bffffe7ffffffceffff6b6b9cffce9cffffff7bb5e76b 6b6b636363846b6bffe7b5ffffff84b5e76b6b6b6363636b6b6b9c6363ffffd6ffffffd6ffff63639c6b6b6b636363e7bd84ffffffa5d6ff9c6363bde7d66363 846b6b6b7b6363ffe7bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff21214a732121ffffbdffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffff ffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffefffffd6d6deb5c6cea5adb594949c84848c848484848484848484948c8cb5a59cbdb5b5d6d6cef7efdeffffffffffffffffffffffffffffffffffffff ffffffffff84bde7b57b63ffffe7ffffffffffffffffffe7ffff6384b5e7bd84ffffffd6ffff63639ce7d6a5637bb56b6b6b636363e7bd84ffffffffffffffff ff6ba5d66363636b6b6be7b584ffffff639cce6b6b6b6363636b6b6bb57b63ffffe7e7ffff6b84bd6363636b6b6bb58463ffffe7ffffffe7ffff6384b5d6bd84 637bb56b6b6bffce9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c212121ffbd73ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffff ffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffe7ffff6b84bd946363ffffceffffffffffff94cef76b6b6bce9c63ffffffffffffffffffffffffffffffffffffffffff84b5e7bd846bffffe7ffffffffff ffffffffffffffffffffceffff6b6ba56363636b6b6b9c6363ffffd6ffffffffffff9cceffa56b6b9ccece6b6b6bb58463d6ffe763639cffd69cffffffd6ffff 63639c9c6b6bffffceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73bdff212121732121ffffbdffff ffffffffffffffffffffffffff2173bd212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff dededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffff4a9cde212121212121212121ffbd73deffff21529c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff deffff214a94732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5cece8c42c6 8442d6944affdeadfffffffffffff7ffffcea5b5ce8c42ce8442ffe7a5ffffffffffffffffffd6b5d6e7b573ffffe7ffffffffffffffffffded6ffc6845ace8c 4af7bd73ffffffffffffdedeffc68463ce8c42f7c67bfffffffffffffffffff7ffffefdedeffffefffffffffffffefffffc69494ce8c42ffc67bffffffffffff ffffffffffffceb5cec68442d69442ffffc6ffffffffffffffffffffffffd6ceffc6844ad68c42fff7bdffffffcea5b5ce8c42d69442ffffd6ffffffffffffff ffffeff7ffffded6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffbdc6decebdb5ffff efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeffc6845ace8c4affd694ffffffffffffffffffffffff efffffc69494ce8c4ad69442ffffdeffffffffffffc6a5b5ce8c42dea542ffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5dece8c42ce 8442ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63ce8442ffde9cffffffffffffffffffffff ffffffffffffffffffffffffffdee7ffce8c73c68442de9c52fff7ceffffffffffffffffffdedef7ce8c7bc68442de9c4affffceffffffffffffefffffce9c9c f7ce9cfffff7ffffffffffffffffffceadcece8c4ace8c42fff7adffffffffffffefffffce9ca5c68442d6944affdeadffffffffffffffffffd6cee7ce8c63c6 8442ce8c4affc67bffffffffffffffffffceadc6ce8c42ce8c42ffdeadffffffffffffffffffd6bddec6844ad68c42ffdea5ffffffffffffd6c6ffc68442ce8c 4ace945ae7bd73fff7effffffff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffeff7ffa5bdd68c949c8484848c8c8c9c948cd6bdadffefe7ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffff84b5e7bd846bffffe7ffffffffffffffffffe7ffff6b84bde7b584ffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffb5e7ff846b84ffe7b5ffffffffffffffffffffffffffffffffffffffffffffffffffffff9cceffa56b6bffffceffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff214a9c292929bd7321ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7 e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffff7ffff94b5de8484848c8c8cb58c84ffffdeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84b5e7bd846bff ffe7ffffffffffffffffffe7ffff6b84bde7b584ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff9cceffa56b6bffffceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff529ce72121217b2929ffffbdffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6f7ff637ba58c6b6bff e7bdffffffffffff94c6ef636363c6946bffffefffffffffffffffffffffffffffffffffffff84bdefb58463ffffe7ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceffff6b6ba5ffce9cffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff217bc67321217bc6c62121217b2121ffffbdffffffffffffc6ffff212173c67b 292173bd212121bd7321ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a94d62121212121 21212121ffb573ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff214a9c732121ffffbd ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5d6c68442d69442c69c94ce8442ce9c52d6 a584c68c63ce8442c68442dea552ffffe7ffffffffffffffffffceadcece8442c68442d69c63cea57bce9c84c6844ace8c42ce8c42fff7bdfffffffffffff7ff ffcea5b5c68442ce8c42ce9452d6a584ce9c7bce8c5ad69442ffffd6d6d6ffce8c63c68442ce8442c68442ce8c42c68442ce8442dea542e7ffffc68c84ce8442 e7ad52ffffffffffffffffffffffffffffffdef7ffce8c84c68442f7bd73ffffffd6d6ffc68463ce8c42ce8c42d6a573cea57bce9c73c6844affc67bffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6def7bdbdbdf7dec6ffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63ce8442ffd69cffffffffffffffffffffffffffffffd6bdefc68442ce8442 ffde9cffffffffffffcea5b5c68442dea542ffffffffffffffffffffffffffffffffffffffffffffffffffffffceadbdc68442d69442ffffc6ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffc6845ace8c42ffd694ffffffffffffffffffffffffffffffffffffffffffffff ffffffffd6c6e7ce8c5ac68442ce8c42ce9c5ad6a584c69473ce844ac68442d68c42ffe7adffffffffffffffffffe7ffffce949cc68442ce8c4ace9c6bd6a584 c69473ce8c4ac68442e7ad52fffff7ffffffffffffffffffdee7ffce8c7bc68442ce8442ce944ad6a584c68c6bce844ace9c42ce8c6bc68442ffc67bffffffff ffffffffffe7f7ffc69c9cce8c42c68442d69c5acea57bce9473c68442ce8442e7ad63ffffffffffffffffffcebdffce8c42ce8442d6bda5c68442ce8c42c684 42dea542ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffff84bde7b57b63ffffe7ffffffffffffffffffe7ffff6384b5e7bd84ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbde7ff846384ff e7bdffffffffffffffffffffffffffffffffffffffffffffffffffffff9cd6ff9c6363ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffff9cdeff21214a212121212121212121732121ffffbdffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6e7ff84849c 848484efce9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84bde7b58463ffffe7ffffffffffffffffffe7 ffff637bb5e7bd84ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5d6ff9c63 63ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffdeffff214a9c212121212121212121212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff948cc6ffefc6ceefffbd949cffffe7c6efffc6948cff ffef94c6efefc694ffffffffffffffffffffffffffffffffffff7bb5e7bd846bffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff63639cffd6a5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffff2173bd212121212121212121732121ffffbdffffffffffffbdffff212173212121212121212121bd7321ffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff529cde212121212121212121ffbd73ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c732121ffffbdffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceb5cece8c4ad69442f7ffd6ceb5c6ce8c5ac68442ce8c42c68442dea55aff f7ceffffffffffffffffffffffffeff7ffceadadce8c5ac68442ce8c42c68442ce8c4ad6944affe7bdfffffffffffffffffffffffff7ffffd6bdc6ce8c63ce8c 42c68442ce8c4ace8442de9c52ffffd6dedeffc68463ce8c42c68442ce8c4ac68442ce8c42c68442e7a54ad6c6f7ce8c52ce8442ffd694ffffffffffffffffff ffffffffffffffffffcea5bdce8c4ade9c42ffffefffffffe7deffce9c8cce8c4ac68442ce8c4ac68442ce8c42ffc684ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffb5bdcedec6bdffffefffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffdedeffc68463ce8c42ffd694ffffffffffffffffffffffffffffffd6c6ffce8c42ce8442ffde9cffffffffffffc6a5b5 ce8c4adea542ffffffffffffffffffffffffffffffffffffffffffffffffe7ffffc68c84ce8c4ae7a54affffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffd6d6ffce8c63ce8442ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedef7cea5 94c6844ace8c4ac68442ce8c42c68442dea563ffe7c6ffffffffffffffffffffffffffffffdedef7ce9c8cc6844ace8c42c68442ce8c4ace8c42e7ad63fff7de ffffffffffffffffffffffffffffffe7e7ffcea59cc6844ace8c4ac68442ce8c42d69c52e7f7cec6847bce8c42ffc67bfffffffffffffffffffffffff7ffffce b5bdce8c5ac68442ce8c4ac68442ce8c4aefbd84ffffffffffffffffffffffffd6c6ffc68442d68c42f7ffb5d6b5c6c6844ace8c42dea542ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84b5e7bd84 6bffffe7ffffffffffffffffffe7ffff6b84bde7b584ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffff9cceffa56b6bffffceffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffc6ffff2121732929292121217b2121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8cb5d6b58c8cfff7d6ffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84b5e7bd846bffffe7ffffffffffffffffffe7ffff6b84bde7b584ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffff217bc6212121292929212121ffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffff948cbdffefc6deffffb58ca5ffffe7bde7ffd6a58cffffffa5d6ffe7bd8cffffffff ffffffffffffffffffffffffffff84bde76363636b6b6b6363636b6b6b9c6363ffffd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffceffff6b6ba5ffce9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffff529ce72121217b2929ffffbdffffffffffffffffffffffffe7ffff214a9c292929bd7321ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a94d6212121212121212121ffb573deffff3963a5844242ffffbdffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff214a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ffefe7e7efdedeffefe7ffffffffffffffffffffffffffffffff fffffffffffffffff7ffffefe7efefdedeefe7def7efdeffffffffffffffffffffffffffffffffffffffffffffffffffffffefe7efefe7deefdedeffefe7ffff ffffffffffffffffffffe7ffffce949cc68442ffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffeff7ffefe7deefdedef7e7deffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffbdd6efbdb5b5ffefd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffd6d6ffce8463ce8442ffde9cffffffffffffffffffffffffffffffd6c6f7c68442ce8c42ffd694ffffffffffffcea5b5c68442dea542ffffffffffff ffffffffffffffffffffffffffffffffffffceadcece8c42ce8442ffd69cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffdedeffc6845ace8442ffd694fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffefdedeefe7deefde deffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ffefdedeefe7deefdedefff7efffffffffffffffffffffffffffffffffffff fffffffffffffffffff7f7ffefdedeefe7def7efdeffffffdeffffce847bc68442ffc67bfffffffffffffffffffffffffffffffffffff7ffffefe7efefdedef7 e7defffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7ffefdedefff7efffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeff ffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffceefffe7c6b5ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffff ffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffadd6ef847b8c847b7bf7d6adfffffff7ffff84a5d684847bad847bfff7d6ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffff4a9cde212121212121212121ffbd73deffff21529c732121ffffbdffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffdeffff214a94732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefff ffc69494ce8c42ffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffd6efffbdbdc6e7cebdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeffc6845ace8c 4affd694fffffffffffffffffffffffff7ffffc69cadce8c4ad68c42ffffbdffffffffffffc6a5b5ce8c42dea542ffffffffffffffffffffffffffffffffffff f7ffffceadc6ce8c4ace8442efb563fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63ce 8442ffde9cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdeffffc6847bce8c4affc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffff ffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffff ffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffff4a94d6212121212121212121ffb573ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffd6ffff214a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffffce949cc68442ffc67bffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7 ffffb5bdd6cebdbdfff7deffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63ce8442ffd69cffffffffffffffff ffe7e7f7cea5a5ce8c4ac68442e7ad5affffffffffffffffffcea5b5c68442dea542ffffffffffffffffffffffffe7e7efd6bdc6c68c6bce8c42c68442dea552 ffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffc6845ace8c42ffd694ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff deffffce8c7bc68442ffc67bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffff ffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff529cde21 2121212121212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a9c7321 21ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7deefd6b5adffc694ffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeeff7d6d6d6ffefe7ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdedeffc68463ce8c42c68442ce8c4ac68442ce8c42c68442ce8c4ac68442de9c 4afff7ceffffffffffffffffffc6a5b5ce8c4ac68442ce8c42c68442ce8c4ac68442ce8c42c68442ce8c4ace8c42e7bd73fffff7ffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d6ffce8c63ce8442ffde9cffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7ffffc6847bce8c42ffc67b ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a94d6212121212121212121ffb573de ffff214a94732121ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff214a9c732121ffffbdffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffd6d6ffce8463c68442ce8c42c68442ce8442c68442ce8c42ce8c4ae7bd8cfff7deffffffffffffffffffffff ffcea5b5c68442ce8442c68442ce8c42c68442ce8442c68442d6944adead7bfff7d6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffdedeffc6845ace8442ffd694ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffffce847bc68442ffc67bffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde212121212121212121ffbd73deffff4263ad843939ffffc6ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a94732121ffffbdffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffff7ffffefe7def7e7e7efe7def7e7deefe7def7e7e7fff7efffffffffffffffffffffffffffffffffffffffffffefeff7f7e7deefe7def7e7 e7efe7def7e7def7e7deffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffff7f7fff7e7e7efe7deffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffffc6847bce8c4affc67bffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffff ffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffff4a94d6212121212121212121ffb573ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffd6ffff214a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffff7ffffefe7efefdedefff7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffff ffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffff ffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffff529cde212121212121212121ffbd73ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffdeffff214a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffff ffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7 e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffde dedeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7 e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 4a94d6212121212121212121ffb573deffff214a94732121ffffb5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff21 4a9c732121ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7dedeffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a9cde212121212121212121 ffbd73deffff4263ad843939ffffc6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeffff214a94732121ffffbdffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a94d6212121212121212121ffb573ffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6ffff214a9c732121ffffbdffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ef efefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fff7f7f7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7efefefffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7efefef ffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffdededeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffff7f7f7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffff52a5e7212121212121212121423931393939424242393939424242393939424242393939 4242423939394242423939394242423939394242423939393942422129317b2921ffffbdffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7f7f7f7ffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7e7e7e7ffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffe7e7e7f7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7f7e7e7e7ffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffe7e7e7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffe7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffff7f7f7e7e7e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffb5e7ff29427b212121212121212121212121212121212121212121212121212121212121212121212121212121212121 212121212121212121212121212121312921d69c52ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefe7e7e7dededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7 e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7efefefffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffefefefe7e7e7dededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dedee7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7de dee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7e7e7e7efefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffefefefe7e7e7dedededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededededede dedee7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7de dee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7e7dedee7e7e7dededee7e7e7efefefffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffff040000002701ffff030000000000} } \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\loch\f5\loch This is the source code! It can NOT be used to play PDAFT!} \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\loch\f5\loch If you just wanted to play the game, }{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ul\ulc0\loch\f5\loch you downloaded the wrong thing}{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\loch\f5\loch .} \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b\loch\f5\loch Do not click the download button next to the git URL}{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch , that's for the }{{\field{\*\fldinst HYPERLINK "https://en.wikipedia.org/wiki/Source_code" }{\fldrslt {\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch source code}{}}}\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch .} \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch For information on getting and installing the latest release,} \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch please read the wiki at }{{\field{\*\fldinst HYPERLINK "https://github.com/PDModdingCommunity/PD-Loader/wiki" }{\fldrslt {\rtlch\dbch\af8\hich\af5 \ltrch\langfe255\cf9\lang255\ul\ulc0\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch https://github.com/PDModdingCommunity/PD-Loader/wiki}}}} \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch If you've already read it, pay more attention and you'll find the right link.} \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch \par \pard\plain \s0\dbch\af6\langfe1081\dbch\af7\afs24\alang1081\ql\nowidctlpar\hyphpar0\ltrpar\cf0\loch\f3\fs24\lang1040\kerning1\sl276\slmult1\ql\sb0\sa200{\rtlch\dbch\af8\hich\af5 \ltrch\fs22\lang16\ulnone\ulc0\b0\loch\f5\loch You should also read the wiki if you have any issues, before asking questions. } \par } ================================================ FILE: README.txt ================================================ This is the source code! It can NOT be used to play PDAFT! If you just wanted to play the game, you downloaded the wrong thing. Do not click the download button next to the git URL, that's for the source code. For information on getting and installing the latest release, please read the wiki at https://github.com/nastys/PD-Loader/wiki If you've already read it, pay more attention and you'll find the right link. You should also read the wiki if you have any issues, before asking questions. ================================================ FILE: appveyor.yml ================================================ version: '{build}' image: Visual Studio 2019 configuration: - Release platform: x64 build: project: source-code/PD-Loader.sln verbosity: minimal after_build: - cmd: >- md %TMP%\full\ md %TMP%\full\patches\ md %TMP%\full\plugins\ md "%TMP%\full\plugins\Novidia Shaders" md %TMP%\full\ram\ md %TMP%\full\ram\databank_template_v2\ copy %APPVEYOR_BUILD_FOLDER%\source-code\x64\%CONFIGURATION%\dnsapi.dll %TMP%\full\ copy %APPVEYOR_BUILD_FOLDER%\source-code\x64\%CONFIGURATION%\*.dva %TMP%\full\plugins\ copy "%APPVEYOR_BUILD_FOLDER%\source-code\data\README - PD Loader.url" %TMP%\full\ copy %APPVEYOR_BUILD_FOLDER%\source-code\data\verify_base_game.sfv %TMP%\full\ copy %APPVEYOR_BUILD_FOLDER%\source-code\data\verify_mount_data.sfv %TMP%\full\ copy %APPVEYOR_BUILD_FOLDER%\source-code\data\plugins\*.* %TMP%\full\plugins\ copy "%APPVEYOR_BUILD_FOLDER%\source-code\data\plugins\Novidia Shaders\*.*" "%TMP%\full\plugins\Novidia Shaders\" copy %APPVEYOR_BUILD_FOLDER%\source-code\data\ram\databank_template_v2\*.dat %TMP%\full\ram\databank_template_v2\ copy %APPVEYOR_BUILD_FOLDER%\source-code\data\patches\custom_freeplay_text_example.p %TMP%\full\patches\ cd %TMP%\full\ 7z a %APPVEYOR_BUILD_FOLDER%\PD-Loader-%CONFIGURATION%-AppVeyor.zip * artifacts: - path: PD-Loader-*.zip ================================================ FILE: source-code/LICENSE ================================================ PD Loader and the included plugins are distributed under MIT License: Copyright (c) Project DIVA Modding 2nd Community Copyright (c) samyuu (nop) (original TLAC code) Copyright (c) ThirteenAG (original Ultimate ASI Loader code) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Microsoft Detours, utilized by many plugins, is licensed under MIT License: # Copyright (c) Microsoft Corporation All rights reserved. # MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Launcher, Patches, Render and TLAC plugins utilize files from FreeGLUT: Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies or substantial portions of the Software. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of Pawel W. Olszta shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Pawel W. Olszta. Launcher uses SimpleIni, licensed under MIT License: The MIT License (MIT) Copyright (c) 2006-2013 Brodie Thiesfield Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. DivaSound uses miniaudio (public domain or MIT-0) and BASSASIO (free for non-commercial use only) AMD compatibilty pack dependencies have additional licenses, detailed in the AMD Pack's readme file. ================================================ FILE: source-code/PD-Loader.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.12.35527.113 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PD-Loader", "source\PD-Loader\PD-Loader.vcxproj", "{CA479467-D518-46A2-AC86-3098ADA99FE5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TLAC", "source\plugins\TLAC\TLAC.vcxproj", "{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Patches", "source\plugins\Patches\Patches.vcxproj", "{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Launcher", "source\plugins\Launcher\Launcher.vcxproj", "{60D5E9F4-335F-402B-9A07-D78674DFFC9B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Render", "source\plugins\Render\Render.vcxproj", "{89F87459-768F-4638-9267-0F90CD74452D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakedll", "source\fakedll\fakedll.vcxproj", "{B49C6ABE-931C-4F91-9A94-21A41A305FEE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DivaSound", "source\plugins\DivaSound\DivaSound.vcxproj", "{EE1A551A-49A0-40F2-8C2E-862D0AE55B43}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DivaMovie", "source\plugins\DivaMovie\DivaMovie.vcxproj", "{1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShaderPatch", "source\plugins\ShaderPatch\ShaderPatch.vcxproj", "{C07E495E-A16F-48FA-80E4-0296B5234F0B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DivaWig", "source\plugins\DivaWig\DivaWig.vcxproj", "{2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DSCRemote", "source\plugins\DSCRemote\DSCRemote.vcxproj", "{8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Novidia", "source\plugins\Novidia\Novidia.vcxproj", "{47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CA479467-D518-46A2-AC86-3098ADA99FE5}.Debug|x64.ActiveCfg = Debug|x64 {CA479467-D518-46A2-AC86-3098ADA99FE5}.Debug|x64.Build.0 = Debug|x64 {CA479467-D518-46A2-AC86-3098ADA99FE5}.Release|x64.ActiveCfg = Release|x64 {CA479467-D518-46A2-AC86-3098ADA99FE5}.Release|x64.Build.0 = Release|x64 {2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Debug|x64.ActiveCfg = Debug|x64 {2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Debug|x64.Build.0 = Debug|x64 {2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Release|x64.ActiveCfg = Release|x64 {2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Release|x64.Build.0 = Release|x64 {3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Debug|x64.ActiveCfg = Debug|x64 {3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Debug|x64.Build.0 = Debug|x64 {3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Release|x64.ActiveCfg = Release|x64 {3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Release|x64.Build.0 = Release|x64 {60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Debug|x64.ActiveCfg = Debug|x64 {60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Debug|x64.Build.0 = Debug|x64 {60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Release|x64.ActiveCfg = Release|x64 {60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Release|x64.Build.0 = Release|x64 {89F87459-768F-4638-9267-0F90CD74452D}.Debug|x64.ActiveCfg = Debug|x64 {89F87459-768F-4638-9267-0F90CD74452D}.Debug|x64.Build.0 = Debug|x64 {89F87459-768F-4638-9267-0F90CD74452D}.Release|x64.ActiveCfg = Release|x64 {89F87459-768F-4638-9267-0F90CD74452D}.Release|x64.Build.0 = Release|x64 {B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Debug|x64.ActiveCfg = Debug|x64 {B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Debug|x64.Build.0 = Debug|x64 {B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Release|x64.ActiveCfg = Release|x64 {B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Release|x64.Build.0 = Release|x64 {EE1A551A-49A0-40F2-8C2E-862D0AE55B43}.Debug|x64.ActiveCfg = Debug|x64 {EE1A551A-49A0-40F2-8C2E-862D0AE55B43}.Debug|x64.Build.0 = Debug|x64 {EE1A551A-49A0-40F2-8C2E-862D0AE55B43}.Release|x64.ActiveCfg = Release|x64 {EE1A551A-49A0-40F2-8C2E-862D0AE55B43}.Release|x64.Build.0 = Release|x64 {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.ActiveCfg = Debug|x64 {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.Build.0 = Debug|x64 {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.ActiveCfg = Release|x64 {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.Build.0 = Release|x64 {C07E495E-A16F-48FA-80E4-0296B5234F0B}.Debug|x64.ActiveCfg = Debug|x64 {C07E495E-A16F-48FA-80E4-0296B5234F0B}.Debug|x64.Build.0 = Debug|x64 {C07E495E-A16F-48FA-80E4-0296B5234F0B}.Release|x64.ActiveCfg = Release|x64 {C07E495E-A16F-48FA-80E4-0296B5234F0B}.Release|x64.Build.0 = Release|x64 {2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.ActiveCfg = Debug|x64 {2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.Build.0 = Debug|x64 {2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.ActiveCfg = Release|x64 {2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.Build.0 = Release|x64 {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.ActiveCfg = Debug|x64 {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.Build.0 = Debug|x64 {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.ActiveCfg = Release|x64 {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.Build.0 = Release|x64 {47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}.Debug|x64.ActiveCfg = Debug|x64 {47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}.Debug|x64.Build.0 = Debug|x64 {47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}.Release|x64.ActiveCfg = Release|x64 {47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F5AD7464-338F-4150-9DDC-85AD115BA616} EndGlobalSection EndGlobal ================================================ FILE: source-code/README.md ================================================ # PD Loader **PD Loader** lets you load plugins into **PDAFT** by placing them into a **"plugins"** folder, it includes useful ones such as input emulation and a graphical launcher. ## License and Legal PD Loader is intended for educational purposes only; not for piracy. The code included is intended to be used sole for investigative purposes related to the **PDAFT** video game. **Users should possess a legally-obtained dump of the game to use this software.** Please check your local laws/regulataions to verify the legality of tampering with and dumping data from protected arcade machine hardware. Code is licensed under the MIT License. ## Installation * Have a **full clean** game version **"7.10"** decompressed without any modifications. * Download the latest release of **PD Loader**. * Decompress everything into the **root folder** of the game. * Install the official **"mdata"**. **M215** to **M270** are supported, custom ones are also supported. To install them you have to drop each **"mdata"** update decompressed into the **"mdata\"** folder in the root folder of the game (create it if it doesn't exists). **e.g.** For all the official **"mdata"** you should have the following folders inside: * M215 * M220 * M230 * M240 * M250 * M260 * M270 Files required to make **"mdata"** available in the game are included (**"ram\databank\PvList*"** files). ## Usage **IMPORTANT:** Do *not* edit any of the *.ini* configuration files with Notepad. Use [Notepad++](https://notepad-plus-plus.org/download) (or WordPad) with UTF-8 encoding instead, otherwise your game may crash. Use **"plugins\components.ini"** to enable or disable TLAC components. Use **"plugins\config.ini"** to enable or disable plugins loading along other useful settings. Use **"plugins\keyconfig.ini"** to change your game keybinds. Use **"plugins\playerdata.ini"** to change your playername and other player customization. Place any **.dva** plugin you want to use inside the **"plugins"** folder. Launch **"diva.exe"**. Use **"--launch"** argument to bypass the launcher and to be able to use other arguments. ## Modules Edit **"plugins\playerdata.ini** with [Notepad++](https://notepad-plus-plus.org/download) (or WordPad) and set use_card to true. ## Sound If you do not hear any audio from the game, please install [DivaSound](https://github.com/somewhatlurker/DivaSound). ## Screenshots Your **root** game folder should look like this: ![root game folder](https://i.imgur.com/c57lQPH.png) Your **"mdata"** folder should look like this: ![mdata folder](https://i.imgur.com/2jUjosM.png) ## Contributing Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to update tests as appropriate. ## License MIT (see "LICENSE"). ## Third party plugins [DiscordDiva](https://github.com/bela333/DiscordDiva) - Discord integration by **bela333**. [DivaSound](https://github.com/somewhatlurker/DivaSound) - Replacement audio output by **somewhatlurker**, this plugin is a must if you have audio issues or no audio at all. ## FAQ Only **NVIDIA** videocards are supported for now, AMD and Intel GPU support is possible but further research needs to be done. On computers with multiple GPUs, such as most laptops, the game must be set to run on the NVIDIA GPU manually. **Linux** can run the game with **Wine**, for audio you must use [DivaSound](https://github.com/somewhatlurker/DivaSound). WMV movie videos are not supported and it is recommended to set **No_Movies** to **1** to prevent crashes when the game attempts to load a movie. **Windows 7** is supported except for WMV movie videos. Previous versions used **dinput8.dll** in the game root folder, if you still have it you must delete it. Always use the original game executable. Special thanks to **Brolijah**, **Skyth**, **korenkonder**, **Samyuu**, **somewhatlurker**, **SwigS-27**, **crash5band**, **ano**, **lybxlpsv** and everyone else who helped at the [Project DIVA Modding 2nd Community Discord](https://discord.gg/cvBVGDZ), come join us if you want to help us to improve this project. ## Developer FAQ To enable logs and dumps create a folder called "logs" in the root folder, each dump size is 200MB so watch your disk space. This is a stripdown of [**ThirteenAG's** Ultimate ASI Loader v4.47](https://github.com/ThirteenAG/Ultimate-ASI-Loader/) for **"dnsapi.dll"** usage only. Solution for **Visual Studio 2019**. Requires platform toolset **v142**. Requires **Windows 10 SDK (10.0.17763.0)**. Requires **Desktop development with C++**. Requires **Windows Universal CRT SDK**. Requires **.NET desktop development** (Launcher plugin). Requires **.NET Framework 4 targeting pack** (Launcher plugin). Requires **C++/CLI support for v142 build tools (14.21)** (Launcher plugin) Requires [**Microsoft Research Detours Package**](https://github.com/microsoft/Detours) (included in the solution). Requires [**FreeGLUT 3.0.0 PD**](https://github.com/Rayduxz/FreeGLUT) (included in the solution). ================================================ FILE: source-code/data/Download .NET Framework Runtime.url ================================================ [InternetShortcut] URL=https://dotnet.microsoft.com/download/dotnet-framework/net48 ================================================ FILE: source-code/data/Download QuickSFV.url ================================================ [InternetShortcut] URL=https://www.quicksfv.org/qsfv236x64.exe ================================================ FILE: source-code/data/Download Visual C++ Runtime.url ================================================ [InternetShortcut] URL=https://aka.ms/vs/16/release/vc_redist.x64.exe ================================================ FILE: source-code/data/README - PD Loader.url ================================================ [{000214A0-0000-0000-C000-000000000046}] Prop3=19,11 [InternetShortcut] IDList= URL=https://github.com/PDModdingCommunity/PD-Loader/wiki HotKey=0 ================================================ FILE: source-code/data/patches/custom_freeplay_text_example.p ================================================ # Enable FREE PLAY // Just in case it's disabled... @1403BABEA:75 // ...enable it. # Custom FREE PLAY text 1409F61F0:!Miku\0 # Custom text colour 1401964A2:00 FF FF 7F // Syntax: // "#" console comment // "//" hidden comment // "@" omit patch console output // ":" address:bytes (hex) // " " byte byte // ":!" address:!string (escape characters require PD Loader 2.1+) // "IGNORE" skip patch file (deprecated) ================================================ FILE: source-code/data/plugins/ShaderPatch.ini ================================================ [Config] # As of 1 November 2019, this is just data about config, to be used for UI generation and default values. # User config data is stored in ShaderPatchConfig.ini # Patches to remove glitching with modern GPUs. # Appropriate patches will automatically be selected based on your GPU. Compat=1 # Lyb's toon shader improvements (24 sept 2019) # Toon_Improve: Adjusts toon shader lighting Toon_Improve=0 # Specular Multiplier Toon_Improve_Val1=0.9 # Specular Offset Toon_Improve_Val2=-0.5 # Lyb's toon shader improvements (24 sept 2019) # Toon_Eyes_Improve: Adjusts toon shader eyes Toon_Eyes_Improve=0 # Lyb's toon shader improvements (24 sept 2019) # Toon_Hair_Improve: Adjusts toon shader hair Toon_Hair_Improve=0 # Diffuse Brightness Toon_Hair_Improve_Val1=1.25 # Lyb's toon shader improvements (24 sept 2019) # Fixes by korenkonder (11 jan 2025) # Toon_Lines_Improve: Adjusts toon shader outlines Toon_Lines_Improve=0 # Skin Shadow Strength Toon_Lines_Improve_Val1=0.05 # Skin Outline Strength Toon_Lines_Improve_Val2=0.9 # Outline Strength Multiplier Toon_Lines_Improve_Val3=0.7 # Outline Strength Offset Toon_Lines_Improve_Val4=0.25 [Patches] # Compatibility patches: # Star Story (and etc.) stage corruption (Maxwell+) blinn_per_vert\.0010010[23]00[01]\.fp=arch:GB,AD,GA,GV,TU,GP,GM||cfg:compat||from:TEX tex_col, a_tex_color0, texture\[0\], 2D; ALIAS||to:TEX tex_col, a_tex_color0, texture[0], 2D; MUL tex_col, 1, tex_col; ALIAS # Turing shading lines (new patch by samyuu, hopefully ported to here correctly) .*=arch:GB,AD,GA,GV,TU||cfg:compat||from:SHORT ||to: # Turing NPR cloth noise cloth_npr1.*=arch:GB,AD,GA,GV,TU||cfg:compat||from:SSG _tmp0.yw, ybr.xxzz;||to:TEMP _tmpForSSG; SGE _tmpForSSG.xz, ybr.xxzz, 0; SUB _tmpForSSG.xz, _tmpForSSG.xxzz, 1; SGT _tmpForSSG.yw, ybr.xxzz, 0; ADD _tmp0.yw, _tmpForSSG.xxzz, _tmpForSSG.yyww; # Turing auto-exposure fix by samyuu stage_blinn.*\.fp=arch:GB,AD,GA,GV,TU||cfg:compat||from:NRMH normal, a_normal;||to:NRM normal, a_normal; # Lyb's toon shader improvements: cloth_npr1.*=cfg:toon_improve||from:MAD tmp.y, lc.z, 1.2, -0.5;||to:MAD tmp.y, lc.z, , ; skin_default.*=cfg:toon_improve||from:MAD diff.xyz, spec, spec_ratio, diff;||to: .*eye.*=cfg:toon_eyes_improve||from:ADD o_color_f0.w, diff.x, diff.y;||to: .*eye.*=cfg:toon_eyes_improve||from:ADD result.color.w, diff.x, diff.y;||to: hair_npr1.*=cfg:toon_hair_improve||from:MUL spec.x, tmp.x, 0.7;||to:MUL spec.x, tmp.x, 0.7; MUL diff, diff, ; tone_map_npr1.*=cfg:toon_lines_improve||from:MUL density.y, density.y, 0.05;||to:MUL density.y, density.y, ; tone_map_npr1.*=cfg:toon_lines_improve||from:MUL density.y, density.y, 0.9;||to:MUL density.y, density.y, ; tone_map_npr1.*=cfg:toon_lines_improve||from:MAD density.w, density.x, 0.7, 0.25;||to:MAD density.w, density.x, , ; # Intel related patches (?:movie|sprite|imgfilter).*=cfg:intel||from:; ||to:;\n (?:movie|sprite|imgfilter).*=cfg:intel||from:(?:RET|TXL|NRM|OPTION NV_fragment|PARAM p_charfragment.color|ATTRIB).*?||to:## (?:movie|sprite|imgfilter).*=cfg:intel||from:(?:SHORT |LONG ).*?||to: .*sprite.100.fp.*=cfg:intel||from:MUL result.color, col1, fragment.color;||to:##MUL result.color, col1, fragment.color; # Debug patches: # Nametags # Adds comments with the shader file name to the shader text. Useful for debugging issues # `nametags_val1` and `nametags_val2` are a dirty hack to hide this in launcher (options ending in _val. must belong to a parent to be displayed) # `nametags_val2` is a bit faster, but the tags are placed at the end of the file and you may not like that # Notes: # * `(\r?\n)` is used to capture the line ending type used and ensure we're at the start of a line # * `[^!]` ensures the comment is inserted after all start program lines (not sure if this even matters) # * `[\s\S]` matches all characters *including* new lines .*=cfg:nametags1||from:(\r?\n)([^!][\s\S]*)||to:$1#$1$2 .*=cfg:nametags2||from:[\s\S]*?(\r?\n)[\s\S]*||to:$&$1# ================================================ FILE: source-code/data/verify_base_game.sfv ================================================ ; Generated by QuickSFV 3.00 on 2020-01-04 at 14:24:56 ; http://www.QuickSFV.org ; ; 140616748778912 23:14.30 1988-08-09 CPUSBSG.dll ; 140616748778912 17:05.50 1989-05-24 diva.exe ; 140616748778912 17:05.50 1989-05-24 glut32.dll ; 140616748778912 17:05.50 1989-05-24 MUsbPuIf.dll ; 140616748778912 17:05.50 1989-05-24 rom/bone_data.bin ; 140616748778912 17:05.50 1989-05-24 rom/chritm_prop.farc ; 140616748778912 17:05.50 1989-05-24 rom/fontmap.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_btn_se_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_chainslide_se_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_collection_card_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_customize_item_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_module_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_plate_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_pv_list_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_slidertouch_se_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/gm_slide_se_tbl.farc ; 140616748778912 17:05.50 1989-05-24 rom/hand_item_data.txt ; 140616748778912 17:05.50 1989-05-24 rom/iet.bin ; 140616748778912 17:05.50 1989-05-24 rom/ng_server.conf ; 140616748778912 17:05.50 1989-05-24 rom/pv_db.txt ; 140616748778912 17:05.50 1989-05-24 rom/pv_field.txt ; 140616748778912 17:05.50 1989-05-24 rom/rob_sleeve_data.txt ; 140616748778912 17:05.50 1989-05-24 rom/shader.farc ; 140616748778912 17:05.50 1989-05-24 rom/shader_cg.farc ; 140616748778912 17:05.50 1989-05-24 rom/stage_data.bin ; 140616748778912 17:05.50 1989-05-24 rom/star_catalog_megastar2.farc ; 140616748778912 17:05.50 1989-05-24 rom/star_catalog_random.farc ; 140616748778912 17:05.50 1989-05-24 rom/STGTST_COLI.000.bin ; 140616748778912 17:05.50 1989-05-24 rom/movie/adv_cfm_cm.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/adv_sega_cm.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/diva_adv.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/diva_adv02.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_203.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_209.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_215.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_216.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_255.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_257.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_265.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_428.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_429.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_430.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_431.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_601.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_604.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_609.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_618.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_623.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_625.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_627.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_630.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_631.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_722.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_723.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_724.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_728.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_734.wmv ; 140616748778912 17:05.50 1989-05-24 rom/movie/pv_739_001.wmv ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_adv_cmn.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_adv_nobl.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_adv_rnk.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_adv_scrnk.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_cmn_all.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_db.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_ent_cmn.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_ent_name.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_ent_passintro.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_cmn.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_cont.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_ctstrslt.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_edttit.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff000.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff001.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff002.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff004.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff005.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff006.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff007.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff008.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff009.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff010.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff011.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff012.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff013.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff014.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff015.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff016.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff017.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff018.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff019.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff021.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff022.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff023.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff024.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff025.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff026.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff027.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff028.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff029.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff030.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff031.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff032.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff033.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff034.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff035.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff036.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff040.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff041.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff042.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff044.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff050.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff051.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff052.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff053.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff054.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff055.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff058.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff059.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff062.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff064.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff066.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff068.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff003.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff020.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff039.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff069.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv012.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv029.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv051.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv081.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv101.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv219.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv241.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv401.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv418.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv439.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv614.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff070.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_eff071.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_gover.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_loadsc.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_prize.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv001.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv002.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv003.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv004.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv005.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv006.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv007.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv008.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv009.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv010.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv011.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv013.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv014.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv015.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv016.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv017.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv018.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv019.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv020.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv021.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv022.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv023.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv024.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv025.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv026.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv027.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv028.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv030.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv031.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv032.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv037.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv038.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv039.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv040.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv041.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv042.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv043.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv044.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv045.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv046.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv047.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv049.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv050.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv052.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv053.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv054.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv055.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv056.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv057.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv058.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv059.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv060.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv061.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv062.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv063.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv064.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv065.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv066.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv079.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv082.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv083.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv084.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv085.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv086.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv087.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv088.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv089.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv090.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv091.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv092.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv093.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv094.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv095.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv096.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv097.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv102.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv103.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv104.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv201.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv202.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv203.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv204.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv205.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv206.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv207.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv208.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv210.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv211.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv212.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv214.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv218.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv220.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv221.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv222.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv223.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv224.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv225.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv227.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv231.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv232.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv233.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv234.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv235.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv236.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv238.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv239.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv240.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv242.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv243.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv244.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv246.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv247.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv248.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv249.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv250.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv251.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv253.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv255.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv257.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv259.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv260.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv261.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv262.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv402.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv403.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv404.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv405.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv406.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv407.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv408.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv409.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv410.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv411.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv412.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv413.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv414.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv415.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv416.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv417.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv419.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv420.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv421.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv422.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv423.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv424.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv425.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv426.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv427.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv432.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv433.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv434.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv435.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv436.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv437.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv438.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv440.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv441.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv442.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv443.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv600.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv601.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv602.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv603.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv604.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv605.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv607.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv609.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv610.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv611.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv612.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv613.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv615.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv616.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv617.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv618.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv619.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv620.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv621.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv622.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv623.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv624.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv625.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv626.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv627.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv628.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv629.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv630.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv637.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv638.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv639.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv640.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv641.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv642.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv710.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv722.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv723.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv724.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv725.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv726.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv727.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv728.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv729.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv730.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv732.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv733.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv734.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv736.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv737.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv738.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv739.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv740.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv832.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_qstrslt.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_result.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_sc.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin001.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin002.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin003.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin004.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin006.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin007.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin008.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin009.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin010.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin011.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin012.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin013.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin014.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin015.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin016.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin017.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin018.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin019.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin020.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin021.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin023.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin024.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin025.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin026.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin027.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin028.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin029.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin030.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin031.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin032.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin033.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin034.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin035.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin036.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin037.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin038.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin040.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin041.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin042.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin043.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin044.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin045.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin046.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin047.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin048.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin049.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin050.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin051.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin052.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin053.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin054.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin055.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin057.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin058.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin059.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin060.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin061.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin062.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin063.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin064.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin065.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin066.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin067.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin068.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin069.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin070.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin071.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin072.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin074.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin075.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin076.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin077.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin078.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin079.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin080.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin081.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin082.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin083.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin084.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin085.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin086.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin087.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin088.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin089.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin091.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin092.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin093.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin094.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin095.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin096.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin097.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin098.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin099.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin100.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin101.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin102.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin103.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin104.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin105.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin106.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin108.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin109.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin110.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin111.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin112.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin113.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin114.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin115.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin116.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin117.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin118.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin119.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin120.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin121.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin122.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin123.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin125.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin126.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin127.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin128.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin129.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin130.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin131.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin132.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin133.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin134.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin135.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin136.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin137.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin138.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin139.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin140.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin142.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin143.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin144.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin145.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin146.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin147.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin148.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin149.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin150.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin151.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin152.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin153.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin154.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin155.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin156.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin157.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin159.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin160.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin161.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin162.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin163.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin164.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin165.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin166.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin167.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin168.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin169.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin170.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin171.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin172.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin173.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin174.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin176.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin177.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin178.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin179.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin180.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin181.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin182.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin183.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin184.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin185.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin186.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin187.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin188.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin189.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin190.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin191.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin193.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin194.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin195.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin196.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin197.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin198.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin199.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin200.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin201.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin202.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin203.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin204.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin205.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin206.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin207.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin208.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin210.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin211.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin212.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin213.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin214.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin215.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin216.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin217.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin218.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin219.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin220.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin221.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin222.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin223.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin224.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin225.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin227.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin228.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin229.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin230.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin231.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin232.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin233.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin234.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin235.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin236.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin237.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin238.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin239.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin240.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin241.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin242.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin244.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin245.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin246.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin247.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin248.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin249.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin250.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin251.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin252.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin253.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin254.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin255.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin256.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin257.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin258.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin259.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv731.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin005.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin022.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin039.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin056.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin073.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin090.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin107.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin124.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin141.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin158.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin175.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin192.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin209.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin226.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin261.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin262.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin263.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin264.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin265.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin266.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin267.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin268.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin269.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin270.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin271.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin272.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin273.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin274.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin275.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin276.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin278.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin279.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin280.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin281.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin282.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin283.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin284.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin285.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin286.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin287.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin288.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin289.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin290.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin291.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin292.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin293.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin295.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin296.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin297.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin298.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin299.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin300.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin301.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin302.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin303.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin304.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin305.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin306.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin307.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin308.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin309.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin310.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin312.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin313.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin314.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin315.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin316.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin317.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin318.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin319.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin320.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin321.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin322.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin323.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin324.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin325.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin326.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin327.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin329.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin330.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin331.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin332.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin333.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin334.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin335.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin336.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin337.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin338.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin339.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin340.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin341.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin342.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin343.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin344.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin346.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin347.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin348.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin349.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin350.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin351.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin352.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin353.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin354.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin355.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin356.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin357.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin358.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin359.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin360.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin361.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin363.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin364.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin365.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin366.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin367.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin368.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin369.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin370.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin371.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin372.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin373.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin374.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin375.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin376.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin377.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin378.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin380.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin381.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin382.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin383.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin384.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin385.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin386.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin387.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin388.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin389.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin390.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin391.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin392.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin393.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin394.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin395.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin397.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin398.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin399.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin400.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin401.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin402.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin403.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin404.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin405.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin406.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin407.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin408.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin409.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin410.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin411.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin412.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin414.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin415.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin416.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin417.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin418.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin419.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin420.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin421.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin422.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin423.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin424.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin425.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin426.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin427.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin428.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin429.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin431.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin432.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin433.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin434.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin435.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin436.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin437.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin438.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin439.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin440.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin441.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin442.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin443.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin444.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin445.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin446.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin448.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin449.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin450.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin451.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin452.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin453.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin454.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin455.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin456.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin457.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin458.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin459.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin460.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin461.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin462.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin463.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin465.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin466.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin467.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin468.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin469.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin470.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin471.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin472.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin473.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin474.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin475.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin476.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin477.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin478.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin479.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin480.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin482.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin483.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin484.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin485.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin486.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin487.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin488.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin489.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin490.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin491.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin492.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin493.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin494.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin495.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin496.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin497.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin499.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin500.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin501.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin502.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin503.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin504.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin505.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin506.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin507.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin508.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin509.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin510.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin511.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin512.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin513.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin514.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin516.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin517.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin518.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin519.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin520.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin521.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin522.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin523.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin524.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin525.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin526.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin527.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin528.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin529.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin530.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin531.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin260.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin277.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin294.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin311.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin328.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin345.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin362.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin379.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin396.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin413.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin430.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin447.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin464.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin481.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin498.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin533.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin534.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin535.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin536.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin537.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin538.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin539.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin540.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin541.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin542.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin543.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin544.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin545.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin546.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin547.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin548.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin550.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin551.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin552.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin553.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin554.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin555.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin556.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin557.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin558.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin559.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin560.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin561.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin562.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin563.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin564.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin565.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin567.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin568.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin569.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin570.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin571.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin572.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin573.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin574.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin575.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin576.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin577.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin578.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin579.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin580.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin581.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin582.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin584.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin585.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin586.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin587.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin588.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin589.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin590.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin591.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin592.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin593.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin594.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin595.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin596.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin597.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin598.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin599.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin601.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin602.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin603.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin604.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin605.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin606.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin607.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin608.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin609.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin610.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin611.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin612.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin613.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin614.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin615.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin616.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin618.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin619.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin620.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin621.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin622.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin623.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin624.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin625.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin626.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin627.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin628.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin629.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin630.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin631.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin632.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin633.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin635.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin636.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin637.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin638.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin639.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin640.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin641.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin642.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin643.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin644.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin645.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin646.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin647.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin648.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin649.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin650.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin652.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin653.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin654.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin655.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin656.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin657.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin658.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin659.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin660.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin661.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin662.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin663.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin664.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin665.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin666.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin667.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin669.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin670.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin671.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin672.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin673.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin674.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin675.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin676.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin677.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin678.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin679.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin680.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin681.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin682.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin683.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin684.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin686.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin687.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin688.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin689.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin690.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin691.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin692.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin693.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin694.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin695.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin696.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin697.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin698.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin699.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin700.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin701.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin703.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin704.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin705.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin706.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin707.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin708.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin709.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin710.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin711.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin712.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin713.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin714.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin715.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin716.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin717.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin718.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin720.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin721.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin722.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin723.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin724.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin725.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin726.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin727.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin728.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin729.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin730.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin731.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin732.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin733.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin734.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin735.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin737.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin738.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_key_input.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_key_pass.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_key_svol.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_key_win.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_belt.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_camp.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_camp02.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_card.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_cardbg.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_cardinfo.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_chlle.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_cmn.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_credit.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_ctst.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_module.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_pleff.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_print.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_procedure.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_pv.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_qst.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_result.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_sc.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_stamp.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_ticket.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_vaccess.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_watch.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_adv_cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_adv_nobl.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_adv_rnk.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_adv_scrnk.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin532.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin549.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin566.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin583.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin600.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin617.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin634.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin651.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin668.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin685.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin702.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin719.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin736.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_sel_ctstinfo.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0000.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_pv631.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin243.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/aet_gam_skin515.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0256.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0496.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb126.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback124.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback120.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv250.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin140.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin380.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin620.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md106cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md387cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0033.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0034.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0035.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0036.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0037.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0038.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0039.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0040.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0041.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0042.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0043.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0044.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0045.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0046.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0047.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0049.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0050.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0051.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0052.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0053.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0054.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0055.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0056.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0057.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0058.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0059.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0060.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0061.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0062.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0063.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0065.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0066.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0067.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0068.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0069.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0070.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0071.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0072.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0073.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0074.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0075.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0076.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0077.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0078.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0079.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0081.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0082.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0083.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0084.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0085.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0086.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0087.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0088.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0089.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0090.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0091.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0092.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0093.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0094.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0095.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0097.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0098.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0099.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0100.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0101.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0102.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0103.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0104.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0105.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0106.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0107.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0108.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0109.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0110.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0111.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0113.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0114.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0115.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0116.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0117.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0118.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0119.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0120.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0121.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0122.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0123.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0124.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0125.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0126.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0127.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0129.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0130.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0131.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0132.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0133.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0134.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0135.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0136.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0137.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0138.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0139.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0140.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0141.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0142.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0143.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0145.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0146.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0147.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0148.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0149.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0150.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0151.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0152.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0153.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0154.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0155.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0156.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0157.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0158.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0159.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0161.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0162.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0163.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0164.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0165.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0166.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0167.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0168.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0169.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0170.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0171.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0172.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0173.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0174.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0175.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0177.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0178.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0179.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0180.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0181.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0182.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0183.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0184.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0185.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0186.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0187.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0188.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0189.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0190.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0191.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0193.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0194.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0195.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0196.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0197.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0198.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0199.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0200.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0201.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0202.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0203.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0204.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0205.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0206.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0207.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0209.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0210.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0211.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0212.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0213.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0214.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0215.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0216.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0217.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0218.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0219.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0220.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0221.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0222.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0223.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0225.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0226.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0227.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0228.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0229.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0230.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0231.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0232.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0233.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0234.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0235.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0236.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0237.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0238.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0239.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0241.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0242.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0243.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0244.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0245.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0246.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0247.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0248.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0249.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0250.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0251.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0252.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0253.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0254.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0255.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0257.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0258.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0259.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0260.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0261.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0262.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0263.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0264.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0265.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0266.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0267.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0268.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0269.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0270.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0271.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0048.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0064.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0080.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0096.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0112.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0128.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0144.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0160.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0176.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0192.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0208.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0224.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0240.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0273.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0274.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0275.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0276.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0277.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0278.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0279.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0280.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0281.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0282.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0283.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0284.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0285.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0286.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0287.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0289.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0290.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0291.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0292.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0293.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0294.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0295.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0296.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0297.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0298.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0299.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0300.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0301.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0302.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0303.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0305.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0306.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0307.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0308.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0309.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0310.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0311.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0312.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0313.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0314.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0315.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0316.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0317.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0318.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0319.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0321.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0322.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0323.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0324.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0325.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0326.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0327.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0328.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0329.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0330.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0331.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0332.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0333.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0334.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0335.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0337.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0338.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0339.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0340.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0341.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0342.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0343.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0344.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0345.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0346.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0347.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0348.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0349.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0350.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0351.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0353.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0354.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0355.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0356.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0357.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0358.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0359.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0360.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0361.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0362.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0363.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0364.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0365.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0366.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0367.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0369.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0370.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0371.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0372.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0373.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0374.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0375.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0376.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0377.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0378.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0379.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0380.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0381.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0382.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0383.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0385.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0386.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0387.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0388.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0389.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0390.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0391.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0392.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0393.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0394.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0395.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0396.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0397.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0398.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0399.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0401.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0402.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0403.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0404.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0405.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0406.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0407.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0408.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0409.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0410.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0411.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0412.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0413.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0414.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0415.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0417.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0418.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0419.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0420.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0421.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0422.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0423.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0424.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0425.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0426.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0427.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0428.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0429.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0430.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0431.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0433.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0434.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0435.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0436.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0437.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0438.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0439.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0440.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0441.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0442.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0443.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0444.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0445.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0446.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0447.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0449.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0450.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0451.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0452.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0453.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0454.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0455.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0456.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0457.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0458.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0459.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0460.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0461.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0462.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0463.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0465.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0466.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0467.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0468.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0469.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0470.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0471.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0472.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0473.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0474.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0475.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0476.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0477.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0478.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0479.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0481.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0482.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0483.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0484.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0485.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0486.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0487.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0488.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0489.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0490.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0491.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0492.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0493.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0494.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0495.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0497.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0498.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0499.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0500.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0501.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0502.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0503.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0504.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0505.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0506.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0507.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0508.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0509.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0510.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0511.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0272.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0288.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0304.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0320.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0336.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0352.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0368.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0384.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0400.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0416.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0432.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0448.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0464.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0480.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0513.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0514.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0515.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0516.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0517.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0518.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0519.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0520.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0521.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0522.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0523.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0524.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0525.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0526.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0527.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0529.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0530.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0531.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0532.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0533.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0534.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0535.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0536.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0537.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0538.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0539.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0540.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0541.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0542.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0543.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0545.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0546.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0547.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0554.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0555.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0556.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0557.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0558.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0559.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0560.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0561.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0562.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0563.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0564.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0565.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0567.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0568.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0569.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0570.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0571.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0572.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0573.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0574.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0575.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0576.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0577.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0578.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0579.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0580.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0581.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0583.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0584.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0585.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0586.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0587.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0588.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0589.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0590.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0591.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0592.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0593.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0594.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0595.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0596.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0597.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0599.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0600.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0601.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0602.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0603.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0604.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0605.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0606.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0607.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0608.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0609.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0610.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0611.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0612.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0613.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0615.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0616.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0617.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0618.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0619.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0620.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0621.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0622.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0623.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0624.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0625.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0626.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0627.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0628.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0629.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0631.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0632.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0633.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb000.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb033.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb034.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb035.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb036.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb037.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb038.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb039.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb040.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb041.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb042.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb043.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb045.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb046.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb047.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb048.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb049.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb050.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb051.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb052.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb053.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb054.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb055.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb056.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb057.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb058.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb059.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb061.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb062.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb067.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb068.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb069.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb070.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb071.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb072.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb073.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb074.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb075.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb076.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb077.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb078.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb079.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb081.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb082.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb083.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb084.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb085.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb086.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb087.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb088.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb089.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb097.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb098.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb099.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb100.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb101.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb102.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb104.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb105.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb106.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb107.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb115.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb116.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb117.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb118.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb119.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb120.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb121.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb122.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb123.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb124.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb125.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb127.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb128.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb129.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb130.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb131.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb132.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb133.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb134.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb135.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb136.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb137.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb138.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb139.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb140.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb141.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0512.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0528.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0544.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0566.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0582.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0598.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0614.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_clt_crd0630.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb044.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb060.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb080.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb103.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb143.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb144.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb145.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb146.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb147.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb148.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb149.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb150.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb151.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb152.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb153.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb154.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb155.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb156.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb157.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb159.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb160.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb161.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb162.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb163.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb164.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb165.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb166.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb167.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb168.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb169.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb170.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb171.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb172.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb173.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb175.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb176.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb177.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb178.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb179.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb180.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb181.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb182.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb183.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb184.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb185.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb186.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb187.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb188.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb189.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb191.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb192.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb193.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb194.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb195.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb196.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb197.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb198.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb199.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb200.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb201.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb204.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb205.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb206.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb207.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb209.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb210.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb211.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb212.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb213.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb214.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb215.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb216.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb217.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb218.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb219.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb220.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb221.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb222.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb223.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb225.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb226.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb227.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb228.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb229.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb230.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb231.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb232.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb233.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmbdummy.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmn_all.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_db.bin ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback033.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback035.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback036.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback037.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback038.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback039.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback040.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback041.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback042.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback043.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback044.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback045.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback046.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback047.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback048.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback050.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback051.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback052.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback053.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback054.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback055.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback056.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback057.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback058.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback059.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback060.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback061.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback062.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback063.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback065.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback066.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback067.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback068.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback069.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback070.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback071.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback072.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback073.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback074.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback075.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback076.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback077.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback078.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback080.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback081.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback082.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback083.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback084.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback085.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback086.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback087.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback088.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback089.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback090.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback091.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback092.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback093.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback095.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback096.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback097.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback098.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback099.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback100.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback101.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback102.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback103.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback104.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback105.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback106.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback107.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback108.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback110.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback111.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback112.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback113.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback114.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback115.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback116.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback117.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback118.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback119.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback120.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback121.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback122.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback123.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback125.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback126.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback127.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback128.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback129.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback130.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback131.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback132.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback133.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback134.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback135.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback136.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback137.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback138.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb142.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb158.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb174.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb190.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb208.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_cmnitm_thmb224.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback034.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback049.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback064.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback079.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback094.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback109.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback140.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback141.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback142.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback143.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback144.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback145.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback146.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback147.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback148.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback149.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback150.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback151.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback152.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback153.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback155.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback156.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback157.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback158.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback159.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback160.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback161.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback162.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback163.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback164.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback165.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback166.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback167.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback168.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback170.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback171.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback172.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback173.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback174.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback175.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback176.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback177.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback178.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback179.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback180.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback181.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback182.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback183.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback185.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback186.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback187.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback188.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback189.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback190.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback191.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback192.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback193.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvbackblack.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvbackwhite.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvback112.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvback5017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvbackblack.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvbackpgreen.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvbackppink.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvbackpsky.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvbackpyellow.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvbacksky.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvbackwhite.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback033.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback034.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback035.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback036.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback037.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback038.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback039.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback041.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback042.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback043.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback044.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback045.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback046.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback047.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback048.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback049.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback050.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback051.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback052.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback053.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback054.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback055.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback057.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback058.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback059.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback060.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback061.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback062.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback063.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback064.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback065.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback066.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback067.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback068.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback069.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback070.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback071.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback073.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback074.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback075.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback076.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback077.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback078.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback079.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback080.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback081.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback082.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback083.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback084.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback085.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback086.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback087.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback089.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback090.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback091.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback092.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback093.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback094.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback095.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback096.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback097.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback098.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback099.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback100.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback101.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback102.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback103.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback105.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback106.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback107.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback108.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback109.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback110.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback111.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback112.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback113.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback114.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback115.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback116.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback117.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback118.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback119.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback139.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback154.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback169.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_d2pvback184.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_expvback019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_fpvback5012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback040.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback056.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback072.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback088.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback104.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback121.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback122.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback123.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback124.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback125.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback126.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback127.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback128.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback129.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback130.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback131.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback132.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback133.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback134.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback135.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback137.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback138.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback139.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback140.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback141.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback142.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback143.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback144.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback145.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback146.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback147.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback148.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback149.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback150.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback151.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback153.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback154.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback155.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback156.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback157.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback158.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback159.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback160.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback161.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback162.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback163.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback164.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback165.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback166.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback167.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback169.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback170.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback171.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback172.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback173.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback174.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback175.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback176.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback177.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback178.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback179.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback180.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback181.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback182.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback183.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback185.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback186.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback187.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback188.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback189.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback190.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback191.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback192.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback193.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback194.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback195.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback196.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_ent_cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_ent_name.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_ent_passintro.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_fnt_24.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_fnt_cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_cont.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_ctstrslt.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_edttit.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff000.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff033.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff034.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff035.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff036.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff039.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff040.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff041.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff042.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff044.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff050.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff051.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff052.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff054.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff055.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff058.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff059.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff062.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff064.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff066.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff068.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff069.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff070.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff071.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_gover.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_loadsc.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_prize.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv037.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv038.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv039.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv040.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv042.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv043.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv044.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv045.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv046.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv047.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv049.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv050.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv051.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv052.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv053.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv054.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv055.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv056.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv057.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv058.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv060.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv061.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv062.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv063.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv064.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv065.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv066.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv079.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv081.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv082.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv083.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv084.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv085.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv086.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv087.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv088.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv090.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv091.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv092.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv093.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv094.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv095.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv096.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv097.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv101.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv102.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv103.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv104.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv201.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv202.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv203.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv204.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv206.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv207.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv208.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv210.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv211.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv212.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv214.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv218.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv219.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv220.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv221.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv222.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv223.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv224.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv225.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv227.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv232.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv233.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv234.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv235.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv236.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv238.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv239.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv240.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv241.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv242.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv243.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv244.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv246.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv247.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv248.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv249.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback136.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback152.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback168.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_edit_pvback184.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_fnt_bold24.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_eff053.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv041.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv059.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv089.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv205.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv231.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv251.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv253.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv255.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv257.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv259.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv260.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv261.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv262.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv401.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv402.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv403.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv404.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv405.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv406.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv407.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv408.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv410.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv411.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv412.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv413.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv414.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv415.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv416.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv417.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv418.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv419.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv420.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv421.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv422.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv423.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv424.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv425.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv427.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv432.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv433.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv434.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv435.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv436.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv437.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv438.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv439.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv440.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv441.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv442.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv443.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv600.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv601.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv602.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv604.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv605.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv607.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv609.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv610.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv611.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv612.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv613.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv614.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv615.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv616.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv617.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv618.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv619.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv620.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv621.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv623.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv624.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv625.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv626.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv627.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv628.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv629.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv630.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv631.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv637.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv638.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv639.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv640.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv641.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv642.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv710.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv723.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv724.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv725.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv726.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv727.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv728.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv729.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv730.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv731.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv732.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv733.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv734.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv736.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv737.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv738.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv739.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv832.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_qstrslt.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_result.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_sc.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin033.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin034.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin035.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin036.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin037.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin038.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin039.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin040.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin041.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin042.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin043.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin045.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin046.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin047.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin048.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin049.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin050.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin051.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin052.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin053.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin054.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin055.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin056.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin057.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin058.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin059.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin061.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin062.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin063.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin064.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin065.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin066.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin067.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin068.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin069.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin070.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin071.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin072.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin073.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin074.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin075.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin077.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin078.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin079.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin080.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin081.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin082.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin083.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin084.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin085.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin086.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin087.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin088.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin089.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin090.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin091.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin093.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin094.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin095.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin096.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin097.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin098.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin099.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin100.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin101.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin102.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin103.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin104.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin105.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin106.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin107.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin109.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin110.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin111.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin112.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin113.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin114.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin115.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin116.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin117.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin118.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin119.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin120.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin121.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin122.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin123.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin125.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin126.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin127.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin128.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin129.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin130.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin131.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin132.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin133.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin134.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin135.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin136.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin137.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin138.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin139.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin141.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin142.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin143.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin144.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin145.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin146.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin147.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin148.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin149.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin150.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin151.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin152.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin153.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin154.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin155.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv409.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv426.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv603.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv622.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv722.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_pv740.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin044.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin060.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin076.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin092.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin108.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin124.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin157.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin158.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin159.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin160.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin161.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin162.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin163.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin164.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin165.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin166.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin167.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin168.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin169.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin170.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin171.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin173.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin174.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin175.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin176.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin177.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin178.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin179.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin180.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin181.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin182.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin183.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin184.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin185.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin186.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin187.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin189.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin190.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin191.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin192.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin193.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin194.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin195.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin196.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin197.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin198.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin199.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin200.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin201.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin202.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin203.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin205.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin206.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin207.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin208.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin209.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin210.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin211.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin212.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin213.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin214.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin215.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin216.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin217.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin218.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin219.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin221.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin222.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin223.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin224.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin225.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin226.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin227.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin228.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin229.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin230.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin231.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin232.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin233.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin234.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin235.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin237.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin238.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin239.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin240.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin241.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin242.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin243.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin244.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin245.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin246.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin247.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin248.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin249.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin250.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin251.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin253.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin254.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin255.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin256.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin257.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin258.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin259.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin260.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin261.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin262.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin263.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin264.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin265.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin266.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin267.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin269.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin270.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin271.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin272.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin273.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin274.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin275.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin276.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin277.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin278.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin279.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin280.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin281.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin282.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin283.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin285.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin286.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin287.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin288.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin289.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin290.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin291.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin292.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin293.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin294.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin295.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin296.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin297.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin298.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin299.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin301.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin302.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin303.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin304.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin305.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin306.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin307.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin308.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin309.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin310.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin311.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin312.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin313.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin314.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin315.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin317.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin318.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin319.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin320.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin321.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin322.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin323.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin324.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin325.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin326.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin327.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin328.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin329.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin330.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin331.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin333.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin334.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin335.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin336.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin337.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin338.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin339.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin340.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin341.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin342.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin343.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin344.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin345.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin346.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin347.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin349.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin350.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin351.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin352.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin353.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin354.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin355.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin356.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin357.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin358.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin359.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin360.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin361.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin362.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin363.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin365.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin366.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin367.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin368.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin369.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin370.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin371.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin372.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin373.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin374.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin375.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin376.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin377.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin378.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin379.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin381.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin382.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin383.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin384.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin385.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin386.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin387.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin388.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin389.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin390.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin391.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin392.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin393.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin394.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin395.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin156.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin172.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin188.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin204.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin220.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin236.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin252.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin268.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin284.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin300.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin316.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin332.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin348.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin364.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin397.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin398.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin399.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin400.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin401.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin402.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin403.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin404.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin405.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin406.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin407.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin408.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin409.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin410.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin411.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin413.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin414.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin415.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin416.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin417.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin418.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin419.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin420.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin421.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin422.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin423.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin424.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin425.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin426.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin427.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin429.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin430.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin431.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin432.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin433.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin434.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin435.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin436.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin437.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin438.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin439.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin440.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin441.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin442.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin443.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin445.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin446.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin447.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin448.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin449.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin450.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin451.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin452.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin453.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin454.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin455.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin456.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin457.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin458.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin459.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin461.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin462.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin463.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin464.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin465.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin466.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin467.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin468.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin469.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin470.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin471.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin472.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin473.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin474.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin475.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin477.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin478.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin479.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin480.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin481.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin482.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin483.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin484.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin485.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin486.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin487.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin488.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin489.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin490.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin491.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin493.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin494.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin495.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin496.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin497.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin498.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin499.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin500.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin501.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin502.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin503.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin504.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin505.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin506.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin507.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin509.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin510.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin511.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin512.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin513.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin514.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin515.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin516.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin517.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin518.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin519.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin520.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin521.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin522.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin523.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin525.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin526.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin527.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin528.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin529.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin530.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin531.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin532.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin533.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin534.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin535.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin536.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin537.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin538.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin539.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin541.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin542.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin543.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin544.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin545.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin546.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin547.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin548.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin549.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin550.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin551.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin552.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin553.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin554.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin555.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin557.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin558.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin559.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin560.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin561.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin562.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin563.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin564.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin565.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin566.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin567.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin568.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin569.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin570.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin571.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin573.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin574.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin575.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin576.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin577.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin578.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin579.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin580.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin581.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin582.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin583.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin584.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin585.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin586.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin587.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin589.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin590.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin591.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin592.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin593.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin594.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin595.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin596.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin597.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin598.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin599.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin600.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin601.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin602.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin603.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin605.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin606.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin607.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin608.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin609.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin610.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin611.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin612.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin613.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin614.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin615.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin616.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin617.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin618.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin619.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin621.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin622.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin623.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin624.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin625.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin626.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin627.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin628.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin629.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin630.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin631.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin632.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin633.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin634.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin635.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin396.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin412.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin428.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin444.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin460.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin476.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin492.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin508.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin524.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin540.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin556.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin572.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin588.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin604.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin637.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin638.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin639.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin640.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin641.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin642.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin643.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin644.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin645.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin646.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin647.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin648.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin649.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin650.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin651.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin653.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin654.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin655.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin656.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin657.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin658.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin659.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin660.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin661.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin662.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin663.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin664.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin665.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin666.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin667.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin669.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin670.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin671.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin672.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin673.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin674.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin675.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin676.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin677.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin678.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin679.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin680.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin681.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin682.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin683.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin685.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin686.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin687.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin688.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin689.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin690.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin691.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin692.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin693.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin694.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin695.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin696.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin697.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin698.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin699.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin701.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin702.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin703.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin704.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin705.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin706.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin707.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin708.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin709.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin710.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin711.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin712.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin713.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin714.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin715.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin717.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin718.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin719.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin720.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin721.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin722.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin723.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin724.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin725.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin726.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin727.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin728.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin729.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin730.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin731.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin732.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin734.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin735.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin736.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin737.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin738.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_key_input.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_key_pass.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_key_svol.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_key_win.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_ps3_cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_belt.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_camp.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_camp02.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_card.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_cardbg.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_cardinfo.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_chlle.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_credit.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_ctst.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_ctstinfo.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md000cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md001cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md002cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md003cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md004cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md005cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md006cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md007cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md008cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md009cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md011cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md012cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md013cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md014cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md015cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md016cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md017cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md018cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md019cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md020cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md021cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md022cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md023cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md024cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md025cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md027cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md028cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md029cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md030cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md031cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md032cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md033cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md034cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md035cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md036cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md037cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md038cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md039cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md040cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md041cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md043cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md044cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md045cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md046cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md047cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md048cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md049cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md050cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md051cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md052cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md053cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md054cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md055cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md056cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md057cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md059cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md060cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md061cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md062cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md063cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md064cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md065cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md066cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md067cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md068cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md069cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md070cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md071cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md072cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md073cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md075cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md076cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md077cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md078cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md079cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md080cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md081cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md082cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md083cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md084cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md085cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md086cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md087cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md088cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md089cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md091cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md092cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md093cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md094cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md095cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md096cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md097cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md098cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md099cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md100cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md101cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md102cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md103cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md104cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md105cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md107cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md108cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md109cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md110cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md111cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md112cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md113cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md114cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md115cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md116cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md117cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md118cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md119cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md120cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md121cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin636.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin652.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin668.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin684.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin700.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin716.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_gam_skin733.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_cardpt.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md010cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md026cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md042cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md058cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md074cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md090cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md124cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md125cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md126cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md127cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md128cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md129cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md130cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md131cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md132cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md133cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md134cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md135cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md136cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md137cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md138cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md141cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md142cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md143cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md144cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md145cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md146cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md147cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md148cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md149cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md150cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md151cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md153cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md154cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md155cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md156cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md158cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md159cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md160cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md161cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md162cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md163cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md164cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md165cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md166cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md167cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md168cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md169cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md170cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md171cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md172cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md189cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md190cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md191cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md192cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md193cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md194cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md195cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md196cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md197cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md198cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md199cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md200cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md201cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md202cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md203cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md205cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md206cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md207cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md208cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md209cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md210cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md211cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md212cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md213cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md214cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md215cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md216cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md217cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md218cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md219cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md221cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md222cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md223cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md224cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md225cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md226cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md227cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md228cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md229cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md230cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md231cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md232cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md233cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md234cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md235cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md237cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md238cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md239cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md240cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md241cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md242cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md243cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md244cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md245cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md246cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md247cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md248cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md249cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md250cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md251cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md253cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md254cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md255cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md256cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md257cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md258cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md259cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md260cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md261cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md262cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md263cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md264cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md265cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md266cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md267cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md269cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md270cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md271cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md272cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md273cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md274cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md275cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md276cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md277cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md278cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md279cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md280cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md281cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md282cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md283cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md285cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md286cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md287cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md288cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md289cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md290cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md291cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md292cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md293cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md294cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md295cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md296cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md297cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md298cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md299cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md301cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md302cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md303cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md304cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md305cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md306cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md308cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md309cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md310cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md311cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md313cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md314cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md315cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md316cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md317cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md319cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md320cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md321cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md322cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md323cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md324cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md325cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md326cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md327cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md328cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md329cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md330cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md331cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md332cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md334cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md336cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md338cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md339cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md340cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md341cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md343cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md344cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md345cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md346cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md347cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md348cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md349cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md350cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md351cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md352cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md354cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md355cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md356cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md358cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md359cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md360cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md361cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md362cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md363cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md364cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md365cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md366cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md367cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md368cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md369cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md371cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md372cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md373cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md374cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md375cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md376cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md377cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md378cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md379cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md380cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md381cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md382cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md383cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md385cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md386cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md122cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md139cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md157cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md188cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md204cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md220cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md236cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md252cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md268cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md284cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md300cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md318cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md335cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md353cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md370cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md389cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md390cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md391cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md392cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md393cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md394cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md395cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md398cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md402cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md403cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md404cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md405cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md406cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md407cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md408cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md410cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md411cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md412cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md420cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md421cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md422cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md423cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrallcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrhakcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrkaicmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrlencmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrlukcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrmeicmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrmikcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrnercmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrrincmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrtetcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_module.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_plate.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pleff.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_print.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_procedure.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv002.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv003.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv004.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv005.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv006.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv007.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv008.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv009.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv011.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv012.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv013.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv014.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv015.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv016.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv017.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv018.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv019.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv020.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv021.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv022.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv023.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv024.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv025.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv026.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv028.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv029.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv030.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv031.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv032.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv037.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv038.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv039.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv040.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv041.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv042.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv043.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv044.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv045.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv046.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv047.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv049.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv050.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv051.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv052.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv053.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv054.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv055.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv056.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv057.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv058.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv059.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv060.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv061.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv062.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv063.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv064.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv066.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv079.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv081.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv082.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv083.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv084.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv085.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv086.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv087.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv088.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv089.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv090.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv091.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv092.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv093.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv094.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv096.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv097.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv101.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv102.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv103.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv104.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv201.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv202.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv203.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv204.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv205.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv206.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv207.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv208.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv209.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv210.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv212.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv213.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv214.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv215.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv216.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv218.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv219.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv220.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv221.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv222.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv223.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv224.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv225.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv226.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv227.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv228.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv232.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv233.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv234.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv235.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv236.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv238.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv239.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv240.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv241.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv242.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv243.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv244.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv246.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv247.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv248.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv249.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv251.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv253.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv255.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv257.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv259.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv260.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv261.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv262.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv265.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv401.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv402.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv403.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv404.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv405.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv406.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv407.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv409.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv410.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv411.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv412.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv413.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv414.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv415.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv416.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv417.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv418.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv419.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv420.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv421.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv422.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv423.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv424.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv426.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv427.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv428.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv429.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv430.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv431.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv432.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv433.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv434.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv435.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv436.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv437.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv438.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv439.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv440.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv441.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv443.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv600.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv601.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv602.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv603.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv604.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv605.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv607.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv608.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv609.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv610.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv611.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv612.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv613.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv614.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv615.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv617.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv618.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv619.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv620.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv621.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv622.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv623.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv624.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv625.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv626.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv627.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv628.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv629.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv630.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv631.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv637.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv639.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv640.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv641.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv642.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv710.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv722.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv723.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv724.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv725.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv726.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv727.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv728.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv729.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv730.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv731.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv732.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_md409cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_mdrsakcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv010.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv027.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv048.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv065.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv095.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv211.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv231.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv250.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv408.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv425.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv442.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv616.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv638.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv733.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv734.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv736.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv737.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv738.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv739.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv740.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_pv832.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_qst.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_result.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_sc.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_skin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_song.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_songcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_stamp.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_ticket.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_vaccess.farc ; 140616748778912 17:05.50 1989-05-24 rom/2d/spr_sel_watch.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/auth_3d_db.bin ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/auth_3d_setting.bin ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV004.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV005.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV006.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV007.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV008.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV009.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV010.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV011.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV012.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV013.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV014.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV015.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV017.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV018.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV019.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV020.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV021.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV0211.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV022.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV023.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV024.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV025.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV027.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV028.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV029.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV030.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV031.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV032.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV037.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV039.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV040.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV041.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV042.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV043.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV044.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV045.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV046.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV047.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV048.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV049.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV050.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV051.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV052.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV053.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV054.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV055.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV057.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV058.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV059.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV060.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV061.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV062.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV063.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV064.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV065.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV066.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV067.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV068.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV079.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV081.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV082.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV083.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV084.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV016.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV038.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV056.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV085.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV204.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV226.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV248.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV603.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV622.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV723.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV832.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262MIK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV086.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV087.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV088.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV089.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV090.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV091.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV092.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV093.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV094.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV095.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV096.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV097.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV102.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV103.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV104.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV201.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV202.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV205.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV206.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV207.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV208.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV210.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV211.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV212.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV213.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV214.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV218.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV219.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV220.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV221.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV222.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV223.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV224.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV225.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV227.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV228.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV231.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV232.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV233.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV234.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV235.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV236.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV238.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV239.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV240.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV241.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV242.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV243.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV244.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV246.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV247.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV249.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV250.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV251.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV253.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV255.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV257.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV259.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV260.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV261.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV262.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV432.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV433.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV434.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV435.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV600.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV601.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV602.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV604.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV605.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV607.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV608.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV609.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV610.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV611.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV612.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV613.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV614.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV615.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV616.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV617.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV618.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV619.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV620.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV621.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV623.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV624.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV625.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV626.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV627.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV628.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV629.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV630.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV631.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV637.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV638.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV639.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV640.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV641.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV642.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV710.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV722.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV724.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV725.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV726.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV727.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV728.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV729.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV730.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV731.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV732.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV733.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV734.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV736.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV737.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV738.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV739.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CAMPV740.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/CHRPV605.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV243TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV244KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV244KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV244LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV244LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262HAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262KAI100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262KAI101.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262MEI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262MEI100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262MEI101.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262MIK101.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262NER002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262RIN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262RIN100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262RIN101.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262SAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV262TET002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV441TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV602TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV605TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV609LEN003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV609LUK004.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV609MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV609RIN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612HAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612MEI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612NER002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612RIN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612SAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV612TET002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614KAI009.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK004.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK005.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK006.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK007.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK008.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK009.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK010.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614MEI009.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614MIK009.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614TET009.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624EXT001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624EXT002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624HAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624MEI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624NER002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624RIN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624SAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624TET002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630HAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630MEI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630NER002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630RIN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630SAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637KAI005.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637LUK003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637MEI004.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637MIK003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637MIK004.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637MIK005.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV637RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641HAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641HAK003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641KAI003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641LUK003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641MEI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641MEI003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641MIK003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641NER002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641NER003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641RIN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641RIN003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641SAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641SAK003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641TET002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641TET003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722KAI100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722LEN100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722LUK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722MEI100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722MIK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722NER100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722RIN100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722SAK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722TET100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726HAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726MEI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726SAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726TET002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730HAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730MEI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730NER002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730RIN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730SAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730TET002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737HAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737HAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737KAI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737LEN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737LEN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737MEI001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737MEI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737MIK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737NER002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737RIN002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737SAK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737SAK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737TET001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737TET002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739HAK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739KAI100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739LEN100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739LUK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739MIK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739NER100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739RIN100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739SAK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739TET100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS035.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS036.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS037.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS038.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS039.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS040.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS041.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS042.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS043.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS044.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS045.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS047.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS048.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS049.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS050.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS051.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS052.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS053.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS054.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS055.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS056.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS057.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS058.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS059.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS060.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS061.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS062.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS064.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS065.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS066.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS067.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS068.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS069.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS070.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS071.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS072.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS073.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS074.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS075.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS076.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS077.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS078.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS079.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS081.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS082.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV037.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV038.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV039.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV040.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV041.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV042.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV043.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV044.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV045.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV046.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV047.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV048.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV050.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV051.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV614LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV617LUK001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV624LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630KAI002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV630TET002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV641LEN003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV722HAK100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV725NER001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV726RIN001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV730MIK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV737LUK002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFCHRPV739MEI100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS046.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS063.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2NS080.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV052.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS018.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS083.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS102.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS120.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV005.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV067.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV096.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV233.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV253.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV604.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV622.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV723.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGTST002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV053.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV055.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV056.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV057.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV058.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV060.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV061.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV062.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV063.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV064.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV065.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV066.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV208.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV212.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV213.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGD2PV214.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS002.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS004.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS005.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS006.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS007.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS008.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS009.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS010.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS011.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS012.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS013.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS014.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS015.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS016.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS017.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS019.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS020.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS021.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS022.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS023.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS024.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS025.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS026.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS027.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS028.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS029.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS030.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS031.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS032.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS033.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS034.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS084.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS085.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS086.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS087.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS088.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS089.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS090.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS091.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS093.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS094.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS095.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS096.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS097.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS099.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS100.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS101.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS103.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS104.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS105.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS106.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS107.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS108.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS109.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS111.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS112.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS113.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS114.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS115.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS116.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS117.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS118.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS119.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS121.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS122.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS123.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS124.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS125.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS126.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS210.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS221.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS249.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS257.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS266.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS267.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGNS272.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV001.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV004.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV006.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV007.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV008.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV009.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV011.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV012.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV013.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV014.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV015.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV018.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV019.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV020.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV022.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV024.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV025.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV028.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV079.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV081.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV082.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV083.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV084.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV085.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV086.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV087.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV088.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV089.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV090.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV091.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV092.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV093.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV094.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV095.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV097.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV103.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV104.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV218.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV219.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV220.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV221.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV222.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV223.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV224.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV225.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV226.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV227.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV228.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV231.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV232.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV234.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV235.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV236.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV238.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV239.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV240.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV241.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV242.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV243.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV244.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV246.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV247.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV248.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV249.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV250.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV251.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV255.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV257.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV259.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV260.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV261.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV262.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV432.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV433.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV434.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV435.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV440.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV441.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV600.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV601.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV602.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV603.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV605.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV607.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV608.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV609.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV610.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV611.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV612.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV613.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV614.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV615.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV616.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV617.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV618.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV619.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV620.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV621.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV623.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV624.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV625.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV626.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV627.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV628.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV629.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV630.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV631.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV637.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV638.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV639.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV640.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV641.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV642.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV710.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV724.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV725.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV726.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV727.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV728.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV729.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV730.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV731.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV732.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV733.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV734.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV736.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV737.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV738.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV739.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV740.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGPV832.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/EFFSTGTST003.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV045.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV060.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV084.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV085.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV086.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV088.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV089.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV103.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV212.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV218.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV221.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV232.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV233.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV441.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV600.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV602.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV616.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV618.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV619.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV620.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV641.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV725.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV726.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV731.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV733.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/ITMPV737.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/auth_3d/SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s20.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/aetback.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns035.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns036.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns037.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns038.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns039.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns040.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns041.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns042.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns043.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns044.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns045.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns046.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns047.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns048.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns049.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns050.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns051.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns052.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns054.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns055.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns056.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns057.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns058.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns059.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns060.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns062.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns063.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns064.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns065.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns066.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns067.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns068.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns069.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns070.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns071.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns072.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns074.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns075.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns076.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns077.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns078.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns079.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns080.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns081.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns082.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv037s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv037s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv037s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv038s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv039s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv039s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv039s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv040s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv041s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv042s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv042s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv042s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv043s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv044s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv044s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv044s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv046s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv046s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv046s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv046s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv046s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv047s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv047s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv047s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv047s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv047s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv048s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv050s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv051s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv051s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv051s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv051s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv051s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv053s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv053s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv053s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv053s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv053s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv053s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv053s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv053s15.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv055s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv055s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns053.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2ns073.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv042s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv047s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv057s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv065s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns008.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns030.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns099.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns119.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv001s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv005s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv008s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv013s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv020s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv058s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv058s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv060s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv061s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv061s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv062s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s12.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv063s13.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv064s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv064s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv065s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv065s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv065s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv065s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv065s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv065s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv065s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv066s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv208s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv212s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv213s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/d2pv214s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns001.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns002.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns003.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns004.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns005.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns006.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns007.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns009.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns010.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns011.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns012.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns013.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns014.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns015.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns016.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns017.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns018.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns019.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns020.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns021.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns022.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns023.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns024.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns025.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns026.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns029.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns031.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns032.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns033.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns034.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns083.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns084.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns085.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns087.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns088.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns089.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns090.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns091.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns092.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns093.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns094.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns095.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns096.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns097.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns098.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns100.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns101.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns102.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns103.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns104.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns105.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns106.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns107.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns108.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns109.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns110.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns111.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns112.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns113.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns114.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns115.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns116.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns117.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns118.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns120.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns121.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns122.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns123.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns124.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns125.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns126.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns221.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns249.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns257.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns263.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns266.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns267.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns272.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/ns292.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv001s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv001s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv001s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv001s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv001s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv001s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv003s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv004s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv004s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv004s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv004s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv004s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv005s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv005s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv006s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv007s12.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv008s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv008s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv008s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv008s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv008s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv009s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv009s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv009s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv009s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv009s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv009s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv011s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv011s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv011s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv011s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv011s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv013s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv013s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv013s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv014s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv015s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv015s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv015s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv015s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv018s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv018s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv018s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv018s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv018s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv019s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv019s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv019s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv019s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv019s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv019s13.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv019s14.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv020s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv020s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s12.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s13.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv024s14.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s12.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s13.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s14.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s15.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s16.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s17.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s18.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s19.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s21.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s22.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s23.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s24.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s25.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s26.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv025s27.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv028s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv079s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s12.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv082s61.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv082s62.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv082s63.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv082s64.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv082s65.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s14.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s18.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s25.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s26.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s27.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s28.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv084s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv085s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv086s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv086s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv087s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv087s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv087s16.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv087s17.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv088s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv088s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv088s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv088s12.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv088s14.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv089s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv089s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv089s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv090s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv090s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s13.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s14.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv091s15.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv092s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv092s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv092s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv092s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv092s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv092s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv092s12.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv094s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv094s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv094s16.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv094s17.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv094s18.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv096s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv097s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv103s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv104s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv104s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv104s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv104s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv218s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv218s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv218s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s12.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s13.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv219s14.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv220s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv220s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s11.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv221s14.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv222s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv222s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s10.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv224s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv224s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv224s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv225s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv225s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv225s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv226s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv227s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv228s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv228s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv228s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv228s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv231s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv231s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv231s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv231s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv231s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv231s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv232s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv232s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv232s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv233s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv233s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv233s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv233s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv233s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv233s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv233s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv233s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv234s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv235s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv236s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv236s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv236s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv236s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv236s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv236s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv236s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv238s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv240s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv240s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv240s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv241s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv241s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv243s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv244s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv244s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv246s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv248s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv248s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv250s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv251s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv251s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv251s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv251s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv251s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv251s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv253s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv255s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv257s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv262s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv432s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv432s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv432s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv433s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv433s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv433s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv433s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv433s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv434s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv435s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv435s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv435s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv435s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv435s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv435s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv435s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv435s08.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv441s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv600s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv600s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv600s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv601s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv601s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv601s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv601s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv602s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv602s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv602s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv602s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv603s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv604s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv605s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv605s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv605s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv607s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv608s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv609s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv609s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv610s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv611s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv612s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv612s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv612s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv612s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv613s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv613s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv613s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv614s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv614s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv615s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv616s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv616s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv616s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv617s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv617s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv619s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv619s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv619s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv620s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv621s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv622s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv623s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv623s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv625s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv625s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv626s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv628s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv629s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv630s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv630s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv630s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv630s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv631s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv637s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv637s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv638s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv638s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv639s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv639s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv639s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv639s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv640s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv640s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv641s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv642s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv722s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv722s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv723s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv725s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv725s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv727s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv728s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv729s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv729s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv732s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv734s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv736s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv737s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv737s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv738s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv739s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/selpvback.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/tst.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/tst001.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/tst002.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/tst006.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/tst007.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/tst008.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/tst009.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/tst010.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv081s09.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv083s24.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv089s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv092s07.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv218s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv220s03.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv223s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv231s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv234s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv239s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv251s06.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv433s02.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv600s04.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv610s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv619s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv630s05.ibl ; 140616748778912 17:05.50 1989-05-24 rom/ibl/pv726s01.ibl ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns035.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns036.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns037.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns038.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns039.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns040.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns041.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns042.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns043.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns046.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns047.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns048.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns049.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns050.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns051.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns052.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns054.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns055.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns059.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns060.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns065.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns067.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns070.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns071.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns072.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns073.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns079.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns080.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns081.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns082.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv037s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv038s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv043s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv044s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv044s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv046s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv046s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv046s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv047s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv047s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv047s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv047s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv047s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv051s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv051s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv051s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv051s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv051s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv057s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv060s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv061s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv061s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv063s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv064s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv065s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv065s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv065s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv065s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv065s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv065s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv066s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns002.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns003.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns005.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns013.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2ns053.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv039s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_d2pv055s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns014.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns120.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv024s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv083s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv092s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv233s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns036.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns058.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns080.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv047s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv058s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns020.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns024.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns030.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns033.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns084.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns088.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns098.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns099.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns101.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns103.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns104.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns105.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns111.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns112.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns115.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns116.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns117.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns123.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns124.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns125.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns249.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_ns272.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv004s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv004s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv007s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv009s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv009s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv009s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv009s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv015s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv020s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv020s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv020s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv024s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv024s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv024s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv024s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv024s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv024s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s20.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s21.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s22.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s23.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv025s24.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv028s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv081s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv081s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv082s61.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv082s62.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv082s63.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv082s64.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv082s65.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv083s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv083s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv083s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv083s26.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv083s27.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv083s28.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv085s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv086s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv086s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv087s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv087s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv087s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv087s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv090s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv090s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv092s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv092s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv092s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv092s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv092s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv096s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv096s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_PV097s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv104s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv218s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv218s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv220s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv220s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv232s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv232s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv232s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv233s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv233s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv233s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv233s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv233s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv236s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv432s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv432s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv616s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv616s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv616s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv618s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv621s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv638s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_pv638s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_selpvback.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_stgns105.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/face_tst.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns035.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns037.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns040.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns041.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns042.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns043.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns044.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns045.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns046.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns047.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns048.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns049.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns050.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns052.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns053.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns054.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns056.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns057.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns059.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns060.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns062.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns063.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns064.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns065.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns066.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns068.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns069.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns070.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns071.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns072.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns073.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns074.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns075.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns076.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns079.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns081.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2ns082.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv037s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv038s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv039s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv039s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv039s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv040s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv041s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv042s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv042s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv042s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv043s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv044s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv044s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv046s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv047s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv047s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv047s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv048s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv050s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv051s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv051s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv051s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv051s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv051s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv053s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv053s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv053s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv053s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv055s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv055s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv058s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv060s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv061s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv061s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv062s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv063s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv063s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv063s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv063s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv063s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv063s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv063s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv065s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv065s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv065s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv065s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv065s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv065s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv066s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv212s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv213s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv214s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns001.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns002.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns003.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns004.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns005.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns006.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns007.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns009.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns010.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns011.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns012.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns013.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns015.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns016.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns017.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns018.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns019.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns020.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns021.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns022.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns023.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns025.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns029.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns030.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns031.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns032.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns033.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns034.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns083.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns085.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns086.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns087.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns088.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns089.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns090.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns091.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns092.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns093.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns094.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns095.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns096.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns097.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns098.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns099.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns100.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns101.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns103.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns104.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns105.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns106.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns107.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns108.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns109.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns110.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns111.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns112.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns113.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns114.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns115.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns116.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns117.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns120.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns121.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns123.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns124.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns126.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns221.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns249.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns257.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns263.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns272.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns292.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv001s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv001s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv001s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv001s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv001s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv001s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv001s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv004s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv004s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv004s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv004s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv005s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv005s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv005s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv008s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv008s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv008s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv009s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv011s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv011s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv011s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv013s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv013s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv013s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv015s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv015s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv015s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv015s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv020s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv020s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv020s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv024s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv024s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv024s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv025s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv025s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv025s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv025s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv028s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv079s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv081s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv081s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv081s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv081s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv081s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv082s61.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv082s62.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv082s63.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv082s65.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s24.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s25.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s26.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s27.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv083s28.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv084s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv086s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv086s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv087s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv087s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv087s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv087s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv088s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv088s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv088s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv088s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv088s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv089s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv089s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv089s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv089s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv090s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv091s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv091s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv091s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv091s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv091s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv091s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv092s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv092s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv092s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv092s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv094s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv094s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv094s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv094s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv094s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv096s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv103s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv103s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv103s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv104s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv104s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv104s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv104s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv218s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv218s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv218s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv218s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv220s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv220s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv222s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv222s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv223s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv223s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv223s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv223s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv223s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv223s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv223s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv223s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv224s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv224s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv224s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv225s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv225s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv226s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv227s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv228s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv231s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv231s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv231s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv231s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv231s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv231s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv231s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv232s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv232s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv232s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv233s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv233s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv233s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv233s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv233s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv233s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv233s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv234s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv234s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv236s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv236s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv236s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv236s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv236s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv236s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv236s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv238s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv239s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv240s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv241s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv241s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv243s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv244s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv249s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv253s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv257s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns014.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns084.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns102.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_ns122.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv003s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv008s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv024s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv082s64.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv085s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv090s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv096s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv219s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv221s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv225s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv233s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv260s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv261s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv261s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv262s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv262s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv262s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv262s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv262s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv262s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv432s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv432s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv433s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv433s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv433s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv433s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv434s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv435s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv435s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv600s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv600s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv600s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv600s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv601s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv601s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv601s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv601s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv602s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv602s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv603s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv604s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv605s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv607s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv611s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv613s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv613s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv613s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv614s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv615s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv616s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv616s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv617s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv618s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv618s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv618s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv618s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv619s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv619s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv619s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv622s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv623s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv625s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv628s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv637s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv637s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv638s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv639s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv639s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv639s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv639s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv727s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv728s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv728s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv728s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv729s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv731s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv732s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv734s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv734s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv736s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv738s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv738s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv740s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv740s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv832s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_selpvback.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_stgns105.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_tst.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_aetback.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns035.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns036.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns039.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns040.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns041.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns042.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns043.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns044.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns045.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns046.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns047.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns048.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns049.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns051.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns052.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns053.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns054.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns055.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns057.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns058.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns059.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns060.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns062.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns063.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns064.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns065.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns066.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns067.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns068.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns069.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns070.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns071.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns072.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns073.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns075.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns076.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns077.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns078.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns079.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns081.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns082.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv037s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv037s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv037s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv038s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv039s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv039s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv039s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv040s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv041s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv043s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv044s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv044s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv044s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv046s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv046s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv047s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv047s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv047s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv047s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv047s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv048s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv050s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv051s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv051s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv051s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv051s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv053s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv053s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv053s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv053s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv053s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv053s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv053s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv053s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv055s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv055s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv057s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv058s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv058s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv060s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv061s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv062s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv063s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv064s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv064s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv065s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv065s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv065s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv065s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv065s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv065s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv065s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv066s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv208s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv212s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv213s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv214s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns001.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns002.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns003.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns004.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns005.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns006.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns007.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns008.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns009.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns010.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns012.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns013.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns014.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns015.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns016.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns017.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns018.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns019.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns020.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns021.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns022.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns023.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns024.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns025.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns026.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns029.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns030.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns032.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns033.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns034.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns083.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns084.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns085.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns086.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns087.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns088.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns089.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns090.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns091.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns093.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns095.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns096.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns097.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns098.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns101.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns102.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns103.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns104.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns105.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns106.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns107.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns108.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns109.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns111.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns112.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns113.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns114.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns115.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns116.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns117.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns118.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns121.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns122.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns123.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns124.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns125.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns126.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns221.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns223.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns249.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns257.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns263.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns266.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns272.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns292.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv001s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv001s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv001s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv259s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv435s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv608s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv621s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv729s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns037.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns056.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2ns074.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv042s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv051s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv061s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_d2pv065s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns011.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns031.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns099.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv001s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv001s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv001s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv003s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv004s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv004s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv004s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv004s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv004s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv004s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv005s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv005s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv005s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv007s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv007s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv007s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv007s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv007s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv007s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv007s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv007s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv008s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv008s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv008s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv008s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv009s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv011s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv011s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv011s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv011s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv011s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv013s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv013s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv013s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv015s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv015s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv019s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv020s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv020s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv020s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s19.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s20.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s22.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s23.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s24.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s27.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv028s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv079s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv081s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv081s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv081s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv081s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv081s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv081s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv081s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv081s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv082s61.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv082s62.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv082s64.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv082s65.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s26.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s27.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv083s28.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv084s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv085s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv086s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv087s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv087s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv087s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv087s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv088s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv088s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv088s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv088s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv088s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv089s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv089s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv090s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv090s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv092s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv094s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv094s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv094s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv094s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv096s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv096s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_PV097s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv103s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv103s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv103s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv104s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv104s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv104s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv104s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv218s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv218s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv218s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv219s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv220s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv220s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv220s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv222s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv222s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv224s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv224s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv224s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv225s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv225s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv225s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv226s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv227s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv228s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv228s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv228s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv228s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv231s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv231s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv231s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv231s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv231s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv231s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv232s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv232s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv232s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv233s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv233s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv233s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv233s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv233s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv233s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv234s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv234s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv235s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv235s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv235s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv235s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv235s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv235s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv235s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv236s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv236s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv236s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv236s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv236s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv236s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv236s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv238s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv239s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv001s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv004s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv008s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv013s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv024s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv025s21.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv082s63.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv086s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv091s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv094s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv218s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv221s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv223s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv231s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_d2pv065s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/fog_pv240s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_ns120.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv235s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns017.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv240s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv240s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv241s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv241s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv242s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv243s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv247s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv247s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv249s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv250s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv257s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv259s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv260s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv261s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv261s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv432s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv432s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv433s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv433s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv433s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv433s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv433s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv433s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv434s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv435s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv435s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv435s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv435s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv435s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv435s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv435s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv600s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv600s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv600s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv600s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv601s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv601s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv601s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv601s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv602s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv602s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv602s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv602s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv603s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv604s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv604s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv604s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv605s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv605s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv605s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv605s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv607s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv608s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv610s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv611s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv613s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv613s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv614s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv615s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv616s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv616s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv616s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv617s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv618s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv618s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv618s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv618s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv618s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv618s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv619s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv619s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv619s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv620s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv621s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv622s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv623s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv623s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv623s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv624s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv625s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv625s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv625s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv626s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv627s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv627s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv627s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv628s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv629s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv631s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv637s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv637s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv638s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv638s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv639s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv639s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv641s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv642s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv710s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv723s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv723s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv726s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv727s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv727s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv727s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv728s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv728s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv728s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv729s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv729s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv730s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv730s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv731s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv732s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv734s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv734s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv734s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv734s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv736s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv736s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv738s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv739s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv740s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv740s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv740s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv740s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv740s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv832s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_stgns105.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_tst.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_tst002.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_aetback.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns035.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns036.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns037.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns039.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns040.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns042.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns043.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns044.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns045.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns046.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns047.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns048.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns053.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns054.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns055.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns056.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns057.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns058.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns059.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns060.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns062.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns063.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns066.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns067.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns068.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns069.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns071.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns073.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns075.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns076.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns077.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns078.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns079.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns081.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns082.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv037s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv039s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv039s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv039s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv040s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv041s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv042s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv042s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv043s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv044s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv044s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv044s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv047s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv047s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv047s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv047s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv047s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv048s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv050s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv051s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv051s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv051s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv051s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv053s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv053s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv053s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv053s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv053s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv053s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv053s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv058s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv058s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv060s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv061s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv062s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv063s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv063s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv063s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv063s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv064s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv065s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv065s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv065s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv208s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv212s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns001.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns002.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns005.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns006.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns007.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns008.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns009.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns010.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns011.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns012.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns013.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns024.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns025.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns031.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns032.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns083.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns084.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns087.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns088.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns089.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns090.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns093.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns095.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns096.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns097.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns098.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns099.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns100.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv240s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv253s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv262s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv435s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv604s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv617s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv625s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv639s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_pv731s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/glow_selpvback.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns049.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2ns074.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv042s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv051s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_d2pv064s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns102.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns103.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns104.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns105.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns106.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns107.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns108.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns109.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns110.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns111.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns112.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns114.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns116.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns117.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns118.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns119.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns120.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns122.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns123.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns124.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns125.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns126.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns221.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns223.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns249.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns257.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns263.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns266.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns292.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv004s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv004s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv007s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv007s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv007s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv007s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv008s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv008s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv008s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv008s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv008s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv008s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv009s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv009s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv009s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv009s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv009s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv009s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv009s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv011s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv011s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv011s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv013s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv013s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv013s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv013s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv015s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv015s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv015s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv018s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv019s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv019s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv019s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv019s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv019s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s19.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s20.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s21.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s22.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s24.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s27.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv028s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv079s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv081s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv081s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv081s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv081s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv081s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv081s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv082s61.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv082s62.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv082s63.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv082s64.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv082s65.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s24.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s25.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s26.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s27.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s28.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv084s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv085s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv086s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv087s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv087s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv087s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv087s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv088s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv088s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv088s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv088s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv088s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv089s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv089s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv089s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv089s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv090s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv090s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv091s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv091s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv092s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv094s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv094s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv094s16.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv094s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv094s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv096s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_PV097s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv103s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv103s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv103s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv104s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv104s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv104s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv218s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv218s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv218s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv220s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv220s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv222s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv222s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv223s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv223s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv223s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv223s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv223s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv223s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv223s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv223s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv224s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv224s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv224s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv225.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv225s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv225s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv226s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv227s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv228s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv228s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv228s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv231s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv231s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv231s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv231s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv231s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv231s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv231s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv232s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv232s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv232s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv233s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv233s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv233s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv233s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv233s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv233s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv233s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv235s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv235s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv235s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv235s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv235s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv235s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv235s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv236s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv236s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv236s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns101.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_ns121.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv003s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv009s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv015s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv024s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv025s23.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv083s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv086s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv091s13.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv096s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv219s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv221s14.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv225s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv233s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv236s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv249.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv259.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv432s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv601s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv611s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv619s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv629s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv710s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv728s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv736s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_tst.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv009s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv236s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv236s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv238s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv240s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv240s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv240s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv241s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv241s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv242s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv243.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv243s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv246s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv247.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv247s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv247s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv248.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv249s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv250s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv251.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv253s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv255.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv257.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv257s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv259s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv259_old.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv260.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv260s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv261.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv261s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv261s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv262s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv432s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv433s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv433s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv433s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv433s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv433s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv433s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv434s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv435s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv441s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv600s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv600s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv600s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv600s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv601s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv601s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv601s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv602s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv602s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv602s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv602s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv603s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv604s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv604s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv604s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv604s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv604s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv605s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv605s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv605s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv607s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv610s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv612s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv613s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv613s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv613s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv614s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv615s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv616s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv616s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv616s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv617s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv617s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv618s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv618s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv618s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv618s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv618s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv619s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv619s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv619s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv620s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv621s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv622s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv623s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv623s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv624s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv625s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv625s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv626s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv627s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv627s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv627s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv628s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv630s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv630s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv631s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv637s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv637s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv638s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv638s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv639s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv639s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv639s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv639s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv639s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv642s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv710s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv710s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv710s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv722.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv723.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv723s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv723s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv724s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv724s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv724s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv725.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv726.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv726s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv727.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv727s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv727s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv728.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv728s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv728s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv729.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv729s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv729s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv730s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv730s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv731.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv731s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv732.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv732s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv733.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv734.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv734s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv734s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv734s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv734s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv736.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv736s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv737.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv738.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv738s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv739.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv739s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv740.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv740s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv740s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv740s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv740s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv740s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv832.farc ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_pv832s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_selpvback.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/light_stgns105.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_ns221.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv003s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv003s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv003s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv003s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv003s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv003s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv003s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv008s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv008s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv008s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv008s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv008s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv009s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv009s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv009s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv009s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv009s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv009s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv024s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv024s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv024s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv211_d2ns048.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv262s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv262s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv262s12.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv601s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv604s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv604s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv604s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv604s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv612s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv612s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv612s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv613s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv639s01_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv722s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv723s02_clone.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv732s02_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_pv732s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_selpvback.txt ; 140616748778912 17:05.50 1989-05-24 rom/light_param/wind_tst.txt ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1016.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1021.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1032.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1033.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1034.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1035.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1037.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1038.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1039.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1040.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1041.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1042.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1043.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1044.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1047.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1048.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1049.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1050.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1051.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1101.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1104.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1105.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1106.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1108.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1109.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1201.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1202.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1203.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1204.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1205.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1206.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1207.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1208.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1209.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1210.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1211.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1212.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1213.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1214.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1215.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1036.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1107.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1216.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1236.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1254.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1272.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1311.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1415.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1514.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1616.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/dbg.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262hak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262mik101.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1217.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1218.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1219.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1220.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1221.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1222.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1223.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1224.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1227.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1228.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1229.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1230.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1231.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1232.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1233.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1234.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1235.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1237.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1238.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1239.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1240.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1241.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1242.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1243.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1244.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1245.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1246.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1247.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1248.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1249.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1250.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1251.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1252.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1253.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1255.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1256.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1257.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1258.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1259.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1260.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1261.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1262.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1263.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1264.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1265.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1266.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1267.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1268.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1269.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1270.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1271.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1273.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1274.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1275.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1276.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1277.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1278.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1279.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1302.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1303.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1304.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1305.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1306.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1307.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1308.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1309.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1310.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1312.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1313.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1314.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1315.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1316.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1317.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1318.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1401.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1402.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1403.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1404.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1405.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1406.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1411.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1412.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1413.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1414.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1416.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1417.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1418.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1419.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1503.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1504.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1505.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1506.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1507.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1508.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1509.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1510.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1511.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1512.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1513.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1515.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1516.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1601.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1602.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1603.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1604.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1605.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1606.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1607.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1608.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1609.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1610.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1611.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1612.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1613.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1614.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1615.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1617.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1618.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1619.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1620.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1621.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1625.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1626.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1627.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1701.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1702.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1703.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1704.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1705.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1706.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1707.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/cmnitm1708.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv243tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv244kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv244kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv244len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv244len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262kai100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262kai101.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262mei100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262mei101.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262mik100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262ner002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262rin100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262rin101.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv262tet002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv441tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv602tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609len003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609luk004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609mik003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609mik004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612hak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612ner002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612tet002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614len010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mik010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614sak010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv617tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624ext001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624ext002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624hak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624ner002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630hak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630ner002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630tet002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637kai005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637luk003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637mei004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637mik003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637mik004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637mik005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv637rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641hak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641kai003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641len003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641luk003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641mei003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641mik003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641ner002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641ner003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641rin003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641sak003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641tet002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641tet003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722hak100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722kai100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722len100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722luk100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722mei100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722mik100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722ner100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722rin100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722sak100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv722tet100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726hak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726ner002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726tet002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730hak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730ner002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730tet002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv609mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv612mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614kai007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614luk003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614mei009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614rin005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv614tet009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv624tet002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv630rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641hak003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv641sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv725len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv726mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv730len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737hak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737kai002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737len001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737len002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737luk001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737luk002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737mei001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737mei002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737mik001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737mik002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737ner001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737ner002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737rin001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737rin002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737sak002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737tet001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737tet002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739hak100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739kai100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739len100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739luk100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739mei100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739mik100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739ner100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739rin100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739sak100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv739tet100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effmodulemik149.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm302.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm304.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm016.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm021.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm035.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm036.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm054.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm056.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm057.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm058.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm300.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm302.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm303.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm400.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm401.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm402.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm403.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm404.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm405.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm406.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm600.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm601.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm603.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm604.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm605.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv045.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv060.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv086.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv088.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv089.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv103.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv212.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv218.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv221.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv232.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv233.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv435.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv441.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv600.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv602.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv603.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv607.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv610.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv612.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv618.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv619.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv620.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv622.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv630.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv641.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv726.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv727.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv731.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv733.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv737.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm016.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm032.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm033.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm034.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm036.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm037.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm038.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm041.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm042.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm304.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm310.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm311.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm315.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm316.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm320.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm322.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm323.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm324.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm325.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm327.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm328.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm329.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm330.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm331.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm332.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm334.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm337.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm341.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm342.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm503.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm504.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm505.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm506.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm507.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm508.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm509.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm510.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm520.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm522.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm523.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm524.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm527.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm528.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm529.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm532.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm533.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm534.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm536.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm541.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm542.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm701.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm702.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm703.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm705.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm706.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm707.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm726.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm727.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm728.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm730.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm750.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm751.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm775.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm809.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm810.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm815.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm820.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm822.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm824.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm827.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm828.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm829.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm831.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm832.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm834.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm837.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm842.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm021.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm032.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm033.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm034.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm036.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm037.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm038.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm039.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm040.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm309.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm310.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm311.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm313.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm315.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm316.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm321.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm322.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm324.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm325.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm326.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737sak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hakitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/hnditm304.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv085.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/itmpv616.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm312.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm531.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm729.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/kaiitm841.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm016.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm035.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm328.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm329.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm331.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm332.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm334.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm336.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm337.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm339.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm340.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm503.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm504.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm505.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm506.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm507.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm509.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm511.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm519.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm521.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm522.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm523.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm524.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm525.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm526.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm528.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm529.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm530.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm531.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm532.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm533.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm534.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm535.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm537.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm538.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm540.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm542.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm701.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm702.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm703.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm704.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm726.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm729.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm770.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm771.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm775.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm807.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm808.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm810.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm811.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm812.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm814.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm815.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm819.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm822.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm824.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm825.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm826.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm828.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm831.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm832.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm833.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm834.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm836.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm837.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm839.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm842.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm997.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm021.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm032.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm034.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm035.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm036.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm037.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm038.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm039.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm040.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm041.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm042.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm304.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm305.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm310.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm311.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm312.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm313.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm314.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm317.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm320.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm324.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm325.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm326.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm328.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm329.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm330.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm331.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm332.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm334.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm335.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm336.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm337.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm339.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm341.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm342.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm503.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm504.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm505.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm506.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm507.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm508.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm509.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm510.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm511.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm512.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm513.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm514.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm515.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm516.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm517.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm526.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm527.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm528.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm529.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm530.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm531.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm532.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm533.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm534.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm535.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm536.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm537.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm538.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm539.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm540.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm542.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm702.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm703.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm704.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm705.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm706.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm726.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm727.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm810.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm815.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm817.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm825.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm829.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm830.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm833.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm836.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm837.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm840.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm841.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm021.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm032.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm033.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm304.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm305.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm309.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm311.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm313.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm314.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm320.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm321.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm322.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm323.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm324.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm325.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm327.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm330.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm331.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm332.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm333.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm503.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm504.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm505.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm506.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm507.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm508.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm509.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm510.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm511.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm512.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm513.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm514.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm515.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm521.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm522.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm524.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm525.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm526.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm527.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm528.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm529.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm530.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm532.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm533.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm701.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm702.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm703.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm704.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm705.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm706.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm707.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm775.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm809.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm816.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm820.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm821.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm823.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm827.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm828.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm831.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm833.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm016.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm021.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm508.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm536.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm809.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm838.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm033.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm315.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm525.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm701.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lukitm839.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm016.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm523.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/meiitm709.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv605kai001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/effchrpv737hak001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/lenitm327.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm540.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm331.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv236s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm032.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm033.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm034.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm035.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm036.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm037.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm038.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm039.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm040.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm041.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm043.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm044.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm045.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm046.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm047.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm048.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm049.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm050.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm051.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm052.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm053.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm054.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm055.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm056.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm057.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm058.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm059.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm061.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm063.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm064.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm065.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm066.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm067.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm068.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm069.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm070.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm071.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm072.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm073.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm074.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm075.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm076.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm077.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm078.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm080.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm081.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm082.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm083.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm084.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm085.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm087.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm088.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm089.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm090.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm091.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm092.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm093.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm094.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm095.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm096.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm097.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm099.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm101.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm102.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm103.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm104.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm105.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm106.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm107.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm108.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm109.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm110.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm111.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm112.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm113.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm114.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm115.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm118.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm119.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm120.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm123.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm124.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm125.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm126.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm127.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm128.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm129.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm130.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm131.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm132.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm133.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm134.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm135.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm136.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm138.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm139.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm140.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm141.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm142.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm143.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm144.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm145.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm146.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm147.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm148.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm149.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm151.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm152.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm153.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm155.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm156.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm160.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm162.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm163.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm164.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm165.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm166.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm167.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm169.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm170.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm173.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm302.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm303.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm304.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm305.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm306.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm308.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm311.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm312.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm313.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm314.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm315.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm316.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm317.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm318.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm319.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm321.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm322.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm323.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm325.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm326.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm327.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm329.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm332.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm334.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm335.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm336.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm337.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm338.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm339.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm340.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm341.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm342.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm343.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm345.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm349.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm350.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm353.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm357.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm360.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm361.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm364.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm365.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm366.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm368.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm369.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm370.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm371.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm372.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm373.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm374.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm375.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm376.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm377.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm379.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm380.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm381.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm382.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm384.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm387.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm388.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm389.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm392.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm393.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm394.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm395.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm396.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm397.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm398.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm399.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm400.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm401.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm402.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm404.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm405.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm410.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm411.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm412.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm413.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm414.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm415.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm416.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm418.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm419.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm420.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm423.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm424.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm427.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm428.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm429.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm431.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm432.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm434.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm435.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm436.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm437.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm438.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm439.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm441.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm443.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm444.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm445.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm446.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm447.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm448.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm449.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm450.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm451.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm455.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm460.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm462.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm463.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm464.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm466.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm467.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm469.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm470.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm473.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm503.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm504.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm505.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm506.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm507.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm509.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm520.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm522.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm524.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm525.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm526.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm527.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm528.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm530.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm531.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm532.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm533.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm534.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm536.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm537.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm538.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm539.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm541.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm542.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm543.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm544.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm545.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm546.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm547.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm548.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm549.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm550.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm551.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm552.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm553.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm554.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm555.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm556.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm557.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm042.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm060.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm079.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm098.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm116.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm137.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm158.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm310.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm333.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm363.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm383.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm409.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm433.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm458.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm508.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm559.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm560.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm593.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm594.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm595.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm596.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm597.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm598.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm599.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm600.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm601.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm602.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm603.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm604.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm605.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm606.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm607.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm609.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm610.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm611.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm612.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm613.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm614.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm615.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm616.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm617.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm618.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm619.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm620.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm621.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm623.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm624.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm625.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm626.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm628.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm630.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm631.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm632.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm633.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm634.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm635.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm636.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm637.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm638.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm639.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm640.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm641.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm642.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm643.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm644.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm645.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm647.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm648.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm649.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm651.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm652.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm653.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm655.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm656.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm658.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm660.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm662.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm663.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm664.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm665.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm667.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm669.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm670.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm701.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm702.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm703.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm704.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm705.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm706.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm707.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm708.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm709.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm710.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm711.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm712.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm713.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm714.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm715.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm716.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm718.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm719.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm720.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm721.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm722.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm723.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm724.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm726.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm727.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm728.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm729.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm730.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm740.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm741.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm742.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm743.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm745.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm746.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm747.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm748.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm749.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm750.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm751.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm752.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm770.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm771.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm772.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm773.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm775.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm776.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm777.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm778.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm779.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm781.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm782.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm783.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm784.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm790.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm791.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm804.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm833.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm834.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm835.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm836.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm837.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm838.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm839.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm840.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm841.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm842.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm851.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm852.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm856.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm857.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm863.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm865.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm866.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm868.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm869.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm873.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm874.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm876.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm878.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm879.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm880.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm882.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm884.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm893.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm894.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm895.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm896.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm897.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm899.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm900.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm901.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm902.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm904.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm905.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm910.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm913.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm914.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm915.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm916.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm917.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm924.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm926.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm927.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm928.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm931.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm932.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm933.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm934.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm935.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm936.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm937.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm938.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm939.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm940.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm941.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm942.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm943.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm945.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm946.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm947.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm948.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm949.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm951.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm956.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm958.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm962.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm963.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm965.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm966.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm967.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm970.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm973.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm997.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm998.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm302.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/neritm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/obj_db.bin ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm016.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm021.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm032.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm033.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm034.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm035.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm036.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm037.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm038.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm039.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm040.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm041.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm043.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm045.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm046.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm047.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm048.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm304.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm309.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm311.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm312.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm313.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm314.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm315.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm316.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm320.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm326.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm329.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm330.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm333.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm334.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm336.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm337.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm339.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm340.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm343.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm346.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm347.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm348.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm503.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm504.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm505.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm506.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm558.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm608.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm627.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm646.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm673.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm717.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm744.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm780.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm843.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm892.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm919.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm944.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/mikitm999.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm044.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm508.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm509.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm510.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm511.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm512.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm513.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm514.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm515.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm516.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm517.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm518.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm519.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm520.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm526.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm527.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm528.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm529.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm531.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm532.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm533.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm534.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm535.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm536.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm537.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm538.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm539.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm540.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm541.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm543.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm544.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm545.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm547.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm548.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm550.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm701.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm702.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm703.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm704.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm705.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm706.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm707.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm708.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm709.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm710.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm711.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm712.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm713.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm714.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm715.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm716.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm717.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm719.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm720.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm721.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm726.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm750.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm770.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm771.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm775.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm776.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm777.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm810.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm811.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm814.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm815.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm816.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm817.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm829.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm831.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm836.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm837.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm838.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm839.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm840.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm843.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm844.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm845.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm846.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm848.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm850.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm997.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm998.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm999.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm302.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm303.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm305.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm501.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm701.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm775.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/selcmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns035.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns036.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns037.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns038.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns040.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns041.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns042.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns043.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns044.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns045.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns046.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns047.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns048.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns049.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns050.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns051.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns052.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns053.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns054.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns055.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns056.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns058.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns059.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns060.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns061.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns062.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns063.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns064.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns065.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns066.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns067.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns068.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns069.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns070.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns071.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns072.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns073.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns074.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns076.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns077.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns078.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns079.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns080.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns081.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns082.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv037.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv037s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv037s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv037s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv038.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv038s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv039.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv039s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv039s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv039s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv040s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv041.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv041s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv042s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv043.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv043s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv044s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv044s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv044s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv045.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv045s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv046.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv046s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv046s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv046s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv046s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv046s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv046s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv047.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv047s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv047s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv047s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv047s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv047s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv048.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv048s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv048s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv048s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv050.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv050s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv051.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv051s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv051s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv051s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv051s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv051s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv052.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv052s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s15.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv055.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv055s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv055s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv056s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv057.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv057s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv058.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv058s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv058s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv060.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv060s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv061.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv061s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv061s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv062.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv062s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv064.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv064s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv064s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv066.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv066s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv208.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv208s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv212.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv212s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv213.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv213s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv214.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv214s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns016.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns017.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns021.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm507.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm530.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm718.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/rinitm826.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/sakitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns039.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns057.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2ns075.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv040.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv044.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv047s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv053s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv056.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv063s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgd2pv065s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns026.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns027.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns029.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns030.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns031.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns032.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns033.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns034.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns083.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns084.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns085.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns086.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns087.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns088.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns090.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns091.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns092.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns093.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns094.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns095.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns096.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns097.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns098.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns099.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns100.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns101.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns102.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns103.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns104.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns105.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns106.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns108.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns109.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns110.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns111.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns112.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns113.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns114.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns115.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns116.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns117.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns118.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns119.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns120.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns121.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns122.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns123.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns124.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns126.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns210.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns221.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns223.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns249.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns257.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns263.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns266.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns267.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns272.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns292.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv001s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv001s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv001s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv001s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv001s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv001s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv003s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv004s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv004s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv004s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv004s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv004s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv004s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv005s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv005s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv005s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv005s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv005s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv005s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv006s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv006s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv009s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv011.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv011s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv011s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv011s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv011s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv011s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv012.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv012s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv013.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv013s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv013s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv013s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv013s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv014.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv014s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv015.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv015s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv015s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv015s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv015s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv015s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv018s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv020.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv020s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv020s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv020s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv022.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv022s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s15.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s16.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s17.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s18.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s20.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s21.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s22.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s23.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s24.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s25.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s26.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s27.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv028.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv028s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv067.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv067s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv079.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv079s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s21.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s22.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s23.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s24.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s27.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s28.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s29.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s41.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s42.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s51.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s52.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s53.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns023.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns089.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns107.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgns125.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv001s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv004s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv007s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv008s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv011s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv015s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv019s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv024.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv025s19.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv081s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s55.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s61.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s15.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s16.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s17.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s18.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s19.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s20.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s21.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s22.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s23.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s24.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s25.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s26.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s27.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s28.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv084.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv084s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv085s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv086.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv086s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv086s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s15.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s16.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s17.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv089.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv089s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv089s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv089s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv089s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv089s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv090.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv090s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv090s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv093.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv093s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s15.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s16.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s17.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s18.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s19.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s20.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv095.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv095s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv097.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv097s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv103.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv103s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv103s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv103s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv104.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv104s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv104s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv104s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv218.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv218s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv218s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv218s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv218s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv220.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv220s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv220s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv220s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv222.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv222s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv222s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv224.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv224s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv224s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv224s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv224s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv225.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv225s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv225s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv225s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv226.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv226s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv227.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv227s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv228.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv228s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv228s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv228s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv231.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv231s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv231s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv231s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv231s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv231s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv231s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv231s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv232.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv232s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv232s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv232s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv234.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv234s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv234s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv235.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv235s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv235s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv235s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv235s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv235s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv236.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv236s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv236s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv236s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv236s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv236s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv236s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv238.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv238s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv239.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv239s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv240.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv240s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv240s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv240s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv241.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv241s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv241s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv241s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv082s54.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv083s14.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv085.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv087s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv088s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv091s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv092s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv094s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv096s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv104s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv219s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv221s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv223s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv228s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv233s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv242.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv242s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv243.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv243hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv243s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv243s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv243s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv243s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv243s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv244.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv244s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv244s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv246.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv246s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv247.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv247s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv248.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv248s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv248s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv248s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv248s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv249.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv249s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv250.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv250s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv253s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv255.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv255hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv255s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv257.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv257s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv259s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv260.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv260s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv261.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv261hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv261s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv261s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s09.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s10.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s11.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s12.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s13.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv432.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv432hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv432s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv432s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv432s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv433.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv433hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv433s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv433s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv433s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv433s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv433s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv434.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv434hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv434s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv435s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv441.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv441s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv600hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv600s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv600s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv600s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv600s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv601.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv601hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv601s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv601s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv601s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv601s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv602.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv602hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv602s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv602s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv602s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv603.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv603s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv604.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv604s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv604s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv604s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv604s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv604s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv604s07.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv605.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv605s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv605s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv605s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv605s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv605s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv607.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv607hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv608.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv608hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv608s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv609.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv609hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv609s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv609s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv609s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv610.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv610s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv610s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv610s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv611.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv611s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv612.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv612hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv612s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv612s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv612s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv613.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv613hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv613s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv613s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv613s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv614.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv614hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv614s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv614s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv614s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv614s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv614s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv614s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv615.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv615s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv616.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv616s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv616s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv616s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv617.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv617hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv617s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv617s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv617s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv617s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv618.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv618s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv618s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv618s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv618s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv618s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv619.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv619s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv619s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv619s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv619s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv620.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv620s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv621.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv621s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv622.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv622hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv622s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv623.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv623hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv623s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv623s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv623s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv624s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv624s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv625.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv625hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv625s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv625s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv625s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv625s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv625s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv626.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv626s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv626s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv627.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv627s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv627s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv627s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv628.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv628s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv628s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv629.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv629s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv630.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv630hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv630s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv630s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv630s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv630s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv630s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv631.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv631s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv631s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv637.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv637hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv637s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv638.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv638s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv638s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv639.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv639hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv639s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv639s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv639s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv639s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv639s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv639s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv640.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv640hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv640s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv640s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv641.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv641hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv642.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv642hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv642s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv642s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv642s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv642s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv710.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv710hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv710s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv710s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv710s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv710s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv722.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv722s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv723.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv723s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv723s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv241s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv248s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv251s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv259.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv262s08.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv433s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv600.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv602s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv607s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv612s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv615hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv618s06.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv624.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv628hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv637s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv641s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv724.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv727hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv731s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv736.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv740s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv724hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv724s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv724s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv724s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv724s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv724s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv725.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv725hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv725s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv725s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv725s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv725s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv726.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv726hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv726s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv727.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv727s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv728.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv728s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv728s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv728s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv729.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv729hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv729s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv729s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv730.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv730hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv730s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv730s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv731.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv731s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv731s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv732.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv732hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv732s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv732s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv732s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv733.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv733hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv733s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv733s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv733s03.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv733s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv733s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv734.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv734s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv734s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv734s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv734s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv736hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv736s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv736s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv737.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv737hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv737s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv737s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv738.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv738hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv738s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv738s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv739.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv739hrc.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv739s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv740.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv740s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv740s02.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv740s04.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv740s05.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv832.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgpv832s01.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst004.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst005.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst006.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst007.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst008.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst009.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/stgtst010.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm000.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm001.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm002.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm003.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm301.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm303.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm500.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm502.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm503.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tetitm700.farc ; 140616748778912 17:05.50 1989-05-24 rom/objset/tex_db.bin ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm022_joha_outer_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm032_joha_outer_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm546_atam_atama_46__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/hakitm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/hakitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/hakitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/hakitm004_joha_outer_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/hakitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/hakitm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/hakitm502_atam_atama_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/hakitm700_atam_zujo_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm004_joha_outer_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm008_joha_outer_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm009_joha_outer_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm010_joha_outer_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm011_joha_outer_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm012_joha_outer_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm015_joha_outer_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm016_joha_outer_16__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm018_joha_outer_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm019_joha_outer_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm020_joha_outer_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm022_joha_outer_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm024_joha_outer_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm027_joha_outer_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm028_joha_outer_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm029_joha_outer_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm030_joha_outer_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm031_joha_outer_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm032_joha_outer_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm033_joha_outer_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm034_joha_outer_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm036_joha_outer_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm041_joha_outer_41__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm042_joha_outer_42__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm502_atam_atama_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm503_atam_atama_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm504_atam_atama_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm505_atam_atama_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm506_atam_atama_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm507_atam_atama_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm508_atam_atama_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm509_atam_atama_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm510_atam_atama_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm520_atam_atama_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm522_atam_atama_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm523_atam_atama_23__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm527_atam_atama_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm528_atam_atama_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm529_atam_atama_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm531_atam_atama_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm532_atam_atama_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm533_atam_atama_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm534_atam_atama_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm536_atam_atama_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm541_atam_atama_41__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm542_atam_atama_42__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm701_atam_zujo_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm705_atam_zujo_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm750_joha_neck_50__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm751_joha_neck_51__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm775_joha_ushiro_75__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm004_joha_outer_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm005_joha_outer_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm007_joha_outer_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm008_joha_outer_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm009_joha_outer_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm010_joha_outer_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm006_joha_outer_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm025_joha_outer_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm524_atam_atama_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/kaiitm706_atam_zujo_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm011_joha_outer_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm025_joha_outer_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm040_joha_outer_40__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm522_atam_atama_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm536_atam_atama_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm008_joha_outer_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm012_joha_outer_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm013_joha_outer_13__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm014_joha_outer_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm015_joha_outer_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm016_joha_outer_16__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm017_joha_outer_17__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm018_joha_outer_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm019_joha_outer_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm021_joha_outer_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm022_joha_outer_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm023_joha_outer_23__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm024_joha_outer_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm026_joha_outer_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm027_joha_outer_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm028_joha_outer_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm029_joha_outer_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm030_joha_outer_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm031_joha_outer_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm032_joha_outer_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm033_joha_outer_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm034_joha_outer_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm035_joha_outer_35__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm036_joha_outer_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm038_joha_outer_38__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm502_atam_atama_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm503_atam_atama_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm504_atam_atama_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm505_atam_atama_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm506_atam_atama_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm508_atam_atama_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm509_atam_atama_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm511_atam_atama_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm519_atam_atama_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm521_atam_atama_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm523_atam_atama_23__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm524_atam_atama_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm525_atam_atama_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm526_atam_atama_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm528_atam_atama_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm529_atam_atama_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm530_atam_atama_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm531_atam_atama_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm532_atam_atama_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm533_atam_atama_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm534_atam_atama_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm535_atam_atama_35__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm537_atam_atama_37__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm538_atam_atama_38__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm540_atam_atama_40__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm700_atam_zujo_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lenitm775_joha_ushiro_75__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm001_joha_outer_01_zzc__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm004_joha_outer_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm005_joha_outer_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm006_joha_outer_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm007_joha_outer_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm009_joha_outer_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm010_joha_outer_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm011_joha_outer_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm012_joha_outer_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm013_joha_outer_13__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm014_joha_outer_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm015_joha_outer_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm017_joha_outer_17_zzc__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm018_joha_outer_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm019_joha_outer_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm020_joha_outer_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm021_joha_outer_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm023_joha_outer_23__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm024_joha_outer_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm025_joha_outer_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm026_joha_outer_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm027_joha_outer_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm028_joha_outer_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm029_joha_outer_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm030_joha_outer_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm031_joha_outer_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm032_joha_outer_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm033_joha_outer_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm034_joha_outer_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm036_joha_outer_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm037_joha_outer_37__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm038_joha_outer_38__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm039_joha_outer_39__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm040_joha_outer_40__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm042_joha_outer_42__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm311_ude_hand_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm502_atam_atama_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm503_atam_atama_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm504_atam_atama_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm506_atam_atama_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm507_atam_atama_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm508_atam_atama_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm509_atam_atama_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm510_atam_atama_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm511_atam_atama_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm512_atam_atama_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm513_atam_atama_13__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm514_atam_atama_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm515_atam_atama_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm516_atam_atama_16__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm517_atam_atama_17__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm526_atam_atama_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm527_atam_atama_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm528_atam_atama_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm529_atam_atama_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm530_atam_atama_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm531_atam_atama_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm532_atam_atama_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm533_atam_atama_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm534_atam_atama_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm535_atam_atama_35__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm536_atam_atama_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm537_atam_atama_37__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm539_atam_atama_39__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm540_atam_atama_40__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm542_atam_atama_42__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm700_atam_zujo_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm702_atam_zujo_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm703_atam_zujo_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm705_atam_zujo_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm004_joha_outer_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm005_joha_outer_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm008_joha_outer_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm009_joha_outer_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm010_joha_outer_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm011_joha_outer_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm012_joha_outer_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm013_joha_outer_13__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm014_joha_outer_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm015_joha_outer_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm016_joha_outer_16__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm017_joha_outer_17_zzc__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm018_joha_outer_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm019_joha_outer_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm021_joha_outer_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm022_joha_outer_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm023_joha_outer_23__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm024_joha_outer_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm025_joha_outer_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm026_joha_outer_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm027_joha_outer_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm028_joha_outer_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm029_joha_outer_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm030_joha_outer_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm032_joha_outer_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm033_joha_outer_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm502_atam_atama_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm503_atam_atama_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm504_atam_atama_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm505_atam_atama_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm506_atam_atama_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm507_atam_atama_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm508_atam_atama_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm509_atam_atama_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm510_atam_atama_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm511_atam_atama_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm512_atam_atama_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm514_atam_atama_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm515_atam_atama_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm521_atam_atama_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm522_atam_atama_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm523_atam_atama_23__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm524_atam_atama_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm525_atam_atama_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm526_atam_atama_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm527_atam_atama_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm528_atam_atama_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm529_atam_atama_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm530_atam_atama_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm533_atam_atama_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm700_atam_zujo_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm701_atam_zujo_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm702_atam_zujo_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm704_atam_zujo_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm705_atam_zujo_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm709_atam_zujo_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm775_joha_ushiro_75__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm004_joha_outer_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm006_joha_outer_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm007_joha_outer_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm008_joha_outer_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm009_joha_outer_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm010_joha_outer_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm011_joha_outer_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm012_joha_outer_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm013_joha_outer_13__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm014_joha_outer_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm015_joha_outer_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm016_joha_outer_16__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm017_joha_outer_17__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm019_joha_outer_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm020_joha_outer_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm021_joha_outer_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm022_joha_outer_22_zzc__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm023_joha_outer_23__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm024_joha_outer_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm025_joha_outer_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm026_joha_outer_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm027_joha_outer_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm029_joha_outer_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm030_joha_outer_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm031_joha_outer_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm038_joha_outer_38__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm040_joha_outer_40__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm041_joha_outer_41__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm042_joha_outer_42__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm043_joha_outer_43__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm044_joha_outer_44__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm045_joha_outer_45__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm046_joha_outer_46__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm047_joha_outer_47__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm048_joha_outer_48__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm049_joha_outer_49__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm050_joha_outer_50__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm035_joha_outer_35__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm505_atam_atama_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm525_atam_atama_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/lukitm538_atam_atama_38__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm006_joha_outer_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm020_joha_outer_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm513_atam_atama_13__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/meiitm532_atam_atama_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm005_joha_outer_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm018_joha_outer_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm052_joha_outer_52__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm053_joha_outer_53__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm054_joha_outer_54__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm055_joha_outer_55__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm056_joha_outer_56__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm057_joha_outer_57__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm058_joha_outer_58__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm059_joha_outer_59__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm060_joha_outer_60__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm061_joha_outer_61__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm063_joha_outer_63__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm064_joha_outer_64__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm066_joha_outer_66__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm067_joha_outer_67__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm068_joha_outer_68__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm069_joha_outer_69__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm070_joha_outer_70__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm071_joha_outer_71__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm072_joha_outer_72__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm073_joha_outer_73__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm074_joha_outer_74__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm075_joha_outer_75__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm076_joha_outer_76__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm077_joha_outer_77__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm079_joha_outer_79__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm080_joha_outer_80__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm081_joha_outer_81__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm082_joha_outer_82__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm083_joha_outer_83__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm084_joha_outer_84__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm085_joha_outer_85__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm087_joha_outer_87__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm088_joha_outer_88__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm089_joha_outer_89__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm090_joha_outer_90__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm091_joha_outer_91__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm093_joha_outer_93__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm094_joha_outer_94__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm095_joha_outer_95__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm096_joha_outer_96__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm097_joha_outer_97__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm098_joha_outer_98__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm099_joha_outer_99__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm100_joha_outer_100__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm101_joha_outer_101__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm102_joha_outer_102__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm103_joha_outer_103__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm104_joha_outer_104__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm106_joha_outer_106__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm107_joha_outer_107__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm108_joha_outer_108__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm109_joha_outer_109__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm110_joha_outer_110__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm111_joha_outer_111__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm112_joha_outer_112__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm113_joha_outer_113__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm114_joha_outer_114__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm115_joha_outer_115__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm116_joha_outer_116__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm118_joha_outer_118__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm120_joha_outer_120__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm123_joha_outer_123__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm124_joha_outer_124__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm125_joha_outer_125__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm126_joha_outer_126__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm127_joha_outer_127__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm128_joha_outer_128__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm129_joha_outer_129__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm130_joha_outer_130__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm131_joha_outer_131__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm132_joha_outer_132__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm133_joha_outer_133__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm135_joha_outer_135__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm136_joha_outer_136__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm137_joha_outer_137__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm138_joha_outer_138__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm139_joha_outer_139__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm140_joha_outer_140__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm141_joha_outer_141__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm142_joha_outer_142__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm143_joha_outer_143__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm144_joha_outer_144__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm145_joha_outer_145__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm146_joha_outer_146__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm148_joha_outer_148__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm149_joha_outer_149__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm151_joha_outer_151__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm152_joha_outer_152__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm153_joha_outer_153__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm155_joha_outer_155__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm156_joha_outer_156__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm158_joha_outer_158__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm160_joha_outer_160__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm162_joha_outer_162__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm163_joha_outer_163__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm164_joha_outer_164__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm167_joha_outer_167__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm169_joha_outer_169__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm170_joha_outer_170__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm173_joha_outer_173__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm431_ude_hand_131__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm438_ude_hand_138__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm467_ude_hand_167__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm502_atam_atama_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm504_atam_atama_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm505_atam_atama_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm507_atam_atama_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm508_atam_atama_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm509_atam_atama_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm520_atam_atama_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm522_atam_atama_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm524_atam_atama_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm525_atam_atama_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm526_atam_atama_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm527_atam_atama_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm528_atam_atama_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm530_atam_atama_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm531_atam_atama_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm533_atam_atama_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm534_atam_atama_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm536_atam_atama_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm537_atam_atama_37__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm538_atam_atama_38__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm539_atam_atama_39__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm540_atam_atama_40__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm541_atam_atama_41__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm542_atam_atama_42__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm543_atam_atama_43__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm544_atam_atama_44__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm545_atam_atama_45__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm547_atam_atama_47__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm548_atam_atama_48__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm549_atam_atama_49__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm550_atam_atama_50__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm551_atam_atama_51__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm552_atam_atama_52__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm553_atam_atama_53__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm554_atam_atama_54__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm555_atam_atama_55__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm556_atam_atama_56__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm557_atam_atama_57__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm558_atam_atama_58__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm051_joha_outer_51__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm065_joha_outer_65__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm078_joha_outer_78__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm092_joha_outer_92__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm105_joha_outer_105__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm119_joha_outer_119__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm134_joha_outer_134__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm147_joha_outer_147__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm165_joha_outer_165__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm506_atam_atama_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm532_atam_atama_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm560_atam_atama_60__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm593_atam_atama_93__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm594_atam_atama_94__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm595_atam_atama_95__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm596_atam_atama_96__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm597_atam_atama_97__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm598_atam_atama_98__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm599_atam_atama_99__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm600_atam_atama_100__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm601_atam_atama_101__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm602_atam_atama_102__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm603_atam_atama_103__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm605_atam_atama_105__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm606_atam_atama_106__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm607_atam_atama_107__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm608_atam_atama_108__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm609_atam_atama_109__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm610_atam_atama_110__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm611_atam_atama_111__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm612_atam_atama_112__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm613_atam_atama_113__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm614_atam_atama_114__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm615_atam_atama_115__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm616_atam_atama_116__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm619_atam_atama_119__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm620_atam_atama_120__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm621_atam_atama_121__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm623_atam_atama_123__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm624_atam_atama_124__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm625_atam_atama_125__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm626_atam_atama_126__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm627_atam_atama_127__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm628_atam_atama_128__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm630_atam_atama_130__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm631_atam_atama_131__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm632_atam_atama_132__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm634_atam_atama_134__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm635_atam_atama_135__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm636_atam_atama_136__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm637_atam_atama_137__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm638_atam_atama_138__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm639_atam_atama_139__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm640_atam_atama_140__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm641_atam_atama_141__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm642_atam_atama_142__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm643_atam_atama_143__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm644_atam_atama_144__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm645_atam_atama_145__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm647_atam_atama_147__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm648_atam_atama_148__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm649_atam_atama_149__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm651_atam_atama_151__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm652_atam_atama_152__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm653_atam_atama_153__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm655_atam_atama_155__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm656_atam_atama_156__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm658_atam_atama_158__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm660_atam_atama_160__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm662_atam_atama_162__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm663_atam_atama_163__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm665_atam_atama_165__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm667_atam_atama_167__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm669_atam_atama_169__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm670_atam_atama_170__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm673_atam_atama_173__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm700_atam_zujo_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm702_atam_zujo_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm709_atam_zujo_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm711_atam_zujo_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm715_atam_zujo_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm718_atam_zujo_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm721_atam_zujo_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm722_atam_zujo_22__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm746_atam_zujo_46__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm748_atam_zujo_48__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm749_atam_zujo_49__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm751_joha_neck_51__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm752_joha_neck_52__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm775_joha_ushiro_75__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm776_joha_ushiro_76__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm777_joha_ushiro_77__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm780_joha_ushiro_80__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm781_joha_ushiro_81__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm782_joha_ushiro_82__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm783_joha_ushiro_83__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm784_joha_ushiro_84__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/neritm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/neritm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/neritm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/neritm004_joha_outer_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/neritm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/neritm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/opd_db.txt ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm004_joha_outer_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm006_joha_outer_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm007_joha_outer_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm009_joha_outer_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm010_joha_outer_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm011_joha_outer_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm012_joha_outer_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm013_joha_outer_13__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm014_joha_outer_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm015_joha_outer_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm016_joha_outer_16__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm017_joha_outer_17__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm018_joha_outer_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm020_joha_outer_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm021_joha_outer_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm023_joha_outer_23__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm024_joha_outer_24__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm025_joha_outer_25__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm026_joha_outer_26_zzc__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm027_joha_outer_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm028_joha_outer_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm029_joha_outer_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm030_joha_outer_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm031_joha_outer_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm032_joha_outer_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm034_joha_outer_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm035_joha_outer_35__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm036_joha_outer_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm037_joha_outer_37__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm038_joha_outer_38__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm039_joha_outer_39__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm040_joha_outer_40__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm041_joha_outer_41__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm043_joha_outer_43__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm044_joha_outer_44__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm045_joha_outer_45__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm047_joha_outer_47__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm502_atam_atama_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm503_atam_atama_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm504_atam_atama_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm505_atam_atama_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm506_atam_atama_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm507_atam_atama_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm508_atam_atama_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm509_atam_atama_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm510_atam_atama_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm511_atam_atama_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm559_atam_atama_59__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm604_atam_atama_104__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm618_atam_atama_118__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm633_atam_atama_133__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm646_atam_atama_146__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm664_atam_atama_164__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm745_atam_zujo_45__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/mikitm790_atam_zujo_90__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm005_joha_outer_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm019_joha_outer_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm033_joha_outer_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm048_joha_outer_48__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm512_atam_atama_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm530_atam_atama_30__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm544_atam_atama_44__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm711_atam_zujo_11__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm999_atam_zujo_99__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm513_atam_atama_13__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm514_atam_atama_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm515_atam_atama_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm516_atam_atama_16__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm517_atam_atama_17__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm518_atam_atama_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm519_atam_atama_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm520_atam_atama_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm526_atam_atama_26__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm527_atam_atama_27__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm528_atam_atama_28__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm529_atam_atama_29__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm531_atam_atama_31__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm532_atam_atama_32__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm533_atam_atama_33__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm534_atam_atama_34__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm535_atam_atama_35__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm536_atam_atama_36__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm537_atam_atama_37__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm538_atam_atama_38__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm539_atam_atama_39__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm540_atam_atama_40__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm541_atam_atama_41__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm543_atam_atama_43__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm545_atam_atama_45__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm547_atam_atama_47__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm548_atam_atama_48__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm701_atam_zujo_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm702_atam_zujo_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm703_atam_zujo_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm704_atam_zujo_04__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm705_atam_zujo_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm706_atam_zujo_06__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm707_atam_zujo_07__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm708_atam_zujo_08__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm709_atam_zujo_09__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm710_atam_zujo_10__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm712_atam_zujo_12__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm714_atam_zujo_14__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm715_atam_zujo_15__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm716_atam_zujo_16__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm717_atam_zujo_17__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm718_atam_zujo_18__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm719_atam_zujo_19__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm720_atam_zujo_20__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm721_atam_zujo_21__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm775_joha_ushiro_75__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm776_joha_ushiro_76__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/rinitm777_joha_ushiro_77__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/sakitm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/sakitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/sakitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/sakitm005_joha_outer_05__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/sakitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/sakitm501_atam_atama_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/sakitm775_joha_ushiro_75__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/tetitm001_joha_outer_01__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/tetitm002_joha_outer_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/tetitm003_joha_outer_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/tetitm500_atam_atama_00__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/tetitm502_atam_atama_02__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/osage_play_data/tetitm503_atam_atama_03__divskn.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv247_cookie.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv247_offset_test.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv247_star.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv249_kirakira.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv250_burneer.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv250_taxi.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv250_yuge.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_hanabi.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_hanabi_test.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_konpei.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_light_glow.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_light_glow_test.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_moyasmoke.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_s05_coaster.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_smoke.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv255_onpu.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv262_light_glow.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv604_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv604_tail.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv710_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv710_success.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv717_rain.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV722_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv723_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv723_success.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV724_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV726_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv726_success.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV727_cut042.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV727_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV728_cut050.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV728_cut051.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv728_cut127.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV728_lightbar.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV728_lightbar_climax.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV728_lightbar_nomalmax.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV728_smoke.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv729_gimmick.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv729_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv729_reef.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv729_steam_1f.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv729_steam_2f.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv729_steam_3f.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_ayasaki.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_katana_aura_p1.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_miku.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_miku_delete.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_reef.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_stop.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_sword_p1.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV732_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv733_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv733_rain.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV734_hibana.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV734_hibana_n.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV734_hibana_s.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV734_hibana_success.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv734_hinoko.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv734_hokori.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv253_smoke_cloud.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv728_cut011.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv731_katana_aura_p2.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv734_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_lightchip.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv734_nor.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv734_nor_hinoko.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv734_spark.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv734_suc.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv734_suc_hinoko.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV734_thunder.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_barbroken.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_bubble.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_bubble01.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_chip.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_crushball.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_crushball01.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_cubebird.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_dustchip01.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_guitar.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV736_whitechip.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv737_breath.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv737_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV737_shitsunai.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv738_card_particle.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv738_success.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv738_success_start.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV739_daiza.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV739_fireworks.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV739_hover.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_kirakira.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_kirakira_hand.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_kirakira_line.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_kirakira_line_jikki.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_light.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_main_jikki.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_PV739_monitor.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_smoke.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_star.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_star_down.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv739_star_jikki.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv740_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv740_mik_foot.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv740_mik_room.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv740_mik_sky.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv740_skyonpu.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_pv740_success.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_stgpv832_cream_snow.farc ; 140616748778912 17:05.50 1989-05-24 rom/particle/eff_stgpv832_main.farc ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/aime_frame.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/header01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/header02.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_img01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_img02.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_img03_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_img04_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_pity01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_pity02.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_pity03.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_pity04.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ic_pity05.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/img01_sample.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/img02_sample.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/img03_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/img04_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/pity01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/pity02.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/pity03.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/pity04.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/pity05.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights01.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights01_ic.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights02.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights02_ic.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights03.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights03_ic.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights04_l.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights04_l_ic.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights04_r.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights04_r_ic.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ss_rights05.tga ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV206.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV219.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV238.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV239.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV240.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV241.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV242.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV243.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV244.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV246.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV247.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV248.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV249.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV250.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV251.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV253.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV255.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV259.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV260.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV261.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV262.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV432.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV433.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV434.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV435.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV600.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV601.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV602.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV603.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV604.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV605.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV607.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV608.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV609.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV611.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV612.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV613.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV614.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV615.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV616.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV617.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV618.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV619.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV620.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV621.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV622.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV623.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV624.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV625.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV626.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV627.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV629.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV630.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV631.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV637.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV638.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV639.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV640.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV641.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV642.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV710.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV722.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV723.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV724.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV725.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV726.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV727.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV728.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV729.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV730.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV731.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV732.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV733.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV734.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV736.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV737.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV738.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV739.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV740.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV832.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV257.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV610.bin ; 140616748778912 17:05.50 1989-05-24 rom/pv_expression/exp_PV628.bin ; 140616748778912 17:05.50 1989-05-24 rom/ranking/dummy_thumb.jpg ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_HAK.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_KAI.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_LEN.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_LUK.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_MEI.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_MIK.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_NER.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_RIN.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_AUTH_SAK.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_CMN.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_EDT.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_EDT2.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_EDTF1.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV001.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV002.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV003.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV005.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV006.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV007.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV008.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV009.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV010.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV011.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV012.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV013.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV014.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV015.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV016.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV017.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV018.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV019.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV020.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV022.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV023.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV024.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV025.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV027.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV028.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV029.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV030.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV031.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV032.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV037.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV038.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV039.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV040.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV041.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV042.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV044.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV045.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV046.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV047.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV048.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV049.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV050.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV051.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV052.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV053.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV054.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV055.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV056.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV057.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV058.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV059.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV004.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV021.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV043.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV060.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV090.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV208.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV231.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV250.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV604.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV622.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV722.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV740.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV012.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV061.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV062.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV063.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV064.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV065.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV066.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV079.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV081.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV082.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV083.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV084.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV085.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV086.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV087.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV088.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV089.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV091.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV092.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV093.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV094.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV095.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV096.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV097.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV102.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV103.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV104.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV201.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV202.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV204.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV205.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV206.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV207.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV210.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV211.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV212.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV213.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV214.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV218.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV219.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV220.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV221.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV222.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV223.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV224.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV225.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV226.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV227.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV228.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV232.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV233.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV234.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV235.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV236.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV238.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV239.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV240.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV241.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV242.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV243.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV244.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV246.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV247.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV248.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV249.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV251.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV253.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV255.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV257.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV259.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV260.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV261.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV262.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV432.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV433.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV434.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV435.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV600.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV601.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV602.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV603.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV605.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV607.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV608.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV609.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV610.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV611.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV612.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV613.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV614.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV615.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV616.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV617.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV618.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV619.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV620.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV621.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV623.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV624.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV625.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV626.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV627.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV628.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV629.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV630.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV631.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV637.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV638.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV639.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV640.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV641.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV642.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV710.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV723.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV724.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV725.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV726.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV727.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV728.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV729.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV730.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV731.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV732.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV733.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV734.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV736.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV737.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV738.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV739.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_PV832.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mothead_TEST_DESIGN.bin ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_ALL_SELECTOR_POSE.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_AUTH_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_CMN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_db.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_EDT.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_EDT2.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_EDTF1.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV001.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV002.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV003.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV004.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV005.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV006.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV007.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV008.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV009.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV010.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV011.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV013.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV014.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV015.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV016.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV017.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV018.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV019.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV020.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV021.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV022.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV023.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV024.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV025.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV027_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV028.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV029_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV030_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV037.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV038.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV039.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV040.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV041.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV042.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV043.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV044.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV045.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV046.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV047.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV048.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV049.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV050.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV052.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV053.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV054.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV055.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV056.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV057.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV058.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV059.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV060.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV061.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV062.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV063.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV064.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV065.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV066.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV079.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV081.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV083.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV084.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV085.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV086.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV087.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV088.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV089.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV090.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV091.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV092.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV093.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV094.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV095.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV096.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV097.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV104_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV205_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV208_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV212_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV213.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV219_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV031_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV032_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV051.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV082.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV102_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV103_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV201.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV202_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV204_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV206_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV207_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV210_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV211_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV214_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV218_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV255.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV609.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV627.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV220_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV221_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV222_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV223_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV224_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV225_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV226.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV227.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV228.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV231_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV232_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV233_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV234_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_NER.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV235_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_HAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_KAI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_LEN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_LUK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_MEI.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_MIK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV236_FACE_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV238.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV239.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV240.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV241.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV242.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV243.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV244.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV246.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV247.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV248.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV249.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV250.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV251.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV253.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV257.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV259.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV260.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV261.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV262.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV432.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV433.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV434.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV435.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV600.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV601.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV602.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV603.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV604.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV605.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV607.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV608.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV610.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV611.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV612.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV613.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV614.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV615.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV616.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV617.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV618.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV619.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV620.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV621.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV622.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV623.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV624.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV625.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV626.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV628.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV629.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV630.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV631.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV637.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV638.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV639.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV640.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV641.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV642.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV710.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV722.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV723.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV724.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV725.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV726.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV727.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV728.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV729.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV730.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV731.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV732.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV733.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV734.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV736.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV737.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV738.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV739.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV740.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_PV832.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_RIN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_SAK.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_TEST_DESIGN.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/mot_TET.farc ; 140616748778912 17:05.50 1989-05-24 rom/rob/rob_mot_tbl.bin ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_079_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_260_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_001_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_001_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_001_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_001_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_001_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_002_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_002_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_002_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_002_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_002_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_003_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_003_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_003_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_003_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_003_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_004_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_004_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_005_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_005_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_005_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_005_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_005_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_006_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_006_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_006_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_006_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_007_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_007_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_007_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_007_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_008_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_008_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_008_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_008_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_009_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_009_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_009_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_010_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_010_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_010_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_010_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_011_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_011_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_011_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_011_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_011_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_012_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_012_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_012_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_013_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_013_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_013_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_014_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_014_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_014_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_014_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_015_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_015_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_015_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_015_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_016_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_016_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_016_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_017_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_017_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_017_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_017_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_004_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_008_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_013_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_018_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_023_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_027_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_031_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_039_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_043_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_046_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_050_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_054_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_058_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_061_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_065_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_018_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_018_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_019_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_019_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_019_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_019_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_020_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_020_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_020_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_020_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_021_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_021_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_021_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_022_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_022_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_022_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_022_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_023_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_023_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_023_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_023_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_024_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_024_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_024_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_024_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_024_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_025_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_025_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_025_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_025_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_027_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_027_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_027_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_027_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_028_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_028_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_028_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_028_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_028_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_029_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_029_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_029_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_029_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_030_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_030_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_030_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_030_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_030_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_031_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_031_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_031_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_032_encore.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_032_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_032_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_032_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_032_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_037_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_037_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_037_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_037_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_037_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_038_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_038_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_038_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_038_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_038_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_039_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_039_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_039_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_039_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_040_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_040_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_040_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_040_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_040_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_041_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_041_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_041_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_041_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_042_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_042_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_042_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_042_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_043_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_043_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_043_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_043_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_044_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_044_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_044_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_044_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_045_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_045_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_045_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_045_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_045_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_046_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_046_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_046_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_046_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_047_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_047_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_047_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_047_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_048_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_048_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_048_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_048_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_049_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_049_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_049_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_049_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_049_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_050_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_050_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_050_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_050_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_051_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_051_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_051_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_051_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_051_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_052_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_052_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_052_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_052_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_052_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_053_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_053_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_053_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_053_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_053_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_054_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_054_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_054_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_054_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_055_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_055_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_055_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_055_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_055_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_056_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_056_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_056_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_056_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_057_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_057_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_057_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_057_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_057_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_058_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_058_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_058_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_058_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_059_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_059_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_059_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_059_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_059_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_060_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_060_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_060_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_060_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_060_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_061_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_061_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_061_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_061_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_062_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_062_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_062_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_062_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_062_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_063_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_063_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_063_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_063_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_063_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_064_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_064_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_064_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_064_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_064_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_065_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_065_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_065_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_065_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_066_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_066_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_066_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_066_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_066_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_067_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_067_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_067_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_068_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_068_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_068_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_068_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_079_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_079_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_079_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_081_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_081_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_081_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_081_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_081_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_082_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_082_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_082_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_082_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_082_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_083_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_083_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_083_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_083_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_084_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_084_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_084_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_084_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_085_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_085_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_085_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_085_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_086_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_086_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_086_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_086_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_087_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_087_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_087_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_087_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_087_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_088_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_088_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_088_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_088_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_089_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_089_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_089_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_089_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_089_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_090_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_090_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_090_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_090_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_090_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_091_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_091_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_091_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_091_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_092_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_092_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_092_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_093_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_093_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_093_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_093_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_094_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_094_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_094_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_094_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_094_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_095_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_095_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_095_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_095_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_096_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_096_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_096_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_096_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_097_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_097_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_097_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_097_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_101_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_101_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_101_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_101_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_102_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_102_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_102_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_102_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_103_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_103_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_103_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_104_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_104_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_201_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_201_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_201_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_201_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_202_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_202_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_202_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_202_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_203_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_203_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_203_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_204_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_204_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_204_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_204_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_205_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_205_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_206_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_206_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_206_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_206_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_207_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_207_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_207_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_208_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_208_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_208_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_208_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_208_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_209_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_209_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_209_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_210_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_210_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_210_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_210_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_211_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_211_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_211_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_211_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_212_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_212_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_212_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_212_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_213_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_213_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_213_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_213_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_214_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_214_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_214_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_215_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_215_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_215_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_216_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_216_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_216_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_216_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_218_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_218_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_218_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_219_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_219_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_219_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_219_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_220_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_220_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_220_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_220_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_221_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_221_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_221_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_221_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_221_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_222_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_222_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_222_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_223_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_223_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_223_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_224_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_224_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_224_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_225_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_225_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_225_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_225_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_226_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_226_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_226_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_226_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_227_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_227_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_227_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_228_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_228_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_228_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_231_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_231_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_231_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_232_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_232_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_232_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_232_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_232_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_233_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_233_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_233_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_234_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_234_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_234_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_234_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_234_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_235_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_235_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_235_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_236_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_236_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_236_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_238_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_238_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_238_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_238_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_239_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_239_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_239_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_240_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_240_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_240_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_241_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_241_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_241_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_241_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_242_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_242_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_242_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_243_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_243_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_243_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_243_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_244_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_244_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_244_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_244_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_246_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_246_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_246_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_247_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_247_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_247_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_248_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_248_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_248_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_248_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_249_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_249_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_249_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_249_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_250_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_250_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_250_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_250_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_251_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_251_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_251_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_251_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_253_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_253_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_253_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_255_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_255_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_255_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_255_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_257_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_257_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_257_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_257_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_259_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_259_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_259_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_259_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_260_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_260_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_260_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_261_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_261_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_261_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_261_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_262_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_262_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_262_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_262_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_265_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_265_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_265_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_265_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_401_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_401_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_401_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_401_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_402_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_084_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_088_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_092_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_096_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_104_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_205_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_209_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_214_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_219_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_224_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_231_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_235_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_242_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_247_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_253_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_402_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_402_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_402_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_403_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_403_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_403_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_403_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_404_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_404_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_404_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_404_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_405_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_405_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_405_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_405_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_405_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_407_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_407_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_407_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_408_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_408_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_408_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_409_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_409_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_409_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_409_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_410_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_410_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_410_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_410_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_411_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_411_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_411_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_412_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_412_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_413_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_413_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_413_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_413_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_414_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_414_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_414_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_414_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_415_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_415_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_415_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_415_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_415_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_416_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_416_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_416_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_417_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_417_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_417_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_418_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_418_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_418_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_418_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_419_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_419_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_419_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_419_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_420_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_420_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_420_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_421_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_421_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_421_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_422_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_422_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_422_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_422_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_423_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_423_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_423_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_423_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_424_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_424_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_424_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_424_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_424_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_425_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_425_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_426_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_426_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_426_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_427_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_427_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_427_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_427_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_428_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_428_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_428_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_428_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_429_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_429_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_429_extreme_1.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_429_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_429_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_430_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_430_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_430_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_431_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_431_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_431_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_432_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_432_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_432_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_432_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_433_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_433_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_433_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_433_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_434_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_434_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_434_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_434_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_435_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_435_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_436_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_436_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_436_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_436_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_437_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_437_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_437_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_438_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_438_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_438_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_439_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_439_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_439_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_439_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_440_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_440_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_440_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_441_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_441_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_441_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_442_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_442_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_442_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_442_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_443_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_443_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_443_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_443_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_600_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_600_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_600_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_600_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_601_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_601_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_601_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_602_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_602_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_602_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_602_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_603_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_603_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_603_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_603_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_604_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_604_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_604_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_604_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_605_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_605_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_605_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_607_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_607_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_607_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_607_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_608_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_608_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_608_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_608_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_609_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_609_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_609_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_609_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_610_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_610_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_610_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_610_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_611_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_611_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_611_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_612_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_612_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_612_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_612_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_613_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_613_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_613_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_613_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_614_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_614_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_614_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_615_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_615_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_615_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_616_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_616_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_616_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_616_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_617_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_617_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_617_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_618_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_618_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_618_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_618_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_619_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_619_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_619_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_619_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_620_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_620_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_620_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_621_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_621_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_621_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_621_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_622_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_622_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_622_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_622_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_623_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_623_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_623_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_623_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_624_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_624_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_624_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_624_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_625_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_625_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_626_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_626_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_626_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_626_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_627_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_627_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_627_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_627_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_628_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_628_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_628_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_628_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_629_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_629_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_629_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_630_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_630_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_630_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_630_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_631_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_631_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_631_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_631_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_637_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_637_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_637_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_637_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_638_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_638_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_638_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_638_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_639_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_402_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_407_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_412_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_416_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_421_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_425_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_430_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_435_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_440_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_601_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_605_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_611_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_615_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_620_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_625_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_629_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_639_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_722_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_726_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_731_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_736_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_639_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_640_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_640_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_640_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_640_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_641_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_641_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_641_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_641_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_642_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_642_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_642_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_642_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_710_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_710_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_710_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_710_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_722_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_722_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_722_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_723_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_723_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_723_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_723_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_724_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_724_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_724_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_724_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_725_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_725_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_725_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_725_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_726_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_726_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_726_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_727_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_727_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_727_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_727_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_728_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_728_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_728_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_728_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_729_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_729_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_729_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_729_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_730_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_730_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_730_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_730_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_731_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_731_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_731_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_732_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_732_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_732_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_732_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_733_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_733_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_733_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_733_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_734_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_734_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_734_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_734_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_736_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_736_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_736_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_737_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_737_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_737_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_737_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_738_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_738_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_738_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_739_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_739_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_739_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_739_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_740_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_740_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_740_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_740_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_832_easy.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_832_extreme.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_832_hard.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_832_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/script/pv_999_normal.dsc ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hakitm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hakitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hakitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hakitm004_joha_outer_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hakitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hakitm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hakitm502_atam_atama_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hakitm700_atam_zujo_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hnditm057_schoolbag_b_close_bone_l__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hnditm057_schoolbag_b_close_bone_r__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_l_kai__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_l__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_r_kai__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_r_len__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_r__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm004_joha_outer_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm006_joha_outer_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm008_joha_outer_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm009_joha_outer_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm011_joha_outer_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm012_joha_outer_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm015_joha_outer_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm016_joha_outer_16__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm018_joha_outer_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm019_joha_outer_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm020_joha_outer_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm022_joha_outer_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm024_joha_outer_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm025_joha_outer_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm027_joha_outer_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_l_len__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm010_joha_outer_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm028_joha_outer_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm502_atam_atama_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm524_atam_atama_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm705_atam_zujo_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm009_joha_outer_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm022_joha_outer_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm034_joha_outer_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm507_atam_atama_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm528_atam_atama_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm029_joha_outer_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm030_joha_outer_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm031_joha_outer_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm032_joha_outer_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm033_joha_outer_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm034_joha_outer_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm036_joha_outer_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm041_joha_outer_41__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm042_joha_outer_42__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm503_atam_atama_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm504_atam_atama_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm505_atam_atama_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm506_atam_atama_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm507_atam_atama_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm508_atam_atama_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm509_atam_atama_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm510_atam_atama_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm520_atam_atama_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm522_atam_atama_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm523_atam_atama_23__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm527_atam_atama_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm528_atam_atama_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm529_atam_atama_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm531_atam_atama_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm532_atam_atama_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm533_atam_atama_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm534_atam_atama_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm536_atam_atama_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm541_atam_atama_41__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm542_atam_atama_42__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm701_atam_zujo_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm706_atam_zujo_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm750_joha_neck_50__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm751_joha_neck_51__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_kaiitm775_joha_ushiro_75__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm004_joha_outer_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm005_joha_outer_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm007_joha_outer_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm008_joha_outer_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm010_joha_outer_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm011_joha_outer_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm012_joha_outer_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm013_joha_outer_13__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm014_joha_outer_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm015_joha_outer_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm016_joha_outer_16__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm017_joha_outer_17__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm018_joha_outer_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm019_joha_outer_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm021_joha_outer_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm023_joha_outer_23__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm024_joha_outer_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm025_joha_outer_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm026_joha_outer_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm027_joha_outer_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm028_joha_outer_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm029_joha_outer_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm030_joha_outer_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm031_joha_outer_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm032_joha_outer_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm033_joha_outer_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm035_joha_outer_35__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm036_joha_outer_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm038_joha_outer_38__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm040_joha_outer_40__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm502_atam_atama_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm503_atam_atama_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm504_atam_atama_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm505_atam_atama_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm506_atam_atama_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm508_atam_atama_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm509_atam_atama_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm510_atam_atama_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm511_atam_atama_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm519_atam_atama_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm521_atam_atama_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm522_atam_atama_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm523_atam_atama_23__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm524_atam_atama_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm525_atam_atama_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm526_atam_atama_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm529_atam_atama_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm530_atam_atama_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm531_atam_atama_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm532_atam_atama_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm533_atam_atama_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm534_atam_atama_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm535_atam_atama_35__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm536_atam_atama_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm537_atam_atama_37__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm538_atam_atama_38__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm540_atam_atama_40__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm775_joha_ushiro_75__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm001_joha_outer_01_zzc__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm004_joha_outer_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm005_joha_outer_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm006_joha_outer_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm007_joha_outer_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm008_joha_outer_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm009_joha_outer_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm010_joha_outer_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm012_joha_outer_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm013_joha_outer_13__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm014_joha_outer_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm015_joha_outer_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm017_joha_outer_17_zzc__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm018_joha_outer_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm019_joha_outer_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm020_joha_outer_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm021_joha_outer_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm022_joha_outer_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm023_joha_outer_23__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm025_joha_outer_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm026_joha_outer_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm027_joha_outer_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm028_joha_outer_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm029_joha_outer_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm030_joha_outer_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm031_joha_outer_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm032_joha_outer_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm033_joha_outer_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm034_joha_outer_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm035_joha_outer_35__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm037_joha_outer_37__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm038_joha_outer_38__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm039_joha_outer_39__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm040_joha_outer_40__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm042_joha_outer_42__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm311_ude_hand_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm502_atam_atama_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm503_atam_atama_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm504_atam_atama_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm506_atam_atama_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm507_atam_atama_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm508_atam_atama_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm509_atam_atama_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm510_atam_atama_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm511_atam_atama_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm512_atam_atama_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm513_atam_atama_13__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm514_atam_atama_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm515_atam_atama_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm516_atam_atama_16__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm525_atam_atama_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm526_atam_atama_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm527_atam_atama_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm528_atam_atama_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm529_atam_atama_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm530_atam_atama_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm531_atam_atama_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm532_atam_atama_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm533_atam_atama_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm534_atam_atama_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm535_atam_atama_35__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm537_atam_atama_37__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm538_atam_atama_38__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm539_atam_atama_39__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm540_atam_atama_40__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm542_atam_atama_42__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm700_atam_zujo_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm702_atam_zujo_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm703_atam_zujo_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm705_atam_zujo_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm004_joha_outer_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm005_joha_outer_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm006_joha_outer_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm008_joha_outer_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm009_joha_outer_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm010_joha_outer_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm011_joha_outer_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm012_joha_outer_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm013_joha_outer_13__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm014_joha_outer_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm015_joha_outer_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm017_joha_outer_17_zzc__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm018_joha_outer_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm019_joha_outer_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm020_joha_outer_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm021_joha_outer_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm022_joha_outer_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm023_joha_outer_23__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm024_joha_outer_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm025_joha_outer_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm026_joha_outer_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm027_joha_outer_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm029_joha_outer_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm030_joha_outer_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm032_joha_outer_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm033_joha_outer_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm502_atam_atama_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm503_atam_atama_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm504_atam_atama_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm505_atam_atama_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm506_atam_atama_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm508_atam_atama_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm509_atam_atama_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm510_atam_atama_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm511_atam_atama_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm512_atam_atama_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm513_atam_atama_13__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm514_atam_atama_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm515_atam_atama_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm521_atam_atama_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm522_atam_atama_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm523_atam_atama_23__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm525_atam_atama_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm526_atam_atama_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm527_atam_atama_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm528_atam_atama_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm529_atam_atama_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm530_atam_atama_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm532_atam_atama_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm533_atam_atama_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm700_atam_zujo_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm701_atam_zujo_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm702_atam_zujo_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm011_joha_outer_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm024_joha_outer_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm036_joha_outer_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm505_atam_atama_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm517_atam_atama_17__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lukitm536_atam_atama_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm016_joha_outer_16__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm028_joha_outer_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm507_atam_atama_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm524_atam_atama_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm705_atam_zujo_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm709_atam_zujo_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm775_joha_ushiro_75__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm004_joha_outer_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm005_joha_outer_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm006_joha_outer_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm007_joha_outer_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm008_joha_outer_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm010_joha_outer_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm011_joha_outer_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm012_joha_outer_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm013_joha_outer_13__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm014_joha_outer_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm015_joha_outer_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm016_joha_outer_16__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm017_joha_outer_17__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm018_joha_outer_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm019_joha_outer_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm020_joha_outer_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm022_joha_outer_22_zzc__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm023_joha_outer_23__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm024_joha_outer_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm025_joha_outer_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm026_joha_outer_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm027_joha_outer_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm029_joha_outer_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm030_joha_outer_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm031_joha_outer_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm032_joha_outer_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm038_joha_outer_38__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm041_joha_outer_41__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm042_joha_outer_42__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm043_joha_outer_43__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm044_joha_outer_44__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm045_joha_outer_45__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm046_joha_outer_46__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm047_joha_outer_47__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm048_joha_outer_48__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm049_joha_outer_49__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm050_joha_outer_50__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm051_joha_outer_51__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm053_joha_outer_53__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm054_joha_outer_54__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm055_joha_outer_55__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm056_joha_outer_56__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm057_joha_outer_57__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm058_joha_outer_58__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm059_joha_outer_59__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm060_joha_outer_60__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm061_joha_outer_61__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm063_joha_outer_63__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm064_joha_outer_64__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm066_joha_outer_66__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm067_joha_outer_67__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm068_joha_outer_68__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm069_joha_outer_69__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm070_joha_outer_70__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm071_joha_outer_71__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm072_joha_outer_72__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm073_joha_outer_73__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm074_joha_outer_74__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm075_joha_outer_75__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm076_joha_outer_76__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm078_joha_outer_78__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm079_joha_outer_79__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm080_joha_outer_80__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm081_joha_outer_81__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm082_joha_outer_82__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm083_joha_outer_83__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm084_joha_outer_84__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm085_joha_outer_85__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm087_joha_outer_87__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm088_joha_outer_88__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm089_joha_outer_89__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm091_joha_outer_91__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm092_joha_outer_92__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm093_joha_outer_93__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm094_joha_outer_94__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm095_joha_outer_95__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm096_joha_outer_96__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm097_joha_outer_97__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm098_joha_outer_98__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm099_joha_outer_99__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm100_joha_outer_100__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm101_joha_outer_101__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm103_joha_outer_103__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm104_joha_outer_104__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm105_joha_outer_105__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm106_joha_outer_106__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm107_joha_outer_107__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm108_joha_outer_108__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm109_joha_outer_109__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm110_joha_outer_110__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm111_joha_outer_111__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm112_joha_outer_112__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm113_joha_outer_113__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm115_joha_outer_115__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm116_joha_outer_116__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm118_joha_outer_118__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm119_joha_outer_119__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm120_joha_outer_120__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm123_joha_outer_123__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm124_joha_outer_124__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm125_joha_outer_125__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm126_joha_outer_126__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm127_joha_outer_127__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm128_joha_outer_128__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm130_joha_outer_130__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm131_joha_outer_131__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm132_joha_outer_132__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm133_joha_outer_133__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm134_joha_outer_134__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm135_joha_outer_135__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm136_joha_outer_136__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm137_joha_outer_137__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm138_joha_outer_138__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm139_joha_outer_139__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm140_joha_outer_140__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm142_joha_outer_142__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm143_joha_outer_143__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm144_joha_outer_144__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm145_joha_outer_145__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm146_joha_outer_146__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm147_joha_outer_147__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm148_joha_outer_148__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm149_joha_outer_149__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm151_joha_outer_151__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm152_joha_outer_152__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm153_joha_outer_153__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm009_joha_outer_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm021_joha_outer_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm040_joha_outer_40__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm052_joha_outer_52__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm065_joha_outer_65__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm077_joha_outer_77__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm090_joha_outer_90__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm102_joha_outer_102__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm114_joha_outer_114__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm129_joha_outer_129__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm141_joha_outer_141__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_lenitm700_atam_zujo_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_meiitm704_atam_zujo_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm155_joha_outer_155__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm156_joha_outer_156__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm158_joha_outer_158__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm160_joha_outer_160__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm162_joha_outer_162__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm163_joha_outer_163__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm164_joha_outer_164__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm165_joha_outer_165__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm167_joha_outer_167__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm169_joha_outer_169__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm170_joha_outer_170__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm173_joha_outer_173__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm467_ude_hand_167__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm502_atam_atama_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm504_atam_atama_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm505_atam_atama_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm506_atam_atama_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm507_atam_atama_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm508_atam_atama_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm509_atam_atama_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm520_atam_atama_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm524_atam_atama_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm525_atam_atama_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm526_atam_atama_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm527_atam_atama_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm528_atam_atama_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm530_atam_atama_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm531_atam_atama_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm532_atam_atama_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm533_atam_atama_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm534_atam_atama_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm535_atam_atama_35__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm537_atam_atama_37__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm538_atam_atama_38__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm539_atam_atama_39__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm540_atam_atama_40__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm541_atam_atama_41__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm542_atam_atama_42__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm543_atam_atama_43__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm544_atam_atama_44__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm545_atam_atama_45__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm546_atam_atama_46__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm547_atam_atama_47__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm549_atam_atama_49__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm550_atam_atama_50__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm551_atam_atama_51__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm552_atam_atama_52__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm553_atam_atama_53__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm554_atam_atama_54__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm555_atam_atama_55__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm556_atam_atama_56__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm557_atam_atama_57__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm558_atam_atama_58__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm559_atam_atama_59__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm593_atam_atama_93__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm594_atam_atama_94__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm595_atam_atama_95__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm596_atam_atama_96__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm597_atam_atama_97__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm598_atam_atama_98__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm599_atam_atama_99__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm600_atam_atama_100__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm601_atam_atama_101__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm602_atam_atama_102__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm603_atam_atama_103__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm605_atam_atama_105__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm606_atam_atama_106__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm607_atam_atama_107__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm608_atam_atama_108__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm609_atam_atama_109__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm610_atam_atama_110__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm611_atam_atama_111__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm612_atam_atama_112__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm613_atam_atama_113__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm614_atam_atama_114__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm615_atam_atama_115__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm618_atam_atama_118__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm619_atam_atama_119__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm620_atam_atama_120__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm621_atam_atama_121__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm623_atam_atama_123__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm624_atam_atama_124__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm625_atam_atama_125__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm626_atam_atama_126__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm627_atam_atama_127__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm628_atam_atama_128__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm630_atam_atama_130__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm632_atam_atama_132__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm633_atam_atama_133__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm634_atam_atama_134__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm635_atam_atama_135__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm636_atam_atama_136__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm637_atam_atama_137__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm638_atam_atama_138__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm639_atam_atama_139__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm640_atam_atama_140__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm641_atam_atama_141__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm642_atam_atama_142__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm644_atam_atama_144__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm645_atam_atama_145__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm646_atam_atama_146__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm647_atam_atama_147__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm648_atam_atama_148__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm649_atam_atama_149__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm651_atam_atama_151__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm652_atam_atama_152__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm653_atam_atama_153__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm655_atam_atama_155__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm656_atam_atama_156__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm660_atam_atama_160__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm662_atam_atama_162__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm663_atam_atama_163__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm664_atam_atama_164__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm665_atam_atama_165__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm667_atam_atama_167__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm669_atam_atama_169__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm670_atam_atama_170__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm673_atam_atama_173__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm700_atam_zujo_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm701_face_hitai_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm709_atam_zujo_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm711_atam_zujo_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm715_atam_zujo_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm718_atam_zujo_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm721_atam_zujo_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm722_atam_zujo_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm745_atam_zujo_45__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm746_atam_zujo_46__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm748_atam_zujo_48__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm749_atam_zujo_49__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm751_joha_neck_51__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm438_ude_hand_138__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm522_atam_atama_22__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm536_atam_atama_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm548_atam_atama_48__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm560_atam_atama_60__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm604_atam_atama_104__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm616_atam_atama_116__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm631_atam_atama_131__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm643_atam_atama_143__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm658_atam_atama_158__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm702_atam_zujo_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm752_joha_neck_52__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_neritm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm010_joha_outer_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm023_joha_outer_23__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm035_joha_outer_35__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm512_atam_atama_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm529_atam_atama_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm541_atam_atama_41__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm706_atam_zujo_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm719_atam_zujo_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm775_joha_ushiro_75__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm776_joha_ushiro_76__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm777_joha_ushiro_77__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm780_joha_ushiro_80__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm781_joha_ushiro_81__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm782_joha_ushiro_82__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm783_joha_ushiro_83__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm784_joha_ushiro_84__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_mikitm790_atam_zujo_90__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_neritm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_neritm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_neritm004_joha_outer_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_neritm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_neritm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm004_joha_outer_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm005_joha_outer_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm006_joha_outer_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm007_joha_outer_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm009_joha_outer_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm011_joha_outer_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm012_joha_outer_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm013_joha_outer_13__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm014_joha_outer_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm015_joha_outer_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm016_joha_outer_16__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm017_joha_outer_17__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm018_joha_outer_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm019_joha_outer_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm020_joha_outer_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm021_joha_outer_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm024_joha_outer_24__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm025_joha_outer_25__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm026_joha_outer_26_zzc__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm027_joha_outer_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm028_joha_outer_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm029_joha_outer_29__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm030_joha_outer_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm031_joha_outer_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm032_joha_outer_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm033_joha_outer_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm034_joha_outer_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm036_joha_outer_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm037_joha_outer_37__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm038_joha_outer_38__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm039_joha_outer_39__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm040_joha_outer_40__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm041_joha_outer_41__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm043_joha_outer_43__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm044_joha_outer_44__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm045_joha_outer_45__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm047_joha_outer_47__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm048_joha_outer_48__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm502_atam_atama_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm503_atam_atama_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm504_atam_atama_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm505_atam_atama_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm506_atam_atama_06__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm507_atam_atama_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm508_atam_atama_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm509_atam_atama_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm510_atam_atama_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm511_atam_atama_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm513_atam_atama_13__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm514_atam_atama_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm515_atam_atama_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm516_atam_atama_16__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm517_atam_atama_17__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm518_atam_atama_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm519_atam_atama_19__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm520_atam_atama_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm526_atam_atama_26__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm527_atam_atama_27__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm528_atam_atama_28__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm530_atam_atama_30__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm531_atam_atama_31__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm532_atam_atama_32__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm533_atam_atama_33__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm534_atam_atama_34__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm535_atam_atama_35__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm536_atam_atama_36__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm537_atam_atama_37__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm538_atam_atama_38__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm539_atam_atama_39__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm540_atam_atama_40__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm543_atam_atama_43__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm544_atam_atama_44__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm545_atam_atama_45__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm547_atam_atama_47__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm548_atam_atama_48__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm600_atama_cat_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm701_atam_zujo_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm702_atam_zujo_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm703_atam_zujo_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm704_atam_zujo_04__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm705_atam_zujo_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm707_atam_zujo_07__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm708_atam_zujo_08__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm709_atam_zujo_09__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm710_atam_zujo_10__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm711_atam_zujo_11__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm712_atam_zujo_12__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm714_atam_zujo_14__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm715_atam_zujo_15__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm716_atam_zujo_16__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm717_atam_zujo_17__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm718_atam_zujo_18__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm720_atam_zujo_20__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm721_atam_zujo_21__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm775_joha_ushiro_75__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm776_joha_ushiro_76__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm777_joha_ushiro_77__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm997_atam_zujo_97__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_rinitm999_atam_zujo_99__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_sakitm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_sakitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_sakitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_sakitm005_joha_outer_05__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_sakitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_sakitm501_atam_atama_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_sakitm600_atama_cat_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_sakitm775_joha_ushiro_75__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_tetitm001_joha_outer_01__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_tetitm002_joha_outer_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_tetitm003_joha_outer_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_tetitm500_atam_atama_00__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_tetitm502_atam_atama_02__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/ext_skp_tetitm503_atam_atama_03__divskn.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/osage_setting.txt ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/sp_skp.farc ; 140616748778912 17:05.50 1989-05-24 rom/skin_param/sp_skp_db.txt ; 140616748778912 17:05.50 1989-05-24 rom/sound/button.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv600_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv601_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv602_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv603_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv604_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv605_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv607_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv608_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv609_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv610_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv611_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv612_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv613_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv614_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv615_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv617_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv618_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv619_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv620_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv621_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv622_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv623_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv624_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv625_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv626_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv627_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv628_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv629_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv630_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv631_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv637_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv639_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv640_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv641_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv642_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv710_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv722_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv723_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv724_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv725_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv726_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv727_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv728_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv729_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv730_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv731_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv732_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv733_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv736_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv737_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv738_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv739_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv740_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pvchange.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/result_len.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/result_miku.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/result_rin.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/se.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/se_adv.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/se_aime.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/se_cmn.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/se_over.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/se_result.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/se_sel.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/slide_bell.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/slide_bell2.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/slide_harp.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/slide_laser.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/slide_long.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/slide_piano.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/slide_se.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/slide_windchime.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv616_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv638_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/sound/pv734_effect.farc ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_no_ring.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv083_stgns098.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv434_mhd3070.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv434_mhd6677.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv614_mhd0000.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv614_mhd7334.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p1_00000.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p1_03848.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p1_06720.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p1_07038.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p1_11992.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p2_00000.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p2_01568.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p2_07518.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv620_p2_11992.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv037s01_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv038s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv044s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv046s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv047s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv047s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv051s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv058s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgd2pv065s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv081s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv081s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv082s62.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv082s63.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv083s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv083s18.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv091s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv091s15.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv104s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv219s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv219s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv221s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv221s11.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv222s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv226s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv233s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv235s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv236s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv240s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv241s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv241_mhd481.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv601s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv602s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv602s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv605s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv622s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv625s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv625s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv740s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_d2ns058.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_d2ns082.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_d2pv050s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns004.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns021.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns022.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns023.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_pv625_mhd3860.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv083s18_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/coli_stgpv600s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns032.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/leaf_ns094.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv233s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv233s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv007s10.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/splash_d2ns064.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns084.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns084_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns086.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_ns249.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv001s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv001s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv001s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv001s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv001s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv001s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv001s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv008s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv008s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv223s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv223s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/fog_ring_pv241s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/leaf_pv081s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/leaf_pv087s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/leaf_pv087s17.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/leaf_pv221s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/leaf_pv441s01_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/leaf_tst.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/litproj_d2pv208s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/litproj_pv255s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/litproj_pv257s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/litproj_pv627s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_ns005_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv011s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv011s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv083s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv083s24.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv089s03_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv233s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv233s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv233s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv432s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv432s02_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv609s01_rain.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv619s02_rain.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/rain_pv625s01_clone.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_d2ns064.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_ns123.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv083s24.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv089s03_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv219s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv219s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv220s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv233s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv233s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv233s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv236s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv432s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/ripple_pv432s02_clone1.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_d2pv037s01_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_d2pv051s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_ns005_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_ns014_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_ns015_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_ns033.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_ns084_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv007s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv007s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv007s07_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv007s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv007s11_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv020s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv020s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv020s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv086s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv218s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv218s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv224s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv224s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv224s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv244s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv247s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv609s01_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv622s01_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv737s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/snow_pv737s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/splash_ns123.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/splash_pv220s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/splash_pv233s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/splash_pv233s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/splash_pv233s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/splash_pv233s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/splash_pv236s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_ns266.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv242s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s02.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s03.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s05.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s06.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s07.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s08.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv253s09.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv621s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv622s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv622s01_snow.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv626s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv638s01.txt ; 140616748778912 17:05.50 1989-05-24 rom/stage_param/star_pv642s04.txt ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0271_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0000_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0001_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0002_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0003_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0004_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0005_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0006_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0007_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0008_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0009_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0010_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0011_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0012_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0013_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0014_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0015_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0017_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0018_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0019_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0020_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0021_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0022_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0023_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0024_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0025_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0026_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0027_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0028_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0029_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0030_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0031_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0032_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0034_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0035_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0036_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0037_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0038_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0039_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0040_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0041_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0042_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0043_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0044_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0045_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0046_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0047_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0048_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0049_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0051_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0052_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0053_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0054_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0055_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0056_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0057_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0058_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0059_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0060_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0061_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0062_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0063_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0064_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0065_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0066_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0016_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0033_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0050_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0067_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0084_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0101_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0118_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0135_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0152_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0169_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0186_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0203_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0220_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0237_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0254_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0068_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0069_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0070_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0071_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0072_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0073_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0074_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0075_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0076_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0077_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0078_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0079_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0080_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0081_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0082_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0083_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0085_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0086_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0087_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0088_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0089_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0090_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0091_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0092_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0093_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0094_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0095_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0096_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0097_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0098_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0099_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0100_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0102_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0103_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0104_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0105_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0106_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0107_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0108_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0109_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0110_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0111_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0112_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0113_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0114_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0115_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0116_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0117_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0119_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0120_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0121_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0122_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0123_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0124_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0125_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0126_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0127_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0128_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0129_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0130_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0131_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0132_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0133_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0134_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0136_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0137_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0138_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0139_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0140_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0141_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0142_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0143_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0144_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0145_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0146_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0147_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0148_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0149_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0150_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0151_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0153_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0154_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0155_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0156_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0157_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0158_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0159_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0160_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0161_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0162_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0163_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0164_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0165_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0166_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0167_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0168_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0170_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0171_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0172_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0173_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0174_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0175_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0176_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0177_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0178_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0179_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0180_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0181_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0182_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0183_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0184_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0185_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0187_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0188_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0189_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0190_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0191_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0192_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0193_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0194_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0195_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0196_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0197_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0198_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0199_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0200_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0201_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0202_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0204_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0205_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0206_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0207_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0208_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0209_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0210_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0211_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0212_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0213_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0214_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0215_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0216_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0217_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0218_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0219_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0221_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0222_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0223_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0224_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0225_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0226_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0227_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0228_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0229_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0230_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0231_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0232_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0233_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0234_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0235_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0236_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0238_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0239_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0240_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0241_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0242_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0243_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0244_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0245_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0246_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0247_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0248_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0249_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0250_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0251_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0252_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0253_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0255_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0256_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0257_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0258_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0259_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0260_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0261_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0262_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0263_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0264_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0265_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0266_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0267_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0268_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0269_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0270_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0272_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0273_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0274_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0275_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0276_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0277_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0278_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0279_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0280_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0281_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0282_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0283_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0284_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0285_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0286_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0287_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0289_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0290_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0291_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0292_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0293_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0294_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0295_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0296_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0297_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0298_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0299_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0300_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0301_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0302_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0303_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0304_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0306_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0307_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0308_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0309_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0310_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0311_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0312_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0313_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0314_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0315_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0316_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0317_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0318_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0319_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0320_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0321_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0323_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0324_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0325_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0326_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0327_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0328_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0329_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0330_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0331_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0332_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0333_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0334_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0335_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0336_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0337_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0338_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0340_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0341_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0342_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0343_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0344_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0345_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0346_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0347_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0348_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0349_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0350_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0351_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0352_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0353_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0354_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0355_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0357_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0358_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0359_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0360_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0361_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0362_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0363_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0364_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0365_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0366_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0367_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0368_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0369_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0370_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0371_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0372_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0374_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0375_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0376_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0377_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0378_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0379_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0380_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0381_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0382_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0383_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0384_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0385_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0386_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0387_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0388_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0389_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0391_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0392_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0393_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0394_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0395_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0396_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0397_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0398_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0399_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0400_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0401_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0402_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0403_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0404_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0405_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0406_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0408_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0409_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0410_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0411_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0412_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0413_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0414_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0415_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0416_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0417_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0418_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0419_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0420_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0421_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0422_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0423_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0425_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0426_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0427_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0428_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0429_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0430_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0431_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0432_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0433_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0434_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0435_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0436_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0437_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0438_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0439_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0440_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0442_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0443_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0444_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0445_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0446_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0447_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0448_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0449_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0450_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0451_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0452_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0453_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0454_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0455_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0456_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0457_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0459_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0460_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0461_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0462_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0463_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0464_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0465_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0466_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0467_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0468_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0469_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0470_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0471_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0472_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0473_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0474_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0476_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0477_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0478_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0479_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0480_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0481_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0482_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0483_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0484_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0485_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0486_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0487_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0488_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0489_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0490_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0491_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0493_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0494_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0495_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0496_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0497_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0498_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0499_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0500_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0501_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0502_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0503_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0504_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0505_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0506_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0507_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0508_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0510_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0511_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0512_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0513_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0514_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0515_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0516_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0517_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0518_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0519_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0520_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0521_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0522_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0523_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0524_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0525_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0527_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0528_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0529_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0530_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0531_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0532_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0533_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0534_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0535_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0536_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0537_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0538_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0539_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0540_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0541_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0542_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0544_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0545_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0546_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0547_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0554_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0555_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0556_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0557_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0558_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0559_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0560_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0561_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0562_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0563_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0564_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0565_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0288_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0305_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0322_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0339_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0356_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0373_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0390_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0407_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0424_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0441_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0458_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0475_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0492_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0509_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0526_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0543_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0566_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0583_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0600_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0567_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0568_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0569_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0570_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0571_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0572_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0573_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0574_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0575_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0576_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0577_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0578_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0579_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0580_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0581_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0582_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0584_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0585_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0586_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0587_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0588_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0589_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0590_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0591_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0592_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0593_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0594_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0595_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0596_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0597_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0598_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0599_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0601_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0602_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0603_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0604_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0605_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0606_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0607_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0608_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0609_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0610_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0611_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0612_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0613_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0614_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0615_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0616_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0617_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0618_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0619_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0620_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0621_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0622_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0623_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0624_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0625_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0626_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0627_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0628_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0629_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0630_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0631_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0632_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/card/CLT_CRD0633_01.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ic_img01_00.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ic_img02_00.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ic_img03_00.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_img01_00.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_img02_00.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_img03_00.jpg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ss_rights01.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ss_rights01_ic.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ss_rights02.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ss_rights02_ic.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ss_rights03.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/ext/ext_ss_rights03_ic.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp000_01.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp001_01.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp002_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp003_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp004_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp005_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp006_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp007_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp008_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp009_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp010_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp011_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp012_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp013_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp014_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp016_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp017_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp018_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp019_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp020_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp021_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp022_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp023_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp024_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp030_02.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp031_02.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp032_02.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp033_02.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp034_02.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp035_02.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp040_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp041_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp043_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp044_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp045_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp046_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp047_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp048_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp049_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp050_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp051_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp052_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp053_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp054_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp055_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp056_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp057_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp058_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp059_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp061_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp062_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp063_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp064_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp065_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp066_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp067_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp068_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp069_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp070_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp071_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp072_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp073_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp074_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp075_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp076_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp077_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp078_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp079_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp080_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp081_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp082_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp083_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp084_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp085_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp086_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp087_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp015_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp042_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/stamp060_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/pv_param/pv710/bloom.txt ; 140616748778912 17:05.50 1989-05-24 rom/pv_param/pv710/cc.txt ; 140616748778912 17:05.50 1989-05-24 rom/pv_param/pv710/chara_light.txt ; 140616748778912 17:05.50 1989-05-24 rom/pv_param/pv710/dof.txt ; 140616748778912 17:05.50 1989-05-24 rom/pv_param/pv710/stage_light.txt ; 140616748778912 17:05.50 1989-05-24 rom/pv_param/pv740/dof.txt ; 140616748778912 17:05.50 1989-05-24 rom/sound/bgm/encore_jng_adx.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/bgm/random_select.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/bgm/result_ft_clear.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/bgm/result_lp.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/bgm/result_verB_clear.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/bgm/screenshot.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/bgm/selector_ft_lp.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/bgm/selector_verB_a_lp.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_001.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_002.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_003.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_004.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_005.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_006.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_007.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_008.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_009.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_010.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_011.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_012.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_013.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_014.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_015.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_016.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_017.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_018.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_019.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_021.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_022.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_023.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_024.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_025.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_026.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_027.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_028.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_029.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_030.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_031.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_032.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_033.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_034.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_035.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_036.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_037.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_038.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_039.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_041.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_042.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_043.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_044.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_045.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_046.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_047.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_048.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_049.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_050.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_051.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_052.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_053.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_054.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_055.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_056.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_057.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_058.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_059.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_061.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_062.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_063.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_064.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_065.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_066.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_079.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_081.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_082.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_083.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_084.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_085.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_086.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_087.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_088.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_089.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_090.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_091.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_092.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_094.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_095.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_096.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_097.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_101.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_102.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_103.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_104.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_201.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_202.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_203.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_204.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_205.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_206.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_207.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_208.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_209.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_210.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_211.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_020.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_040.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_060.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_093.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_212.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_233.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_244.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_265.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_421.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_441.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_618.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_641.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_213.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_214.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_215.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_216.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_218.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_219.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_220.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_221.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_222.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_223.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_224.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_225.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_226.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_227.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_227_rin.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_228.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_231.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_232.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_234.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_235.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_236.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_238.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_238_kaito.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_238_len.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_238_luka.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_238_meiko.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_238_rin.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_239.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_239_luka.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_239_meiko.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_239_rin.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_240.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_241.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_242.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_243.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_243_miku.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_244_len.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_246.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_246_kaito.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_247.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_248.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_249.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_250.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_251.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_253.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_254.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_255.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_257.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_259.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_260.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_261.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_262.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_262_kai.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_262_mik.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_262_rin.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_401.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_402.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_403.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_404.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_405.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_407.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_408.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_409.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_410.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_411.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_412.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_413.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_414.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_415.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_416.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_417.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_418.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_419.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_420.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_422.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_423.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_424.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_425.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_426.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_427.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_428.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_429.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_430.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_431.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_432.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_433.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_434.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_435.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_436.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_437.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_438.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_439.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_440.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_442.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_443.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_600.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_601.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_602.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_603.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_604.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_605.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_607.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_608.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_609.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_610.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_611.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_612.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_613.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_614.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_615.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_616.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_617.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_619.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_620.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_621.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_621_meiko.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_622.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_623.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_624.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_625.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_626.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_627.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_628.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_629.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_630.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_631.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_637.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_637_all.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_638.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_639.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_640.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_642.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_710.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_722.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_723.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_724.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_725.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_726.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_727.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_728.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_729.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_730.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_731.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_732.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_733.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_734.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_736.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_737.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_738.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_739.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_740.ogg ; 140616748778912 17:05.50 1989-05-24 rom/sound/song/pv_832.ogg ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/ext/ext_stamp001_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/ext/ext_stamp002_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/ext/ext_stamp003_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/ext/ext_stamp004_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_000_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_001_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_002_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_003_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_004_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_005_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_006_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_007_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_008_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_009_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_010_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_011_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_012_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_013_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_014_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_016_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_017_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_018_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_019_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_020_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_021_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_022_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_023_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_024_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_025_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_026_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_027_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_028_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_029_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_030_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_032_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_033_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_034_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_035_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_036_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_037_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_038_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_039_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_040_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_041_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_042_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_043_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_044_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_045_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_046_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_048_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_049_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_050_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_051_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_052_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_053_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_054_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_055_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_056_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_057_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_058_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_059_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_060_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_061_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_062_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_015_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_031_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_047_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_063_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_079_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_095_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_111_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_128_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_145_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_162_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_193_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_209_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_225_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_241_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_257_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_273_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_289_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_305_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_323_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_341_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_359_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_375_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_393_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_064_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_065_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_066_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_067_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_068_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_069_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_070_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_071_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_072_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_073_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_074_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_075_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_076_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_077_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_078_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_080_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_081_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_082_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_083_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_084_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_085_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_086_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_087_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_088_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_089_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_090_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_091_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_092_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_093_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_094_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_096_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_097_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_098_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_099_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_100_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_101_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_102_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_103_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_104_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_105_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_106_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_107_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_108_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_109_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_110_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_112_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_113_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_114_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_115_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_116_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_117_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_118_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_119_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_120_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_121_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_122_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_124_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_125_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_126_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_127_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_129_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_130_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_131_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_132_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_133_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_134_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_135_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_136_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_137_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_138_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_139_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_141_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_142_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_143_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_144_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_146_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_147_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_148_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_149_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_150_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_151_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_153_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_154_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_155_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_156_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_157_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_158_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_159_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_160_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_161_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_163_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_164_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_165_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_166_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_167_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_168_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_169_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_170_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_171_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_172_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_188_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_189_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_190_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_191_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_192_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_194_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_195_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_196_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_197_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_198_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_199_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_200_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_201_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_202_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_203_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_204_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_205_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_206_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_207_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_208_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_210_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_211_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_212_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_213_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_214_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_215_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_216_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_217_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_218_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_219_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_220_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_221_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_222_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_223_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_224_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_226_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_227_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_228_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_229_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_230_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_231_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_232_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_233_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_234_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_235_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_236_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_237_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_238_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_239_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_240_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_242_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_243_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_244_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_245_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_246_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_247_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_248_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_249_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_250_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_251_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_252_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_253_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_254_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_255_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_256_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_258_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_259_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_260_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_261_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_262_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_263_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_264_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_265_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_266_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_267_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_268_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_269_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_270_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_271_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_272_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_274_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_275_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_276_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_277_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_278_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_279_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_280_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_281_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_282_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_283_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_284_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_285_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_286_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_287_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_288_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_290_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_291_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_292_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_293_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_294_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_295_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_296_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_297_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_298_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_299_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_300_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_301_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_302_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_303_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_304_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_306_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_308_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_309_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_310_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_311_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_313_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_314_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_315_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_316_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_317_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_318_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_319_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_320_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_321_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_322_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_324_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_325_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_326_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_327_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_328_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_329_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_330_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_331_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_332_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_334_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_335_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_336_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_338_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_339_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_340_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_343_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_344_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_345_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_346_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_347_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_348_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_349_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_350_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_351_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_352_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_353_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_354_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_355_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_356_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_358_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_360_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_361_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_362_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_363_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_364_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_365_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_366_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_367_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_368_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_369_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_370_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_371_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_372_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_373_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_374_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_376_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_377_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_378_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_379_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_380_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_381_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_382_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_383_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_385_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_386_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_387_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_389_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_390_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_391_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_392_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_394_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_395_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_398_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_402_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_403_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_404_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_405_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_406_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_407_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_408_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_409_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_410_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_411_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_412_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_420_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_421_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_422_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_423_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext001_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext002_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext003_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext004_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext005_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext006_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext007_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext008_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext009_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext010_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext011_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/module/stamp_md_sub_ext012_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv001_logo001_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv002_logo002_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv003_logo003_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv004_logo004_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv005_logo005_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv006_logo006_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv007_logo007_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv008_logo008_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv009_logo009_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv010_logo010_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv011_logo011_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv012_logo012_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv013_logo013_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv014_logo014_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv016_logo016_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv017_logo017_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv018_logo018_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv019_logo019_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv020_logo020_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv021_logo021_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv022_logo022_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv023_logo023_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv024_logo024_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv025_logo025_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv027_logo027_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv028_logo028_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv029_logo029_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv030_logo030_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv032_logo032_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv037_logo037_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv038_logo038_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv039_logo039_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv040_logo040_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv041_logo041_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv042_logo042_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv043_logo043_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv044_logo044_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv045_logo045_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv046_logo046_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv047_logo047_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv048_logo048_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv049_logo049_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv051_logo051_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv052_logo052_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv053_logo053_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv054_logo054_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv055_logo055_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv056_logo056_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv057_logo057_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv058_logo058_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv059_logo059_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv060_logo060_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv061_logo061_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv062_logo062_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv063_logo063_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv064_logo064_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv015_logo015_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv031_logo031_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv050_logo050_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv065_logo065_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv093_logo093_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv207_logo207_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv223_logo223_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv241_logo241_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv261_logo261_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv413_logo413_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv428_logo428_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv443_logo443_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv615_logo615_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv630_logo630_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv066_logo066_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv079_logo079_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv081_logo081_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv082_logo082_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv083_logo083_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv084_logo084_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv085_logo085_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv086_logo086_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv087_logo087_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv088_logo088_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv089_logo089_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv090_logo090_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv091_logo091_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv092_logo092_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv094_logo094_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv095_logo095_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv096_logo096_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv097_logo097_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv101_logo101_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv102_logo102_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv103_logo103_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv104_logo104_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv201_logo201_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv202_logo202_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv203_logo203_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv204_logo204_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv205_logo205_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv206_logo206_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv208_logo208_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv209_logo209_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv210_logo210_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv211_logo211_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv212_logo212_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv213_logo213_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv214_logo214_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv215_logo215_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv216_logo216_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv218_logo218_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv219_logo219_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv220_logo220_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv221_logo221_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv222_logo222_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv224_logo224_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv225_logo225_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv226_logo226_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv227_logo227_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv228_logo228_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv231_logo231_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv232_logo232_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv233_logo233_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv234_logo234_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv235_logo235_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv236_logo236_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv238_logo238_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv239_logo239_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv240_logo240_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv242_logo242_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv243_logo243_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv244_logo244_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv246_logo246_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv247_logo247_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv248_logo248_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv249_logo249_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv250_logo250_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv251_logo251_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv253_logo253_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv255_logo255_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv257_logo257_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv259_logo259_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv260_logo260_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv262_logo262_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv265_logo265_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv401_logo401_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv402_logo402_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv403_logo403_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv403_logo403_ex_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv404_logo404_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv405_logo405_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv407_logo407_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv408_logo408_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv409_logo409_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv410_logo410_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv411_logo411_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv412_logo412_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv414_logo414_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv415_logo415_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv416_logo416_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv417_logo417_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv418_logo418_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv419_logo419_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv420_logo420_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv421_logo421_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv422_logo422_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv423_logo423_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv424_logo424_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv425_logo425_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv426_logo426_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv427_logo427_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv429_logo429_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv430_logo430_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv431_logo431_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv432_logo432_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv433_logo433_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv434_logo434_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv435_logo435_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv436_logo436_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv437_logo437_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv438_logo438_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv439_logo439_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv440_logo440_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv441_logo441_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv442_logo442_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv600_logo600_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv601_logo601_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv602_logo602_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv603_logo603_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv604_logo604_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv605_logo605_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv607_logo607_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv608_logo608_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv609_logo609_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv610_logo610_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv611_logo611_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv612_logo612_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv613_logo613_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv614_logo614_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv616_logo616_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv617_logo617_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv618_logo618_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv619_logo619_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv620_logo620_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv621_logo621_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv622_logo622_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv623_logo623_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv624_logo624_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv625_logo625_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv626_logo626_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv627_logo627_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv628_logo628_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv629_logo629_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv631_logo631_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv637_logo637_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv638_logo638_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv639_logo639_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv640_logo640_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv641_logo641_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv642_logo642_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv710_logo710_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv722_logo722_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv723_logo723_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv724_logo724_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv725_logo725_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv726_logo726_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv727_logo727_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv728_logo728_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv729_logo729_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv730_logo730_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv731_logo731_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv732_logo732_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv733_logo733_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv734_logo734_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv736_logo736_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv737_logo737_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv738_logo738_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv739_logo739_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv740_logo740_00.tga ; 140616748778912 17:05.50 1989-05-24 rom/photo_print/stamp/pv/stamp_pv832_logo832_00.tga CPUSBSG.dll 27F4EB58 diva.exe 05D8544B glut32.dll C9F91206 MUsbPuIf.dll 83AD0967 rom/bone_data.bin D7806130 rom/chritm_prop.farc 1B5F63EF rom/fontmap.farc 0CEFD7F2 rom/gm_btn_se_tbl.farc 1B82C8A7 rom/gm_chainslide_se_tbl.farc DA5FAAD8 rom/gm_collection_card_tbl.farc 4D72B956 rom/gm_customize_item_tbl.farc 6F123A85 rom/gm_module_tbl.farc 536A066E rom/gm_plate_tbl.farc 3215EB74 rom/gm_pv_list_tbl.farc F0AF5B09 rom/gm_slidertouch_se_tbl.farc 1A37AAE4 rom/gm_slide_se_tbl.farc 6B3A04F2 rom/hand_item_data.txt 0D15A291 rom/iet.bin CEE780CE rom/ng_server.conf 128C6D9E rom/pv_db.txt 3FF63795 rom/pv_field.txt 81DE2009 rom/rob_sleeve_data.txt A5E70EB8 rom/shader.farc E6D9187B rom/shader_cg.farc E75FE112 rom/stage_data.bin 7C7FA78C rom/star_catalog_megastar2.farc A67068E0 rom/star_catalog_random.farc 7722B790 rom/STGTST_COLI.000.bin E04A5A65 rom/movie/adv_cfm_cm.wmv 5CDB6805 rom/movie/adv_sega_cm.wmv 4A324B07 rom/movie/diva_adv.wmv D90ED9DD rom/movie/diva_adv02.wmv 85227E86 rom/movie/pv_203.wmv DD03764B rom/movie/pv_209.wmv 4E8DA2B4 rom/movie/pv_215.wmv A24E5820 rom/movie/pv_216.wmv 9CDD6F93 rom/movie/pv_255.wmv C9262697 rom/movie/pv_257.wmv 7225EE18 rom/movie/pv_265.wmv 40CC004B rom/movie/pv_428.wmv EC492699 rom/movie/pv_429.wmv 0D3A64D5 rom/movie/pv_430.wmv 7CCC83F2 rom/movie/pv_431.wmv 43DF3886 rom/movie/pv_601.wmv 416BE1AF rom/movie/pv_604.wmv 66E7203A rom/movie/pv_609.wmv 68C33FE4 rom/movie/pv_618.wmv 44B355D1 rom/movie/pv_623.wmv BA662C0A rom/movie/pv_625.wmv 45D72066 rom/movie/pv_627.wmv 0A98C665 rom/movie/pv_630.wmv EFC062AC rom/movie/pv_631.wmv 1CDD9ABC rom/movie/pv_722.wmv 4B263C8A rom/movie/pv_723.wmv D4D22D7D rom/movie/pv_724.wmv BDD0CBE3 rom/movie/pv_728.wmv 48B964A3 rom/movie/pv_734.wmv C4C9B86A rom/movie/pv_739_001.wmv B338E9A4 rom/2d/aet_adv_cmn.bin 8496B47B rom/2d/aet_adv_nobl.bin 9BA6BB51 rom/2d/aet_adv_rnk.bin F328DC96 rom/2d/aet_adv_scrnk.bin 7C033233 rom/2d/aet_cmn_all.bin BD5BEB34 rom/2d/aet_db.bin 9D90DB4E rom/2d/aet_ent_cmn.bin 738D06F7 rom/2d/aet_ent_name.bin 06C35596 rom/2d/aet_ent_passintro.bin ACC3B852 rom/2d/aet_gam_cmn.bin 26621ACA rom/2d/aet_gam_cont.bin C504754B rom/2d/aet_gam_ctstrslt.bin 84BDFCAF rom/2d/aet_gam_edttit.bin B79B955F rom/2d/aet_gam_eff000.bin F2318B7C rom/2d/aet_gam_eff001.bin 21B2E956 rom/2d/aet_gam_eff002.bin B86DDA6C rom/2d/aet_gam_eff004.bin 602BBE34 rom/2d/aet_gam_eff005.bin 59CDB042 rom/2d/aet_gam_eff006.bin BC1048F1 rom/2d/aet_gam_eff007.bin F5FC2D26 rom/2d/aet_gam_eff008.bin 7F73EBC5 rom/2d/aet_gam_eff009.bin 7C1A9850 rom/2d/aet_gam_eff010.bin ABA5A88C rom/2d/aet_gam_eff011.bin 1B57E97D rom/2d/aet_gam_eff012.bin C0B5E93A rom/2d/aet_gam_eff013.bin B4B8A5F6 rom/2d/aet_gam_eff014.bin 83520690 rom/2d/aet_gam_eff015.bin 288168FB rom/2d/aet_gam_eff016.bin 62DA2C92 rom/2d/aet_gam_eff017.bin 2818F2DB rom/2d/aet_gam_eff018.bin 8D9FE4AC rom/2d/aet_gam_eff019.bin 91089C14 rom/2d/aet_gam_eff021.bin 39005777 rom/2d/aet_gam_eff022.bin 92D67D2F rom/2d/aet_gam_eff023.bin 5F39E2E9 rom/2d/aet_gam_eff024.bin 52FB75F4 rom/2d/aet_gam_eff025.bin EAF9907B rom/2d/aet_gam_eff026.bin 284D5C81 rom/2d/aet_gam_eff027.bin 3487BFC1 rom/2d/aet_gam_eff028.bin 10817327 rom/2d/aet_gam_eff029.bin 71E16F04 rom/2d/aet_gam_eff030.bin 1A379F98 rom/2d/aet_gam_eff031.bin 644C44E8 rom/2d/aet_gam_eff032.bin 04F84018 rom/2d/aet_gam_eff033.bin 3782E428 rom/2d/aet_gam_eff034.bin FE8D6892 rom/2d/aet_gam_eff035.bin 3612AD72 rom/2d/aet_gam_eff036.bin EC0D19CA rom/2d/aet_gam_eff040.bin 7F1AF739 rom/2d/aet_gam_eff041.bin 6F000779 rom/2d/aet_gam_eff042.bin A160E9BE rom/2d/aet_gam_eff044.bin F1563F3B rom/2d/aet_gam_eff050.bin BAF8A0C2 rom/2d/aet_gam_eff051.bin 6ED914D5 rom/2d/aet_gam_eff052.bin 20D69954 rom/2d/aet_gam_eff053.bin 74FB229D rom/2d/aet_gam_eff054.bin 0ABFE77E rom/2d/aet_gam_eff055.bin C2C0B4AF rom/2d/aet_gam_eff058.bin 0BF1E920 rom/2d/aet_gam_eff059.bin EE1E53CA rom/2d/aet_gam_eff062.bin 190E50E7 rom/2d/aet_gam_eff064.bin ED06C4CA rom/2d/aet_gam_eff066.bin D835C1A3 rom/2d/aet_gam_eff068.bin 8903F7AA rom/2d/aet_gam_eff003.bin EAC1934E rom/2d/aet_gam_eff020.bin 5DBBF6FE rom/2d/aet_gam_eff039.bin 1ECBFA5A rom/2d/aet_gam_eff069.bin 416890D6 rom/2d/aet_gam_pv012.bin AEE04144 rom/2d/aet_gam_pv029.bin AD7D5AE0 rom/2d/aet_gam_pv051.bin 2122D840 rom/2d/aet_gam_pv081.bin 7664E65C rom/2d/aet_gam_pv101.bin 8393438D rom/2d/aet_gam_pv219.bin EE806ADF rom/2d/aet_gam_pv241.bin A7D2614D rom/2d/aet_gam_pv401.bin D07BCAAC rom/2d/aet_gam_pv418.bin 53ECF586 rom/2d/aet_gam_pv439.bin B2C28B89 rom/2d/aet_gam_pv614.bin 6EDE3B97 rom/2d/aet_gam_eff070.bin 09BC7C1C rom/2d/aet_gam_eff071.bin CC73DB84 rom/2d/aet_gam_gover.bin 09D7C254 rom/2d/aet_gam_loadsc.bin 7963C4A9 rom/2d/aet_gam_prize.bin 1E2846DA rom/2d/aet_gam_pv001.bin E6E74F84 rom/2d/aet_gam_pv002.bin 8D6DF4FD rom/2d/aet_gam_pv003.bin 1CE7D3CA rom/2d/aet_gam_pv004.bin FE48B122 rom/2d/aet_gam_pv005.bin 8FD8AFA1 rom/2d/aet_gam_pv006.bin 07EB0DA9 rom/2d/aet_gam_pv007.bin 7E74CFEA rom/2d/aet_gam_pv008.bin B2574F07 rom/2d/aet_gam_pv009.bin 2E301A10 rom/2d/aet_gam_pv010.bin BABB0D20 rom/2d/aet_gam_pv011.bin CB1429ED rom/2d/aet_gam_pv013.bin 05D2C5C1 rom/2d/aet_gam_pv014.bin C41C7FE1 rom/2d/aet_gam_pv015.bin EF41F5DA rom/2d/aet_gam_pv016.bin D7B1123E rom/2d/aet_gam_pv017.bin 546DB118 rom/2d/aet_gam_pv018.bin 9AB30147 rom/2d/aet_gam_pv019.bin 64B4B5DC rom/2d/aet_gam_pv020.bin 6E5C96E6 rom/2d/aet_gam_pv021.bin 088838FA rom/2d/aet_gam_pv022.bin 1A8F6532 rom/2d/aet_gam_pv023.bin C056AD4B rom/2d/aet_gam_pv024.bin 515ED110 rom/2d/aet_gam_pv025.bin 6FE12511 rom/2d/aet_gam_pv026.bin 6E26F328 rom/2d/aet_gam_pv027.bin EFD6C9B6 rom/2d/aet_gam_pv028.bin 1482CFCF rom/2d/aet_gam_pv030.bin 160EE7EA rom/2d/aet_gam_pv031.bin AA7C9174 rom/2d/aet_gam_pv032.bin F9C2598D rom/2d/aet_gam_pv037.bin EAA27AB5 rom/2d/aet_gam_pv038.bin 1F4AA200 rom/2d/aet_gam_pv039.bin BFD68A30 rom/2d/aet_gam_pv040.bin CF95644A rom/2d/aet_gam_pv041.bin 5A2ECE48 rom/2d/aet_gam_pv042.bin B6310B5E rom/2d/aet_gam_pv043.bin E2898816 rom/2d/aet_gam_pv044.bin B1AB87E9 rom/2d/aet_gam_pv045.bin 28C73421 rom/2d/aet_gam_pv046.bin CEFEA9B0 rom/2d/aet_gam_pv047.bin 588C06ED rom/2d/aet_gam_pv049.bin 85EF545C rom/2d/aet_gam_pv050.bin B91CBEF8 rom/2d/aet_gam_pv052.bin 005901F8 rom/2d/aet_gam_pv053.bin BA007D9B rom/2d/aet_gam_pv054.bin 04D136CD rom/2d/aet_gam_pv055.bin 68E2082D rom/2d/aet_gam_pv056.bin CA212F05 rom/2d/aet_gam_pv057.bin BFF02BCB rom/2d/aet_gam_pv058.bin 3B65AF12 rom/2d/aet_gam_pv059.bin E6ABAADF rom/2d/aet_gam_pv060.bin 13C8094A rom/2d/aet_gam_pv061.bin 1012FCB1 rom/2d/aet_gam_pv062.bin 3F0EF22D rom/2d/aet_gam_pv063.bin 0784436F rom/2d/aet_gam_pv064.bin C9A7A9DA rom/2d/aet_gam_pv065.bin 9E850405 rom/2d/aet_gam_pv066.bin 4F5F6A11 rom/2d/aet_gam_pv079.bin 9F655847 rom/2d/aet_gam_pv082.bin B33E8479 rom/2d/aet_gam_pv083.bin 79E07D40 rom/2d/aet_gam_pv084.bin A6A91BD3 rom/2d/aet_gam_pv085.bin E378723B rom/2d/aet_gam_pv086.bin 5BF9496E rom/2d/aet_gam_pv087.bin CEFB8796 rom/2d/aet_gam_pv088.bin 7FE8E46E rom/2d/aet_gam_pv089.bin 6004FBFD rom/2d/aet_gam_pv090.bin 57D0927D rom/2d/aet_gam_pv091.bin EBCD72F8 rom/2d/aet_gam_pv092.bin AE0D55A0 rom/2d/aet_gam_pv093.bin E8E74C32 rom/2d/aet_gam_pv094.bin 9796D219 rom/2d/aet_gam_pv095.bin FB26493B rom/2d/aet_gam_pv096.bin B220A23E rom/2d/aet_gam_pv097.bin CEB4C05D rom/2d/aet_gam_pv102.bin FA09CCE9 rom/2d/aet_gam_pv103.bin D65FA7D7 rom/2d/aet_gam_pv104.bin 031B7F2A rom/2d/aet_gam_pv201.bin CFD26150 rom/2d/aet_gam_pv202.bin 6CA90732 rom/2d/aet_gam_pv203.bin 4C8F8074 rom/2d/aet_gam_pv204.bin F97799C3 rom/2d/aet_gam_pv205.bin 4511EFBB rom/2d/aet_gam_pv206.bin C0E46571 rom/2d/aet_gam_pv207.bin 3D640DCF rom/2d/aet_gam_pv208.bin DBA3F7B8 rom/2d/aet_gam_pv210.bin FCB7D648 rom/2d/aet_gam_pv211.bin F74B0B3C rom/2d/aet_gam_pv212.bin C2F1FA82 rom/2d/aet_gam_pv214.bin B3ABD741 rom/2d/aet_gam_pv218.bin A0053424 rom/2d/aet_gam_pv220.bin 4ACB327D rom/2d/aet_gam_pv221.bin 11C26E3A rom/2d/aet_gam_pv222.bin C7032A46 rom/2d/aet_gam_pv223.bin B84D2EAC rom/2d/aet_gam_pv224.bin 682A403E rom/2d/aet_gam_pv225.bin 2DF9AF01 rom/2d/aet_gam_pv227.bin 5F0E38C9 rom/2d/aet_gam_pv231.bin 1C2B920D rom/2d/aet_gam_pv232.bin 78DF2216 rom/2d/aet_gam_pv233.bin 19BD1844 rom/2d/aet_gam_pv234.bin B282DBBC rom/2d/aet_gam_pv235.bin 54248A02 rom/2d/aet_gam_pv236.bin EA51F69F rom/2d/aet_gam_pv238.bin 4C387743 rom/2d/aet_gam_pv239.bin AFC2E4AC rom/2d/aet_gam_pv240.bin 18D3033B rom/2d/aet_gam_pv242.bin 05F31BAC rom/2d/aet_gam_pv243.bin 45DCD9CD rom/2d/aet_gam_pv244.bin B061306F rom/2d/aet_gam_pv246.bin 52E56E4B rom/2d/aet_gam_pv247.bin A2D0D07E rom/2d/aet_gam_pv248.bin D557386D rom/2d/aet_gam_pv249.bin 0D1E8591 rom/2d/aet_gam_pv250.bin 19CCD433 rom/2d/aet_gam_pv251.bin E13D3214 rom/2d/aet_gam_pv253.bin 02B0356C rom/2d/aet_gam_pv255.bin DEF1DCBE rom/2d/aet_gam_pv257.bin B5788C4A rom/2d/aet_gam_pv259.bin C1361A15 rom/2d/aet_gam_pv260.bin 6F8A00AB rom/2d/aet_gam_pv261.bin 1EB9B443 rom/2d/aet_gam_pv262.bin C193CF99 rom/2d/aet_gam_pv402.bin 29CE5FFA rom/2d/aet_gam_pv403.bin F6097E3C rom/2d/aet_gam_pv404.bin 9C14B8C8 rom/2d/aet_gam_pv405.bin B6BD1746 rom/2d/aet_gam_pv406.bin 9365F284 rom/2d/aet_gam_pv407.bin 95DA3DD2 rom/2d/aet_gam_pv408.bin 8BCB843A rom/2d/aet_gam_pv409.bin 21C37D5B rom/2d/aet_gam_pv410.bin 36AC625B rom/2d/aet_gam_pv411.bin 912BB58A rom/2d/aet_gam_pv412.bin EB7A4904 rom/2d/aet_gam_pv413.bin AB8E5AAF rom/2d/aet_gam_pv414.bin 11CC7550 rom/2d/aet_gam_pv415.bin 0925C041 rom/2d/aet_gam_pv416.bin 736FC49D rom/2d/aet_gam_pv417.bin D0082398 rom/2d/aet_gam_pv419.bin 03554786 rom/2d/aet_gam_pv420.bin 1D8F1E8D rom/2d/aet_gam_pv421.bin F1F00E73 rom/2d/aet_gam_pv422.bin 925DC0BF rom/2d/aet_gam_pv423.bin AF8CA86A rom/2d/aet_gam_pv424.bin D8DA8F9E rom/2d/aet_gam_pv425.bin D32053E1 rom/2d/aet_gam_pv426.bin F889402A rom/2d/aet_gam_pv427.bin 0D1E1E52 rom/2d/aet_gam_pv432.bin 19FCFC52 rom/2d/aet_gam_pv433.bin E1A4490A rom/2d/aet_gam_pv434.bin E2E311BA rom/2d/aet_gam_pv435.bin 5F2D875C rom/2d/aet_gam_pv436.bin 7D1D22A9 rom/2d/aet_gam_pv437.bin A5300656 rom/2d/aet_gam_pv438.bin 103D7878 rom/2d/aet_gam_pv440.bin BA13691A rom/2d/aet_gam_pv441.bin E0E9AD35 rom/2d/aet_gam_pv442.bin D8A61C74 rom/2d/aet_gam_pv443.bin 795B315A rom/2d/aet_gam_pv600.bin D1C06C7B rom/2d/aet_gam_pv601.bin BE69364D rom/2d/aet_gam_pv602.bin 1B202632 rom/2d/aet_gam_pv603.bin 93F706FB rom/2d/aet_gam_pv604.bin 04191A0E rom/2d/aet_gam_pv605.bin 1FC591D6 rom/2d/aet_gam_pv607.bin 2AC99219 rom/2d/aet_gam_pv609.bin 293F4B15 rom/2d/aet_gam_pv610.bin 10400231 rom/2d/aet_gam_pv611.bin ACAD04ED rom/2d/aet_gam_pv612.bin 37656207 rom/2d/aet_gam_pv613.bin 9B5C31D9 rom/2d/aet_gam_pv615.bin 8EFD4DEA rom/2d/aet_gam_pv616.bin 7CD942CC rom/2d/aet_gam_pv617.bin D3A2B388 rom/2d/aet_gam_pv618.bin A8720EEA rom/2d/aet_gam_pv619.bin 0B88450C rom/2d/aet_gam_pv620.bin 007BE74C rom/2d/aet_gam_pv621.bin 5DDBE09A rom/2d/aet_gam_pv622.bin 84F8CB7E rom/2d/aet_gam_pv623.bin 4926BFCE rom/2d/aet_gam_pv624.bin 8CEEF213 rom/2d/aet_gam_pv625.bin 559C83E0 rom/2d/aet_gam_pv626.bin 08E0EE65 rom/2d/aet_gam_pv627.bin CBD252A9 rom/2d/aet_gam_pv628.bin 28A40F96 rom/2d/aet_gam_pv629.bin 7E431FDA rom/2d/aet_gam_pv630.bin 656B5435 rom/2d/aet_gam_pv637.bin 19B6FE3C rom/2d/aet_gam_pv638.bin 6E68391D rom/2d/aet_gam_pv639.bin AFD77F7C rom/2d/aet_gam_pv640.bin BF0AF0B4 rom/2d/aet_gam_pv641.bin EAAAB719 rom/2d/aet_gam_pv642.bin 6A68C8AC rom/2d/aet_gam_pv710.bin B2EEA5DE rom/2d/aet_gam_pv722.bin 92377687 rom/2d/aet_gam_pv723.bin 7203235E rom/2d/aet_gam_pv724.bin 4E29F7BB rom/2d/aet_gam_pv725.bin 3E436F62 rom/2d/aet_gam_pv726.bin 1F9E0044 rom/2d/aet_gam_pv727.bin 4B7EFEC0 rom/2d/aet_gam_pv728.bin 1509033A rom/2d/aet_gam_pv729.bin A3D7DE5F rom/2d/aet_gam_pv730.bin 50DF7386 rom/2d/aet_gam_pv732.bin 66A76C51 rom/2d/aet_gam_pv733.bin 4D4F08A3 rom/2d/aet_gam_pv734.bin 6ED126DD rom/2d/aet_gam_pv736.bin A369B8C5 rom/2d/aet_gam_pv737.bin 48DA06E9 rom/2d/aet_gam_pv738.bin 25C9970F rom/2d/aet_gam_pv739.bin C2A6D2EC rom/2d/aet_gam_pv740.bin 74BDF12D rom/2d/aet_gam_pv832.bin DF13EE28 rom/2d/aet_gam_qstrslt.bin E8E0E478 rom/2d/aet_gam_result.bin 31B3BA04 rom/2d/aet_gam_sc.bin C63569D5 rom/2d/aet_gam_skin001.bin C2413FB5 rom/2d/aet_gam_skin002.bin BA5EF4C0 rom/2d/aet_gam_skin003.bin FAB0CFD2 rom/2d/aet_gam_skin004.bin 4DEFD50F rom/2d/aet_gam_skin006.bin AE73E1BE rom/2d/aet_gam_skin007.bin 1AF8F2A3 rom/2d/aet_gam_skin008.bin 9F3FEF8A rom/2d/aet_gam_skin009.bin 1101004A rom/2d/aet_gam_skin010.bin EE0B0ED1 rom/2d/aet_gam_skin011.bin FC66A3A0 rom/2d/aet_gam_skin012.bin A698122B rom/2d/aet_gam_skin013.bin C462CA57 rom/2d/aet_gam_skin014.bin 263A4098 rom/2d/aet_gam_skin015.bin D38F22A1 rom/2d/aet_gam_skin016.bin 8971932A rom/2d/aet_gam_skin017.bin DED47AF3 rom/2d/aet_gam_skin018.bin E3DA794F rom/2d/aet_gam_skin019.bin 68225A98 rom/2d/aet_gam_skin020.bin FA84AB90 rom/2d/aet_gam_skin021.bin C4E1BE5C rom/2d/aet_gam_skin023.bin B82B95C4 rom/2d/aet_gam_skin024.bin CF8C46B4 rom/2d/aet_gam_skin025.bin 4A6A3638 rom/2d/aet_gam_skin026.bin ED018827 rom/2d/aet_gam_skin027.bin D3649DEB rom/2d/aet_gam_skin028.bin 5DA04F45 rom/2d/aet_gam_skin029.bin 80702CC7 rom/2d/aet_gam_skin030.bin 7F7A225C rom/2d/aet_gam_skin031.bin F144CD9C rom/2d/aet_gam_skin032.bin 20D38CA0 rom/2d/aet_gam_skin033.bin 5E0F1E2E rom/2d/aet_gam_skin034.bin 65CC92F8 rom/2d/aet_gam_skin035.bin D14781E5 rom/2d/aet_gam_skin036.bin EE20BC79 rom/2d/aet_gam_skin037.bin 90FC2EF7 rom/2d/aet_gam_skin038.bin 3BB72E35 rom/2d/aet_gam_skin040.bin 78403F7A rom/2d/aet_gam_skin041.bin 069CADF4 rom/2d/aet_gam_skin042.bin 751B6728 rom/2d/aet_gam_skin043.bin B4FB8D8F rom/2d/aet_gam_skin044.bin B6F1A991 rom/2d/aet_gam_skin045.bin C82D3B1F rom/2d/aet_gam_skin046.bin BBAAF1C3 rom/2d/aet_gam_skin047.bin 35941E03 rom/2d/aet_gam_skin048.bin 632EC7CE rom/2d/aet_gam_skin049.bin 1DF25540 rom/2d/aet_gam_skin050.bin E2F85BDB rom/2d/aet_gam_skin051.bin C9CF4208 rom/2d/aet_gam_skin052.bin 720A7B31 rom/2d/aet_gam_skin053.bin AFF1445D rom/2d/aet_gam_skin054.bin 9432C88B rom/2d/aet_gam_skin055.bin 1A0C274B rom/2d/aet_gam_skin057.bin B547F4F9 rom/2d/aet_gam_skin058.bin 1E0CF43B rom/2d/aet_gam_skin059.bin AA87E726 rom/2d/aet_gam_skin060.bin 1883A570 rom/2d/aet_gam_skin061.bin 665F37FE rom/2d/aet_gam_skin062.bin 30456988 rom/2d/aet_gam_skin063.bin BE7B8648 rom/2d/aet_gam_skin064.bin 27A8817E rom/2d/aet_gam_skin065.bin 597413F0 rom/2d/aet_gam_skin066.bin 2AF3D92C rom/2d/aet_gam_skin067.bin EB13338B rom/2d/aet_gam_skin068.bin 98C98C6B rom/2d/aet_gam_skin069.bin E6151EE5 rom/2d/aet_gam_skin070.bin 191F107E rom/2d/aet_gam_skin071.bin F5C5850D rom/2d/aet_gam_skin072.bin 2452C431 rom/2d/aet_gam_skin074.bin 614DDA69 rom/2d/aet_gam_skin075.bin D5C6C974 rom/2d/aet_gam_skin076.bin 33F7D0D4 rom/2d/aet_gam_skin077.bin 4D2B425A rom/2d/aet_gam_skin078.bin E6604298 rom/2d/aet_gam_skin079.bin CD575B4B rom/2d/aet_gam_skin080.bin 70868130 rom/2d/aet_gam_skin081.bin 777BFF13 rom/2d/aet_gam_skin082.bin 04FC35CF rom/2d/aet_gam_skin083.bin B07726D2 rom/2d/aet_gam_skin084.bin B6F43065 rom/2d/aet_gam_skin085.bin C828A2EB rom/2d/aet_gam_skin086.bin BBAF6837 rom/2d/aet_gam_skin087.bin 359187F7 rom/2d/aet_gam_skin088.bin 3CCA0CD5 rom/2d/aet_gam_skin089.bin 42169E5B rom/2d/aet_gam_skin091.bin 0770982A rom/2d/aet_gam_skin092.bin 74F752F6 rom/2d/aet_gam_skin093.bin FAC9BD36 rom/2d/aet_gam_skin094.bin 631ABA00 rom/2d/aet_gam_skin095.bin 1DC6288E rom/2d/aet_gam_skin096.bin 6E41E252 rom/2d/aet_gam_skin097.bin AFA108F5 rom/2d/aet_gam_skin098.bin DC7BB715 rom/2d/aet_gam_skin099.bin A2A7259B rom/2d/aet_gam_skin100.bin D9F1EEA9 rom/2d/aet_gam_skin101.bin C1CE1500 rom/2d/aet_gam_skin102.bin B249DFDC rom/2d/aet_gam_skin103.bin 06C2CCC1 rom/2d/aet_gam_skin104.bin 0041DA76 rom/2d/aet_gam_skin105.bin 7E9D48F8 rom/2d/aet_gam_skin106.bin 0D1A8224 rom/2d/aet_gam_skin108.bin 8A7FE6C6 rom/2d/aet_gam_skin109.bin F4A37448 rom/2d/aet_gam_skin110.bin 8735ECD8 rom/2d/aet_gam_skin111.bin E93DCE5C rom/2d/aet_gam_skin112.bin 4965294A rom/2d/aet_gam_skin113.bin BCD04B73 rom/2d/aet_gam_skin114.bin AE6ABCF2 rom/2d/aet_gam_skin115.bin AB3DA385 rom/2d/aet_gam_skin116.bin 624A1CCB rom/2d/aet_gam_skin117.bin 97FF7EF2 rom/2d/aet_gam_skin118.bin 15CD0567 rom/2d/aet_gam_skin119.bin 4268ECBE rom/2d/aet_gam_skin120.bin 5B6937F7 rom/2d/aet_gam_skin121.bin D45D610C rom/2d/aet_gam_skin122.bin 8EA3D087 rom/2d/aet_gam_skin123.bin D906395E rom/2d/aet_gam_skin125.bin E101CAFF rom/2d/aet_gam_skin126.bin 4A17BF01 rom/2d/aet_gam_skin127.bin 34CB2D8F rom/2d/aet_gam_skin128.bin 8FFA5D8C rom/2d/aet_gam_skin129.bin 11BEC28D rom/2d/aet_gam_skin130.bin 4CA447F6 rom/2d/aet_gam_skin131.bin AF2B9FA6 rom/2d/aet_gam_skin132.bin EA38377F rom/2d/aet_gam_skin133.bin BD9DDEA6 rom/2d/aet_gam_skin134.bin 101B510E rom/2d/aet_gam_skin135.bin 9F2F07F5 rom/2d/aet_gam_skin136.bin C5D1B67E rom/2d/aet_gam_skin137.bin 92745FA7 rom/2d/aet_gam_skin138.bin DFE79842 rom/2d/aet_gam_skin139.bin D8A8FC50 rom/2d/aet_gam_skin140.bin 156102DF rom/2d/aet_gam_skin142.bin 183A5A8D rom/2d/aet_gam_skin143.bin 330D435E rom/2d/aet_gam_skin144.bin C08C3C6D rom/2d/aet_gam_skin145.bin D9075B8E rom/2d/aet_gam_skin146.bin AD2B3E15 rom/2d/aet_gam_skin147.bin FA8ED7CC rom/2d/aet_gam_skin148.bin 2389C7AD rom/2d/aet_gam_skin149.bin 9DC8441F rom/2d/aet_gam_skin150.bin 4BBB31D3 rom/2d/aet_gam_skin151.bin 1C1ED80A rom/2d/aet_gam_skin152.bin B60214CF rom/2d/aet_gam_skin153.bin A39481C7 rom/2d/aet_gam_skin154.bin C93E0CD3 rom/2d/aet_gam_skin155.bin 9E9BE50A rom/2d/aet_gam_skin156.bin 7B592CA8 rom/2d/aet_gam_skin157.bin F46D7A53 rom/2d/aet_gam_skin159.bin 21FAE81F rom/2d/aet_gam_skin160.bin 77253631 rom/2d/aet_gam_skin161.bin 82905408 rom/2d/aet_gam_skin162.bin E3BCE134 rom/2d/aet_gam_skin163.bin B41908ED rom/2d/aet_gam_skin164.bin 6CF47EFF rom/2d/aet_gam_skin165.bin 06110D47 rom/2d/aet_gam_skin166.bin 5CEFBCCC rom/2d/aet_gam_skin167.bin 0B4A5515 rom/2d/aet_gam_skin168.bin E33C7FAC rom/2d/aet_gam_skin169.bin D773E190 rom/2d/aet_gam_skin170.bin 2879EF0B rom/2d/aet_gam_skin171.bin A64700CB rom/2d/aet_gam_skin172.bin 77D041F7 rom/2d/aet_gam_skin173.bin 090CD379 rom/2d/aet_gam_skin174.bin 32CF5FAF rom/2d/aet_gam_skin176.bin 5839C0F6 rom/2d/aet_gam_skin177.bin 26E55278 rom/2d/aet_gam_skin178.bin 91881848 rom/2d/aet_gam_skin179.bin 96332EA8 rom/2d/aet_gam_skin180.bin E3A00736 rom/2d/aet_gam_skin181.bin DBF43F1E rom/2d/aet_gam_skin182.bin 02DAACB5 rom/2d/aet_gam_skin183.bin 7C063E3B rom/2d/aet_gam_skin184.bin 47C5B2ED rom/2d/aet_gam_skin185.bin C9FB5D2D rom/2d/aet_gam_skin186.bin 186C1C11 rom/2d/aet_gam_skin187.bin 59168BCC rom/2d/aet_gam_skin188.bin E1705DA3 rom/2d/aet_gam_skin189.bin 6E440B58 rom/2d/aet_gam_skin190.bin B8377E94 rom/2d/aet_gam_skin191.bin EF92974D rom/2d/aet_gam_skin193.bin B03B39B1 rom/2d/aet_gam_skin194.bin A281CE30 rom/2d/aet_gam_skin195.bin F52427E9 rom/2d/aet_gam_skin196.bin 1BF0A7EB rom/2d/aet_gam_skin197.bin 7181C6B3 rom/2d/aet_gam_skin198.bin 42909FCE rom/2d/aet_gam_skin199.bin 15357617 rom/2d/aet_gam_skin200.bin 7ED2A040 rom/2d/aet_gam_skin201.bin 000E32CE rom/2d/aet_gam_skin202.bin 7389F812 rom/2d/aet_gam_skin203.bin FDB717D2 rom/2d/aet_gam_skin204.bin 0EA52218 rom/2d/aet_gam_skin205.bin 2171F566 rom/2d/aet_gam_skin206.bin 03FE7A4A rom/2d/aet_gam_skin207.bin 7ED85B9A rom/2d/aet_gam_skin208.bin 849B1EA8 rom/2d/aet_gam_skin210.bin 120098DC rom/2d/aet_gam_skin211.bin 9D34CE27 rom/2d/aet_gam_skin212.bin 6D0DC1B5 rom/2d/aet_gam_skin213.bin 3AA8286C rom/2d/aet_gam_skin214.bin D8F0A2A3 rom/2d/aet_gam_skin215.bin 2D45C09A rom/2d/aet_gam_skin216.bin 77BB7111 rom/2d/aet_gam_skin217.bin 201E98C8 rom/2d/aet_gam_skin218.bin 687B62CE rom/2d/aet_gam_skin219.bin E4AC0313 rom/2d/aet_gam_skin220.bin 88C621E0 rom/2d/aet_gam_skin221.bin E2235258 rom/2d/aet_gam_skin222.bin B8DDE3D3 rom/2d/aet_gam_skin223.bin EF780A0A rom/2d/aet_gam_skin224.bin 0D2080C5 rom/2d/aet_gam_skin225.bin F895E2FC rom/2d/aet_gam_skin227.bin 4EEF2D66 rom/2d/aet_gam_skin228.bin 8A55FC55 rom/2d/aet_gam_skin229.bin 77594CFB rom/2d/aet_gam_skin230.bin A12A3937 rom/2d/aet_gam_skin231.bin F68FD0EE rom/2d/aet_gam_skin232.bin 5C931C2B rom/2d/aet_gam_skin233.bin A9267E12 rom/2d/aet_gam_skin234.bin BB9C8993 rom/2d/aet_gam_skin235.bin EC39604A rom/2d/aet_gam_skin236.bin 7C905052 rom/2d/aet_gam_skin237.bin 01879BB8 rom/2d/aet_gam_skin238.bin 36200621 rom/2d/aet_gam_skin239.bin D6C22F75 rom/2d/aet_gam_skin240.bin 74EAAC35 rom/2d/aet_gam_skin241.bin C652758F rom/2d/aet_gam_skin242.bin 6E5FF8DC rom/2d/aet_gam_skin244.bin 14D3C19D rom/2d/aet_gam_skin245.bin A66B1827 rom/2d/aet_gam_skin246.bin 0E669574 rom/2d/aet_gam_skin247.bin 42384B55 rom/2d/aet_gam_skin248.bin B87B0E67 rom/2d/aet_gam_skin249.bin C55D2FB7 rom/2d/aet_gam_skin250.bin 6B5F64DC rom/2d/aet_gam_skin251.bin 448BB3A2 rom/2d/aet_gam_skin252.bin 66043C8E rom/2d/aet_gam_skin253.bin BEC7F002 rom/2d/aet_gam_skin254.bin E9B75E96 rom/2d/aet_gam_skin255.bin C00AEAED rom/2d/aet_gam_skin256.bin E4EC06C4 rom/2d/aet_gam_skin257.bin 9FA34411 rom/2d/aet_gam_skin258.bin F333BEDF rom/2d/aet_gam_skin259.bin DA8E0AA4 rom/2d/aet_gam_pv731.bin FC604D55 rom/2d/aet_gam_skin005.bin E0B4B103 rom/2d/aet_gam_skin022.bin E000DD02 rom/2d/aet_gam_skin039.bin B589C1F5 rom/2d/aet_gam_skin056.bin CB9B6677 rom/2d/aet_gam_skin073.bin 5A8E56BF rom/2d/aet_gam_skin090.bin 318006CB rom/2d/aet_gam_skin107.bin 83246DE4 rom/2d/aet_gam_skin124.bin 7F96FF56 rom/2d/aet_gam_skin141.bin 6BBD9051 rom/2d/aet_gam_skin158.bin 765F01C6 rom/2d/aet_gam_skin175.bin F32FB508 rom/2d/aet_gam_skin192.bin 458E5B88 rom/2d/aet_gam_skin209.bin 7B4F9539 rom/2d/aet_gam_skin226.bin A26B5377 rom/2d/aet_gam_skin261.bin 4AD2E413 rom/2d/aet_gam_skin262.bin 685D6B3F rom/2d/aet_gam_skin263.bin 4C27202D rom/2d/aet_gam_skin264.bin 039D5AC2 rom/2d/aet_gam_skin265.bin 2B6B26AA rom/2d/aet_gam_skin266.bin 4B38DD44 rom/2d/aet_gam_skin267.bin 63CEA12C rom/2d/aet_gam_skin268.bin E32F65E3 rom/2d/aet_gam_skin269.bin 9E094433 rom/2d/aet_gam_skin270.bin 300B0F58 rom/2d/aet_gam_skin271.bin 3D8CC0F9 rom/2d/aet_gam_skin272.bin 3D50570A rom/2d/aet_gam_skin273.bin E5939B86 rom/2d/aet_gam_skin274.bin 8F5852A0 rom/2d/aet_gam_skin275.bin A08C85DE rom/2d/aet_gam_skin276.bin A050122D rom/2d/aet_gam_skin278.bin 096EA68E rom/2d/aet_gam_skin279.bin 2AB2B96E rom/2d/aet_gam_skin280.bin 20720541 rom/2d/aet_gam_skin281.bin A579161E rom/2d/aet_gam_skin282.bin A9AD4973 rom/2d/aet_gam_skin283.bin A42A86D2 rom/2d/aet_gam_skin284.bin C2E9876A rom/2d/aet_gam_skin285.bin B0F58FC7 rom/2d/aet_gam_skin286.bin BC21D0AA rom/2d/aet_gam_skin287.bin BDAED795 rom/2d/aet_gam_skin288.bin A1F5BC51 rom/2d/aet_gam_skin289.bin E2240B60 rom/2d/aet_gam_skin290.bin EAEED3A3 rom/2d/aet_gam_skin291.bin 13537904 rom/2d/aet_gam_skin292.bin 7F8A8EB8 rom/2d/aet_gam_skin293.bin 8064DE9E rom/2d/aet_gam_skin295.bin A2D607CD rom/2d/aet_gam_skin296.bin F828B646 rom/2d/aet_gam_skin297.bin AF8D5F9F rom/2d/aet_gam_skin298.bin FF0E419B rom/2d/aet_gam_skin299.bin 06B3EB3C rom/2d/aet_gam_skin300.bin 66E1C1EA rom/2d/aet_gam_skin301.bin 3D4CE0AD rom/2d/aet_gam_skin302.bin 83BE00F4 rom/2d/aet_gam_skin303.bin ACA5AC98 rom/2d/aet_gam_skin304.bin 90448B58 rom/2d/aet_gam_skin305.bin E9BAB2C0 rom/2d/aet_gam_skin306.bin 751B4A46 rom/2d/aet_gam_skin307.bin 13F6F160 rom/2d/aet_gam_skin308.bin 4B45843A rom/2d/aet_gam_skin309.bin 1CE06DE3 rom/2d/aet_gam_skin310.bin 3A716561 rom/2d/aet_gam_skin312.bin 953AB6D3 rom/2d/aet_gam_skin313.bin C29F5F0A rom/2d/aet_gam_skin314.bin 1A722918 rom/2d/aet_gam_skin315.bin 70975AA0 rom/2d/aet_gam_skin316.bin 2A69EB2B rom/2d/aet_gam_skin317.bin 7DCC02F2 rom/2d/aet_gam_skin318.bin 0F1C0429 rom/2d/aet_gam_skin319.bin FAA96610 rom/2d/aet_gam_skin320.bin 5C94C570 rom/2d/aet_gam_skin321.bin 0B312CA9 rom/2d/aet_gam_skin322.bin EEF3E50B rom/2d/aet_gam_skin323.bin 61C7B3F0 rom/2d/aet_gam_skin324.bin 737D4471 rom/2d/aet_gam_skin325.bin 24D8ADA8 rom/2d/aet_gam_skin326.bin 8EC4616D rom/2d/aet_gam_skin327.bin 7B710354 rom/2d/aet_gam_skin329.bin AEE69118 rom/2d/aet_gam_skin330.bin B2C26547 rom/2d/aet_gam_skin331.bin D82716FF rom/2d/aet_gam_skin332.bin 82D9A774 rom/2d/aet_gam_skin333.bin 7B8B05C0 rom/2d/aet_gam_skin334.bin 6931F241 rom/2d/aet_gam_skin335.bin 3E941B98 rom/2d/aet_gam_skin336.bin 3F5FC1E7 rom/2d/aet_gam_skin337.bin 811E4255 rom/2d/aet_gam_skin338.bin 647BCCAD rom/2d/aet_gam_skin339.bin EA45236D rom/2d/aet_gam_skin340.bin 278CDDE2 rom/2d/aet_gam_skin341.bin 59504F6C rom/2d/aet_gam_skin342.bin 2AD785B0 rom/2d/aet_gam_skin343.bin 5F0F3A74 rom/2d/aet_gam_skin344.bin 9EBA43DC rom/2d/aet_gam_skin346.bin 93E11B8E rom/2d/aet_gam_skin347.bin 1DDFF44E rom/2d/aet_gam_skin348.bin 14847F6C rom/2d/aet_gam_skin349.bin 6A58EDE2 rom/2d/aet_gam_skin350.bin 9552E379 rom/2d/aet_gam_skin351.bin 21D9F064 rom/2d/aet_gam_skin352.bin 6F1EA0D9 rom/2d/aet_gam_skin353.bin 11C23257 rom/2d/aet_gam_skin354.bin 2A01BE81 rom/2d/aet_gam_skin355.bin A43F5141 rom/2d/aet_gam_skin356.bin 75A8107D rom/2d/aet_gam_skin357.bin 0B7482F3 rom/2d/aet_gam_skin358.bin A03F8231 rom/2d/aet_gam_skin359.bin 61DF6896 rom/2d/aet_gam_skin360.bin 360A0F83 rom/2d/aet_gam_skin361.bin 48D69D0D rom/2d/aet_gam_skin363.bin B56FB811 rom/2d/aet_gam_skin364.bin 2CBCBF27 rom/2d/aet_gam_skin365.bin 52602DA9 rom/2d/aet_gam_skin366.bin 695698EF rom/2d/aet_gam_skin367.bin 178A0A61 rom/2d/aet_gam_skin368.bin F963D178 rom/2d/aet_gam_skin369.bin 87BF43F6 rom/2d/aet_gam_skin370.bin 78B54D6D rom/2d/aet_gam_skin371.bin F68BA2AD rom/2d/aet_gam_skin372.bin 271CE391 rom/2d/aet_gam_skin373.bin 59C0711F rom/2d/aet_gam_skin374.bin 6203FDC9 rom/2d/aet_gam_skin375.bin 47EA04B3 rom/2d/aet_gam_skin376.bin DD89A404 rom/2d/aet_gam_skin377.bin A355368A rom/2d/aet_gam_skin378.bin 081E3648 rom/2d/aet_gam_skin380.bin 51A37BF6 rom/2d/aet_gam_skin381.bin 2F7FE978 rom/2d/aet_gam_skin382.bin 5CF823A4 rom/2d/aet_gam_skin383.bin E87330B9 rom/2d/aet_gam_skin384.bin EEF0260E rom/2d/aet_gam_skin385.bin A388B533 rom/2d/aet_gam_skin386.bin F97604B8 rom/2d/aet_gam_skin387.bin AED3ED61 rom/2d/aet_gam_skin388.bin E6B61767 rom/2d/aet_gam_skin389.bin 8C946F3B rom/2d/aet_gam_skin390.bin 90B09B64 rom/2d/aet_gam_skin391.bin FA55E8DC rom/2d/aet_gam_skin392.bin 9779BA90 rom/2d/aet_gam_skin393.bin F70EB08E rom/2d/aet_gam_skin394.bin 15563A41 rom/2d/aet_gam_skin395.bin E0E35878 rom/2d/aet_gam_skin397.bin E7B4ACFB rom/2d/aet_gam_skin398.bin DABAAF47 rom/2d/aet_gam_skin399.bin 556C4E03 rom/2d/aet_gam_skin400.bin A1C7E655 rom/2d/aet_gam_skin401.bin F6620F8C rom/2d/aet_gam_skin402.bin 5C7EC349 rom/2d/aet_gam_skin403.bin A9CBA170 rom/2d/aet_gam_skin404.bin BB7156F1 rom/2d/aet_gam_skin405.bin ECD4BF28 rom/2d/aet_gam_skin406.bin 7C7D8F30 rom/2d/aet_gam_skin407.bin 1698FC88 rom/2d/aet_gam_skin408.bin 94AA871D rom/2d/aet_gam_skin409.bin C30F6EC4 rom/2d/aet_gam_skin410.bin 036BE362 rom/2d/aet_gam_skin411.bin F6DE815B rom/2d/aet_gam_skin412.bin AC2030D0 rom/2d/aet_gam_skin414.bin AFB7842E rom/2d/aet_gam_skin415.bin 52BB3480 rom/2d/aet_gam_skin416.bin 0E41E144 rom/2d/aet_gam_skin417.bin 5FE06CD2 rom/2d/aet_gam_skin418.bin 2D306A09 rom/2d/aet_gam_skin419.bin D8850830 rom/2d/aet_gam_skin420.bin E729A267 rom/2d/aet_gam_skin421.bin C104C0D7 rom/2d/aet_gam_skin422.bin 51ADF0CF rom/2d/aet_gam_skin423.bin 3B488377 rom/2d/aet_gam_skin424.bin 3DEB2D54 rom/2d/aet_gam_skin425.bin 7E579D2F rom/2d/aet_gam_skin426.bin D44B51EA rom/2d/aet_gam_skin427.bin 21FE33D3 rom/2d/aet_gam_skin428.bin A3CC4846 rom/2d/aet_gam_skin429.bin F469A19F rom/2d/aet_gam_skin431.bin 000FC76C rom/2d/aet_gam_skin432.bin 5AF176E7 rom/2d/aet_gam_skin433.bin 0B50FB71 rom/2d/aet_gam_skin434.bin EF0C15F1 rom/2d/aet_gam_skin435.bin 1AB977C8 rom/2d/aet_gam_skin436.bin 4047C643 rom/2d/aet_gam_skin437.bin 17E22F9A rom/2d/aet_gam_skin438.bin 5F87D59C rom/2d/aet_gam_skin439.bin 3562A624 rom/2d/aet_gam_skin440.bin 47A746ED rom/2d/aet_gam_skin441.bin 1002AF34 rom/2d/aet_gam_skin442.bin BA1E63F1 rom/2d/aet_gam_skin443.bin 4FAB01C8 rom/2d/aet_gam_skin444.bin 60C796B1 rom/2d/aet_gam_skin445.bin 37627F68 rom/2d/aet_gam_skin446.bin 0B7FC5EF rom/2d/aet_gam_skin448.bin E59C561D rom/2d/aet_gam_skin449.bin 8FEFDF3C rom/2d/aet_gam_skin450.bin F76BE19D rom/2d/aet_gam_skin451.bin E092E735 rom/2d/aet_gam_skin452.bin 77584B08 rom/2d/aet_gam_skin453.bin BF3B49C9 rom/2d/aet_gam_skin454.bin A18976D6 rom/2d/aet_gam_skin455.bin B0563E07 rom/2d/aet_gam_skin456.bin 20FF0E1F rom/2d/aet_gam_skin457.bin 4A1A7DA7 rom/2d/aet_gam_skin458.bin C8280632 rom/2d/aet_gam_skin459.bin D9F74EE3 rom/2d/aet_gam_skin460.bin C95231C5 rom/2d/aet_gam_skin461.bin 3F587124 rom/2d/aet_gam_skin462.bin 65A6C0AF rom/2d/aet_gam_skin463.bin 32032976 rom/2d/aet_gam_skin465.bin 10B1F025 rom/2d/aet_gam_skin466.bin 4A4F41AE rom/2d/aet_gam_skin467.bin 1DEAA877 rom/2d/aet_gam_skin468.bin B1A20DE7 rom/2d/aet_gam_skin469.bin 44176FDE rom/2d/aet_gam_skin470.bin 92641A12 rom/2d/aet_gam_skin471.bin C5C1F3CB rom/2d/aet_gam_skin472.bin 5568C3D3 rom/2d/aet_gam_skin473.bin 3F8DB06B rom/2d/aet_gam_skin474.bin 2D3747EA rom/2d/aet_gam_skin475.bin A40A0D78 rom/2d/aet_gam_skin476.bin 0E16C1BD rom/2d/aet_gam_skin477.bin FBA3A384 rom/2d/aet_gam_skin478.bin 7991D811 rom/2d/aet_gam_skin479.bin 2E3431C8 rom/2d/aet_gam_skin480.bin 3C0ADF5D rom/2d/aet_gam_skin482.bin 733D5142 rom/2d/aet_gam_skin483.bin ECDA4B7E rom/2d/aet_gam_skin484.bin FE60BCFF rom/2d/aet_gam_skin485.bin A9C55526 rom/2d/aet_gam_skin486.bin 03D999E3 rom/2d/aet_gam_skin487.bin F66CFBDA rom/2d/aet_gam_skin488.bin 745E804F rom/2d/aet_gam_skin489.bin DB150030 rom/2d/aet_gam_skin490.bin C731F46F rom/2d/aet_gam_skin491.bin ADD487D7 rom/2d/aet_gam_skin492.bin F72A365C rom/2d/aet_gam_skin493.bin A08FDF85 rom/2d/aet_gam_skin494.bin 42D7554A rom/2d/aet_gam_skin495.bin B7623773 rom/2d/aet_gam_skin496.bin 2EA0EBE9 rom/2d/aet_gam_skin497.bin 79050230 rom/2d/aet_gam_skin499.bin CB3F5777 rom/2d/aet_gam_skin500.bin 8536ADE0 rom/2d/aet_gam_skin501.bin D2934439 rom/2d/aet_gam_skin502.bin 788F88FC rom/2d/aet_gam_skin503.bin DCE630B7 rom/2d/aet_gam_skin504.bin CE5CC736 rom/2d/aet_gam_skin505.bin 99F92EEF rom/2d/aet_gam_skin506.bin 09501EF7 rom/2d/aet_gam_skin507.bin 63B56D4F rom/2d/aet_gam_skin508.bin E18716DA rom/2d/aet_gam_skin509.bin B622FF03 rom/2d/aet_gam_skin510.bin E1DEB885 rom/2d/aet_gam_skin511.bin CBF1DED5 rom/2d/aet_gam_skin512.bin 49DFA154 rom/2d/aet_gam_skin513.bin BC6AC36D rom/2d/aet_gam_skin514.bin AED034EC rom/2d/aet_gam_skin516.bin F660E7E3 rom/2d/aet_gam_skin517.bin 6987FDDF rom/2d/aet_gam_skin518.bin EBB5864A rom/2d/aet_gam_skin519.bin BC106F93 rom/2d/aet_gam_skin520.bin EACFB1BD rom/2d/aet_gam_skin521.bin 15767F55 rom/2d/aet_gam_skin522.bin 4F88CEDE rom/2d/aet_gam_skin523.bin 182D2707 rom/2d/aet_gam_skin524.bin C0C05115 rom/2d/aet_gam_skin525.bin AA2522AD rom/2d/aet_gam_skin526.bin F0DB9326 rom/2d/aet_gam_skin527.bin A77E7AFF rom/2d/aet_gam_skin528.bin D5AE7C24 rom/2d/aet_gam_skin529.bin 201B1E1D rom/2d/aet_gam_skin530.bin 838ECA79 rom/2d/aet_gam_skin531.bin D42B23A0 rom/2d/aet_gam_skin260.bin 02ABF466 rom/2d/aet_gam_skin277.bin FF252B22 rom/2d/aet_gam_skin294.bin 03B98177 rom/2d/aet_gam_skin311.bin CFC40758 rom/2d/aet_gam_skin328.bin F94378C1 rom/2d/aet_gam_skin345.bin E066D152 rom/2d/aet_gam_skin362.bin 3B5157D1 rom/2d/aet_gam_skin379.bin 8620D988 rom/2d/aet_gam_skin396.bin B0114522 rom/2d/aet_gam_skin413.bin FB85D909 rom/2d/aet_gam_skin430.bin 8F3B9197 rom/2d/aet_gam_skin447.bin 5A784D70 rom/2d/aet_gam_skin464.bin 9F85A6DE rom/2d/aet_gam_skin481.bin 9ADDEEB0 rom/2d/aet_gam_skin498.bin 440B018C rom/2d/aet_gam_skin533.bin BEDDBCF9 rom/2d/aet_gam_skin534.bin AC674B78 rom/2d/aet_gam_skin535.bin FBC2A2A1 rom/2d/aet_gam_skin536.bin 51DE6E64 rom/2d/aet_gam_skin537.bin A46B0C5D rom/2d/aet_gam_skin538.bin 5DF5B638 rom/2d/aet_gam_skin539.bin 0A505FE1 rom/2d/aet_gam_skin540.bin 689A8ECF rom/2d/aet_gam_skin541.bin B9A0F78D rom/2d/aet_gam_skin542.bin 2909C795 rom/2d/aet_gam_skin543.bin 43ECB42D rom/2d/aet_gam_skin544.bin 515643AC rom/2d/aet_gam_skin545.bin 06F3AA75 rom/2d/aet_gam_skin546.bin ACEF66B0 rom/2d/aet_gam_skin547.bin 648C6471 rom/2d/aet_gam_skin548.bin E6BE1FE4 rom/2d/aet_gam_skin550.bin 328308AC rom/2d/aet_gam_skin551.bin AD641290 rom/2d/aet_gam_skin552.bin F79AA31B rom/2d/aet_gam_skin553.bin A03F4AC2 rom/2d/aet_gam_skin554.bin 4267C00D rom/2d/aet_gam_skin555.bin 7A747E64 rom/2d/aet_gam_skin556.bin D279F337 rom/2d/aet_gam_skin557.bin 329BDA63 rom/2d/aet_gam_skin558.bin 05699851 rom/2d/aet_gam_skin559.bin 1364A037 rom/2d/aet_gam_skin560.bin E5F312E6 rom/2d/aet_gam_skin561.bin 05113BB2 rom/2d/aet_gam_skin562.bin AD2FFC78 rom/2d/aet_gam_skin563.bin 1F9725C2 rom/2d/aet_gam_skin564.bin 742C5AE8 rom/2d/aet_gam_skin565.bin 94CE73BC rom/2d/aet_gam_skin567.bin D97C3897 rom/2d/aet_gam_skin568.bin EEDBA50E rom/2d/aet_gam_skin569.bin 0E398C5A rom/2d/aet_gam_skin570.bin F98E384B rom/2d/aet_gam_skin571.bin 6DC91FDF rom/2d/aet_gam_skin572.bin C5F7D815 rom/2d/aet_gam_skin573.bin 774F01AF rom/2d/aet_gam_skin574.bin 53BE3211 rom/2d/aet_gam_skin575.bin 041BDBC8 rom/2d/aet_gam_skin576.bin 94B2EBD0 rom/2d/aet_gam_skin577.bin FE579868 rom/2d/aet_gam_skin578.bin 7C65E3FD rom/2d/aet_gam_skin579.bin 2BC00A24 rom/2d/aet_gam_skin580.bin 87C825A3 rom/2d/aet_gam_skin581.bin 727D479A rom/2d/aet_gam_skin582.bin 2883F611 rom/2d/aet_gam_skin584.bin 347FAB8A rom/2d/aet_gam_skin585.bin AB98B1B6 rom/2d/aet_gam_skin586.bin F166003D rom/2d/aet_gam_skin587.bin A6C3E9E4 rom/2d/aet_gam_skin588.bin D413EF3F rom/2d/aet_gam_skin589.bin 21A68D06 rom/2d/aet_gam_skin590.bin F7D5F8CA rom/2d/aet_gam_skin591.bin A0701113 rom/2d/aet_gam_skin592.bin DE62A038 rom/2d/aet_gam_skin593.bin B487D380 rom/2d/aet_gam_skin594.bin A63D2401 rom/2d/aet_gam_skin595.bin F198CDD8 rom/2d/aet_gam_skin596.bin 5B84011D rom/2d/aet_gam_skin597.bin AE316324 rom/2d/aet_gam_skin598.bin 2C0318B1 rom/2d/aet_gam_skin599.bin 7BA6F168 rom/2d/aet_gam_skin601.bin A20EE822 rom/2d/aet_gam_skin602.bin 94A1C04B rom/2d/aet_gam_skin603.bin 1B9596B0 rom/2d/aet_gam_skin604.bin 092F6131 rom/2d/aet_gam_skin605.bin 5E8A88E8 rom/2d/aet_gam_skin606.bin F496442D rom/2d/aet_gam_skin607.bin 01232614 rom/2d/aet_gam_skin608.bin 83115D81 rom/2d/aet_gam_skin609.bin D4B4B458 rom/2d/aet_gam_skin610.bin C8904007 rom/2d/aet_gam_skin611.bin A27533BF rom/2d/aet_gam_skin612.bin 20174530 rom/2d/aet_gam_skin613.bin 77B2ACE9 rom/2d/aet_gam_skin614.bin 95EA2626 rom/2d/aet_gam_skin615.bin 605F441F rom/2d/aet_gam_skin616.bin 3AA1F594 rom/2d/aet_gam_skin618.bin BADDEC85 rom/2d/aet_gam_skin619.bin FBA255F2 rom/2d/aet_gam_skin620.bin 5D9FF692 rom/2d/aet_gam_skin621.bin 0A3A1F4B rom/2d/aet_gam_skin622.bin A026D38E rom/2d/aet_gam_skin623.bin 5593B1B7 rom/2d/aet_gam_skin624.bin 47294636 rom/2d/aet_gam_skin625.bin 108CAFEF rom/2d/aet_gam_skin626.bin C05B5AB0 rom/2d/aet_gam_skin627.bin ECC48800 rom/2d/aet_gam_skin628.bin 6EF6F395 rom/2d/aet_gam_skin629.bin 39531A4C rom/2d/aet_gam_skin630.bin 6EAF5DCA rom/2d/aet_gam_skin631.bin 44803B9A rom/2d/aet_gam_skin632.bin EE9CF75F rom/2d/aet_gam_skin633.bin 1B299566 rom/2d/aet_gam_skin635.bin CADD9E3B rom/2d/aet_gam_skin636.bin 2F1F5799 rom/2d/aet_gam_skin637.bin A02B0162 rom/2d/aet_gam_skin638.bin 22197AF7 rom/2d/aet_gam_skin639.bin 75BC932E rom/2d/aet_gam_skin640.bin C3FEE058 rom/2d/aet_gam_skin641.bin 7A3C5060 rom/2d/aet_gam_skin642.bin 20C2E1EB rom/2d/aet_gam_skin643.bin 77670832 rom/2d/aet_gam_skin644.bin AF8A7E20 rom/2d/aet_gam_skin645.bin C56F0D98 rom/2d/aet_gam_skin646.bin 9F91BC13 rom/2d/aet_gam_skin647.bin C83455CA rom/2d/aet_gam_skin648.bin A74E84BA rom/2d/aet_gam_skin649.bin 4F513128 rom/2d/aet_gam_skin650.bin 992244E4 rom/2d/aet_gam_skin652.bin C19297EB rom/2d/aet_gam_skin653.bin 5E758DD7 rom/2d/aet_gam_skin654.bin 4CCF7A56 rom/2d/aet_gam_skin655.bin 1B6A938F rom/2d/aet_gam_skin656.bin B1765F4A rom/2d/aet_gam_skin657.bin 44C33D73 rom/2d/aet_gam_skin658.bin C6F146E6 rom/2d/aet_gam_skin659.bin 9154AF3F rom/2d/aet_gam_skin660.bin 1303D349 rom/2d/aet_gam_skin661.bin C239AA0B rom/2d/aet_gam_skin662.bin 52909A13 rom/2d/aet_gam_skin663.bin 3875E9AB rom/2d/aet_gam_skin664.bin 2ACF1E2A rom/2d/aet_gam_skin665.bin 7D6AF7F3 rom/2d/aet_gam_skin666.bin D7763B36 rom/2d/aet_gam_skin667.bin 22C3590F rom/2d/aet_gam_skin669.bin C36B40DC rom/2d/aet_gam_skin670.bin EFBBAB87 rom/2d/aet_gam_skin671.bin 89CD921E rom/2d/aet_gam_skin672.bin 01A34840 rom/2d/aet_gam_skin673.bin 8496CA4C rom/2d/aet_gam_skin674.bin B856E3C8 rom/2d/aet_gam_skin675.bin 937B22BA rom/2d/aet_gam_skin676.bin C9859331 rom/2d/aet_gam_skin677.bin 9E207AE8 rom/2d/aet_gam_skin678.bin 04D5EB3B rom/2d/aet_gam_skin679.bin FCDE3611 rom/2d/aet_gam_skin680.bin B8C4A72F rom/2d/aet_gam_skin681.bin 68251FEA rom/2d/aet_gam_skin682.bin 72F43FEE rom/2d/aet_gam_skin683.bin BD138451 rom/2d/aet_gam_skin684.bin 73AC4E4D rom/2d/aet_gam_skin686.bin 9214C369 rom/2d/aet_gam_skin687.bin C69321B9 rom/2d/aet_gam_skin688.bin 62AC5CD2 rom/2d/aet_gam_skin689.bin E439B04A rom/2d/aet_gam_skin690.bin 4D698247 rom/2d/aet_gam_skin691.bin 19BD04B1 rom/2d/aet_gam_skin692.bin 360F11E6 rom/2d/aet_gam_skin693.bin 42A6469A rom/2d/aet_gam_skin694.bin A13FC014 rom/2d/aet_gam_skin695.bin 4E8A99BB rom/2d/aet_gam_skin696.bin A524750B rom/2d/aet_gam_skin697.bin 4A912CA4 rom/2d/aet_gam_skin698.bin 42C414EE rom/2d/aet_gam_skin699.bin AD714D41 rom/2d/aet_gam_skin700.bin 756536B5 rom/2d/aet_gam_skin701.bin 74D58C38 rom/2d/aet_gam_skin703.bin 4E26A389 rom/2d/aet_gam_skin704.bin B818AC9D rom/2d/aet_gam_skin705.bin DCDFF5A8 rom/2d/aet_gam_skin706.bin 03FC6A95 rom/2d/aet_gam_skin707.bin 8B5CA5D5 rom/2d/aet_gam_skin708.bin AD2D3AF8 rom/2d/aet_gam_skin709.bin 258DF5B8 rom/2d/aet_gam_skin710.bin 127CC176 rom/2d/aet_gam_skin711.bin 3558E246 rom/2d/aet_gam_skin712.bin C74A5ACD rom/2d/aet_gam_skin713.bin 4FEA958D rom/2d/aet_gam_skin714.bin D9142814 rom/2d/aet_gam_skin715.bin 7A48D585 rom/2d/aet_gam_skin716.bin B6566BFA rom/2d/aet_gam_skin717.bin 3EF6A4BA rom/2d/aet_gam_skin718.bin 5FDC15F3 rom/2d/aet_gam_skin720.bin 718600C1 rom/2d/aet_gam_skin721.bin F926CF81 rom/2d/aet_gam_skin722.bin 14327470 rom/2d/aet_gam_skin723.bin 64EE32E2 rom/2d/aet_gam_skin724.bin AF02871D rom/2d/aet_gam_skin725.bin 27A2485D rom/2d/aet_gam_skin726.bin CAB6F3AC rom/2d/aet_gam_skin727.bin ED92D09C rom/2d/aet_gam_skin728.bin A94C0E6F rom/2d/aet_gam_skin729.bin 6E6C0D93 rom/2d/aet_gam_skin730.bin C53140D8 rom/2d/aet_gam_skin731.bin 918B0A1B rom/2d/aet_gam_skin732.bin 2B5DC7D2 rom/2d/aet_gam_skin733.bin 6DE631CD rom/2d/aet_gam_skin734.bin 482255AB rom/2d/aet_gam_skin735.bin A8C729C3 rom/2d/aet_gam_skin737.bin 045DF73C rom/2d/aet_gam_skin738.bin B5E78C4D rom/2d/aet_key_input.bin 412AC6F6 rom/2d/aet_key_pass.bin A91ABBA8 rom/2d/aet_key_svol.bin DE7F571C rom/2d/aet_key_win.bin FA746366 rom/2d/aet_sel_belt.bin 6C18ECF9 rom/2d/aet_sel_camp.bin F19129A3 rom/2d/aet_sel_camp02.bin 16B7E02C rom/2d/aet_sel_card.bin 4E59ECF8 rom/2d/aet_sel_cardbg.bin 89300B2F rom/2d/aet_sel_cardinfo.bin 82D22242 rom/2d/aet_sel_chlle.bin 83C0A2DF rom/2d/aet_sel_cmn.bin FAAF83E1 rom/2d/aet_sel_credit.bin E595BD64 rom/2d/aet_sel_ctst.bin 02963C34 rom/2d/aet_sel_module.bin A926F5DB rom/2d/aet_sel_pleff.bin 01AEFCC4 rom/2d/aet_sel_print.bin EAD97CCB rom/2d/aet_sel_procedure.bin 9FED77BC rom/2d/aet_sel_pv.bin DD3699BB rom/2d/aet_sel_qst.bin C51EDE22 rom/2d/aet_sel_result.bin 3DDEDFE1 rom/2d/aet_sel_sc.bin 5C88B3CD rom/2d/aet_sel_stamp.bin EB5BAFB3 rom/2d/aet_sel_ticket.bin 4AC2DA60 rom/2d/aet_sel_vaccess.bin BA76F087 rom/2d/aet_sel_watch.bin 7DD6BA35 rom/2d/spr_adv_cmn.farc 63AC4E17 rom/2d/spr_adv_nobl.farc B7815633 rom/2d/spr_adv_rnk.farc 8461A29F rom/2d/spr_adv_scrnk.farc 7A8840CF rom/2d/spr_clt_crd0001.farc FD13378F rom/2d/spr_clt_crd0002.farc 6EF16A55 rom/2d/spr_clt_crd0003.farc EFA6A229 rom/2d/spr_clt_crd0004.farc 18E61B83 rom/2d/spr_clt_crd0005.farc 88EB5991 rom/2d/spr_clt_crd0006.farc 87FCB3BE rom/2d/spr_clt_crd0007.farc 7C589481 rom/2d/spr_clt_crd0008.farc A0D66982 rom/2d/spr_clt_crd0009.farc C2F3B864 rom/2d/spr_clt_crd0010.farc 4FA0625C rom/2d/spr_clt_crd0011.farc 564BFA88 rom/2d/spr_clt_crd0012.farc 3D23E87B rom/2d/spr_clt_crd0013.farc 4119B616 rom/2d/spr_clt_crd0014.farc 96DAB27B rom/2d/spr_clt_crd0015.farc EDDD981D rom/2d/spr_clt_crd0017.farc 7FC26192 rom/2d/spr_clt_crd0018.farc A45C2651 rom/2d/spr_clt_crd0019.farc 16308EEF rom/2d/spr_clt_crd0020.farc E20646DF rom/2d/spr_clt_crd0021.farc A6410D68 rom/2d/spr_clt_crd0022.farc 9C3F2945 rom/2d/spr_clt_crd0023.farc ED2E4FD2 rom/2d/spr_clt_crd0024.farc 5F6BF9F4 rom/2d/spr_clt_crd0025.farc 8D08B83F rom/2d/spr_clt_crd0026.farc 57E4CC14 rom/2d/spr_clt_crd0027.farc 5B426303 rom/2d/spr_clt_crd0028.farc EDF371C4 rom/2d/spr_clt_crd0029.farc A9A9E428 rom/2d/spr_clt_crd0030.farc 182CE2FC rom/2d/spr_clt_crd0031.farc B823AAA6 rom/2d/aet_gam_skin532.bin 31E9EA02 rom/2d/aet_gam_skin549.bin B11BF63D rom/2d/aet_gam_skin566.bin 3C5B0B20 rom/2d/aet_gam_skin583.bin 732ED756 rom/2d/aet_gam_skin600.bin 5E6FA905 rom/2d/aet_gam_skin617.bin 6D041C4D rom/2d/aet_gam_skin634.bin 9D7877E2 rom/2d/aet_gam_skin651.bin CE87AD3D rom/2d/aet_gam_skin668.bin A0F1229A rom/2d/aet_gam_skin685.bin A34DF688 rom/2d/aet_gam_skin702.bin A193FA26 rom/2d/aet_gam_skin719.bin 78F836C3 rom/2d/aet_gam_skin736.bin 21CE8420 rom/2d/aet_sel_ctstinfo.bin 5906CD1C rom/2d/spr_clt_crd0000.farc 9B8C0B11 rom/2d/aet_gam_pv631.bin 7ECFFA92 rom/2d/aet_gam_skin243.bin 7F5BF42E rom/2d/aet_gam_skin515.bin F975DD35 rom/2d/spr_clt_crd0016.farc 2A9666F4 rom/2d/spr_clt_crd0256.farc 219CEB01 rom/2d/spr_clt_crd0496.farc A6C4BB9C rom/2d/spr_cmnitm_thmb126.farc 92D22208 rom/2d/spr_edit_d2pvback124.farc F3D207D5 rom/2d/spr_edit_pvback120.farc 32405428 rom/2d/spr_gam_pv250.farc 29A2CCEA rom/2d/spr_gam_skin140.farc 63AB73A4 rom/2d/spr_gam_skin380.farc CC6B697A rom/2d/spr_gam_skin620.farc 9687CAB8 rom/2d/spr_sel_md106cmn.farc 2A0ADFEC rom/2d/spr_sel_md387cmn.farc 90C69099 rom/2d/spr_clt_crd0033.farc 8BE4CFBB rom/2d/spr_clt_crd0034.farc 2F88B7F4 rom/2d/spr_clt_crd0035.farc EEFABFBC rom/2d/spr_clt_crd0036.farc F1E1C8B5 rom/2d/spr_clt_crd0037.farc BCA53BA5 rom/2d/spr_clt_crd0038.farc 4BCDD699 rom/2d/spr_clt_crd0039.farc E7C9781E rom/2d/spr_clt_crd0040.farc ECCB31F1 rom/2d/spr_clt_crd0041.farc 0671C1BA rom/2d/spr_clt_crd0042.farc 41A4EA4F rom/2d/spr_clt_crd0043.farc 8386D7A1 rom/2d/spr_clt_crd0044.farc 443AE836 rom/2d/spr_clt_crd0045.farc 3C4F3C9E rom/2d/spr_clt_crd0046.farc C2C19F33 rom/2d/spr_clt_crd0047.farc 8AE4D281 rom/2d/spr_clt_crd0049.farc 16CA7CCD rom/2d/spr_clt_crd0050.farc 9755AD5C rom/2d/spr_clt_crd0051.farc 42432B61 rom/2d/spr_clt_crd0052.farc B09E1FD6 rom/2d/spr_clt_crd0053.farc 728BAE10 rom/2d/spr_clt_crd0054.farc CBEAFAF5 rom/2d/spr_clt_crd0055.farc 39630AB6 rom/2d/spr_clt_crd0056.farc 9AA88312 rom/2d/spr_clt_crd0057.farc 82A11F35 rom/2d/spr_clt_crd0058.farc 1B3C5784 rom/2d/spr_clt_crd0059.farc 917DFF00 rom/2d/spr_clt_crd0060.farc 41286463 rom/2d/spr_clt_crd0061.farc B32BE4DC rom/2d/spr_clt_crd0062.farc DE8BB496 rom/2d/spr_clt_crd0063.farc 032FF2E4 rom/2d/spr_clt_crd0065.farc 8DB1F93E rom/2d/spr_clt_crd0066.farc 12130F6E rom/2d/spr_clt_crd0067.farc CC557569 rom/2d/spr_clt_crd0068.farc 813BB39E rom/2d/spr_clt_crd0069.farc 77ADAFE2 rom/2d/spr_clt_crd0070.farc 7724F616 rom/2d/spr_clt_crd0071.farc C3D0D87D rom/2d/spr_clt_crd0072.farc 6055ECF1 rom/2d/spr_clt_crd0073.farc 2FD22E5D rom/2d/spr_clt_crd0074.farc D6FEC042 rom/2d/spr_clt_crd0075.farc 0D673BE2 rom/2d/spr_clt_crd0076.farc 5741D73E rom/2d/spr_clt_crd0077.farc ACD9924E rom/2d/spr_clt_crd0078.farc 1F41DC88 rom/2d/spr_clt_crd0079.farc 66D4E9A4 rom/2d/spr_clt_crd0081.farc 95EAE737 rom/2d/spr_clt_crd0082.farc 2F634713 rom/2d/spr_clt_crd0083.farc 40BCDB13 rom/2d/spr_clt_crd0084.farc BC796B88 rom/2d/spr_clt_crd0085.farc ECE4A103 rom/2d/spr_clt_crd0086.farc 8E12F327 rom/2d/spr_clt_crd0087.farc E8151174 rom/2d/spr_clt_crd0088.farc 7CFD4768 rom/2d/spr_clt_crd0089.farc D7D8A038 rom/2d/spr_clt_crd0090.farc FB7F4BB6 rom/2d/spr_clt_crd0091.farc 3CCAACB8 rom/2d/spr_clt_crd0092.farc 50D66B02 rom/2d/spr_clt_crd0093.farc 345BE5B8 rom/2d/spr_clt_crd0094.farc 69FEC7FE rom/2d/spr_clt_crd0095.farc EAA6A756 rom/2d/spr_clt_crd0097.farc BE5C8156 rom/2d/spr_clt_crd0098.farc C6C5EF86 rom/2d/spr_clt_crd0099.farc 51A4F68A rom/2d/spr_clt_crd0100.farc CA32F65F rom/2d/spr_clt_crd0101.farc 82E75E5E rom/2d/spr_clt_crd0102.farc 376CC02D rom/2d/spr_clt_crd0103.farc 5F02EB92 rom/2d/spr_clt_crd0104.farc 1ED0BEDA rom/2d/spr_clt_crd0105.farc E5247815 rom/2d/spr_clt_crd0106.farc 2F67D13E rom/2d/spr_clt_crd0107.farc 745E4376 rom/2d/spr_clt_crd0108.farc 30E478DB rom/2d/spr_clt_crd0109.farc 086AE4E3 rom/2d/spr_clt_crd0110.farc D9ACEFB6 rom/2d/spr_clt_crd0111.farc 8C3B8B1F rom/2d/spr_clt_crd0113.farc 196D3031 rom/2d/spr_clt_crd0114.farc 0D7BC41B rom/2d/spr_clt_crd0115.farc 15A2B3E0 rom/2d/spr_clt_crd0116.farc 31F778A7 rom/2d/spr_clt_crd0117.farc 2EDECBFF rom/2d/spr_clt_crd0118.farc F10F5FDE rom/2d/spr_clt_crd0119.farc 45676125 rom/2d/spr_clt_crd0120.farc E10C92DF rom/2d/spr_clt_crd0121.farc 424B780B rom/2d/spr_clt_crd0122.farc B94E1B6E rom/2d/spr_clt_crd0123.farc 9F01DACE rom/2d/spr_clt_crd0124.farc D811F3C7 rom/2d/spr_clt_crd0125.farc F6DDDF7A rom/2d/spr_clt_crd0126.farc 1FB318D5 rom/2d/spr_clt_crd0127.farc B3A0FDBE rom/2d/spr_clt_crd0129.farc BA86CFE3 rom/2d/spr_clt_crd0130.farc F2D6544E rom/2d/spr_clt_crd0131.farc B095FBFB rom/2d/spr_clt_crd0132.farc E449660F rom/2d/spr_clt_crd0133.farc 3FFC3174 rom/2d/spr_clt_crd0134.farc C21A3E56 rom/2d/spr_clt_crd0135.farc E909B7DE rom/2d/spr_clt_crd0136.farc E7BCEAFA rom/2d/spr_clt_crd0137.farc 84A6DB04 rom/2d/spr_clt_crd0138.farc BC382F28 rom/2d/spr_clt_crd0139.farc 70B20385 rom/2d/spr_clt_crd0140.farc 80FD1790 rom/2d/spr_clt_crd0141.farc C69A3C27 rom/2d/spr_clt_crd0142.farc F6B0062A rom/2d/spr_clt_crd0143.farc 6BA3E949 rom/2d/spr_clt_crd0145.farc 6DEA68ED rom/2d/spr_clt_crd0146.farc 067E4234 rom/2d/spr_clt_crd0147.farc DBA7E919 rom/2d/spr_clt_crd0148.farc DEBF860F rom/2d/spr_clt_crd0149.farc FC3FCCAD rom/2d/spr_clt_crd0150.farc 375AF59E rom/2d/spr_clt_crd0151.farc 29D4A822 rom/2d/spr_clt_crd0152.farc 8268A508 rom/2d/spr_clt_crd0153.farc EC0C683C rom/2d/spr_clt_crd0154.farc 79FEBFB7 rom/2d/spr_clt_crd0155.farc 6EF7DAC2 rom/2d/spr_clt_crd0156.farc DF7B69D8 rom/2d/spr_clt_crd0157.farc 0A21D140 rom/2d/spr_clt_crd0158.farc F661E6BD rom/2d/spr_clt_crd0159.farc 5158B2D3 rom/2d/spr_clt_crd0161.farc 25B771E4 rom/2d/spr_clt_crd0162.farc 0E73B6EE rom/2d/spr_clt_crd0163.farc 996C1DBA rom/2d/spr_clt_crd0164.farc 2EF000E6 rom/2d/spr_clt_crd0165.farc 27FB0C89 rom/2d/spr_clt_crd0166.farc 9E60E390 rom/2d/spr_clt_crd0167.farc 460C2218 rom/2d/spr_clt_crd0168.farc 196117C8 rom/2d/spr_clt_crd0169.farc 9C82DBAA rom/2d/spr_clt_crd0170.farc BB09A2DD rom/2d/spr_clt_crd0171.farc 59371886 rom/2d/spr_clt_crd0172.farc FD3E3E1D rom/2d/spr_clt_crd0173.farc C9A8CCFB rom/2d/spr_clt_crd0174.farc 19637D32 rom/2d/spr_clt_crd0175.farc 395F238F rom/2d/spr_clt_crd0177.farc 25C5D9C9 rom/2d/spr_clt_crd0178.farc 338E9473 rom/2d/spr_clt_crd0179.farc 8CD00722 rom/2d/spr_clt_crd0180.farc 7C4EA866 rom/2d/spr_clt_crd0181.farc 8B7ED769 rom/2d/spr_clt_crd0182.farc 95A2432C rom/2d/spr_clt_crd0183.farc 2263E909 rom/2d/spr_clt_crd0184.farc 80260B3A rom/2d/spr_clt_crd0185.farc 93FCC82E rom/2d/spr_clt_crd0186.farc 1042305E rom/2d/spr_clt_crd0187.farc E9D4F837 rom/2d/spr_clt_crd0188.farc DAE20C88 rom/2d/spr_clt_crd0189.farc 3A28F601 rom/2d/spr_clt_crd0190.farc 06EB92B8 rom/2d/spr_clt_crd0191.farc E0D493E2 rom/2d/spr_clt_crd0193.farc 9A313552 rom/2d/spr_clt_crd0194.farc 72852AAE rom/2d/spr_clt_crd0195.farc 8C30F600 rom/2d/spr_clt_crd0196.farc 870462E9 rom/2d/spr_clt_crd0197.farc CB135E66 rom/2d/spr_clt_crd0198.farc F2A88D76 rom/2d/spr_clt_crd0199.farc 4CC2D71A rom/2d/spr_clt_crd0200.farc 8B442C87 rom/2d/spr_clt_crd0201.farc 29155A59 rom/2d/spr_clt_crd0202.farc 597322FF rom/2d/spr_clt_crd0203.farc 5A573EA4 rom/2d/spr_clt_crd0204.farc 27EDBABE rom/2d/spr_clt_crd0205.farc B0C67A20 rom/2d/spr_clt_crd0206.farc EB4DA998 rom/2d/spr_clt_crd0207.farc 3423245D rom/2d/spr_clt_crd0209.farc 826BABE1 rom/2d/spr_clt_crd0210.farc 81970474 rom/2d/spr_clt_crd0211.farc 5B3224DE rom/2d/spr_clt_crd0212.farc A4A7C17F rom/2d/spr_clt_crd0213.farc 16C93BA8 rom/2d/spr_clt_crd0214.farc CC66E68F rom/2d/spr_clt_crd0215.farc 7B4D5D8A rom/2d/spr_clt_crd0216.farc 064BDF75 rom/2d/spr_clt_crd0217.farc 072A2454 rom/2d/spr_clt_crd0218.farc 5509F2FC rom/2d/spr_clt_crd0219.farc 06862E5E rom/2d/spr_clt_crd0220.farc 86A969DB rom/2d/spr_clt_crd0221.farc 1AAE8454 rom/2d/spr_clt_crd0222.farc A3228293 rom/2d/spr_clt_crd0223.farc 6AEDEB84 rom/2d/spr_clt_crd0225.farc FF850087 rom/2d/spr_clt_crd0226.farc D3278B96 rom/2d/spr_clt_crd0227.farc FB67AA09 rom/2d/spr_clt_crd0228.farc 8B3A6187 rom/2d/spr_clt_crd0229.farc B935DC79 rom/2d/spr_clt_crd0230.farc AA954203 rom/2d/spr_clt_crd0231.farc FA801A35 rom/2d/spr_clt_crd0232.farc AA0D04F7 rom/2d/spr_clt_crd0233.farc B44F1CEF rom/2d/spr_clt_crd0234.farc 79F04BD5 rom/2d/spr_clt_crd0235.farc 5DE246BF rom/2d/spr_clt_crd0236.farc EEAD4FD3 rom/2d/spr_clt_crd0237.farc 3D6823DD rom/2d/spr_clt_crd0238.farc CE1ADDA8 rom/2d/spr_clt_crd0239.farc 25554AF5 rom/2d/spr_clt_crd0241.farc 437BD547 rom/2d/spr_clt_crd0242.farc 7C237E02 rom/2d/spr_clt_crd0243.farc 79A2F0ED rom/2d/spr_clt_crd0244.farc C1D2710C rom/2d/spr_clt_crd0245.farc 3DED9D28 rom/2d/spr_clt_crd0246.farc 4F9CAEC8 rom/2d/spr_clt_crd0247.farc 83B8B189 rom/2d/spr_clt_crd0248.farc 3F3627AC rom/2d/spr_clt_crd0249.farc 69F38F97 rom/2d/spr_clt_crd0250.farc 27FA30E2 rom/2d/spr_clt_crd0251.farc 129718E8 rom/2d/spr_clt_crd0252.farc 9AAAD586 rom/2d/spr_clt_crd0253.farc 02E2A863 rom/2d/spr_clt_crd0254.farc ECF37BA4 rom/2d/spr_clt_crd0255.farc F1220D92 rom/2d/spr_clt_crd0257.farc 18D656B7 rom/2d/spr_clt_crd0258.farc 6E805129 rom/2d/spr_clt_crd0259.farc 69794B8B rom/2d/spr_clt_crd0260.farc 69255A94 rom/2d/spr_clt_crd0261.farc 0471A11D rom/2d/spr_clt_crd0262.farc 6A02B7D3 rom/2d/spr_clt_crd0263.farc 8A31D028 rom/2d/spr_clt_crd0264.farc 653557E8 rom/2d/spr_clt_crd0265.farc BCA807A7 rom/2d/spr_clt_crd0266.farc AE171793 rom/2d/spr_clt_crd0267.farc 32EE2148 rom/2d/spr_clt_crd0268.farc 9CD972FF rom/2d/spr_clt_crd0269.farc 9A338227 rom/2d/spr_clt_crd0270.farc 7017A70E rom/2d/spr_clt_crd0271.farc 47B6DE9A rom/2d/spr_clt_crd0032.farc FEE053F3 rom/2d/spr_clt_crd0048.farc 4047B087 rom/2d/spr_clt_crd0064.farc A4133BC6 rom/2d/spr_clt_crd0080.farc 5415E2F0 rom/2d/spr_clt_crd0096.farc 67D90159 rom/2d/spr_clt_crd0112.farc 9836D155 rom/2d/spr_clt_crd0128.farc 62363338 rom/2d/spr_clt_crd0144.farc 57B704DB rom/2d/spr_clt_crd0160.farc 2726750E rom/2d/spr_clt_crd0176.farc 5ADB239B rom/2d/spr_clt_crd0192.farc 0E1F171A rom/2d/spr_clt_crd0208.farc F590124E rom/2d/spr_clt_crd0224.farc 5E7DE45C rom/2d/spr_clt_crd0240.farc 0D0C7A2F rom/2d/spr_clt_crd0273.farc 0450B058 rom/2d/spr_clt_crd0274.farc B4449148 rom/2d/spr_clt_crd0275.farc 94F4C104 rom/2d/spr_clt_crd0276.farc 85D4E2C5 rom/2d/spr_clt_crd0277.farc 86108771 rom/2d/spr_clt_crd0278.farc CD90B87E rom/2d/spr_clt_crd0279.farc 2F9CB5CD rom/2d/spr_clt_crd0280.farc 9EDCDCCE rom/2d/spr_clt_crd0281.farc 14BFE86A rom/2d/spr_clt_crd0282.farc C4D375BD rom/2d/spr_clt_crd0283.farc D6A2A7D0 rom/2d/spr_clt_crd0284.farc 2B93F3B7 rom/2d/spr_clt_crd0285.farc 32F467A3 rom/2d/spr_clt_crd0286.farc F23AA9AB rom/2d/spr_clt_crd0287.farc 5A584321 rom/2d/spr_clt_crd0289.farc DD2C64FA rom/2d/spr_clt_crd0290.farc 60FAD2DD rom/2d/spr_clt_crd0291.farc 1CBB7F3A rom/2d/spr_clt_crd0292.farc 52AFECBF rom/2d/spr_clt_crd0293.farc 03A98975 rom/2d/spr_clt_crd0294.farc C55C4BEE rom/2d/spr_clt_crd0295.farc 14A7A1DF rom/2d/spr_clt_crd0296.farc C8681046 rom/2d/spr_clt_crd0297.farc F6BF8CC6 rom/2d/spr_clt_crd0298.farc 20118285 rom/2d/spr_clt_crd0299.farc E3BB96FF rom/2d/spr_clt_crd0300.farc 93FBC985 rom/2d/spr_clt_crd0301.farc E584BEA5 rom/2d/spr_clt_crd0302.farc AB41692D rom/2d/spr_clt_crd0303.farc 0A9FA74A rom/2d/spr_clt_crd0305.farc 1F530FF4 rom/2d/spr_clt_crd0306.farc 5186EBF9 rom/2d/spr_clt_crd0307.farc 0116C5F3 rom/2d/spr_clt_crd0308.farc 6D1172A9 rom/2d/spr_clt_crd0309.farc EF8069FD rom/2d/spr_clt_crd0310.farc 756D7C0E rom/2d/spr_clt_crd0311.farc 9AC7A389 rom/2d/spr_clt_crd0312.farc EA40A4CE rom/2d/spr_clt_crd0313.farc 3AAD1A03 rom/2d/spr_clt_crd0314.farc FC84EE7B rom/2d/spr_clt_crd0315.farc AB386A59 rom/2d/spr_clt_crd0316.farc 170BBC21 rom/2d/spr_clt_crd0317.farc 6FF211F1 rom/2d/spr_clt_crd0318.farc 4D836995 rom/2d/spr_clt_crd0319.farc 0A14F28B rom/2d/spr_clt_crd0321.farc 9F8F383B rom/2d/spr_clt_crd0322.farc 21EA6834 rom/2d/spr_clt_crd0323.farc 4534FD28 rom/2d/spr_clt_crd0324.farc EC47137F rom/2d/spr_clt_crd0325.farc 24594AFC rom/2d/spr_clt_crd0326.farc EA36DDB2 rom/2d/spr_clt_crd0327.farc D43FBE13 rom/2d/spr_clt_crd0328.farc CC314573 rom/2d/spr_clt_crd0329.farc B5FAE9C7 rom/2d/spr_clt_crd0330.farc 7335A9E7 rom/2d/spr_clt_crd0331.farc 9CF5C21F rom/2d/spr_clt_crd0332.farc 2CE7CEE7 rom/2d/spr_clt_crd0333.farc 076873E3 rom/2d/spr_clt_crd0334.farc 4DECB4F6 rom/2d/spr_clt_crd0335.farc 8DD76A0D rom/2d/spr_clt_crd0337.farc 588A531C rom/2d/spr_clt_crd0338.farc FF8CBE9F rom/2d/spr_clt_crd0339.farc 43DF557D rom/2d/spr_clt_crd0340.farc 0EA7A3D7 rom/2d/spr_clt_crd0341.farc 118AC41A rom/2d/spr_clt_crd0342.farc 0F16C23D rom/2d/spr_clt_crd0343.farc 76F149C0 rom/2d/spr_clt_crd0344.farc 9141DF23 rom/2d/spr_clt_crd0345.farc C0D25B1B rom/2d/spr_clt_crd0346.farc 0B8E62A3 rom/2d/spr_clt_crd0347.farc CAAD2E14 rom/2d/spr_clt_crd0348.farc AA14A495 rom/2d/spr_clt_crd0349.farc A6C49D21 rom/2d/spr_clt_crd0350.farc 991054FC rom/2d/spr_clt_crd0351.farc 449C8583 rom/2d/spr_clt_crd0353.farc 48CC9F52 rom/2d/spr_clt_crd0354.farc BF4A384A rom/2d/spr_clt_crd0355.farc AD03FB36 rom/2d/spr_clt_crd0356.farc D7EA3568 rom/2d/spr_clt_crd0357.farc 0B3F2DF7 rom/2d/spr_clt_crd0358.farc D7587039 rom/2d/spr_clt_crd0359.farc 6F55617A rom/2d/spr_clt_crd0360.farc 34720F1E rom/2d/spr_clt_crd0361.farc 237463DC rom/2d/spr_clt_crd0362.farc C3C26C34 rom/2d/spr_clt_crd0363.farc C25CF7F2 rom/2d/spr_clt_crd0364.farc 45114CF2 rom/2d/spr_clt_crd0365.farc D04DBA12 rom/2d/spr_clt_crd0366.farc D384D410 rom/2d/spr_clt_crd0367.farc 327C4A64 rom/2d/spr_clt_crd0369.farc 06201281 rom/2d/spr_clt_crd0370.farc B55807A7 rom/2d/spr_clt_crd0371.farc 91D77D78 rom/2d/spr_clt_crd0372.farc A2DE2CA0 rom/2d/spr_clt_crd0373.farc 7A12FE36 rom/2d/spr_clt_crd0374.farc 6D6859C1 rom/2d/spr_clt_crd0375.farc 87A92304 rom/2d/spr_clt_crd0376.farc 61AF9CD1 rom/2d/spr_clt_crd0377.farc E2826888 rom/2d/spr_clt_crd0378.farc E503AB73 rom/2d/spr_clt_crd0379.farc A162FC30 rom/2d/spr_clt_crd0380.farc BDAD3E67 rom/2d/spr_clt_crd0381.farc 980206CA rom/2d/spr_clt_crd0382.farc 5EBF95C3 rom/2d/spr_clt_crd0383.farc CBAE7000 rom/2d/spr_clt_crd0385.farc 1F1B515E rom/2d/spr_clt_crd0386.farc 16EC9FC6 rom/2d/spr_clt_crd0387.farc ED9E08F4 rom/2d/spr_clt_crd0388.farc 2D4D7B2F rom/2d/spr_clt_crd0389.farc 45C96158 rom/2d/spr_clt_crd0390.farc 356F0600 rom/2d/spr_clt_crd0391.farc 5D9B501C rom/2d/spr_clt_crd0392.farc F09D5EE5 rom/2d/spr_clt_crd0393.farc 6610C516 rom/2d/spr_clt_crd0394.farc 20C21D8B rom/2d/spr_clt_crd0395.farc 51296B90 rom/2d/spr_clt_crd0396.farc BCA4D64C rom/2d/spr_clt_crd0397.farc 528BCD43 rom/2d/spr_clt_crd0398.farc 5C9B83BB rom/2d/spr_clt_crd0399.farc C08781B4 rom/2d/spr_clt_crd0401.farc 932DCC4B rom/2d/spr_clt_crd0402.farc 1AEC90E0 rom/2d/spr_clt_crd0403.farc A8AD7EB4 rom/2d/spr_clt_crd0404.farc 8B5D140D rom/2d/spr_clt_crd0405.farc FA045AF8 rom/2d/spr_clt_crd0406.farc BB87A584 rom/2d/spr_clt_crd0407.farc 46D54F21 rom/2d/spr_clt_crd0408.farc D7224866 rom/2d/spr_clt_crd0409.farc 225E8284 rom/2d/spr_clt_crd0410.farc 6CD88D60 rom/2d/spr_clt_crd0411.farc 95C4E0F2 rom/2d/spr_clt_crd0412.farc 57C9CEF4 rom/2d/spr_clt_crd0413.farc 4424070C rom/2d/spr_clt_crd0414.farc 21123AF4 rom/2d/spr_clt_crd0415.farc CF16F771 rom/2d/spr_clt_crd0417.farc 2C0B81FF rom/2d/spr_clt_crd0418.farc E104E78A rom/2d/spr_clt_crd0419.farc 5AF1DC70 rom/2d/spr_clt_crd0420.farc F40AFB6B rom/2d/spr_clt_crd0421.farc 6EFB51E4 rom/2d/spr_clt_crd0422.farc 13B9EBA2 rom/2d/spr_clt_crd0423.farc 6EDCBD27 rom/2d/spr_clt_crd0424.farc 251828AE rom/2d/spr_clt_crd0425.farc 6E3F18B7 rom/2d/spr_clt_crd0426.farc 14292F5F rom/2d/spr_clt_crd0427.farc DF277A84 rom/2d/spr_clt_crd0428.farc ACA710F5 rom/2d/spr_clt_crd0429.farc F5111F5E rom/2d/spr_clt_crd0430.farc E2B01983 rom/2d/spr_clt_crd0431.farc 7C872E08 rom/2d/spr_clt_crd0433.farc E9B3BD05 rom/2d/spr_clt_crd0434.farc 9862345D rom/2d/spr_clt_crd0435.farc 72F50BD3 rom/2d/spr_clt_crd0436.farc B81F7F15 rom/2d/spr_clt_crd0437.farc B4118720 rom/2d/spr_clt_crd0438.farc 82813EC0 rom/2d/spr_clt_crd0439.farc 02DD3299 rom/2d/spr_clt_crd0440.farc D85A029F rom/2d/spr_clt_crd0441.farc 6AD2613D rom/2d/spr_clt_crd0442.farc 5E832BAA rom/2d/spr_clt_crd0443.farc C8F6D23F rom/2d/spr_clt_crd0444.farc 0327EB27 rom/2d/spr_clt_crd0445.farc F655A3B6 rom/2d/spr_clt_crd0446.farc 3F74702E rom/2d/spr_clt_crd0447.farc 049FFC38 rom/2d/spr_clt_crd0449.farc 5A74BC97 rom/2d/spr_clt_crd0450.farc 75844781 rom/2d/spr_clt_crd0451.farc 642449CE rom/2d/spr_clt_crd0452.farc 45F9ECFD rom/2d/spr_clt_crd0453.farc 71D446B6 rom/2d/spr_clt_crd0454.farc ED449A89 rom/2d/spr_clt_crd0455.farc 30FDC7AF rom/2d/spr_clt_crd0456.farc C274F4DB rom/2d/spr_clt_crd0457.farc B5D43ED0 rom/2d/spr_clt_crd0458.farc 858A78B1 rom/2d/spr_clt_crd0459.farc 6C8AF025 rom/2d/spr_clt_crd0460.farc 08319FE0 rom/2d/spr_clt_crd0461.farc F6ED92E7 rom/2d/spr_clt_crd0462.farc 57F82118 rom/2d/spr_clt_crd0463.farc 87F738C7 rom/2d/spr_clt_crd0465.farc 818F7E7B rom/2d/spr_clt_crd0466.farc 1EDAA09A rom/2d/spr_clt_crd0467.farc 2118DD73 rom/2d/spr_clt_crd0468.farc 968B1CA3 rom/2d/spr_clt_crd0469.farc 40E6A1B2 rom/2d/spr_clt_crd0470.farc 512331A3 rom/2d/spr_clt_crd0471.farc 50AE8441 rom/2d/spr_clt_crd0472.farc 2F6D3117 rom/2d/spr_clt_crd0473.farc 84BB0A77 rom/2d/spr_clt_crd0474.farc BAA1F6A5 rom/2d/spr_clt_crd0475.farc 305657A9 rom/2d/spr_clt_crd0476.farc A62C0056 rom/2d/spr_clt_crd0477.farc 3EEAA623 rom/2d/spr_clt_crd0478.farc 2D273E3E rom/2d/spr_clt_crd0479.farc 899035AF rom/2d/spr_clt_crd0481.farc AAD4CFC9 rom/2d/spr_clt_crd0482.farc 936FFB1C rom/2d/spr_clt_crd0483.farc E172674D rom/2d/spr_clt_crd0484.farc 4510B167 rom/2d/spr_clt_crd0485.farc F3E577C8 rom/2d/spr_clt_crd0486.farc A4F81A9A rom/2d/spr_clt_crd0487.farc A270D3EC rom/2d/spr_clt_crd0488.farc 63609C14 rom/2d/spr_clt_crd0489.farc 00782258 rom/2d/spr_clt_crd0490.farc 1E55C8B6 rom/2d/spr_clt_crd0491.farc A855DF2E rom/2d/spr_clt_crd0492.farc B2B24B45 rom/2d/spr_clt_crd0493.farc 8EE44FC2 rom/2d/spr_clt_crd0494.farc 8D185B9E rom/2d/spr_clt_crd0495.farc 56B1C991 rom/2d/spr_clt_crd0497.farc 73764F78 rom/2d/spr_clt_crd0498.farc 49DF7E7B rom/2d/spr_clt_crd0499.farc E17884FB rom/2d/spr_clt_crd0500.farc 896E1C1F rom/2d/spr_clt_crd0501.farc A4114828 rom/2d/spr_clt_crd0502.farc FD702D6A rom/2d/spr_clt_crd0503.farc E2932265 rom/2d/spr_clt_crd0504.farc BBEFDA41 rom/2d/spr_clt_crd0505.farc C3B73473 rom/2d/spr_clt_crd0506.farc 15F24578 rom/2d/spr_clt_crd0507.farc D4225F68 rom/2d/spr_clt_crd0508.farc 12169A81 rom/2d/spr_clt_crd0509.farc D3937D2F rom/2d/spr_clt_crd0510.farc 219A5AB5 rom/2d/spr_clt_crd0511.farc 06A9416D rom/2d/spr_clt_crd0272.farc A3DBAF31 rom/2d/spr_clt_crd0288.farc DFD3FDB0 rom/2d/spr_clt_crd0304.farc 0FB24CB1 rom/2d/spr_clt_crd0320.farc 1DD9D751 rom/2d/spr_clt_crd0336.farc FC8CC500 rom/2d/spr_clt_crd0352.farc CD5A1C1C rom/2d/spr_clt_crd0368.farc 152DFE3F rom/2d/spr_clt_crd0384.farc 224862EE rom/2d/spr_clt_crd0400.farc ECF125DE rom/2d/spr_clt_crd0416.farc 70F0FC0B rom/2d/spr_clt_crd0432.farc D4433EC5 rom/2d/spr_clt_crd0448.farc B1B07759 rom/2d/spr_clt_crd0464.farc 0438161E rom/2d/spr_clt_crd0480.farc C3CFC072 rom/2d/spr_clt_crd0513.farc FEA66A2C rom/2d/spr_clt_crd0514.farc 4376A6F0 rom/2d/spr_clt_crd0515.farc 67E940F7 rom/2d/spr_clt_crd0516.farc DE7F0D7F rom/2d/spr_clt_crd0517.farc 699E7AB7 rom/2d/spr_clt_crd0518.farc 40809834 rom/2d/spr_clt_crd0519.farc 17F85980 rom/2d/spr_clt_crd0520.farc 0C0506BC rom/2d/spr_clt_crd0521.farc EE61BF96 rom/2d/spr_clt_crd0522.farc 9CE13B4C rom/2d/spr_clt_crd0523.farc F334C049 rom/2d/spr_clt_crd0524.farc 1DABD845 rom/2d/spr_clt_crd0525.farc 317058A2 rom/2d/spr_clt_crd0526.farc F1A136D5 rom/2d/spr_clt_crd0527.farc B6BBE487 rom/2d/spr_clt_crd0529.farc 39076D2A rom/2d/spr_clt_crd0530.farc B5FD8538 rom/2d/spr_clt_crd0531.farc 0E00E317 rom/2d/spr_clt_crd0532.farc 54238A21 rom/2d/spr_clt_crd0533.farc C2E7C67D rom/2d/spr_clt_crd0534.farc F6B5A045 rom/2d/spr_clt_crd0535.farc 19F6DAA5 rom/2d/spr_clt_crd0536.farc 7CC36CF1 rom/2d/spr_clt_crd0537.farc 0666A026 rom/2d/spr_clt_crd0538.farc DBF02126 rom/2d/spr_clt_crd0539.farc 09765719 rom/2d/spr_clt_crd0540.farc B36E49A1 rom/2d/spr_clt_crd0541.farc 8BAB0700 rom/2d/spr_clt_crd0542.farc E1A544BC rom/2d/spr_clt_crd0543.farc 095F9AF2 rom/2d/spr_clt_crd0545.farc 4A88A5E1 rom/2d/spr_clt_crd0546.farc 61525C24 rom/2d/spr_clt_crd0547.farc C5DF9385 rom/2d/spr_clt_crd0554.farc B8DD3726 rom/2d/spr_clt_crd0555.farc 810505D9 rom/2d/spr_clt_crd0556.farc 4F80BD2C rom/2d/spr_clt_crd0557.farc A3850395 rom/2d/spr_clt_crd0558.farc C644EEA0 rom/2d/spr_clt_crd0559.farc B9CAB4C0 rom/2d/spr_clt_crd0560.farc A2DC96E5 rom/2d/spr_clt_crd0561.farc 55EAE3BF rom/2d/spr_clt_crd0562.farc 41135D7B rom/2d/spr_clt_crd0563.farc 2F8C032D rom/2d/spr_clt_crd0564.farc 41FF084C rom/2d/spr_clt_crd0565.farc 2DD485E4 rom/2d/spr_clt_crd0567.farc 6C490A8D rom/2d/spr_clt_crd0568.farc 2E0762ED rom/2d/spr_clt_crd0569.farc 50BDCB97 rom/2d/spr_clt_crd0570.farc 32B595E8 rom/2d/spr_clt_crd0571.farc 604A8C4F rom/2d/spr_clt_crd0572.farc E9C2C549 rom/2d/spr_clt_crd0573.farc 19C22B5E rom/2d/spr_clt_crd0574.farc 3C2DA897 rom/2d/spr_clt_crd0575.farc D591E13D rom/2d/spr_clt_crd0576.farc 0545499F rom/2d/spr_clt_crd0577.farc 1650954E rom/2d/spr_clt_crd0578.farc 60F704BE rom/2d/spr_clt_crd0579.farc 42211C3D rom/2d/spr_clt_crd0580.farc 179A97EA rom/2d/spr_clt_crd0581.farc 4D6FDC7C rom/2d/spr_clt_crd0583.farc F998C3CA rom/2d/spr_clt_crd0584.farc 979C140B rom/2d/spr_clt_crd0585.farc 2800D55A rom/2d/spr_clt_crd0586.farc EBE4B7C2 rom/2d/spr_clt_crd0587.farc C661BA07 rom/2d/spr_clt_crd0588.farc 715D63F5 rom/2d/spr_clt_crd0589.farc 60CB3A64 rom/2d/spr_clt_crd0590.farc FEEB451E rom/2d/spr_clt_crd0591.farc 472E78D2 rom/2d/spr_clt_crd0592.farc 14AA1B15 rom/2d/spr_clt_crd0593.farc 8F352779 rom/2d/spr_clt_crd0594.farc 34C1EF88 rom/2d/spr_clt_crd0595.farc 2C3D94B2 rom/2d/spr_clt_crd0596.farc 2879D97F rom/2d/spr_clt_crd0597.farc 5668463F rom/2d/spr_clt_crd0599.farc 4204140B rom/2d/spr_clt_crd0600.farc 889E2AD8 rom/2d/spr_clt_crd0601.farc 07E9B906 rom/2d/spr_clt_crd0602.farc 24810A4A rom/2d/spr_clt_crd0603.farc 2125456D rom/2d/spr_clt_crd0604.farc 8AAD1240 rom/2d/spr_clt_crd0605.farc 804AFC36 rom/2d/spr_clt_crd0606.farc 335226DF rom/2d/spr_clt_crd0607.farc DD93E6CD rom/2d/spr_clt_crd0608.farc F5E652B5 rom/2d/spr_clt_crd0609.farc 6523C018 rom/2d/spr_clt_crd0610.farc 847B5F4E rom/2d/spr_clt_crd0611.farc 6E90B0DE rom/2d/spr_clt_crd0612.farc 5C324D55 rom/2d/spr_clt_crd0613.farc D9A2E251 rom/2d/spr_clt_crd0615.farc 52FB3A26 rom/2d/spr_clt_crd0616.farc 6ABDB673 rom/2d/spr_clt_crd0617.farc F3346E42 rom/2d/spr_clt_crd0618.farc F22C7BCB rom/2d/spr_clt_crd0619.farc E81D08CB rom/2d/spr_clt_crd0620.farc F11601CD rom/2d/spr_clt_crd0621.farc E3A9D4CA rom/2d/spr_clt_crd0622.farc EECE482B rom/2d/spr_clt_crd0623.farc F7FB0E0F rom/2d/spr_clt_crd0624.farc 55CC82D0 rom/2d/spr_clt_crd0625.farc EDCC49F7 rom/2d/spr_clt_crd0626.farc 1C654665 rom/2d/spr_clt_crd0627.farc F0DEAA43 rom/2d/spr_clt_crd0628.farc CC637B79 rom/2d/spr_clt_crd0629.farc DA4B1C0C rom/2d/spr_clt_crd0631.farc D0C8FCFE rom/2d/spr_clt_crd0632.farc E7A887A3 rom/2d/spr_clt_crd0633.farc C3B699A2 rom/2d/spr_cmnitm_thmb000.farc 3BF802D7 rom/2d/spr_cmnitm_thmb001.farc 87FE0BAE rom/2d/spr_cmnitm_thmb002.farc 19A94810 rom/2d/spr_cmnitm_thmb003.farc 61F75201 rom/2d/spr_cmnitm_thmb004.farc 57377D31 rom/2d/spr_cmnitm_thmb005.farc 04E78FD9 rom/2d/spr_cmnitm_thmb006.farc B7607B4C rom/2d/spr_cmnitm_thmb007.farc D75DE0D0 rom/2d/spr_cmnitm_thmb008.farc F00FA336 rom/2d/spr_cmnitm_thmb009.farc D3D3EC32 rom/2d/spr_cmnitm_thmb010.farc CD63FAE3 rom/2d/spr_cmnitm_thmb011.farc AE034C03 rom/2d/spr_cmnitm_thmb013.farc 54A57D3B rom/2d/spr_cmnitm_thmb014.farc 157F59C3 rom/2d/spr_cmnitm_thmb015.farc 07D91CE7 rom/2d/spr_cmnitm_thmb016.farc 8055D762 rom/2d/spr_cmnitm_thmb017.farc 3B693DE1 rom/2d/spr_cmnitm_thmb018.farc A02CA759 rom/2d/spr_cmnitm_thmb019.farc F83F3A72 rom/2d/spr_cmnitm_thmb020.farc 030BC2DC rom/2d/spr_cmnitm_thmb021.farc EE81D68B rom/2d/spr_cmnitm_thmb022.farc E0F6CAD1 rom/2d/spr_cmnitm_thmb023.farc 512C9DB6 rom/2d/spr_cmnitm_thmb024.farc 70EB5A92 rom/2d/spr_cmnitm_thmb025.farc 658C848B rom/2d/spr_cmnitm_thmb026.farc 63B0B06E rom/2d/spr_cmnitm_thmb027.farc 9120812A rom/2d/spr_cmnitm_thmb029.farc 21C4AB84 rom/2d/spr_cmnitm_thmb030.farc CFB5FC7C rom/2d/spr_cmnitm_thmb031.farc 7E9EA67D rom/2d/spr_cmnitm_thmb032.farc 61508BA9 rom/2d/spr_cmnitm_thmb033.farc DCDF2232 rom/2d/spr_cmnitm_thmb034.farc C4A4BF5E rom/2d/spr_cmnitm_thmb035.farc 9BE47166 rom/2d/spr_cmnitm_thmb036.farc 4BBE8C73 rom/2d/spr_cmnitm_thmb037.farc F04780D8 rom/2d/spr_cmnitm_thmb038.farc 3AF62619 rom/2d/spr_cmnitm_thmb039.farc 66142A47 rom/2d/spr_cmnitm_thmb040.farc 130F0370 rom/2d/spr_cmnitm_thmb041.farc 0E7DB9DE rom/2d/spr_cmnitm_thmb042.farc 75C7DD4F rom/2d/spr_cmnitm_thmb043.farc 06B5D150 rom/2d/spr_cmnitm_thmb045.farc 19D8C419 rom/2d/spr_cmnitm_thmb046.farc 895800B6 rom/2d/spr_cmnitm_thmb047.farc 94CCD300 rom/2d/spr_cmnitm_thmb048.farc 26ED365F rom/2d/spr_cmnitm_thmb049.farc A7991D43 rom/2d/spr_cmnitm_thmb050.farc 0FD56968 rom/2d/spr_cmnitm_thmb051.farc 635AF470 rom/2d/spr_cmnitm_thmb052.farc 020A137E rom/2d/spr_cmnitm_thmb053.farc 7BD3086D rom/2d/spr_cmnitm_thmb054.farc E9A98D34 rom/2d/spr_cmnitm_thmb055.farc 83D673F7 rom/2d/spr_cmnitm_thmb056.farc 045BFF5A rom/2d/spr_cmnitm_thmb057.farc 39A83BB3 rom/2d/spr_cmnitm_thmb058.farc 544C29DC rom/2d/spr_cmnitm_thmb059.farc 9CAE4C33 rom/2d/spr_cmnitm_thmb061.farc BDE51386 rom/2d/spr_cmnitm_thmb062.farc 0312DE2C rom/2d/spr_cmnitm_thmb067.farc 3F07EFA0 rom/2d/spr_cmnitm_thmb068.farc 0E1B637C rom/2d/spr_cmnitm_thmb069.farc 60854CD6 rom/2d/spr_cmnitm_thmb070.farc 15EE28AD rom/2d/spr_cmnitm_thmb071.farc 8071FE78 rom/2d/spr_cmnitm_thmb072.farc 7122EACF rom/2d/spr_cmnitm_thmb073.farc C5E9C414 rom/2d/spr_cmnitm_thmb074.farc FF1743E3 rom/2d/spr_cmnitm_thmb075.farc 4D1B6952 rom/2d/spr_cmnitm_thmb076.farc 7CE4A2A8 rom/2d/spr_cmnitm_thmb077.farc 1F8DFB07 rom/2d/spr_cmnitm_thmb078.farc EB085A92 rom/2d/spr_cmnitm_thmb079.farc 32A742EC rom/2d/spr_cmnitm_thmb081.farc 8EF0117D rom/2d/spr_cmnitm_thmb082.farc B48788A6 rom/2d/spr_cmnitm_thmb083.farc 6DBC73D0 rom/2d/spr_cmnitm_thmb084.farc 3CC0CF05 rom/2d/spr_cmnitm_thmb085.farc 6ECB207B rom/2d/spr_cmnitm_thmb086.farc DB782B38 rom/2d/spr_cmnitm_thmb087.farc EC115037 rom/2d/spr_cmnitm_thmb088.farc 59F06997 rom/2d/spr_cmnitm_thmb089.farc 4D198A97 rom/2d/spr_cmnitm_thmb097.farc 8996E533 rom/2d/spr_cmnitm_thmb098.farc 2CB25E32 rom/2d/spr_cmnitm_thmb099.farc 21B48F53 rom/2d/spr_cmnitm_thmb100.farc 7C13A883 rom/2d/spr_cmnitm_thmb101.farc 8CEA5684 rom/2d/spr_cmnitm_thmb102.farc 43909A1D rom/2d/spr_cmnitm_thmb104.farc 778C03B3 rom/2d/spr_cmnitm_thmb105.farc 4CB4ECBD rom/2d/spr_cmnitm_thmb106.farc EC74D09C rom/2d/spr_cmnitm_thmb107.farc 7BD4FE5A rom/2d/spr_cmnitm_thmb115.farc 7922A05B rom/2d/spr_cmnitm_thmb116.farc BE5FB8B7 rom/2d/spr_cmnitm_thmb117.farc 3C9AF3E1 rom/2d/spr_cmnitm_thmb118.farc 7B9C0B04 rom/2d/spr_cmnitm_thmb119.farc 233BF573 rom/2d/spr_cmnitm_thmb120.farc 50FFF57F rom/2d/spr_cmnitm_thmb121.farc 5CFBE020 rom/2d/spr_cmnitm_thmb122.farc 7F7EA6D1 rom/2d/spr_cmnitm_thmb123.farc 215B6B54 rom/2d/spr_cmnitm_thmb124.farc 1D73F83A rom/2d/spr_cmnitm_thmb125.farc 936361B6 rom/2d/spr_cmnitm_thmb127.farc 2DEA12C4 rom/2d/spr_cmnitm_thmb128.farc CB898F79 rom/2d/spr_cmnitm_thmb129.farc 84EC8F36 rom/2d/spr_cmnitm_thmb130.farc 19A01BED rom/2d/spr_cmnitm_thmb131.farc AE785C68 rom/2d/spr_cmnitm_thmb132.farc 6792F789 rom/2d/spr_cmnitm_thmb133.farc 0F6BE457 rom/2d/spr_cmnitm_thmb134.farc B62D774D rom/2d/spr_cmnitm_thmb135.farc 14E8F2F6 rom/2d/spr_cmnitm_thmb136.farc 2460E02A rom/2d/spr_cmnitm_thmb137.farc 3E9D4CA3 rom/2d/spr_cmnitm_thmb138.farc 305C875B rom/2d/spr_cmnitm_thmb139.farc 74715668 rom/2d/spr_cmnitm_thmb140.farc E5207DF6 rom/2d/spr_cmnitm_thmb141.farc 0C68A95E rom/2d/spr_clt_crd0512.farc 2E2C4B75 rom/2d/spr_clt_crd0528.farc 5B507467 rom/2d/spr_clt_crd0544.farc FCB89DF6 rom/2d/spr_clt_crd0566.farc 62C863ED rom/2d/spr_clt_crd0582.farc 07EDED80 rom/2d/spr_clt_crd0598.farc 6592A2EB rom/2d/spr_clt_crd0614.farc B7C8BF86 rom/2d/spr_clt_crd0630.farc 7A205AC8 rom/2d/spr_cmnitm_thmb012.farc 291D2C01 rom/2d/spr_cmnitm_thmb028.farc 2B340B5E rom/2d/spr_cmnitm_thmb044.farc 75416E1C rom/2d/spr_cmnitm_thmb060.farc 24118B43 rom/2d/spr_cmnitm_thmb080.farc 64ADEE94 rom/2d/spr_cmnitm_thmb103.farc A48B4491 rom/2d/spr_cmnitm_thmb143.farc 380F10D2 rom/2d/spr_cmnitm_thmb144.farc A7A9C044 rom/2d/spr_cmnitm_thmb145.farc 45FD2861 rom/2d/spr_cmnitm_thmb146.farc EB2ACC0E rom/2d/spr_cmnitm_thmb147.farc 1BE146D3 rom/2d/spr_cmnitm_thmb148.farc 27DC3402 rom/2d/spr_cmnitm_thmb149.farc 6D5F6E74 rom/2d/spr_cmnitm_thmb150.farc 0CCED482 rom/2d/spr_cmnitm_thmb151.farc 1417B4A8 rom/2d/spr_cmnitm_thmb152.farc 7190851D rom/2d/spr_cmnitm_thmb153.farc 77F23130 rom/2d/spr_cmnitm_thmb154.farc 5AF5D394 rom/2d/spr_cmnitm_thmb155.farc 34BDE1E5 rom/2d/spr_cmnitm_thmb156.farc 4E5F6E5C rom/2d/spr_cmnitm_thmb157.farc 76997CFE rom/2d/spr_cmnitm_thmb159.farc 6AE0CE81 rom/2d/spr_cmnitm_thmb160.farc BAEAF750 rom/2d/spr_cmnitm_thmb161.farc 2F0DAE7C rom/2d/spr_cmnitm_thmb162.farc 68C3B12E rom/2d/spr_cmnitm_thmb163.farc 3CCBE77B rom/2d/spr_cmnitm_thmb164.farc 58717997 rom/2d/spr_cmnitm_thmb165.farc 6153243F rom/2d/spr_cmnitm_thmb166.farc 78C7CE03 rom/2d/spr_cmnitm_thmb167.farc B4F8B445 rom/2d/spr_cmnitm_thmb168.farc B06A05F1 rom/2d/spr_cmnitm_thmb169.farc 9AFA7038 rom/2d/spr_cmnitm_thmb170.farc A44A57D7 rom/2d/spr_cmnitm_thmb171.farc 06705E65 rom/2d/spr_cmnitm_thmb172.farc 9E3505B6 rom/2d/spr_cmnitm_thmb173.farc 82BAE98D rom/2d/spr_cmnitm_thmb175.farc 0540496D rom/2d/spr_cmnitm_thmb176.farc A9F7D4F0 rom/2d/spr_cmnitm_thmb177.farc FF8AD638 rom/2d/spr_cmnitm_thmb178.farc C81ED01A rom/2d/spr_cmnitm_thmb179.farc 9DBC752E rom/2d/spr_cmnitm_thmb180.farc 653E74B3 rom/2d/spr_cmnitm_thmb181.farc 41D7E99E rom/2d/spr_cmnitm_thmb182.farc 90CB4836 rom/2d/spr_cmnitm_thmb183.farc 57034357 rom/2d/spr_cmnitm_thmb184.farc B2747FDC rom/2d/spr_cmnitm_thmb185.farc FEEFD811 rom/2d/spr_cmnitm_thmb186.farc A3AEB537 rom/2d/spr_cmnitm_thmb187.farc 8F119FC3 rom/2d/spr_cmnitm_thmb188.farc 955430D9 rom/2d/spr_cmnitm_thmb189.farc 1491F3BF rom/2d/spr_cmnitm_thmb191.farc ED7631EB rom/2d/spr_cmnitm_thmb192.farc 7AC5DD40 rom/2d/spr_cmnitm_thmb193.farc 163D5E77 rom/2d/spr_cmnitm_thmb194.farc 7C1739FC rom/2d/spr_cmnitm_thmb195.farc E689666A rom/2d/spr_cmnitm_thmb196.farc EC9F423C rom/2d/spr_cmnitm_thmb197.farc 732BCFFD rom/2d/spr_cmnitm_thmb198.farc DA55475A rom/2d/spr_cmnitm_thmb199.farc BDEFFDCC rom/2d/spr_cmnitm_thmb200.farc 51935B77 rom/2d/spr_cmnitm_thmb201.farc 074C7AC9 rom/2d/spr_cmnitm_thmb204.farc BB2EFB07 rom/2d/spr_cmnitm_thmb205.farc 82639F9B rom/2d/spr_cmnitm_thmb206.farc 31547CF4 rom/2d/spr_cmnitm_thmb207.farc F6A0C479 rom/2d/spr_cmnitm_thmb209.farc BF505F7B rom/2d/spr_cmnitm_thmb210.farc 764CF999 rom/2d/spr_cmnitm_thmb211.farc 412130F1 rom/2d/spr_cmnitm_thmb212.farc 822FCD98 rom/2d/spr_cmnitm_thmb213.farc 32F04176 rom/2d/spr_cmnitm_thmb214.farc 6DD4F8A1 rom/2d/spr_cmnitm_thmb215.farc E8B3C135 rom/2d/spr_cmnitm_thmb216.farc 7596C1C1 rom/2d/spr_cmnitm_thmb217.farc 42620DE5 rom/2d/spr_cmnitm_thmb218.farc 07DE9C01 rom/2d/spr_cmnitm_thmb219.farc 4EA29B11 rom/2d/spr_cmnitm_thmb220.farc B0715B82 rom/2d/spr_cmnitm_thmb221.farc 98AD437D rom/2d/spr_cmnitm_thmb222.farc ADAC6DCE rom/2d/spr_cmnitm_thmb223.farc 9BD75784 rom/2d/spr_cmnitm_thmb225.farc 1A856805 rom/2d/spr_cmnitm_thmb226.farc 3E3B2CBC rom/2d/spr_cmnitm_thmb227.farc 0B069CA4 rom/2d/spr_cmnitm_thmb228.farc 2B97321B rom/2d/spr_cmnitm_thmb229.farc 9E23D89C rom/2d/spr_cmnitm_thmb230.farc FBA6C68D rom/2d/spr_cmnitm_thmb231.farc 941C997E rom/2d/spr_cmnitm_thmb232.farc B0CB5684 rom/2d/spr_cmnitm_thmb233.farc 6700CE40 rom/2d/spr_cmnitm_thmbdummy.farc 307703B9 rom/2d/spr_cmn_all.farc 80292D0A rom/2d/spr_db.bin EC621CDD rom/2d/spr_edit_d2pvback001.farc 50434D45 rom/2d/spr_edit_d2pvback002.farc 50D9B3BB rom/2d/spr_edit_d2pvback003.farc F3EA746C rom/2d/spr_edit_d2pvback005.farc 9B85FABB rom/2d/spr_edit_d2pvback006.farc B8D0BDC2 rom/2d/spr_edit_d2pvback007.farc 49DC486E rom/2d/spr_edit_d2pvback008.farc C51A0687 rom/2d/spr_edit_d2pvback009.farc 6524CE00 rom/2d/spr_edit_d2pvback010.farc B34A181C rom/2d/spr_edit_d2pvback011.farc 77E9AD66 rom/2d/spr_edit_d2pvback012.farc 1FF58560 rom/2d/spr_edit_d2pvback013.farc 968C5376 rom/2d/spr_edit_d2pvback014.farc D2ABA707 rom/2d/spr_edit_d2pvback015.farc BCA6FD2F rom/2d/spr_edit_d2pvback016.farc E4265452 rom/2d/spr_edit_d2pvback017.farc 6955AC38 rom/2d/spr_edit_d2pvback018.farc CA2E9A0E rom/2d/spr_edit_d2pvback020.farc 4DDDB8B5 rom/2d/spr_edit_d2pvback021.farc 641F80E2 rom/2d/spr_edit_d2pvback022.farc BB5CD0A5 rom/2d/spr_edit_d2pvback023.farc 2C3A26EB rom/2d/spr_edit_d2pvback024.farc 942FFC45 rom/2d/spr_edit_d2pvback025.farc 17438318 rom/2d/spr_edit_d2pvback026.farc 431DCAF6 rom/2d/spr_edit_d2pvback027.farc F3DBA385 rom/2d/spr_edit_d2pvback028.farc 72E0FF74 rom/2d/spr_edit_d2pvback029.farc 120A1687 rom/2d/spr_edit_d2pvback030.farc E8C79524 rom/2d/spr_edit_d2pvback031.farc 0AAE328D rom/2d/spr_edit_d2pvback032.farc B4C83F64 rom/2d/spr_edit_d2pvback033.farc 54A4A25E rom/2d/spr_edit_d2pvback035.farc 91041989 rom/2d/spr_edit_d2pvback036.farc 743FA727 rom/2d/spr_edit_d2pvback037.farc 7A2CAC98 rom/2d/spr_edit_d2pvback038.farc 71607DA7 rom/2d/spr_edit_d2pvback039.farc 25E0E1AC rom/2d/spr_edit_d2pvback040.farc F95566AB rom/2d/spr_edit_d2pvback041.farc 6887CE8F rom/2d/spr_edit_d2pvback042.farc 2CF8D0BE rom/2d/spr_edit_d2pvback043.farc 11973CE3 rom/2d/spr_edit_d2pvback044.farc 51FB335A rom/2d/spr_edit_d2pvback045.farc BF9C43E3 rom/2d/spr_edit_d2pvback046.farc 5D3C0DE6 rom/2d/spr_edit_d2pvback047.farc 229F2C9A rom/2d/spr_edit_d2pvback048.farc 1F8D7B06 rom/2d/spr_edit_d2pvback050.farc CAE2C43C rom/2d/spr_edit_d2pvback051.farc 7DD084AD rom/2d/spr_edit_d2pvback052.farc B16B8932 rom/2d/spr_edit_d2pvback053.farc B5B4CF44 rom/2d/spr_edit_d2pvback054.farc FEA824AE rom/2d/spr_edit_d2pvback055.farc 6BBCCAD6 rom/2d/spr_edit_d2pvback056.farc 3B7538F9 rom/2d/spr_edit_d2pvback057.farc 3B2FF441 rom/2d/spr_edit_d2pvback058.farc 303ECC8A rom/2d/spr_edit_d2pvback059.farc F70C5D5F rom/2d/spr_edit_d2pvback060.farc 5995EF52 rom/2d/spr_edit_d2pvback061.farc EA1175CC rom/2d/spr_edit_d2pvback062.farc 87EEC54B rom/2d/spr_edit_d2pvback063.farc 64491289 rom/2d/spr_edit_d2pvback065.farc 6EB2352B rom/2d/spr_edit_d2pvback066.farc 7A7A88D4 rom/2d/spr_edit_d2pvback067.farc 57315CC6 rom/2d/spr_edit_d2pvback068.farc 0E4B6FCA rom/2d/spr_edit_d2pvback069.farc F81B6262 rom/2d/spr_edit_d2pvback070.farc E92D803B rom/2d/spr_edit_d2pvback071.farc 24E5510A rom/2d/spr_edit_d2pvback072.farc 2F8A79E7 rom/2d/spr_edit_d2pvback073.farc B50AAC8C rom/2d/spr_edit_d2pvback074.farc 9607052B rom/2d/spr_edit_d2pvback075.farc A05A145A rom/2d/spr_edit_d2pvback076.farc B4237AB4 rom/2d/spr_edit_d2pvback077.farc 38EE7DA9 rom/2d/spr_edit_d2pvback078.farc 028AAAC3 rom/2d/spr_edit_d2pvback080.farc F3F4652D rom/2d/spr_edit_d2pvback081.farc 950446AF rom/2d/spr_edit_d2pvback082.farc F224558A rom/2d/spr_edit_d2pvback083.farc F2DBD939 rom/2d/spr_edit_d2pvback084.farc 003BE641 rom/2d/spr_edit_d2pvback085.farc 58AD3731 rom/2d/spr_edit_d2pvback086.farc E7C22119 rom/2d/spr_edit_d2pvback087.farc 2BC3CDFC rom/2d/spr_edit_d2pvback088.farc 2EA1D7C7 rom/2d/spr_edit_d2pvback089.farc 58F8F108 rom/2d/spr_edit_d2pvback090.farc AF2B2BF0 rom/2d/spr_edit_d2pvback091.farc E60EBECD rom/2d/spr_edit_d2pvback092.farc A5800426 rom/2d/spr_edit_d2pvback093.farc 326D06B7 rom/2d/spr_edit_d2pvback095.farc 4C44C536 rom/2d/spr_edit_d2pvback096.farc B1214490 rom/2d/spr_edit_d2pvback097.farc 48DA23C8 rom/2d/spr_edit_d2pvback098.farc 36184D4C rom/2d/spr_edit_d2pvback099.farc AEAA2889 rom/2d/spr_edit_d2pvback100.farc 0DB35A94 rom/2d/spr_edit_d2pvback101.farc 4B9C8AC4 rom/2d/spr_edit_d2pvback102.farc 63FB4EC8 rom/2d/spr_edit_d2pvback103.farc 67A1D26D rom/2d/spr_edit_d2pvback104.farc 6AB8996E rom/2d/spr_edit_d2pvback105.farc 8E1E7394 rom/2d/spr_edit_d2pvback106.farc 242CD76A rom/2d/spr_edit_d2pvback107.farc 17B27107 rom/2d/spr_edit_d2pvback108.farc 9003DB9F rom/2d/spr_edit_d2pvback110.farc D8171151 rom/2d/spr_edit_d2pvback111.farc 92DEE23A rom/2d/spr_edit_d2pvback112.farc 074F9736 rom/2d/spr_edit_d2pvback113.farc 37FF513F rom/2d/spr_edit_d2pvback114.farc 87A6610F rom/2d/spr_edit_d2pvback115.farc B7DDB0F1 rom/2d/spr_edit_d2pvback116.farc 983CC4C6 rom/2d/spr_edit_d2pvback117.farc A2627F69 rom/2d/spr_edit_d2pvback118.farc 64B88794 rom/2d/spr_edit_d2pvback119.farc D1CFB435 rom/2d/spr_edit_d2pvback120.farc E2E9DC78 rom/2d/spr_edit_d2pvback121.farc C6CB7261 rom/2d/spr_edit_d2pvback122.farc 8C84F383 rom/2d/spr_edit_d2pvback123.farc 3D0A274B rom/2d/spr_edit_d2pvback125.farc CD087987 rom/2d/spr_edit_d2pvback126.farc 17A704C5 rom/2d/spr_edit_d2pvback127.farc B08B59C7 rom/2d/spr_edit_d2pvback128.farc CE19EBC3 rom/2d/spr_edit_d2pvback129.farc 192ED88A rom/2d/spr_edit_d2pvback130.farc AD8C49EC rom/2d/spr_edit_d2pvback131.farc C349082A rom/2d/spr_edit_d2pvback132.farc 129E8ACE rom/2d/spr_edit_d2pvback133.farc 17E2F86B rom/2d/spr_edit_d2pvback134.farc 39F50AF3 rom/2d/spr_edit_d2pvback135.farc 3BABA73B rom/2d/spr_edit_d2pvback136.farc 75E032E1 rom/2d/spr_edit_d2pvback137.farc A7E901E5 rom/2d/spr_edit_d2pvback138.farc 7B1ECF89 rom/2d/spr_cmnitm_thmb142.farc B415F12B rom/2d/spr_cmnitm_thmb158.farc 661AA3FB rom/2d/spr_cmnitm_thmb174.farc 1D1E665D rom/2d/spr_cmnitm_thmb190.farc 8C0F26A0 rom/2d/spr_cmnitm_thmb208.farc 95B6DC8C rom/2d/spr_cmnitm_thmb224.farc 48D033B0 rom/2d/spr_edit_d2pvback004.farc BFC8D5FE rom/2d/spr_edit_d2pvback019.farc 54D0F8C6 rom/2d/spr_edit_d2pvback034.farc 0895B8A4 rom/2d/spr_edit_d2pvback049.farc 1B9A0F54 rom/2d/spr_edit_d2pvback064.farc C30335B4 rom/2d/spr_edit_d2pvback079.farc 02423814 rom/2d/spr_edit_d2pvback094.farc 5F902CBB rom/2d/spr_edit_d2pvback109.farc 206BD780 rom/2d/spr_edit_d2pvback140.farc 3EC45D8A rom/2d/spr_edit_d2pvback141.farc B8D74ED9 rom/2d/spr_edit_d2pvback142.farc D874B06A rom/2d/spr_edit_d2pvback143.farc D35510C6 rom/2d/spr_edit_d2pvback144.farc B92625AA rom/2d/spr_edit_d2pvback145.farc 6E2805A6 rom/2d/spr_edit_d2pvback146.farc A40BE610 rom/2d/spr_edit_d2pvback147.farc 24B7E3F9 rom/2d/spr_edit_d2pvback148.farc 775CDD78 rom/2d/spr_edit_d2pvback149.farc FBB7FF91 rom/2d/spr_edit_d2pvback150.farc C0646C7B rom/2d/spr_edit_d2pvback151.farc 5CA98AAF rom/2d/spr_edit_d2pvback152.farc 26D9D688 rom/2d/spr_edit_d2pvback153.farc E070902B rom/2d/spr_edit_d2pvback155.farc F5C4DF62 rom/2d/spr_edit_d2pvback156.farc 2136DAAB rom/2d/spr_edit_d2pvback157.farc 9B416808 rom/2d/spr_edit_d2pvback158.farc B42A755D rom/2d/spr_edit_d2pvback159.farc A95CD414 rom/2d/spr_edit_d2pvback160.farc D6D18534 rom/2d/spr_edit_d2pvback161.farc 5814E4E8 rom/2d/spr_edit_d2pvback162.farc 575079CD rom/2d/spr_edit_d2pvback163.farc C2D6D594 rom/2d/spr_edit_d2pvback164.farc 806BFABE rom/2d/spr_edit_d2pvback165.farc 44082317 rom/2d/spr_edit_d2pvback166.farc EBF8C82F rom/2d/spr_edit_d2pvback167.farc E3929E80 rom/2d/spr_edit_d2pvback168.farc 582DE8AC rom/2d/spr_edit_d2pvback170.farc B775718C rom/2d/spr_edit_d2pvback171.farc 97A57C4C rom/2d/spr_edit_d2pvback172.farc EA07AD8B rom/2d/spr_edit_d2pvback173.farc 98CC4FF0 rom/2d/spr_edit_d2pvback174.farc FB7EB2D4 rom/2d/spr_edit_d2pvback175.farc 59526246 rom/2d/spr_edit_d2pvback176.farc BC5DC445 rom/2d/spr_edit_d2pvback177.farc 2410C5F2 rom/2d/spr_edit_d2pvback178.farc 7EF89BDB rom/2d/spr_edit_d2pvback179.farc C9FC3304 rom/2d/spr_edit_d2pvback180.farc 9EEA1BCF rom/2d/spr_edit_d2pvback181.farc AC1562A9 rom/2d/spr_edit_d2pvback182.farc F03C125E rom/2d/spr_edit_d2pvback183.farc CF25CCA9 rom/2d/spr_edit_d2pvback185.farc B26EA8BB rom/2d/spr_edit_d2pvback186.farc 84E0DB75 rom/2d/spr_edit_d2pvback187.farc F207C202 rom/2d/spr_edit_d2pvback188.farc 33D5277F rom/2d/spr_edit_d2pvback189.farc 50E2C1DC rom/2d/spr_edit_d2pvback190.farc 33107A30 rom/2d/spr_edit_d2pvback191.farc B61B356C rom/2d/spr_edit_d2pvback192.farc C3B0946A rom/2d/spr_edit_d2pvback193.farc ED2822DA rom/2d/spr_edit_d2pvbackblack.farc 24959A65 rom/2d/spr_edit_d2pvbackwhite.farc 365564B8 rom/2d/spr_edit_expvback001.farc 44CFA847 rom/2d/spr_edit_expvback002.farc A7F9DAA0 rom/2d/spr_edit_expvback003.farc B799FAB5 rom/2d/spr_edit_expvback005.farc DBB6603D rom/2d/spr_edit_expvback006.farc 72125736 rom/2d/spr_edit_expvback007.farc 803480EC rom/2d/spr_edit_expvback008.farc FC57C391 rom/2d/spr_edit_expvback009.farc 1FD48307 rom/2d/spr_edit_expvback010.farc 444B6C7C rom/2d/spr_edit_expvback011.farc 854BD288 rom/2d/spr_edit_expvback012.farc 06BA52DF rom/2d/spr_edit_expvback013.farc 3D9E7057 rom/2d/spr_edit_expvback014.farc D7F92668 rom/2d/spr_edit_expvback015.farc F1DBB0E5 rom/2d/spr_edit_expvback016.farc AB08A81F rom/2d/spr_edit_expvback017.farc A7B037ED rom/2d/spr_edit_expvback018.farc 35A097DC rom/2d/spr_edit_expvback020.farc 6505899C rom/2d/spr_edit_expvback021.farc BF2125F8 rom/2d/spr_edit_expvback022.farc A8E71B93 rom/2d/spr_edit_expvback023.farc C2227E57 rom/2d/spr_edit_expvback024.farc 7AE5EB9A rom/2d/spr_edit_expvback025.farc A81172BD rom/2d/spr_edit_expvback026.farc 0ABEAA91 rom/2d/spr_edit_expvback027.farc CA20C59D rom/2d/spr_edit_expvback028.farc 4FF04881 rom/2d/spr_edit_expvback029.farc 976FB916 rom/2d/spr_edit_expvback030.farc B0DDFA27 rom/2d/spr_edit_expvback031.farc EE813946 rom/2d/spr_edit_expvback032.farc C52AD686 rom/2d/spr_edit_fpvback112.farc D98AC008 rom/2d/spr_edit_fpvback5017.farc 834BA1B3 rom/2d/spr_edit_fpvbackblack.farc 6F5366BE rom/2d/spr_edit_fpvbackpgreen.farc 3BE3DA4A rom/2d/spr_edit_fpvbackppink.farc 3B959D87 rom/2d/spr_edit_fpvbackpsky.farc D1363439 rom/2d/spr_edit_fpvbackpyellow.farc A13043D9 rom/2d/spr_edit_fpvbacksky.farc 0E9C493E rom/2d/spr_edit_fpvbackwhite.farc 14ED681D rom/2d/spr_edit_pvback001.farc 09283BCC rom/2d/spr_edit_pvback002.farc 6C4CD251 rom/2d/spr_edit_pvback003.farc C8C5B0E7 rom/2d/spr_edit_pvback004.farc 2B4214C1 rom/2d/spr_edit_pvback005.farc E387202D rom/2d/spr_edit_pvback006.farc C8EA28F8 rom/2d/spr_edit_pvback007.farc 265020DB rom/2d/spr_edit_pvback009.farc 114834EB rom/2d/spr_edit_pvback010.farc 9D434A6D rom/2d/spr_edit_pvback011.farc F6982F09 rom/2d/spr_edit_pvback012.farc 0ED15FB6 rom/2d/spr_edit_pvback013.farc 06FA841E rom/2d/spr_edit_pvback014.farc 67D7CAB2 rom/2d/spr_edit_pvback015.farc 203BF640 rom/2d/spr_edit_pvback016.farc 4B040AD0 rom/2d/spr_edit_pvback017.farc 6AD374AD rom/2d/spr_edit_pvback018.farc 49453A6D rom/2d/spr_edit_pvback019.farc 7387B2C0 rom/2d/spr_edit_pvback020.farc 4997A640 rom/2d/spr_edit_pvback021.farc 9EA0FC5F rom/2d/spr_edit_pvback022.farc 934E9DE5 rom/2d/spr_edit_pvback023.farc B6AA0182 rom/2d/spr_edit_pvback025.farc 04904383 rom/2d/spr_edit_pvback026.farc 1F2EF5AF rom/2d/spr_edit_pvback027.farc E443918B rom/2d/spr_edit_pvback028.farc B2F1F869 rom/2d/spr_edit_pvback029.farc 96DE3B20 rom/2d/spr_edit_pvback030.farc 30D12417 rom/2d/spr_edit_pvback031.farc B96E7637 rom/2d/spr_edit_pvback032.farc 2491B37D rom/2d/spr_edit_pvback033.farc 18B1938F rom/2d/spr_edit_pvback034.farc 87F46128 rom/2d/spr_edit_pvback035.farc 86AA6D4E rom/2d/spr_edit_pvback036.farc 42D51CFF rom/2d/spr_edit_pvback037.farc A3B2A065 rom/2d/spr_edit_pvback038.farc 2BA345A7 rom/2d/spr_edit_pvback039.farc E239A6E9 rom/2d/spr_edit_pvback041.farc 4E420972 rom/2d/spr_edit_pvback042.farc E8B3FD4A rom/2d/spr_edit_pvback043.farc 9EF824C6 rom/2d/spr_edit_pvback044.farc 39C72CC8 rom/2d/spr_edit_pvback045.farc 1417FF93 rom/2d/spr_edit_pvback046.farc B1EEC3A8 rom/2d/spr_edit_pvback047.farc 693A2BDF rom/2d/spr_edit_pvback048.farc AB4C8ABF rom/2d/spr_edit_pvback049.farc 90EF6322 rom/2d/spr_edit_pvback050.farc 9DDC2D9E rom/2d/spr_edit_pvback051.farc B4DA82CC rom/2d/spr_edit_pvback052.farc 6704C01C rom/2d/spr_edit_pvback053.farc FB610011 rom/2d/spr_edit_pvback054.farc F08CC8A3 rom/2d/spr_edit_pvback055.farc C745ECC8 rom/2d/spr_edit_pvback057.farc 1FA3208E rom/2d/spr_edit_pvback058.farc CC50E493 rom/2d/spr_edit_pvback059.farc 8CE5FF80 rom/2d/spr_edit_pvback060.farc 02637918 rom/2d/spr_edit_pvback061.farc E1704EB7 rom/2d/spr_edit_pvback062.farc B4CB222B rom/2d/spr_edit_pvback063.farc EC481E2D rom/2d/spr_edit_pvback064.farc 64A0B004 rom/2d/spr_edit_pvback065.farc 7561B011 rom/2d/spr_edit_pvback066.farc 6E90EE21 rom/2d/spr_edit_pvback067.farc B532DE8F rom/2d/spr_edit_pvback068.farc 24B4D9D3 rom/2d/spr_edit_pvback069.farc 10CA9982 rom/2d/spr_edit_pvback070.farc 7978062E rom/2d/spr_edit_pvback071.farc 759136AD rom/2d/spr_edit_pvback073.farc 8C94FA3A rom/2d/spr_edit_pvback074.farc 87515685 rom/2d/spr_edit_pvback075.farc 02761675 rom/2d/spr_edit_pvback076.farc 30AA4C87 rom/2d/spr_edit_pvback077.farc 9EB20F1D rom/2d/spr_edit_pvback078.farc 667C6458 rom/2d/spr_edit_pvback079.farc 115A96E6 rom/2d/spr_edit_pvback080.farc 0D4F610C rom/2d/spr_edit_pvback081.farc FF6EE782 rom/2d/spr_edit_pvback082.farc 11B35AD6 rom/2d/spr_edit_pvback083.farc D4A18AB2 rom/2d/spr_edit_pvback084.farc 39195830 rom/2d/spr_edit_pvback085.farc 6CB5BC70 rom/2d/spr_edit_pvback086.farc 619AD43B rom/2d/spr_edit_pvback087.farc 43D0EB96 rom/2d/spr_edit_pvback089.farc 01FB7502 rom/2d/spr_edit_pvback090.farc 0DA4D844 rom/2d/spr_edit_pvback091.farc EEB3CC2F rom/2d/spr_edit_pvback092.farc 95737E11 rom/2d/spr_edit_pvback093.farc C75F2A3E rom/2d/spr_edit_pvback094.farc 6A3FD521 rom/2d/spr_edit_pvback095.farc B267084B rom/2d/spr_edit_pvback096.farc 9D16D3E2 rom/2d/spr_edit_pvback097.farc B90C51D6 rom/2d/spr_edit_pvback098.farc EDF08D0C rom/2d/spr_edit_pvback099.farc 55577A20 rom/2d/spr_edit_pvback100.farc CE8C42A0 rom/2d/spr_edit_pvback101.farc 76253B1C rom/2d/spr_edit_pvback102.farc DDD63227 rom/2d/spr_edit_pvback103.farc ED641D06 rom/2d/spr_edit_pvback105.farc 5BC99CA0 rom/2d/spr_edit_pvback106.farc F6F0448E rom/2d/spr_edit_pvback107.farc 93DFE62B rom/2d/spr_edit_pvback108.farc AC34DE5D rom/2d/spr_edit_pvback109.farc 8A82C74B rom/2d/spr_edit_pvback110.farc E996A6B9 rom/2d/spr_edit_pvback111.farc 76289A08 rom/2d/spr_edit_pvback112.farc A926207F rom/2d/spr_edit_pvback113.farc 4F13D3F4 rom/2d/spr_edit_pvback114.farc AF3B46E9 rom/2d/spr_edit_pvback115.farc E796E2DC rom/2d/spr_edit_pvback116.farc 59A89CF9 rom/2d/spr_edit_pvback117.farc EC1818B6 rom/2d/spr_edit_pvback118.farc E95A6168 rom/2d/spr_edit_pvback119.farc 7585C1F6 rom/2d/spr_edit_d2pvback139.farc 4A7027CB rom/2d/spr_edit_d2pvback154.farc D19B8739 rom/2d/spr_edit_d2pvback169.farc 4CBE599D rom/2d/spr_edit_d2pvback184.farc 5C8E2E42 rom/2d/spr_edit_expvback004.farc 56AE7ED9 rom/2d/spr_edit_expvback019.farc EB6FA986 rom/2d/spr_edit_fpvback5012.farc BF5C974C rom/2d/spr_edit_pvback008.farc B027B995 rom/2d/spr_edit_pvback024.farc B60E42AB rom/2d/spr_edit_pvback040.farc 65352F9E rom/2d/spr_edit_pvback056.farc 76D4DFE1 rom/2d/spr_edit_pvback072.farc 2F5C96AB rom/2d/spr_edit_pvback088.farc D1F180CA rom/2d/spr_edit_pvback104.farc 34D8A728 rom/2d/spr_edit_pvback121.farc 5F704564 rom/2d/spr_edit_pvback122.farc A910518E rom/2d/spr_edit_pvback123.farc ABB2A68B rom/2d/spr_edit_pvback124.farc FF03A488 rom/2d/spr_edit_pvback125.farc F2E2C120 rom/2d/spr_edit_pvback126.farc B0FC8FE9 rom/2d/spr_edit_pvback127.farc 6E99B888 rom/2d/spr_edit_pvback128.farc 95D1E0AE rom/2d/spr_edit_pvback129.farc F78F096A rom/2d/spr_edit_pvback130.farc 814C7CA5 rom/2d/spr_edit_pvback131.farc 43FB85AA rom/2d/spr_edit_pvback132.farc 6418D471 rom/2d/spr_edit_pvback133.farc 2501118C rom/2d/spr_edit_pvback134.farc 34353A86 rom/2d/spr_edit_pvback135.farc 10A7CDC1 rom/2d/spr_edit_pvback137.farc 67AF0C5D rom/2d/spr_edit_pvback138.farc D6E866F8 rom/2d/spr_edit_pvback139.farc 4C233E01 rom/2d/spr_edit_pvback140.farc C7160C78 rom/2d/spr_edit_pvback141.farc 51A42A8D rom/2d/spr_edit_pvback142.farc 14863455 rom/2d/spr_edit_pvback143.farc E7B266BD rom/2d/spr_edit_pvback144.farc 7E0F4422 rom/2d/spr_edit_pvback145.farc 12C31787 rom/2d/spr_edit_pvback146.farc 532D09E1 rom/2d/spr_edit_pvback147.farc 6A33F52D rom/2d/spr_edit_pvback148.farc A57A76C7 rom/2d/spr_edit_pvback149.farc 5B4F6F1E rom/2d/spr_edit_pvback150.farc 13A58AF2 rom/2d/spr_edit_pvback151.farc 6FF97F94 rom/2d/spr_edit_pvback153.farc 51F9AC4E rom/2d/spr_edit_pvback154.farc 1C5A7BAE rom/2d/spr_edit_pvback155.farc 0AF11A97 rom/2d/spr_edit_pvback156.farc 06E5FF47 rom/2d/spr_edit_pvback157.farc CC5D54B9 rom/2d/spr_edit_pvback158.farc C2C7318D rom/2d/spr_edit_pvback159.farc 48719D14 rom/2d/spr_edit_pvback160.farc B8E4C10C rom/2d/spr_edit_pvback161.farc BDCA5AB7 rom/2d/spr_edit_pvback162.farc 3EEB25C1 rom/2d/spr_edit_pvback163.farc F13D9FE4 rom/2d/spr_edit_pvback164.farc 042C39E3 rom/2d/spr_edit_pvback165.farc 1CCE8D52 rom/2d/spr_edit_pvback166.farc E22D60C9 rom/2d/spr_edit_pvback167.farc 78619471 rom/2d/spr_edit_pvback169.farc 2D4936D0 rom/2d/spr_edit_pvback170.farc B60244F3 rom/2d/spr_edit_pvback171.farc E10AEEAE rom/2d/spr_edit_pvback172.farc 566E78DB rom/2d/spr_edit_pvback173.farc 9022A4C3 rom/2d/spr_edit_pvback174.farc 94F001F6 rom/2d/spr_edit_pvback175.farc AA3BC42D rom/2d/spr_edit_pvback176.farc C402E3C1 rom/2d/spr_edit_pvback177.farc DC7E8105 rom/2d/spr_edit_pvback178.farc 7DC824BB rom/2d/spr_edit_pvback179.farc 6E7D7242 rom/2d/spr_edit_pvback180.farc FDF1DE98 rom/2d/spr_edit_pvback181.farc 9BF66E68 rom/2d/spr_edit_pvback182.farc DAFC7900 rom/2d/spr_edit_pvback183.farc 59F93331 rom/2d/spr_edit_pvback185.farc 1D3FDAE5 rom/2d/spr_edit_pvback186.farc CB68061D rom/2d/spr_edit_pvback187.farc C8B8F8B1 rom/2d/spr_edit_pvback188.farc F33F5D1F rom/2d/spr_edit_pvback189.farc 2282DE7C rom/2d/spr_edit_pvback190.farc A6E4F6E6 rom/2d/spr_edit_pvback191.farc 318D2AF0 rom/2d/spr_edit_pvback192.farc 24783F09 rom/2d/spr_edit_pvback193.farc D3D2247A rom/2d/spr_edit_pvback194.farc A70DE235 rom/2d/spr_edit_pvback195.farc 001D6C5E rom/2d/spr_edit_pvback196.farc E2F9FFCA rom/2d/spr_ent_cmn.farc 97CDF167 rom/2d/spr_ent_name.farc 152B7D26 rom/2d/spr_ent_passintro.farc 4B8D1660 rom/2d/spr_fnt_24.farc D66210B0 rom/2d/spr_fnt_cmn.farc 941C69B7 rom/2d/spr_gam_cmn.farc 1C98B74A rom/2d/spr_gam_cont.farc F7B7076E rom/2d/spr_gam_ctstrslt.farc 4C578B1F rom/2d/spr_gam_edttit.farc C7EDCEE3 rom/2d/spr_gam_eff000.farc 895A1C83 rom/2d/spr_gam_eff001.farc 3825AF96 rom/2d/spr_gam_eff002.farc E033A2E7 rom/2d/spr_gam_eff003.farc 28240DCC rom/2d/spr_gam_eff004.farc 2BA5D979 rom/2d/spr_gam_eff005.farc E8228193 rom/2d/spr_gam_eff006.farc 40CDE81B rom/2d/spr_gam_eff007.farc 2DE1BDAA rom/2d/spr_gam_eff008.farc 594C9BF5 rom/2d/spr_gam_eff009.farc 5C84ADE3 rom/2d/spr_gam_eff010.farc BF247759 rom/2d/spr_gam_eff012.farc A598D232 rom/2d/spr_gam_eff013.farc 2D0B87E3 rom/2d/spr_gam_eff014.farc 3F04E418 rom/2d/spr_gam_eff015.farc F8AC8969 rom/2d/spr_gam_eff016.farc 0D80D33C rom/2d/spr_gam_eff017.farc F7B28415 rom/2d/spr_gam_eff018.farc 7AEEF16E rom/2d/spr_gam_eff019.farc 6A807A3E rom/2d/spr_gam_eff020.farc 2E022AB8 rom/2d/spr_gam_eff021.farc 92DD2F78 rom/2d/spr_gam_eff022.farc 182DCAFC rom/2d/spr_gam_eff023.farc 78EE92CB rom/2d/spr_gam_eff024.farc 4F4723B8 rom/2d/spr_gam_eff025.farc 6243F306 rom/2d/spr_gam_eff026.farc 20EE883C rom/2d/spr_gam_eff027.farc C6970238 rom/2d/spr_gam_eff029.farc 8B1B08B3 rom/2d/spr_gam_eff030.farc 97D57462 rom/2d/spr_gam_eff031.farc 20C3327C rom/2d/spr_gam_eff032.farc 022540C4 rom/2d/spr_gam_eff033.farc 273F57BA rom/2d/spr_gam_eff034.farc 571353B3 rom/2d/spr_gam_eff035.farc 54952025 rom/2d/spr_gam_eff036.farc E884E6F4 rom/2d/spr_gam_eff039.farc 5F48EA20 rom/2d/spr_gam_eff040.farc 49D6ED5B rom/2d/spr_gam_eff041.farc 77E30035 rom/2d/spr_gam_eff042.farc 2A38C780 rom/2d/spr_gam_eff044.farc F343E336 rom/2d/spr_gam_eff050.farc 0216C5AD rom/2d/spr_gam_eff051.farc 02D2DE8D rom/2d/spr_gam_eff052.farc 3D06885C rom/2d/spr_gam_eff054.farc B2DCF406 rom/2d/spr_gam_eff055.farc 9CCC47CD rom/2d/spr_gam_eff058.farc F48387E1 rom/2d/spr_gam_eff059.farc EBB1E2B6 rom/2d/spr_gam_eff062.farc 7007E324 rom/2d/spr_gam_eff064.farc 68D9E66A rom/2d/spr_gam_eff066.farc E0C04F37 rom/2d/spr_gam_eff068.farc 6D8AC44F rom/2d/spr_gam_eff069.farc 83659F18 rom/2d/spr_gam_eff070.farc 3BA59982 rom/2d/spr_gam_eff071.farc 45DEE936 rom/2d/spr_gam_gover.farc 83F6CE92 rom/2d/spr_gam_loadsc.farc CE39FD1F rom/2d/spr_gam_prize.farc 1820107D rom/2d/spr_gam_pv001.farc B7F24C96 rom/2d/spr_gam_pv002.farc 1A573F87 rom/2d/spr_gam_pv004.farc B673A628 rom/2d/spr_gam_pv005.farc 56D749B5 rom/2d/spr_gam_pv006.farc 31E23BEA rom/2d/spr_gam_pv007.farc B8EB299B rom/2d/spr_gam_pv008.farc 6D6EBA20 rom/2d/spr_gam_pv009.farc 486BA8F6 rom/2d/spr_gam_pv010.farc 6A1E0612 rom/2d/spr_gam_pv011.farc 75DB3950 rom/2d/spr_gam_pv012.farc 93AC16CF rom/2d/spr_gam_pv013.farc C57E34B3 rom/2d/spr_gam_pv014.farc 9C7C9157 rom/2d/spr_gam_pv015.farc 2804B5D4 rom/2d/spr_gam_pv016.farc 4469E014 rom/2d/spr_gam_pv017.farc DFB785B7 rom/2d/spr_gam_pv018.farc 6804CA01 rom/2d/spr_gam_pv019.farc 91829AC1 rom/2d/spr_gam_pv021.farc CFE657E4 rom/2d/spr_gam_pv022.farc 56B47BFA rom/2d/spr_gam_pv023.farc DE5ED11B rom/2d/spr_gam_pv024.farc 96D2E2A2 rom/2d/spr_gam_pv025.farc 2E6567FF rom/2d/spr_gam_pv026.farc 449EA678 rom/2d/spr_gam_pv027.farc 9A0B3989 rom/2d/spr_gam_pv028.farc 670E985F rom/2d/spr_gam_pv029.farc D8B0C086 rom/2d/spr_gam_pv030.farc B20A114D rom/2d/spr_gam_pv031.farc D7A761D0 rom/2d/spr_gam_pv032.farc 45B60CD6 rom/2d/spr_gam_pv037.farc 924161FB rom/2d/spr_gam_pv038.farc 3B880257 rom/2d/spr_gam_pv039.farc 0123CDBB rom/2d/spr_gam_pv040.farc A142070E rom/2d/spr_gam_pv042.farc 1BD21692 rom/2d/spr_gam_pv043.farc BABD4173 rom/2d/spr_gam_pv044.farc 0074558F rom/2d/spr_gam_pv045.farc 086EDC52 rom/2d/spr_gam_pv046.farc 73A205F5 rom/2d/spr_gam_pv047.farc 5B5254D9 rom/2d/spr_gam_pv049.farc 28CC0C87 rom/2d/spr_gam_pv050.farc 7AF5B274 rom/2d/spr_gam_pv051.farc 8058000E rom/2d/spr_gam_pv052.farc B5FF5516 rom/2d/spr_gam_pv053.farc 347FAB6A rom/2d/spr_gam_pv054.farc 8B80C532 rom/2d/spr_gam_pv055.farc 879D7DBF rom/2d/spr_gam_pv056.farc 2CD1269C rom/2d/spr_gam_pv057.farc 86E18952 rom/2d/spr_gam_pv058.farc AD0A5D4F rom/2d/spr_gam_pv060.farc 53DFB303 rom/2d/spr_gam_pv061.farc 277EC0EE rom/2d/spr_gam_pv062.farc BCC2FAD5 rom/2d/spr_gam_pv063.farc 3A53BA51 rom/2d/spr_gam_pv064.farc 5E3B7223 rom/2d/spr_gam_pv065.farc 012C8271 rom/2d/spr_gam_pv066.farc 4DAD13AB rom/2d/spr_gam_pv079.farc A020F8C1 rom/2d/spr_gam_pv081.farc F804650D rom/2d/spr_gam_pv082.farc 633E4BAC rom/2d/spr_gam_pv083.farc 13332444 rom/2d/spr_gam_pv084.farc 1C282285 rom/2d/spr_gam_pv085.farc ACBFB852 rom/2d/spr_gam_pv086.farc F0180ECC rom/2d/spr_gam_pv087.farc 8CF0C2F7 rom/2d/spr_gam_pv088.farc B11726A2 rom/2d/spr_gam_pv090.farc 5653CAF5 rom/2d/spr_gam_pv091.farc D73E1953 rom/2d/spr_gam_pv092.farc 9E5DE42E rom/2d/spr_gam_pv093.farc A83C8E79 rom/2d/spr_gam_pv094.farc 2BF4F79C rom/2d/spr_gam_pv095.farc 01EB6DC8 rom/2d/spr_gam_pv096.farc 64A0E62B rom/2d/spr_gam_pv097.farc 56E47B39 rom/2d/spr_gam_pv101.farc 0FBA2CEE rom/2d/spr_gam_pv102.farc CF81080E rom/2d/spr_gam_pv103.farc 67EE5F6E rom/2d/spr_gam_pv104.farc 36B35829 rom/2d/spr_gam_pv201.farc 02916CE8 rom/2d/spr_gam_pv202.farc 47AD16FB rom/2d/spr_gam_pv203.farc 2DAA64E7 rom/2d/spr_gam_pv204.farc 76B2E933 rom/2d/spr_gam_pv206.farc 492347F5 rom/2d/spr_gam_pv207.farc 791CB511 rom/2d/spr_gam_pv208.farc 988B35C9 rom/2d/spr_gam_pv210.farc 99E20AF0 rom/2d/spr_gam_pv211.farc 1EB4B7B7 rom/2d/spr_gam_pv212.farc 595AB601 rom/2d/spr_gam_pv214.farc C9A3490C rom/2d/spr_gam_pv218.farc ABCE0D51 rom/2d/spr_gam_pv219.farc 18230F8B rom/2d/spr_gam_pv220.farc 3F3942F4 rom/2d/spr_gam_pv221.farc 0C9E2939 rom/2d/spr_gam_pv222.farc 4C42D6E3 rom/2d/spr_gam_pv223.farc 1F31F00B rom/2d/spr_gam_pv224.farc 3B66DEE5 rom/2d/spr_gam_pv225.farc D6AD8EA1 rom/2d/spr_gam_pv227.farc 3A2DCA12 rom/2d/spr_gam_pv232.farc 28E3920A rom/2d/spr_gam_pv233.farc 82FEB22A rom/2d/spr_gam_pv234.farc 313CFCBB rom/2d/spr_gam_pv235.farc 24C08116 rom/2d/spr_gam_pv236.farc 801E1CE2 rom/2d/spr_gam_pv238.farc 0B114887 rom/2d/spr_gam_pv239.farc 31636DBB rom/2d/spr_gam_pv240.farc 2D3E5E05 rom/2d/spr_gam_pv241.farc E148CF9B rom/2d/spr_gam_pv242.farc AC375602 rom/2d/spr_gam_pv243.farc 1528D441 rom/2d/spr_gam_pv244.farc 46972DB4 rom/2d/spr_gam_pv246.farc 8A8D4B04 rom/2d/spr_gam_pv247.farc 328C1C5F rom/2d/spr_gam_pv248.farc 81FCF737 rom/2d/spr_gam_pv249.farc 52AACC86 rom/2d/spr_edit_pvback136.farc 578F6F28 rom/2d/spr_edit_pvback152.farc 1C8D0492 rom/2d/spr_edit_pvback168.farc A016E6C3 rom/2d/spr_edit_pvback184.farc F4865B40 rom/2d/spr_fnt_bold24.farc E14D7C63 rom/2d/spr_gam_eff011.farc 2A7CD334 rom/2d/spr_gam_eff028.farc BCB85E7A rom/2d/spr_gam_eff053.farc D0EE6AA4 rom/2d/spr_gam_pv003.farc D0AE03EE rom/2d/spr_gam_pv020.farc D168A99D rom/2d/spr_gam_pv041.farc 1AFEA73D rom/2d/spr_gam_pv059.farc F9C55BB2 rom/2d/spr_gam_pv089.farc C0949A1C rom/2d/spr_gam_pv205.farc BB5BB526 rom/2d/spr_gam_pv231.farc 142B8B88 rom/2d/spr_gam_pv251.farc 0EBA1C57 rom/2d/spr_gam_pv253.farc 238D6F2A rom/2d/spr_gam_pv255.farc E9B3F903 rom/2d/spr_gam_pv257.farc 226D5FB0 rom/2d/spr_gam_pv259.farc BB7094F4 rom/2d/spr_gam_pv260.farc F60A6F47 rom/2d/spr_gam_pv261.farc 3D6AD59B rom/2d/spr_gam_pv262.farc 9903BA2C rom/2d/spr_gam_pv401.farc 1D38FAAF rom/2d/spr_gam_pv402.farc DA979D0F rom/2d/spr_gam_pv403.farc A75321CC rom/2d/spr_gam_pv404.farc 80727876 rom/2d/spr_gam_pv405.farc EBD9E633 rom/2d/spr_gam_pv406.farc 6833C465 rom/2d/spr_gam_pv407.farc FE14C740 rom/2d/spr_gam_pv408.farc 64E25C14 rom/2d/spr_gam_pv410.farc 7188ED3C rom/2d/spr_gam_pv411.farc DCA400CA rom/2d/spr_gam_pv412.farc 21670C0B rom/2d/spr_gam_pv413.farc A138D53D rom/2d/spr_gam_pv414.farc 0F72886B rom/2d/spr_gam_pv415.farc BC57561B rom/2d/spr_gam_pv416.farc 9C3430B7 rom/2d/spr_gam_pv417.farc 21FF9166 rom/2d/spr_gam_pv418.farc BDA8AABA rom/2d/spr_gam_pv419.farc F0841186 rom/2d/spr_gam_pv420.farc 4099821D rom/2d/spr_gam_pv421.farc 83798474 rom/2d/spr_gam_pv422.farc A38C8989 rom/2d/spr_gam_pv423.farc E082C06A rom/2d/spr_gam_pv424.farc 07E8580D rom/2d/spr_gam_pv425.farc C84ED116 rom/2d/spr_gam_pv427.farc A5B1E7AC rom/2d/spr_gam_pv432.farc 6E6AE632 rom/2d/spr_gam_pv433.farc 4D02FF84 rom/2d/spr_gam_pv434.farc EF164590 rom/2d/spr_gam_pv435.farc D0E5BBB4 rom/2d/spr_gam_pv436.farc AF179835 rom/2d/spr_gam_pv437.farc 6EDBA1CD rom/2d/spr_gam_pv438.farc 184FF550 rom/2d/spr_gam_pv439.farc 93F70524 rom/2d/spr_gam_pv440.farc 5A705391 rom/2d/spr_gam_pv441.farc 54FA5475 rom/2d/spr_gam_pv442.farc FD37418D rom/2d/spr_gam_pv443.farc 9236EFB3 rom/2d/spr_gam_pv600.farc 0AADB7AE rom/2d/spr_gam_pv601.farc 05F774B4 rom/2d/spr_gam_pv602.farc F929E665 rom/2d/spr_gam_pv604.farc BD8A1B75 rom/2d/spr_gam_pv605.farc 3E2C8491 rom/2d/spr_gam_pv607.farc 0F0E0C21 rom/2d/spr_gam_pv609.farc 87C4FE9B rom/2d/spr_gam_pv610.farc D3A48F8B rom/2d/spr_gam_pv611.farc B8A74D3C rom/2d/spr_gam_pv612.farc 72180427 rom/2d/spr_gam_pv613.farc 8871E9B5 rom/2d/spr_gam_pv614.farc 8BA887B0 rom/2d/spr_gam_pv615.farc DF1DC8D3 rom/2d/spr_gam_pv616.farc 736F5AB2 rom/2d/spr_gam_pv617.farc 3DF7A017 rom/2d/spr_gam_pv618.farc 01CF4072 rom/2d/spr_gam_pv619.farc B38C8F0A rom/2d/spr_gam_pv620.farc 017DE469 rom/2d/spr_gam_pv621.farc 6545E375 rom/2d/spr_gam_pv623.farc D93BC612 rom/2d/spr_gam_pv624.farc D7357F48 rom/2d/spr_gam_pv625.farc DD8C91F0 rom/2d/spr_gam_pv626.farc 8A8ADF14 rom/2d/spr_gam_pv627.farc 8B5E2D6B rom/2d/spr_gam_pv628.farc C00B65C9 rom/2d/spr_gam_pv629.farc FE444AA2 rom/2d/spr_gam_pv630.farc AEB1E7CF rom/2d/spr_gam_pv631.farc 2CB8030E rom/2d/spr_gam_pv637.farc 6C46032A rom/2d/spr_gam_pv638.farc 0B26E6D2 rom/2d/spr_gam_pv639.farc 64199178 rom/2d/spr_gam_pv640.farc FF3A3519 rom/2d/spr_gam_pv641.farc D9A89B09 rom/2d/spr_gam_pv642.farc 19650DBC rom/2d/spr_gam_pv710.farc 6A7306E8 rom/2d/spr_gam_pv723.farc BAB6301A rom/2d/spr_gam_pv724.farc 36A206D4 rom/2d/spr_gam_pv725.farc 9BDC1BBB rom/2d/spr_gam_pv726.farc C7A93901 rom/2d/spr_gam_pv727.farc EE206AEF rom/2d/spr_gam_pv728.farc 47FA6AC2 rom/2d/spr_gam_pv729.farc B4A955E8 rom/2d/spr_gam_pv730.farc 1AD6D6D6 rom/2d/spr_gam_pv731.farc 94C2B4C4 rom/2d/spr_gam_pv732.farc D9F40392 rom/2d/spr_gam_pv733.farc 55A88FB8 rom/2d/spr_gam_pv734.farc 9752A452 rom/2d/spr_gam_pv736.farc 605A37C6 rom/2d/spr_gam_pv737.farc F3275FC3 rom/2d/spr_gam_pv738.farc F841D7DA rom/2d/spr_gam_pv739.farc 6EE1ACB4 rom/2d/spr_gam_pv832.farc A82BD0D5 rom/2d/spr_gam_qstrslt.farc 76AB293C rom/2d/spr_gam_result.farc 3F37ECF7 rom/2d/spr_gam_sc.farc C7E3D196 rom/2d/spr_gam_skin001.farc 6E3232AE rom/2d/spr_gam_skin002.farc 29AC0917 rom/2d/spr_gam_skin003.farc 917D9845 rom/2d/spr_gam_skin004.farc 1BA3A30C rom/2d/spr_gam_skin005.farc 56821BD1 rom/2d/spr_gam_skin006.farc 34EDA103 rom/2d/spr_gam_skin007.farc 1445628B rom/2d/spr_gam_skin008.farc 49CE545F rom/2d/spr_gam_skin009.farc 8C62A81A rom/2d/spr_gam_skin010.farc E474C44A rom/2d/spr_gam_skin011.farc 97FF8F67 rom/2d/spr_gam_skin013.farc 10BA9E34 rom/2d/spr_gam_skin014.farc 6F70300B rom/2d/spr_gam_skin015.farc C343A113 rom/2d/spr_gam_skin016.farc 604D410E rom/2d/spr_gam_skin017.farc BC5102D7 rom/2d/spr_gam_skin018.farc F6308CB9 rom/2d/spr_gam_skin019.farc 762215BE rom/2d/spr_gam_skin020.farc 0DB6CAEC rom/2d/spr_gam_skin021.farc AC2214D9 rom/2d/spr_gam_skin022.farc 8F47C96E rom/2d/spr_gam_skin023.farc 1C907271 rom/2d/spr_gam_skin024.farc 9DC04809 rom/2d/spr_gam_skin025.farc BC948EC6 rom/2d/spr_gam_skin026.farc B6E4876D rom/2d/spr_gam_skin027.farc 4BFCAB8C rom/2d/spr_gam_skin029.farc CF98FD1E rom/2d/spr_gam_skin030.farc C4BD909B rom/2d/spr_gam_skin031.farc 3C8A6129 rom/2d/spr_gam_skin032.farc 56FF72D4 rom/2d/spr_gam_skin033.farc EFAE951C rom/2d/spr_gam_skin034.farc 3AD96FF1 rom/2d/spr_gam_skin035.farc 2F3CA13D rom/2d/spr_gam_skin036.farc ADD5ABF5 rom/2d/spr_gam_skin037.farc 3425E921 rom/2d/spr_gam_skin038.farc 70F684C8 rom/2d/spr_gam_skin039.farc E665F275 rom/2d/spr_gam_skin040.farc D7736A19 rom/2d/spr_gam_skin041.farc 3BB0B486 rom/2d/spr_gam_skin042.farc 5AD46ECF rom/2d/spr_gam_skin043.farc 9C67361C rom/2d/spr_gam_skin045.farc 41ADC977 rom/2d/spr_gam_skin046.farc 669665C2 rom/2d/spr_gam_skin047.farc 565A9386 rom/2d/spr_gam_skin048.farc 5316BDCB rom/2d/spr_gam_skin049.farc FCFEF119 rom/2d/spr_gam_skin050.farc CC05B9AE rom/2d/spr_gam_skin051.farc DCD8E2A2 rom/2d/spr_gam_skin052.farc 1D984F35 rom/2d/spr_gam_skin053.farc 6E5CAD95 rom/2d/spr_gam_skin054.farc 24DC4C04 rom/2d/spr_gam_skin055.farc 7507B97E rom/2d/spr_gam_skin056.farc 96DF0077 rom/2d/spr_gam_skin057.farc 5AAAFB99 rom/2d/spr_gam_skin058.farc 2AA54AB3 rom/2d/spr_gam_skin059.farc 877F9460 rom/2d/spr_gam_skin061.farc 016C7903 rom/2d/spr_gam_skin062.farc 95560243 rom/2d/spr_gam_skin063.farc F7F443C1 rom/2d/spr_gam_skin064.farc 3C8B47B8 rom/2d/spr_gam_skin065.farc 609CF6EC rom/2d/spr_gam_skin066.farc 4CBBAD0B rom/2d/spr_gam_skin067.farc 7F9656CE rom/2d/spr_gam_skin068.farc DB45BA3F rom/2d/spr_gam_skin069.farc F5FE0341 rom/2d/spr_gam_skin070.farc C8F05356 rom/2d/spr_gam_skin071.farc F465A6DB rom/2d/spr_gam_skin072.farc 7282F788 rom/2d/spr_gam_skin073.farc 10F60384 rom/2d/spr_gam_skin074.farc FA2C72AD rom/2d/spr_gam_skin075.farc 6C6A9A50 rom/2d/spr_gam_skin077.farc 7338C843 rom/2d/spr_gam_skin078.farc 4BAFBC94 rom/2d/spr_gam_skin079.farc D58843C5 rom/2d/spr_gam_skin080.farc 8187172B rom/2d/spr_gam_skin081.farc 75F08EA0 rom/2d/spr_gam_skin082.farc 6B5C0CDC rom/2d/spr_gam_skin083.farc F88A5E2D rom/2d/spr_gam_skin084.farc AD09953B rom/2d/spr_gam_skin085.farc 53412389 rom/2d/spr_gam_skin086.farc 259F02B7 rom/2d/spr_gam_skin087.farc 53D55B0C rom/2d/spr_gam_skin088.farc 47377FF2 rom/2d/spr_gam_skin089.farc A09CC23F rom/2d/spr_gam_skin090.farc 11BD2585 rom/2d/spr_gam_skin091.farc C8D2E06E rom/2d/spr_gam_skin093.farc 3DB305D3 rom/2d/spr_gam_skin094.farc D6E59229 rom/2d/spr_gam_skin095.farc 5F6F005E rom/2d/spr_gam_skin096.farc 0DD8FBC6 rom/2d/spr_gam_skin097.farc 2C811C23 rom/2d/spr_gam_skin098.farc 3C29C3DC rom/2d/spr_gam_skin099.farc 09B38925 rom/2d/spr_gam_skin100.farc F9F2C57C rom/2d/spr_gam_skin101.farc 597DE267 rom/2d/spr_gam_skin102.farc 8C778668 rom/2d/spr_gam_skin103.farc 06289C62 rom/2d/spr_gam_skin104.farc F9A08822 rom/2d/spr_gam_skin105.farc 13D2A3AC rom/2d/spr_gam_skin106.farc 6400E16D rom/2d/spr_gam_skin107.farc F6EA5BD8 rom/2d/spr_gam_skin109.farc 73D27A79 rom/2d/spr_gam_skin110.farc BDD0B317 rom/2d/spr_gam_skin111.farc 83BC7444 rom/2d/spr_gam_skin112.farc D00ECC79 rom/2d/spr_gam_skin113.farc 45017F1D rom/2d/spr_gam_skin114.farc 8C78C122 rom/2d/spr_gam_skin115.farc 8EE21595 rom/2d/spr_gam_skin116.farc 061C1D8C rom/2d/spr_gam_skin117.farc DB383718 rom/2d/spr_gam_skin118.farc 31FA2872 rom/2d/spr_gam_skin119.farc 5807B613 rom/2d/spr_gam_skin120.farc E517B442 rom/2d/spr_gam_skin121.farc CFEB20FB rom/2d/spr_gam_skin122.farc 53E28516 rom/2d/spr_gam_skin123.farc BA43A0E3 rom/2d/spr_gam_skin125.farc 7FF7CD4D rom/2d/spr_gam_skin126.farc EE653938 rom/2d/spr_gam_skin127.farc 82E9D966 rom/2d/spr_gam_skin128.farc BB2A9498 rom/2d/spr_gam_skin129.farc 5B26789F rom/2d/spr_gam_skin130.farc 2751F41F rom/2d/spr_gam_skin131.farc FD668E17 rom/2d/spr_gam_skin132.farc 6C3FD4FE rom/2d/spr_gam_skin133.farc 7A1CE29C rom/2d/spr_gam_skin134.farc 915008AD rom/2d/spr_gam_skin135.farc 3E88B310 rom/2d/spr_gam_skin136.farc 1C2F18C2 rom/2d/spr_gam_skin137.farc 51940BDF rom/2d/spr_gam_skin138.farc 197E79D6 rom/2d/spr_gam_skin139.farc 2D68E7B9 rom/2d/spr_gam_skin141.farc 82C1463C rom/2d/spr_gam_skin142.farc AFE7FB7E rom/2d/spr_gam_skin143.farc 2821F933 rom/2d/spr_gam_skin144.farc 9A8CA0F7 rom/2d/spr_gam_skin145.farc 9880E40F rom/2d/spr_gam_skin146.farc 3B4DB648 rom/2d/spr_gam_skin147.farc D1AF5BD6 rom/2d/spr_gam_skin148.farc 6E500130 rom/2d/spr_gam_skin149.farc 4C03A954 rom/2d/spr_gam_skin150.farc 1C0E79BE rom/2d/spr_gam_skin151.farc 0A6019A8 rom/2d/spr_gam_skin152.farc 05872897 rom/2d/spr_gam_skin153.farc 44E5DE8B rom/2d/spr_gam_skin154.farc 6C285360 rom/2d/spr_gam_skin155.farc 8146BCE9 rom/2d/spr_gam_pv409.farc 934ACED8 rom/2d/spr_gam_pv426.farc 5F30B69E rom/2d/spr_gam_pv603.farc 418D5D73 rom/2d/spr_gam_pv622.farc E6B1FDF1 rom/2d/spr_gam_pv722.farc 9CE56E7C rom/2d/spr_gam_pv740.farc 0528048C rom/2d/spr_gam_skin012.farc 87C40946 rom/2d/spr_gam_skin028.farc 910C1E78 rom/2d/spr_gam_skin044.farc 303BA1CF rom/2d/spr_gam_skin060.farc 488B746E rom/2d/spr_gam_skin076.farc A56C0654 rom/2d/spr_gam_skin092.farc 4036BEA1 rom/2d/spr_gam_skin108.farc 6A170BC0 rom/2d/spr_gam_skin124.farc 76927D65 rom/2d/spr_gam_skin157.farc AC4AEEA6 rom/2d/spr_gam_skin158.farc BA3A882F rom/2d/spr_gam_skin159.farc 2E28FC72 rom/2d/spr_gam_skin160.farc E5C06523 rom/2d/spr_gam_skin161.farc 213575C2 rom/2d/spr_gam_skin162.farc FAB693FF rom/2d/spr_gam_skin163.farc 62EA4E1B rom/2d/spr_gam_skin164.farc F4C38E6E rom/2d/spr_gam_skin165.farc 546BB9CC rom/2d/spr_gam_skin166.farc 2E3EEAB3 rom/2d/spr_gam_skin167.farc 945875F5 rom/2d/spr_gam_skin168.farc 91A8C4B9 rom/2d/spr_gam_skin169.farc 4F1A93E8 rom/2d/spr_gam_skin170.farc 12008D32 rom/2d/spr_gam_skin171.farc 246AFDD9 rom/2d/spr_gam_skin173.farc 3D06C7A7 rom/2d/spr_gam_skin174.farc DB4D0DB2 rom/2d/spr_gam_skin175.farc 2E37ECDA rom/2d/spr_gam_skin176.farc 8ABD1366 rom/2d/spr_gam_skin177.farc DF1BD45E rom/2d/spr_gam_skin178.farc 7EA1F1A1 rom/2d/spr_gam_skin179.farc C633916F rom/2d/spr_gam_skin180.farc 2D5BB5BE rom/2d/spr_gam_skin181.farc D85320C7 rom/2d/spr_gam_skin182.farc 877DABB6 rom/2d/spr_gam_skin183.farc EBB1BDBF rom/2d/spr_gam_skin184.farc 0D4B2C4D rom/2d/spr_gam_skin185.farc 3BB746DF rom/2d/spr_gam_skin186.farc 194A8FD4 rom/2d/spr_gam_skin187.farc 315F8645 rom/2d/spr_gam_skin189.farc 0C4A1956 rom/2d/spr_gam_skin190.farc 0BD7F47B rom/2d/spr_gam_skin191.farc 3D662BFD rom/2d/spr_gam_skin192.farc 0853096E rom/2d/spr_gam_skin193.farc 8A3B688E rom/2d/spr_gam_skin194.farc 7F3B2C60 rom/2d/spr_gam_skin195.farc EF1265AC rom/2d/spr_gam_skin196.farc BF27249F rom/2d/spr_gam_skin197.farc C62A9A57 rom/2d/spr_gam_skin198.farc 08334067 rom/2d/spr_gam_skin199.farc 6170FFB7 rom/2d/spr_gam_skin200.farc C5A56544 rom/2d/spr_gam_skin201.farc 62A82F14 rom/2d/spr_gam_skin202.farc 03291D9E rom/2d/spr_gam_skin203.farc DE1CE3DE rom/2d/spr_gam_skin205.farc 5349AE91 rom/2d/spr_gam_skin206.farc 4DE2A24E rom/2d/spr_gam_skin207.farc 76CEF542 rom/2d/spr_gam_skin208.farc 84E47E9B rom/2d/spr_gam_skin209.farc 7D4B61DE rom/2d/spr_gam_skin210.farc 2D6C57F0 rom/2d/spr_gam_skin211.farc 0D2A6D4D rom/2d/spr_gam_skin212.farc E3958547 rom/2d/spr_gam_skin213.farc C5837830 rom/2d/spr_gam_skin214.farc 06455AAA rom/2d/spr_gam_skin215.farc 55F5FBE5 rom/2d/spr_gam_skin216.farc 04116B50 rom/2d/spr_gam_skin217.farc 6A51B3D7 rom/2d/spr_gam_skin218.farc 5E53CA0D rom/2d/spr_gam_skin219.farc 750D74E7 rom/2d/spr_gam_skin221.farc 4B93A691 rom/2d/spr_gam_skin222.farc 83BDCB3E rom/2d/spr_gam_skin223.farc 064BC916 rom/2d/spr_gam_skin224.farc C558E788 rom/2d/spr_gam_skin225.farc 5BB4E30A rom/2d/spr_gam_skin226.farc A2E46E44 rom/2d/spr_gam_skin227.farc C8CF8005 rom/2d/spr_gam_skin228.farc E20A2397 rom/2d/spr_gam_skin229.farc D3A63A33 rom/2d/spr_gam_skin230.farc 5FFBD0D2 rom/2d/spr_gam_skin231.farc 0BEB5174 rom/2d/spr_gam_skin232.farc 5B3F1C9D rom/2d/spr_gam_skin233.farc 8D26860B rom/2d/spr_gam_skin234.farc 46AF1572 rom/2d/spr_gam_skin235.farc 3A72DF5A rom/2d/spr_gam_skin237.farc 292A096B rom/2d/spr_gam_skin238.farc F1DD0C79 rom/2d/spr_gam_skin239.farc 765D02D5 rom/2d/spr_gam_skin240.farc 40BE79DD rom/2d/spr_gam_skin241.farc B1C7F323 rom/2d/spr_gam_skin242.farc BAD8C4C6 rom/2d/spr_gam_skin243.farc E4B06316 rom/2d/spr_gam_skin244.farc 642BBC80 rom/2d/spr_gam_skin245.farc 2120628D rom/2d/spr_gam_skin246.farc FC3FF9EB rom/2d/spr_gam_skin247.farc 7DC2500D rom/2d/spr_gam_skin248.farc 64F79258 rom/2d/spr_gam_skin249.farc 98938832 rom/2d/spr_gam_skin250.farc 32A1112D rom/2d/spr_gam_skin251.farc 6CAF075F rom/2d/spr_gam_skin253.farc F17FF505 rom/2d/spr_gam_skin254.farc 88F969CC rom/2d/spr_gam_skin255.farc 46479B89 rom/2d/spr_gam_skin256.farc 791BC41F rom/2d/spr_gam_skin257.farc EFF76375 rom/2d/spr_gam_skin258.farc 63A68EEA rom/2d/spr_gam_skin259.farc 4D2CD618 rom/2d/spr_gam_skin260.farc 7634DEA1 rom/2d/spr_gam_skin261.farc 7C3F941F rom/2d/spr_gam_skin262.farc 513C1ACB rom/2d/spr_gam_skin263.farc 652216E4 rom/2d/spr_gam_skin264.farc F22F1F41 rom/2d/spr_gam_skin265.farc 0400CFFD rom/2d/spr_gam_skin266.farc 69522239 rom/2d/spr_gam_skin267.farc D216645E rom/2d/spr_gam_skin269.farc CCB18287 rom/2d/spr_gam_skin270.farc D350CB27 rom/2d/spr_gam_skin271.farc ECDD5AA7 rom/2d/spr_gam_skin272.farc 104E65A3 rom/2d/spr_gam_skin273.farc CF14413B rom/2d/spr_gam_skin274.farc 4790A140 rom/2d/spr_gam_skin275.farc 8E891B38 rom/2d/spr_gam_skin276.farc FF4302F5 rom/2d/spr_gam_skin277.farc DB8296F7 rom/2d/spr_gam_skin278.farc D5E598BE rom/2d/spr_gam_skin279.farc 63498094 rom/2d/spr_gam_skin280.farc B204B71E rom/2d/spr_gam_skin281.farc B4044ADF rom/2d/spr_gam_skin282.farc 13D27312 rom/2d/spr_gam_skin283.farc 6FBAFA54 rom/2d/spr_gam_skin285.farc B5E2128E rom/2d/spr_gam_skin286.farc FBFD281F rom/2d/spr_gam_skin287.farc 8A4B3ABF rom/2d/spr_gam_skin288.farc BEFE6D90 rom/2d/spr_gam_skin289.farc 823B5350 rom/2d/spr_gam_skin290.farc 76EBDDBB rom/2d/spr_gam_skin291.farc 32B85569 rom/2d/spr_gam_skin292.farc 035E98B6 rom/2d/spr_gam_skin293.farc 14ECF739 rom/2d/spr_gam_skin294.farc 1345B4BD rom/2d/spr_gam_skin295.farc 6A436CB0 rom/2d/spr_gam_skin296.farc EE3669B3 rom/2d/spr_gam_skin297.farc 3DEEF457 rom/2d/spr_gam_skin298.farc 8B36E987 rom/2d/spr_gam_skin299.farc A0D75383 rom/2d/spr_gam_skin301.farc 1E12899B rom/2d/spr_gam_skin302.farc A5259F83 rom/2d/spr_gam_skin303.farc 19D199BE rom/2d/spr_gam_skin304.farc ABCAE847 rom/2d/spr_gam_skin305.farc FDBB8089 rom/2d/spr_gam_skin306.farc 99C492D4 rom/2d/spr_gam_skin307.farc A4D80C00 rom/2d/spr_gam_skin308.farc E4FAC20F rom/2d/spr_gam_skin309.farc 2119CCFC rom/2d/spr_gam_skin310.farc FE2CBF8F rom/2d/spr_gam_skin311.farc D2573BEC rom/2d/spr_gam_skin312.farc 81802175 rom/2d/spr_gam_skin313.farc E67A81AB rom/2d/spr_gam_skin314.farc 2FF053CE rom/2d/spr_gam_skin315.farc C166DC8E rom/2d/spr_gam_skin317.farc 88F0369F rom/2d/spr_gam_skin318.farc 4FC9EA63 rom/2d/spr_gam_skin319.farc 376CAD82 rom/2d/spr_gam_skin320.farc 92DA64DC rom/2d/spr_gam_skin321.farc C7FB624C rom/2d/spr_gam_skin322.farc B0443A14 rom/2d/spr_gam_skin323.farc 186D3B3F rom/2d/spr_gam_skin324.farc 583CC3D2 rom/2d/spr_gam_skin325.farc FBC9575D rom/2d/spr_gam_skin326.farc 4812FEBC rom/2d/spr_gam_skin327.farc 60183558 rom/2d/spr_gam_skin328.farc 7280C762 rom/2d/spr_gam_skin329.farc B45E1DE7 rom/2d/spr_gam_skin330.farc CAE601DD rom/2d/spr_gam_skin331.farc D8FF8505 rom/2d/spr_gam_skin333.farc A761F204 rom/2d/spr_gam_skin334.farc 243B997B rom/2d/spr_gam_skin335.farc 3BE11438 rom/2d/spr_gam_skin336.farc E889ED86 rom/2d/spr_gam_skin337.farc 01328DA6 rom/2d/spr_gam_skin338.farc 672C5A68 rom/2d/spr_gam_skin339.farc C456A306 rom/2d/spr_gam_skin340.farc 1D5D2A6F rom/2d/spr_gam_skin341.farc 4C47932D rom/2d/spr_gam_skin342.farc 6F44F7CF rom/2d/spr_gam_skin343.farc A09CF774 rom/2d/spr_gam_skin344.farc 7C18B8ED rom/2d/spr_gam_skin345.farc A4B0CFB0 rom/2d/spr_gam_skin346.farc 27E1C209 rom/2d/spr_gam_skin347.farc D22E260C rom/2d/spr_gam_skin349.farc 887F3BB2 rom/2d/spr_gam_skin350.farc FE8251EF rom/2d/spr_gam_skin351.farc 19BE22F2 rom/2d/spr_gam_skin352.farc 7D78C170 rom/2d/spr_gam_skin353.farc 03DB4DEC rom/2d/spr_gam_skin354.farc 1AAD4695 rom/2d/spr_gam_skin355.farc C858E37C rom/2d/spr_gam_skin356.farc 758BEAEA rom/2d/spr_gam_skin357.farc 5AE898A6 rom/2d/spr_gam_skin358.farc 46A067E6 rom/2d/spr_gam_skin359.farc 44329EA4 rom/2d/spr_gam_skin360.farc 097A85D7 rom/2d/spr_gam_skin361.farc 8D410442 rom/2d/spr_gam_skin362.farc 1293B821 rom/2d/spr_gam_skin363.farc CE541011 rom/2d/spr_gam_skin365.farc 36B76AC2 rom/2d/spr_gam_skin366.farc 49573C0A rom/2d/spr_gam_skin367.farc 1F25F1B3 rom/2d/spr_gam_skin368.farc 71B2F2EC rom/2d/spr_gam_skin369.farc 3431A816 rom/2d/spr_gam_skin370.farc 9914FBDB rom/2d/spr_gam_skin371.farc B54B13C2 rom/2d/spr_gam_skin372.farc 56F8D19C rom/2d/spr_gam_skin373.farc 2C6CFB72 rom/2d/spr_gam_skin374.farc 15107A13 rom/2d/spr_gam_skin375.farc 05AFA54F rom/2d/spr_gam_skin376.farc B31354F5 rom/2d/spr_gam_skin377.farc BE1C6032 rom/2d/spr_gam_skin378.farc 079AF5BA rom/2d/spr_gam_skin379.farc 5BA201F5 rom/2d/spr_gam_skin381.farc 4D21F93D rom/2d/spr_gam_skin382.farc 45608EA2 rom/2d/spr_gam_skin383.farc C41D03E5 rom/2d/spr_gam_skin384.farc 4DF69F9C rom/2d/spr_gam_skin385.farc A9C3AB92 rom/2d/spr_gam_skin386.farc C6E70899 rom/2d/spr_gam_skin387.farc 0A8141C7 rom/2d/spr_gam_skin388.farc 1505F7C7 rom/2d/spr_gam_skin389.farc 94D0DF39 rom/2d/spr_gam_skin390.farc BECB900B rom/2d/spr_gam_skin391.farc FBCFADB5 rom/2d/spr_gam_skin392.farc ED2A0817 rom/2d/spr_gam_skin393.farc 9054C792 rom/2d/spr_gam_skin394.farc 60C01AE6 rom/2d/spr_gam_skin395.farc B6FA8F6B rom/2d/spr_gam_skin156.farc 55C8558D rom/2d/spr_gam_skin172.farc BB26ACB9 rom/2d/spr_gam_skin188.farc 28572ADE rom/2d/spr_gam_skin204.farc 659837C7 rom/2d/spr_gam_skin220.farc 57B1B695 rom/2d/spr_gam_skin236.farc AFB2024E rom/2d/spr_gam_skin252.farc 0E8FE590 rom/2d/spr_gam_skin268.farc 272700AE rom/2d/spr_gam_skin284.farc 33D7D8B9 rom/2d/spr_gam_skin300.farc 691CBB9C rom/2d/spr_gam_skin316.farc 4A63EF3C rom/2d/spr_gam_skin332.farc 771064B1 rom/2d/spr_gam_skin348.farc 6AF2A532 rom/2d/spr_gam_skin364.farc 5F2BC875 rom/2d/spr_gam_skin397.farc 48F0031C rom/2d/spr_gam_skin398.farc 68FBD5D2 rom/2d/spr_gam_skin399.farc AF7C0FD6 rom/2d/spr_gam_skin400.farc A88F6536 rom/2d/spr_gam_skin401.farc C18E1982 rom/2d/spr_gam_skin402.farc 637E00EA rom/2d/spr_gam_skin403.farc CFDA6BA4 rom/2d/spr_gam_skin404.farc FAC7EBDB rom/2d/spr_gam_skin405.farc 79C7092F rom/2d/spr_gam_skin406.farc 0089897F rom/2d/spr_gam_skin407.farc F6101226 rom/2d/spr_gam_skin408.farc 19BF076C rom/2d/spr_gam_skin409.farc C90A89D2 rom/2d/spr_gam_skin410.farc D4FB5228 rom/2d/spr_gam_skin411.farc 91743714 rom/2d/spr_gam_skin413.farc D6693870 rom/2d/spr_gam_skin414.farc 3447F05C rom/2d/spr_gam_skin415.farc DE0C86AB rom/2d/spr_gam_skin416.farc E116B108 rom/2d/spr_gam_skin417.farc F608CD12 rom/2d/spr_gam_skin418.farc F9A4E896 rom/2d/spr_gam_skin419.farc AFD0E811 rom/2d/spr_gam_skin420.farc 7D6AEE63 rom/2d/spr_gam_skin421.farc B88D0F16 rom/2d/spr_gam_skin422.farc 2EDC376D rom/2d/spr_gam_skin423.farc FD5618F3 rom/2d/spr_gam_skin424.farc 1CB46C9A rom/2d/spr_gam_skin425.farc 40253D85 rom/2d/spr_gam_skin426.farc 491152CE rom/2d/spr_gam_skin427.farc 11DCB0B9 rom/2d/spr_gam_skin429.farc EA1603D6 rom/2d/spr_gam_skin430.farc A8BB6AB1 rom/2d/spr_gam_skin431.farc F606D081 rom/2d/spr_gam_skin432.farc C1BD0920 rom/2d/spr_gam_skin433.farc A3AE2919 rom/2d/spr_gam_skin434.farc 1E25FFA1 rom/2d/spr_gam_skin435.farc 9AC67ED4 rom/2d/spr_gam_skin436.farc 4DBD9041 rom/2d/spr_gam_skin437.farc AE543D9D rom/2d/spr_gam_skin438.farc 276DD19B rom/2d/spr_gam_skin439.farc A5E8DDEE rom/2d/spr_gam_skin440.farc 4A977120 rom/2d/spr_gam_skin441.farc 0E5DAFF2 rom/2d/spr_gam_skin442.farc 9C743A76 rom/2d/spr_gam_skin443.farc 18ECF3E1 rom/2d/spr_gam_skin445.farc 385FBD5B rom/2d/spr_gam_skin446.farc 916EF2E8 rom/2d/spr_gam_skin447.farc 403EC100 rom/2d/spr_gam_skin448.farc 73BDADC2 rom/2d/spr_gam_skin449.farc 69EE1C96 rom/2d/spr_gam_skin450.farc 70FD9817 rom/2d/spr_gam_skin451.farc 547C2D7B rom/2d/spr_gam_skin452.farc E6176EC8 rom/2d/spr_gam_skin453.farc 585279AA rom/2d/spr_gam_skin454.farc 27E15842 rom/2d/spr_gam_skin455.farc 5AB2CB02 rom/2d/spr_gam_skin456.farc 2B7E4D65 rom/2d/spr_gam_skin457.farc 5F76FB14 rom/2d/spr_gam_skin458.farc C53CC6AD rom/2d/spr_gam_skin459.farc 40D75373 rom/2d/spr_gam_skin461.farc CFBFC2B2 rom/2d/spr_gam_skin462.farc 04D5F9F7 rom/2d/spr_gam_skin463.farc BF4B01A5 rom/2d/spr_gam_skin464.farc D4796281 rom/2d/spr_gam_skin465.farc 690749F8 rom/2d/spr_gam_skin466.farc C6925ED9 rom/2d/spr_gam_skin467.farc 723E07EC rom/2d/spr_gam_skin468.farc 147A8591 rom/2d/spr_gam_skin469.farc E9159010 rom/2d/spr_gam_skin470.farc D821D25E rom/2d/spr_gam_skin471.farc C10B3528 rom/2d/spr_gam_skin472.farc EA0CAABE rom/2d/spr_gam_skin473.farc 65C6EBAE rom/2d/spr_gam_skin474.farc 5BCB2893 rom/2d/spr_gam_skin475.farc 5992DF44 rom/2d/spr_gam_skin477.farc A70057B3 rom/2d/spr_gam_skin478.farc D135B10D rom/2d/spr_gam_skin479.farc 61766565 rom/2d/spr_gam_skin480.farc CDACD963 rom/2d/spr_gam_skin481.farc 6C8402FF rom/2d/spr_gam_skin482.farc 6D1752A6 rom/2d/spr_gam_skin483.farc 0C89F0AF rom/2d/spr_gam_skin484.farc BDBD5C1E rom/2d/spr_gam_skin485.farc A916DC24 rom/2d/spr_gam_skin486.farc 36EBBA49 rom/2d/spr_gam_skin487.farc 6786512A rom/2d/spr_gam_skin488.farc 332070E8 rom/2d/spr_gam_skin489.farc 91381044 rom/2d/spr_gam_skin490.farc 43F9C184 rom/2d/spr_gam_skin491.farc CE79517E rom/2d/spr_gam_skin493.farc C52E8C49 rom/2d/spr_gam_skin494.farc D9686DFA rom/2d/spr_gam_skin495.farc A856EFBC rom/2d/spr_gam_skin496.farc F6C8CDED rom/2d/spr_gam_skin497.farc 4E7F2F0A rom/2d/spr_gam_skin498.farc 81A67984 rom/2d/spr_gam_skin499.farc D34DFD11 rom/2d/spr_gam_skin500.farc 04305B74 rom/2d/spr_gam_skin501.farc 55DA9CF5 rom/2d/spr_gam_skin502.farc 98FA1A1F rom/2d/spr_gam_skin503.farc 062A6FBD rom/2d/spr_gam_skin504.farc 5928C9E8 rom/2d/spr_gam_skin505.farc 4FCF679B rom/2d/spr_gam_skin506.farc F1187256 rom/2d/spr_gam_skin507.farc 1ED856FC rom/2d/spr_gam_skin509.farc AB9AD4ED rom/2d/spr_gam_skin510.farc EA2F4A65 rom/2d/spr_gam_skin511.farc 49C18C27 rom/2d/spr_gam_skin512.farc AE59DDAA rom/2d/spr_gam_skin513.farc 0751AE1A rom/2d/spr_gam_skin514.farc F02B33F3 rom/2d/spr_gam_skin515.farc B618804D rom/2d/spr_gam_skin516.farc A2061A99 rom/2d/spr_gam_skin517.farc 2D351823 rom/2d/spr_gam_skin518.farc 0FA870E2 rom/2d/spr_gam_skin519.farc 11FADC90 rom/2d/spr_gam_skin520.farc 51BBA25E rom/2d/spr_gam_skin521.farc 306C2E79 rom/2d/spr_gam_skin522.farc 6389AED2 rom/2d/spr_gam_skin523.farc CE8D9287 rom/2d/spr_gam_skin525.farc BB6DB929 rom/2d/spr_gam_skin526.farc 76E10F3B rom/2d/spr_gam_skin527.farc 49904A1B rom/2d/spr_gam_skin528.farc A23B0274 rom/2d/spr_gam_skin529.farc 2F177209 rom/2d/spr_gam_skin530.farc 558A364D rom/2d/spr_gam_skin531.farc E5525598 rom/2d/spr_gam_skin532.farc 256D6ABD rom/2d/spr_gam_skin533.farc F1AB08E6 rom/2d/spr_gam_skin534.farc 7E29621A rom/2d/spr_gam_skin535.farc 18953920 rom/2d/spr_gam_skin536.farc FD1CA8B1 rom/2d/spr_gam_skin537.farc 88CF9F77 rom/2d/spr_gam_skin538.farc E4F19521 rom/2d/spr_gam_skin539.farc E11BF044 rom/2d/spr_gam_skin541.farc 33F0C4BF rom/2d/spr_gam_skin542.farc 45B647AB rom/2d/spr_gam_skin543.farc A97328FE rom/2d/spr_gam_skin544.farc DB3D45D4 rom/2d/spr_gam_skin545.farc A379E385 rom/2d/spr_gam_skin546.farc 47297228 rom/2d/spr_gam_skin547.farc AC95AABA rom/2d/spr_gam_skin548.farc 7DAD0CB2 rom/2d/spr_gam_skin549.farc 8EECFA07 rom/2d/spr_gam_skin550.farc E41CDA4F rom/2d/spr_gam_skin551.farc DFED7AA6 rom/2d/spr_gam_skin552.farc 21E4CAEB rom/2d/spr_gam_skin553.farc C44F08F9 rom/2d/spr_gam_skin554.farc 6232D35C rom/2d/spr_gam_skin555.farc E3058DC1 rom/2d/spr_gam_skin557.farc F9AFBC1D rom/2d/spr_gam_skin558.farc 284ED781 rom/2d/spr_gam_skin559.farc B1B1566C rom/2d/spr_gam_skin560.farc 28680972 rom/2d/spr_gam_skin561.farc 1FD1D122 rom/2d/spr_gam_skin562.farc B12AEC36 rom/2d/spr_gam_skin563.farc BAC28C56 rom/2d/spr_gam_skin564.farc 12EA7D6C rom/2d/spr_gam_skin565.farc 9DA625FB rom/2d/spr_gam_skin566.farc FB110876 rom/2d/spr_gam_skin567.farc 9A55A9E5 rom/2d/spr_gam_skin568.farc A278E0C1 rom/2d/spr_gam_skin569.farc 6D3DD213 rom/2d/spr_gam_skin570.farc 3BAED99F rom/2d/spr_gam_skin571.farc 1761FE79 rom/2d/spr_gam_skin573.farc 1195494C rom/2d/spr_gam_skin574.farc 5F06E847 rom/2d/spr_gam_skin575.farc 2A98F45D rom/2d/spr_gam_skin576.farc 7EAE9630 rom/2d/spr_gam_skin577.farc 230C603B rom/2d/spr_gam_skin578.farc 8792A9E6 rom/2d/spr_gam_skin579.farc 48086A87 rom/2d/spr_gam_skin580.farc 3F62F27D rom/2d/spr_gam_skin581.farc 2A4F006F rom/2d/spr_gam_skin582.farc D0DB4342 rom/2d/spr_gam_skin583.farc 20BA949A rom/2d/spr_gam_skin584.farc F4C6A89C rom/2d/spr_gam_skin585.farc EE1B36A0 rom/2d/spr_gam_skin586.farc 92152214 rom/2d/spr_gam_skin587.farc F8A8FE2A rom/2d/spr_gam_skin589.farc C10231B4 rom/2d/spr_gam_skin590.farc F1CD4F8C rom/2d/spr_gam_skin591.farc 4B9D029D rom/2d/spr_gam_skin592.farc 66894535 rom/2d/spr_gam_skin593.farc CEE6FA39 rom/2d/spr_gam_skin594.farc 9A3C8770 rom/2d/spr_gam_skin595.farc 47252511 rom/2d/spr_gam_skin596.farc 93406346 rom/2d/spr_gam_skin597.farc 270CF698 rom/2d/spr_gam_skin598.farc F7651610 rom/2d/spr_gam_skin599.farc 2CE3DE17 rom/2d/spr_gam_skin600.farc 135DB950 rom/2d/spr_gam_skin601.farc 1B2C833C rom/2d/spr_gam_skin602.farc 86004CDF rom/2d/spr_gam_skin603.farc 5EF2DF43 rom/2d/spr_gam_skin605.farc 01494348 rom/2d/spr_gam_skin606.farc 6E2F7612 rom/2d/spr_gam_skin607.farc 8C60474C rom/2d/spr_gam_skin608.farc 07EEE36E rom/2d/spr_gam_skin609.farc EF69D980 rom/2d/spr_gam_skin610.farc 84CB09B2 rom/2d/spr_gam_skin611.farc 7196632E rom/2d/spr_gam_skin612.farc 1C48AFA0 rom/2d/spr_gam_skin613.farc 2E320389 rom/2d/spr_gam_skin614.farc 56470FD4 rom/2d/spr_gam_skin615.farc 48333E38 rom/2d/spr_gam_skin616.farc D23274B2 rom/2d/spr_gam_skin617.farc DDE9DD5C rom/2d/spr_gam_skin618.farc 60D1951B rom/2d/spr_gam_skin619.farc FE79B24C rom/2d/spr_gam_skin621.farc BEE1D8D3 rom/2d/spr_gam_skin622.farc B72AFD6E rom/2d/spr_gam_skin623.farc FAA3FB71 rom/2d/spr_gam_skin624.farc 91483F49 rom/2d/spr_gam_skin625.farc 5447A97D rom/2d/spr_gam_skin626.farc 67FEB956 rom/2d/spr_gam_skin627.farc 8BADD44B rom/2d/spr_gam_skin628.farc 478F97DB rom/2d/spr_gam_skin629.farc 04B97C74 rom/2d/spr_gam_skin630.farc 81F447C0 rom/2d/spr_gam_skin631.farc 8064F63E rom/2d/spr_gam_skin632.farc 59F682E3 rom/2d/spr_gam_skin633.farc B1488E05 rom/2d/spr_gam_skin634.farc AF95CFB1 rom/2d/spr_gam_skin635.farc 7BBDB3AC rom/2d/spr_gam_skin396.farc 86FF64EB rom/2d/spr_gam_skin412.farc 5479C73B rom/2d/spr_gam_skin428.farc 51720281 rom/2d/spr_gam_skin444.farc D55BA50C rom/2d/spr_gam_skin460.farc F8C92597 rom/2d/spr_gam_skin476.farc 3201C1F1 rom/2d/spr_gam_skin492.farc 911B0F1E rom/2d/spr_gam_skin508.farc 101357CF rom/2d/spr_gam_skin524.farc D31EB3A9 rom/2d/spr_gam_skin540.farc A4AFA155 rom/2d/spr_gam_skin556.farc AAE533E2 rom/2d/spr_gam_skin572.farc 391D920F rom/2d/spr_gam_skin588.farc 76ED0EEC rom/2d/spr_gam_skin604.farc 5FAB3484 rom/2d/spr_gam_skin637.farc E996E7A9 rom/2d/spr_gam_skin638.farc D9ED3359 rom/2d/spr_gam_skin639.farc DAFB2D5C rom/2d/spr_gam_skin640.farc BEEBF9C2 rom/2d/spr_gam_skin641.farc 15578686 rom/2d/spr_gam_skin642.farc CE899F79 rom/2d/spr_gam_skin643.farc F7C24B32 rom/2d/spr_gam_skin644.farc 1597F1B1 rom/2d/spr_gam_skin645.farc 2609DB1C rom/2d/spr_gam_skin646.farc 53882E2A rom/2d/spr_gam_skin647.farc 8BA46654 rom/2d/spr_gam_skin648.farc 0F2F170D rom/2d/spr_gam_skin649.farc 7D63D287 rom/2d/spr_gam_skin650.farc F3C37917 rom/2d/spr_gam_skin651.farc 1D09A770 rom/2d/spr_gam_skin653.farc EAFAF620 rom/2d/spr_gam_skin654.farc 62A23483 rom/2d/spr_gam_skin655.farc 35C554C8 rom/2d/spr_gam_skin656.farc 55EE1781 rom/2d/spr_gam_skin657.farc 479787C7 rom/2d/spr_gam_skin658.farc 93B31554 rom/2d/spr_gam_skin659.farc F82A66E4 rom/2d/spr_gam_skin660.farc E493E6B2 rom/2d/spr_gam_skin661.farc AA505CCB rom/2d/spr_gam_skin662.farc 7F961122 rom/2d/spr_gam_skin663.farc 2E3F506C rom/2d/spr_gam_skin664.farc 29F196D3 rom/2d/spr_gam_skin665.farc 7984FC3D rom/2d/spr_gam_skin666.farc 5AC71FB4 rom/2d/spr_gam_skin667.farc 2A14F577 rom/2d/spr_gam_skin669.farc 45C4EA57 rom/2d/spr_gam_skin670.farc 0146BAD1 rom/2d/spr_gam_skin671.farc 9602FF0E rom/2d/spr_gam_skin672.farc 2B6F8C48 rom/2d/spr_gam_skin673.farc CF940512 rom/2d/spr_gam_skin674.farc FFE7A6C4 rom/2d/spr_gam_skin675.farc 646442DF rom/2d/spr_gam_skin676.farc 26415E80 rom/2d/spr_gam_skin677.farc A7C5D4FB rom/2d/spr_gam_skin678.farc D7214978 rom/2d/spr_gam_skin679.farc 6AD8BCD6 rom/2d/spr_gam_skin680.farc 9EF3CE2B rom/2d/spr_gam_skin681.farc 10E954BA rom/2d/spr_gam_skin682.farc 7237BF5F rom/2d/spr_gam_skin683.farc 3607D04A rom/2d/spr_gam_skin685.farc 9DDD57A9 rom/2d/spr_gam_skin686.farc D039A92D rom/2d/spr_gam_skin687.farc E39CF117 rom/2d/spr_gam_skin688.farc BFC9CF74 rom/2d/spr_gam_skin689.farc BFA76C24 rom/2d/spr_gam_skin690.farc CAF3BF1A rom/2d/spr_gam_skin691.farc 2FE63DA6 rom/2d/spr_gam_skin692.farc B9FDDA9C rom/2d/spr_gam_skin693.farc 19081AB0 rom/2d/spr_gam_skin694.farc 3D7FA01A rom/2d/spr_gam_skin695.farc 35C471D5 rom/2d/spr_gam_skin696.farc 6223137B rom/2d/spr_gam_skin697.farc 2C37169E rom/2d/spr_gam_skin698.farc 13EA2B8E rom/2d/spr_gam_skin699.farc 63FDDDE3 rom/2d/spr_gam_skin701.farc 246E58E3 rom/2d/spr_gam_skin702.farc 0E52CE69 rom/2d/spr_gam_skin703.farc 9308C215 rom/2d/spr_gam_skin704.farc BDCDF00C rom/2d/spr_gam_skin705.farc F8692CF3 rom/2d/spr_gam_skin706.farc DEBCF063 rom/2d/spr_gam_skin707.farc 04373D68 rom/2d/spr_gam_skin708.farc 3D15E9C4 rom/2d/spr_gam_skin709.farc 4F5EAC67 rom/2d/spr_gam_skin710.farc 6E7A4FCE rom/2d/spr_gam_skin711.farc 939D63EB rom/2d/spr_gam_skin712.farc 270ED214 rom/2d/spr_gam_skin713.farc 8439D0F4 rom/2d/spr_gam_skin714.farc 3968AC7D rom/2d/spr_gam_skin715.farc EE86EB0C rom/2d/spr_gam_skin717.farc 0DC5C341 rom/2d/spr_gam_skin718.farc 0562F88B rom/2d/spr_gam_skin719.farc 00E795BC rom/2d/spr_gam_skin720.farc E296C9F5 rom/2d/spr_gam_skin721.farc 63AB3C06 rom/2d/spr_gam_skin722.farc 3119A062 rom/2d/spr_gam_skin723.farc 80D26AEF rom/2d/spr_gam_skin724.farc 30A08F1B rom/2d/spr_gam_skin725.farc 82977D58 rom/2d/spr_gam_skin726.farc AEF4D6AC rom/2d/spr_gam_skin727.farc 75F58D1F rom/2d/spr_gam_skin728.farc 4030D903 rom/2d/spr_gam_skin729.farc 0259AFEB rom/2d/spr_gam_skin730.farc FE01A120 rom/2d/spr_gam_skin731.farc F413A01E rom/2d/spr_gam_skin732.farc B65939F0 rom/2d/spr_gam_skin734.farc 2C534188 rom/2d/spr_gam_skin735.farc 13619217 rom/2d/spr_gam_skin736.farc 84D4D74F rom/2d/spr_gam_skin737.farc CF85862B rom/2d/spr_gam_skin738.farc 4EAD001B rom/2d/spr_key_input.farc 7B1D919F rom/2d/spr_key_pass.farc 510C4E3E rom/2d/spr_key_svol.farc F36D4C3C rom/2d/spr_key_win.farc B2BF23FC rom/2d/spr_ps3_cmn.farc CBB6BC31 rom/2d/spr_sel_belt.farc 5CA010E4 rom/2d/spr_sel_camp.farc 09B08ECD rom/2d/spr_sel_camp02.farc C0DFBFAC rom/2d/spr_sel_card.farc 3A89847E rom/2d/spr_sel_cardbg.farc 17D7BFCA rom/2d/spr_sel_cardinfo.farc CFAFFF58 rom/2d/spr_sel_chlle.farc 9C363ABD rom/2d/spr_sel_cmn.farc A7C4C6E6 rom/2d/spr_sel_credit.farc E25D8D66 rom/2d/spr_sel_ctst.farc C840A759 rom/2d/spr_sel_ctstinfo.farc F2F85F7B rom/2d/spr_sel_md000cmn.farc D4D72210 rom/2d/spr_sel_md001cmn.farc ED4A373D rom/2d/spr_sel_md002cmn.farc 7E906D98 rom/2d/spr_sel_md003cmn.farc 88067D06 rom/2d/spr_sel_md004cmn.farc D98275B0 rom/2d/spr_sel_md005cmn.farc DF950D67 rom/2d/spr_sel_md006cmn.farc 2935636C rom/2d/spr_sel_md007cmn.farc AF659C86 rom/2d/spr_sel_md008cmn.farc 2C93C6B9 rom/2d/spr_sel_md009cmn.farc DD2840CE rom/2d/spr_sel_md011cmn.farc 6E41366F rom/2d/spr_sel_md012cmn.farc FB9537C0 rom/2d/spr_sel_md013cmn.farc 6AFD4C00 rom/2d/spr_sel_md014cmn.farc 34DBAB4A rom/2d/spr_sel_md015cmn.farc 2F46642A rom/2d/spr_sel_md016cmn.farc 8524D5DA rom/2d/spr_sel_md017cmn.farc 87241B9E rom/2d/spr_sel_md018cmn.farc 4C6B046D rom/2d/spr_sel_md019cmn.farc 48BE5C32 rom/2d/spr_sel_md020cmn.farc EBFE946E rom/2d/spr_sel_md021cmn.farc 29D6BE37 rom/2d/spr_sel_md022cmn.farc 7AD6580A rom/2d/spr_sel_md023cmn.farc ED295AC0 rom/2d/spr_sel_md024cmn.farc AE762D89 rom/2d/spr_sel_md025cmn.farc 7C7CAE55 rom/2d/spr_sel_md027cmn.farc 42CB075E rom/2d/spr_sel_md028cmn.farc 3572F661 rom/2d/spr_sel_md029cmn.farc 2EF6A3E8 rom/2d/spr_sel_md030cmn.farc D184982D rom/2d/spr_sel_md031cmn.farc AF7D6CB0 rom/2d/spr_sel_md032cmn.farc E8419E04 rom/2d/spr_sel_md033cmn.farc 86BCB446 rom/2d/spr_sel_md034cmn.farc 7C3D43AA rom/2d/spr_sel_md035cmn.farc 75790ED0 rom/2d/spr_sel_md036cmn.farc 3218CFD0 rom/2d/spr_sel_md037cmn.farc 51AED5BB rom/2d/spr_sel_md038cmn.farc AAF7CDDD rom/2d/spr_sel_md039cmn.farc E48A72C3 rom/2d/spr_sel_md040cmn.farc 53A11A5C rom/2d/spr_sel_md041cmn.farc D43B82C1 rom/2d/spr_sel_md043cmn.farc E8C131B1 rom/2d/spr_sel_md044cmn.farc D784EBC8 rom/2d/spr_sel_md045cmn.farc 5CD6DF62 rom/2d/spr_sel_md046cmn.farc F56A515F rom/2d/spr_sel_md047cmn.farc 31E8B849 rom/2d/spr_sel_md048cmn.farc F8BA82DE rom/2d/spr_sel_md049cmn.farc B923E35E rom/2d/spr_sel_md050cmn.farc D05E433B rom/2d/spr_sel_md051cmn.farc 67C27B98 rom/2d/spr_sel_md052cmn.farc 8E25972B rom/2d/spr_sel_md053cmn.farc 491B2870 rom/2d/spr_sel_md054cmn.farc CAA63094 rom/2d/spr_sel_md055cmn.farc DF31269D rom/2d/spr_sel_md056cmn.farc 051611BE rom/2d/spr_sel_md057cmn.farc 8E1BB0DB rom/2d/spr_sel_md059cmn.farc 36F5A9C5 rom/2d/spr_sel_md060cmn.farc 6A302388 rom/2d/spr_sel_md061cmn.farc B7A68CB3 rom/2d/spr_sel_md062cmn.farc F42196A8 rom/2d/spr_sel_md063cmn.farc 75DE4B36 rom/2d/spr_sel_md064cmn.farc A82E2824 rom/2d/spr_sel_md065cmn.farc 109EF815 rom/2d/spr_sel_md066cmn.farc 2249BF47 rom/2d/spr_sel_md067cmn.farc CC04472C rom/2d/spr_sel_md068cmn.farc 94F0C985 rom/2d/spr_sel_md069cmn.farc CA877836 rom/2d/spr_sel_md070cmn.farc B65EE353 rom/2d/spr_sel_md071cmn.farc A4AD93D2 rom/2d/spr_sel_md072cmn.farc BCFDD3E5 rom/2d/spr_sel_md073cmn.farc AB3EFB69 rom/2d/spr_sel_md075cmn.farc A5FA2D73 rom/2d/spr_sel_md076cmn.farc 7C3C9D8A rom/2d/spr_sel_md077cmn.farc 0A071331 rom/2d/spr_sel_md078cmn.farc 9E02CD06 rom/2d/spr_sel_md079cmn.farc 5B452564 rom/2d/spr_sel_md080cmn.farc A89AD893 rom/2d/spr_sel_md081cmn.farc F3FF45E6 rom/2d/spr_sel_md082cmn.farc 8B458374 rom/2d/spr_sel_md083cmn.farc 1F618BD1 rom/2d/spr_sel_md084cmn.farc 82ED6A2A rom/2d/spr_sel_md085cmn.farc 66353A29 rom/2d/spr_sel_md086cmn.farc AF3650A6 rom/2d/spr_sel_md087cmn.farc C1E2E969 rom/2d/spr_sel_md088cmn.farc D382F01D rom/2d/spr_sel_md089cmn.farc 56588034 rom/2d/spr_sel_md091cmn.farc D0977447 rom/2d/spr_sel_md092cmn.farc 7CCEB627 rom/2d/spr_sel_md093cmn.farc AB16A101 rom/2d/spr_sel_md094cmn.farc 85D9A5CF rom/2d/spr_sel_md095cmn.farc 79BF62B5 rom/2d/spr_sel_md096cmn.farc B53DC5DE rom/2d/spr_sel_md097cmn.farc CC11C8A4 rom/2d/spr_sel_md098cmn.farc 94143BCB rom/2d/spr_sel_md099cmn.farc B197B409 rom/2d/spr_sel_md100cmn.farc 9464B4F7 rom/2d/spr_sel_md101cmn.farc EBDB8F06 rom/2d/spr_sel_md102cmn.farc 3E7105BF rom/2d/spr_sel_md103cmn.farc 1B176058 rom/2d/spr_sel_md104cmn.farc 541A8979 rom/2d/spr_sel_md105cmn.farc 813D372C rom/2d/spr_sel_md107cmn.farc B935345A rom/2d/spr_sel_md108cmn.farc 2FB06F7F rom/2d/spr_sel_md109cmn.farc A0C37863 rom/2d/spr_sel_md110cmn.farc 2D185F49 rom/2d/spr_sel_md111cmn.farc 94E9DB54 rom/2d/spr_sel_md112cmn.farc 9FEAE96C rom/2d/spr_sel_md113cmn.farc 9932A753 rom/2d/spr_sel_md114cmn.farc 7A06FE4D rom/2d/spr_sel_md115cmn.farc 5DE2131E rom/2d/spr_sel_md116cmn.farc E149D86D rom/2d/spr_sel_md117cmn.farc A0DF197B rom/2d/spr_sel_md118cmn.farc 720A981E rom/2d/spr_sel_md119cmn.farc 7D80ECDE rom/2d/spr_sel_md120cmn.farc 681A24B5 rom/2d/spr_sel_md121cmn.farc DE9C54F1 rom/2d/spr_gam_skin636.farc 6DD57A0D rom/2d/spr_gam_skin652.farc A8A4C31E rom/2d/spr_gam_skin668.farc 8C7D97AD rom/2d/spr_gam_skin684.farc 5052474A rom/2d/spr_gam_skin700.farc E73CE052 rom/2d/spr_gam_skin716.farc 84A226A0 rom/2d/spr_gam_skin733.farc 2C8F3179 rom/2d/spr_sel_cardpt.farc 012B093E rom/2d/spr_sel_md010cmn.farc 9A0493CD rom/2d/spr_sel_md026cmn.farc 57937214 rom/2d/spr_sel_md042cmn.farc 55F7CF20 rom/2d/spr_sel_md058cmn.farc 00423A19 rom/2d/spr_sel_md074cmn.farc 8B84B47B rom/2d/spr_sel_md090cmn.farc D3D4E809 rom/2d/spr_sel_md124cmn.farc 58E31C27 rom/2d/spr_sel_md125cmn.farc 404FAF80 rom/2d/spr_sel_md126cmn.farc B7C49332 rom/2d/spr_sel_md127cmn.farc 69348B7F rom/2d/spr_sel_md128cmn.farc 38312A99 rom/2d/spr_sel_md129cmn.farc 37E8DB5E rom/2d/spr_sel_md130cmn.farc 60AFC1A2 rom/2d/spr_sel_md131cmn.farc 0694C447 rom/2d/spr_sel_md132cmn.farc EA571FDE rom/2d/spr_sel_md133cmn.farc F7C3D15F rom/2d/spr_sel_md134cmn.farc 9559E200 rom/2d/spr_sel_md135cmn.farc 402BA99F rom/2d/spr_sel_md136cmn.farc A77D4A99 rom/2d/spr_sel_md137cmn.farc 3779EC4F rom/2d/spr_sel_md138cmn.farc 9EB48E01 rom/2d/spr_sel_md141cmn.farc 70BEECD3 rom/2d/spr_sel_md142cmn.farc EE331894 rom/2d/spr_sel_md143cmn.farc EC03E85F rom/2d/spr_sel_md144cmn.farc 204E1559 rom/2d/spr_sel_md145cmn.farc C971133B rom/2d/spr_sel_md146cmn.farc 6DF619F2 rom/2d/spr_sel_md147cmn.farc B303A19F rom/2d/spr_sel_md148cmn.farc 26FB8918 rom/2d/spr_sel_md149cmn.farc 0CF40FB3 rom/2d/spr_sel_md150cmn.farc D578C247 rom/2d/spr_sel_md151cmn.farc 513C4674 rom/2d/spr_sel_md153cmn.farc 121BAA44 rom/2d/spr_sel_md154cmn.farc F0D0D1F1 rom/2d/spr_sel_md155cmn.farc CC97C72C rom/2d/spr_sel_md156cmn.farc B8D80793 rom/2d/spr_sel_md158cmn.farc 475E98BE rom/2d/spr_sel_md159cmn.farc 0F5EBB9F rom/2d/spr_sel_md160cmn.farc A94001E5 rom/2d/spr_sel_md161cmn.farc 7865A368 rom/2d/spr_sel_md162cmn.farc 3EB04470 rom/2d/spr_sel_md163cmn.farc 025C7E80 rom/2d/spr_sel_md164cmn.farc 02E3D7CD rom/2d/spr_sel_md165cmn.farc CA35DBC3 rom/2d/spr_sel_md166cmn.farc 72460319 rom/2d/spr_sel_md167cmn.farc 3E4AC722 rom/2d/spr_sel_md168cmn.farc 4C5D03F0 rom/2d/spr_sel_md169cmn.farc 7C49DF15 rom/2d/spr_sel_md170cmn.farc 80705547 rom/2d/spr_sel_md171cmn.farc 7094AC5B rom/2d/spr_sel_md172cmn.farc 2565E954 rom/2d/spr_sel_md189cmn.farc 6A7391EA rom/2d/spr_sel_md190cmn.farc 91F58825 rom/2d/spr_sel_md191cmn.farc 488D3E62 rom/2d/spr_sel_md192cmn.farc 42A35D32 rom/2d/spr_sel_md193cmn.farc 5AAB29EE rom/2d/spr_sel_md194cmn.farc D9FB38C7 rom/2d/spr_sel_md195cmn.farc 0C7027DE rom/2d/spr_sel_md196cmn.farc 51C90E00 rom/2d/spr_sel_md197cmn.farc D96F05BA rom/2d/spr_sel_md198cmn.farc 47813592 rom/2d/spr_sel_md199cmn.farc 1B3066D2 rom/2d/spr_sel_md200cmn.farc B7EDF7C7 rom/2d/spr_sel_md201cmn.farc 3332D891 rom/2d/spr_sel_md202cmn.farc 43769336 rom/2d/spr_sel_md203cmn.farc 85C9BEDC rom/2d/spr_sel_md205cmn.farc 0AC0094A rom/2d/spr_sel_md206cmn.farc 0812A155 rom/2d/spr_sel_md207cmn.farc 4FB9C91C rom/2d/spr_sel_md208cmn.farc 9E4CB7A7 rom/2d/spr_sel_md209cmn.farc 50DB9E5D rom/2d/spr_sel_md210cmn.farc 0B6340CB rom/2d/spr_sel_md211cmn.farc AF61FF44 rom/2d/spr_sel_md212cmn.farc A7EDA87D rom/2d/spr_sel_md213cmn.farc 754663AB rom/2d/spr_sel_md214cmn.farc 986B9915 rom/2d/spr_sel_md215cmn.farc 4F9D3BDE rom/2d/spr_sel_md216cmn.farc 4C123FEA rom/2d/spr_sel_md217cmn.farc 794E52EF rom/2d/spr_sel_md218cmn.farc CE9079CC rom/2d/spr_sel_md219cmn.farc F9BF90CF rom/2d/spr_sel_md221cmn.farc C0771547 rom/2d/spr_sel_md222cmn.farc A402DB51 rom/2d/spr_sel_md223cmn.farc 4071E361 rom/2d/spr_sel_md224cmn.farc DCC74941 rom/2d/spr_sel_md225cmn.farc C55D9503 rom/2d/spr_sel_md226cmn.farc 7F657E0C rom/2d/spr_sel_md227cmn.farc C43CDFEA rom/2d/spr_sel_md228cmn.farc 9769B9AA rom/2d/spr_sel_md229cmn.farc 4F633E0E rom/2d/spr_sel_md230cmn.farc 90544B6F rom/2d/spr_sel_md231cmn.farc 7A281CC8 rom/2d/spr_sel_md232cmn.farc C0A6AB1D rom/2d/spr_sel_md233cmn.farc 709A5C3C rom/2d/spr_sel_md234cmn.farc 9A7DBD71 rom/2d/spr_sel_md235cmn.farc 204463FB rom/2d/spr_sel_md237cmn.farc 45D6DA6F rom/2d/spr_sel_md238cmn.farc E0CEA628 rom/2d/spr_sel_md239cmn.farc ACC55FF7 rom/2d/spr_sel_md240cmn.farc 80E4D2CA rom/2d/spr_sel_md241cmn.farc 44C4B0CA rom/2d/spr_sel_md242cmn.farc 48EC5BCD rom/2d/spr_sel_md243cmn.farc 5F774B2F rom/2d/spr_sel_md244cmn.farc 68A46044 rom/2d/spr_sel_md245cmn.farc 8F078DB7 rom/2d/spr_sel_md246cmn.farc A4008067 rom/2d/spr_sel_md247cmn.farc F7A9F517 rom/2d/spr_sel_md248cmn.farc 95016388 rom/2d/spr_sel_md249cmn.farc 71757242 rom/2d/spr_sel_md250cmn.farc 553F3B79 rom/2d/spr_sel_md251cmn.farc 9F01B411 rom/2d/spr_sel_md253cmn.farc F7250B7B rom/2d/spr_sel_md254cmn.farc 199DFA0E rom/2d/spr_sel_md255cmn.farc 778CBDF7 rom/2d/spr_sel_md256cmn.farc D1A80319 rom/2d/spr_sel_md257cmn.farc 9CB6AF77 rom/2d/spr_sel_md258cmn.farc BD66017E rom/2d/spr_sel_md259cmn.farc 362EAE49 rom/2d/spr_sel_md260cmn.farc 0DC36A01 rom/2d/spr_sel_md261cmn.farc 4EEC97DD rom/2d/spr_sel_md262cmn.farc FE94AA67 rom/2d/spr_sel_md263cmn.farc 4878593D rom/2d/spr_sel_md264cmn.farc 1FD1398A rom/2d/spr_sel_md265cmn.farc E04CE3A5 rom/2d/spr_sel_md266cmn.farc D4A14D6D rom/2d/spr_sel_md267cmn.farc 6ED234AA rom/2d/spr_sel_md269cmn.farc 1A1A9F0F rom/2d/spr_sel_md270cmn.farc 10075705 rom/2d/spr_sel_md271cmn.farc 92D251EA rom/2d/spr_sel_md272cmn.farc 10D674EE rom/2d/spr_sel_md273cmn.farc F0A7A538 rom/2d/spr_sel_md274cmn.farc 12FF184C rom/2d/spr_sel_md275cmn.farc 6DF1C025 rom/2d/spr_sel_md276cmn.farc 9ED5C00C rom/2d/spr_sel_md277cmn.farc 49B0931C rom/2d/spr_sel_md278cmn.farc 5318C2C0 rom/2d/spr_sel_md279cmn.farc BEFE0CA6 rom/2d/spr_sel_md280cmn.farc 6DF1DCDD rom/2d/spr_sel_md281cmn.farc B26BE272 rom/2d/spr_sel_md282cmn.farc 8A121E8E rom/2d/spr_sel_md283cmn.farc E010F359 rom/2d/spr_sel_md285cmn.farc AE4B449F rom/2d/spr_sel_md286cmn.farc 2EE1D789 rom/2d/spr_sel_md287cmn.farc 2E5FDCDE rom/2d/spr_sel_md288cmn.farc 756C92C1 rom/2d/spr_sel_md289cmn.farc 55855678 rom/2d/spr_sel_md290cmn.farc C180C0FF rom/2d/spr_sel_md291cmn.farc 9C2A3E9B rom/2d/spr_sel_md292cmn.farc 725D909C rom/2d/spr_sel_md293cmn.farc EB687739 rom/2d/spr_sel_md294cmn.farc 8B4D7EA6 rom/2d/spr_sel_md295cmn.farc D38A9792 rom/2d/spr_sel_md296cmn.farc D6DB5E38 rom/2d/spr_sel_md297cmn.farc 9D0F3798 rom/2d/spr_sel_md298cmn.farc 56305863 rom/2d/spr_sel_md299cmn.farc 8F883F7A rom/2d/spr_sel_md301cmn.farc 20852DD6 rom/2d/spr_sel_md302cmn.farc 5C3C8CBD rom/2d/spr_sel_md303cmn.farc 75C792B8 rom/2d/spr_sel_md304cmn.farc A0EE04DF rom/2d/spr_sel_md305cmn.farc 4272D6B1 rom/2d/spr_sel_md306cmn.farc 82D49B0E rom/2d/spr_sel_md308cmn.farc 6EB4B05A rom/2d/spr_sel_md309cmn.farc AAABEC37 rom/2d/spr_sel_md310cmn.farc 1D222272 rom/2d/spr_sel_md311cmn.farc 7B900C1B rom/2d/spr_sel_md313cmn.farc A0647392 rom/2d/spr_sel_md314cmn.farc A9866E6F rom/2d/spr_sel_md315cmn.farc 068D6754 rom/2d/spr_sel_md316cmn.farc 83673222 rom/2d/spr_sel_md317cmn.farc 44C0DCD9 rom/2d/spr_sel_md319cmn.farc FBE25B65 rom/2d/spr_sel_md320cmn.farc DE0920D6 rom/2d/spr_sel_md321cmn.farc 3FFFEF3C rom/2d/spr_sel_md322cmn.farc F0437C9A rom/2d/spr_sel_md323cmn.farc EF8D3C8F rom/2d/spr_sel_md324cmn.farc 459AFEBE rom/2d/spr_sel_md325cmn.farc 31E035DD rom/2d/spr_sel_md326cmn.farc 33236FEC rom/2d/spr_sel_md327cmn.farc C851E799 rom/2d/spr_sel_md328cmn.farc B6F3F004 rom/2d/spr_sel_md329cmn.farc 6FA1D011 rom/2d/spr_sel_md330cmn.farc 97B08CB0 rom/2d/spr_sel_md331cmn.farc 66590F3E rom/2d/spr_sel_md332cmn.farc FF419342 rom/2d/spr_sel_md334cmn.farc 22315B17 rom/2d/spr_sel_md336cmn.farc 9A4D6C56 rom/2d/spr_sel_md338cmn.farc 007EEBEF rom/2d/spr_sel_md339cmn.farc A0BB4052 rom/2d/spr_sel_md340cmn.farc 5501E4BC rom/2d/spr_sel_md341cmn.farc 2DF05A46 rom/2d/spr_sel_md343cmn.farc BE824CCC rom/2d/spr_sel_md344cmn.farc 6FC610B7 rom/2d/spr_sel_md345cmn.farc 983FFF53 rom/2d/spr_sel_md346cmn.farc 897276A0 rom/2d/spr_sel_md347cmn.farc 4B51942D rom/2d/spr_sel_md348cmn.farc 1B3A16F6 rom/2d/spr_sel_md349cmn.farc 40BCD8EE rom/2d/spr_sel_md350cmn.farc 6513D83A rom/2d/spr_sel_md351cmn.farc 7D08ED63 rom/2d/spr_sel_md352cmn.farc B867B87C rom/2d/spr_sel_md354cmn.farc 7F3D565D rom/2d/spr_sel_md355cmn.farc 8867F186 rom/2d/spr_sel_md356cmn.farc 93046E0C rom/2d/spr_sel_md358cmn.farc 4108BAFE rom/2d/spr_sel_md359cmn.farc C762D647 rom/2d/spr_sel_md360cmn.farc BC22D320 rom/2d/spr_sel_md361cmn.farc BFAF809A rom/2d/spr_sel_md362cmn.farc EE9A101F rom/2d/spr_sel_md363cmn.farc A7E5861F rom/2d/spr_sel_md364cmn.farc CE2555F5 rom/2d/spr_sel_md365cmn.farc 2102411E rom/2d/spr_sel_md366cmn.farc 6186D355 rom/2d/spr_sel_md367cmn.farc 7F29F9B2 rom/2d/spr_sel_md368cmn.farc E4B42F0C rom/2d/spr_sel_md369cmn.farc A73D4C92 rom/2d/spr_sel_md371cmn.farc C39A440B rom/2d/spr_sel_md372cmn.farc D7619BAD rom/2d/spr_sel_md373cmn.farc BD387821 rom/2d/spr_sel_md374cmn.farc 249E6DE0 rom/2d/spr_sel_md375cmn.farc 60C43316 rom/2d/spr_sel_md376cmn.farc 8E24DD56 rom/2d/spr_sel_md377cmn.farc ED996202 rom/2d/spr_sel_md378cmn.farc 34E44846 rom/2d/spr_sel_md379cmn.farc 6823D1D1 rom/2d/spr_sel_md380cmn.farc 300FC755 rom/2d/spr_sel_md381cmn.farc 22A94428 rom/2d/spr_sel_md382cmn.farc 385F7B3B rom/2d/spr_sel_md383cmn.farc D30C977D rom/2d/spr_sel_md385cmn.farc C8DDEF31 rom/2d/spr_sel_md386cmn.farc 0C42F222 rom/2d/spr_sel_md122cmn.farc 41AEA635 rom/2d/spr_sel_md139cmn.farc EF08F922 rom/2d/spr_sel_md157cmn.farc 8E1F744A rom/2d/spr_sel_md188cmn.farc A6D39499 rom/2d/spr_sel_md204cmn.farc DAF555A8 rom/2d/spr_sel_md220cmn.farc F20B27FF rom/2d/spr_sel_md236cmn.farc A48405CD rom/2d/spr_sel_md252cmn.farc F4A688D6 rom/2d/spr_sel_md268cmn.farc 367B8ADA rom/2d/spr_sel_md284cmn.farc D72B316F rom/2d/spr_sel_md300cmn.farc 95789835 rom/2d/spr_sel_md318cmn.farc 5D72025B rom/2d/spr_sel_md335cmn.farc 146A34BE rom/2d/spr_sel_md353cmn.farc 0D6CA6DF rom/2d/spr_sel_md370cmn.farc F9C4188D rom/2d/spr_sel_md389cmn.farc 75107950 rom/2d/spr_sel_md390cmn.farc F873F513 rom/2d/spr_sel_md391cmn.farc 07CDA695 rom/2d/spr_sel_md392cmn.farc A4D0F65A rom/2d/spr_sel_md393cmn.farc 3368B3C9 rom/2d/spr_sel_md394cmn.farc 42AD8862 rom/2d/spr_sel_md395cmn.farc 51A6E42D rom/2d/spr_sel_md398cmn.farc 30BA5953 rom/2d/spr_sel_md402cmn.farc 52FA728B rom/2d/spr_sel_md403cmn.farc EB8387FE rom/2d/spr_sel_md404cmn.farc 76F7CB66 rom/2d/spr_sel_md405cmn.farc A6B8CCDF rom/2d/spr_sel_md406cmn.farc E70532BE rom/2d/spr_sel_md407cmn.farc 32CC17D8 rom/2d/spr_sel_md408cmn.farc 2456BA5A rom/2d/spr_sel_md410cmn.farc 0E2C8EC9 rom/2d/spr_sel_md411cmn.farc 299F803E rom/2d/spr_sel_md412cmn.farc 946AA144 rom/2d/spr_sel_md420cmn.farc 8806E9ED rom/2d/spr_sel_md421cmn.farc DD4922A0 rom/2d/spr_sel_md422cmn.farc 0C6BA932 rom/2d/spr_sel_md423cmn.farc FB5D32B0 rom/2d/spr_sel_mdrallcmn.farc B6BFCF83 rom/2d/spr_sel_mdrhakcmn.farc 3BD9C57B rom/2d/spr_sel_mdrkaicmn.farc 878212BE rom/2d/spr_sel_mdrlencmn.farc 35F69D1B rom/2d/spr_sel_mdrlukcmn.farc 22E5A6F7 rom/2d/spr_sel_mdrmeicmn.farc EABECED2 rom/2d/spr_sel_mdrmikcmn.farc 885DD236 rom/2d/spr_sel_mdrnercmn.farc 0A74A115 rom/2d/spr_sel_mdrrincmn.farc 261EF27C rom/2d/spr_sel_mdrtetcmn.farc 46840F30 rom/2d/spr_sel_module.farc 3C6630C9 rom/2d/spr_sel_plate.farc BCF8CAAC rom/2d/spr_sel_pleff.farc 8337AB99 rom/2d/spr_sel_print.farc 26D2303D rom/2d/spr_sel_procedure.farc ED11EFA2 rom/2d/spr_sel_pv.farc 81844A7F rom/2d/spr_sel_pv001.farc D46959B5 rom/2d/spr_sel_pv002.farc 2DD72BAD rom/2d/spr_sel_pv003.farc 0CF2CF56 rom/2d/spr_sel_pv004.farc 942F2DB2 rom/2d/spr_sel_pv005.farc 9741ADC1 rom/2d/spr_sel_pv006.farc 7A596887 rom/2d/spr_sel_pv007.farc A9168BE6 rom/2d/spr_sel_pv008.farc E8500089 rom/2d/spr_sel_pv009.farc 1290ED53 rom/2d/spr_sel_pv011.farc 28FE23F2 rom/2d/spr_sel_pv012.farc 6FD7ED24 rom/2d/spr_sel_pv013.farc 697866A7 rom/2d/spr_sel_pv014.farc 9782DEE5 rom/2d/spr_sel_pv015.farc 739D0D6D rom/2d/spr_sel_pv016.farc FCB1DE3F rom/2d/spr_sel_pv017.farc 0A3D0748 rom/2d/spr_sel_pv018.farc 02EFBE70 rom/2d/spr_sel_pv019.farc 9B72B2B4 rom/2d/spr_sel_pv020.farc 3EA38C78 rom/2d/spr_sel_pv021.farc 90D1D986 rom/2d/spr_sel_pv022.farc 3985D648 rom/2d/spr_sel_pv023.farc 590175EC rom/2d/spr_sel_pv024.farc 6EC6CC27 rom/2d/spr_sel_pv025.farc C8440080 rom/2d/spr_sel_pv026.farc 31FC176D rom/2d/spr_sel_pv028.farc BAE101F4 rom/2d/spr_sel_pv029.farc 0B1DE72B rom/2d/spr_sel_pv030.farc 05F3E845 rom/2d/spr_sel_pv031.farc C201E872 rom/2d/spr_sel_pv032.farc 2D78EBA8 rom/2d/spr_sel_pv037.farc F8B04AD7 rom/2d/spr_sel_pv038.farc C7CB6E4E rom/2d/spr_sel_pv039.farc F035DFBA rom/2d/spr_sel_pv040.farc 86DAFB68 rom/2d/spr_sel_pv041.farc 0724327D rom/2d/spr_sel_pv042.farc 76200131 rom/2d/spr_sel_pv043.farc B2D79FF0 rom/2d/spr_sel_pv044.farc 2FCD192D rom/2d/spr_sel_pv045.farc A21E7EBD rom/2d/spr_sel_pv046.farc 6A90C874 rom/2d/spr_sel_pv047.farc 95CD9431 rom/2d/spr_sel_pv049.farc E900B8E9 rom/2d/spr_sel_pv050.farc 209D945E rom/2d/spr_sel_pv051.farc D0BBB8DE rom/2d/spr_sel_pv052.farc F123017A rom/2d/spr_sel_pv053.farc 84454657 rom/2d/spr_sel_pv054.farc A94822FA rom/2d/spr_sel_pv055.farc 67674E3F rom/2d/spr_sel_pv056.farc 662C5554 rom/2d/spr_sel_pv057.farc C4284A2A rom/2d/spr_sel_pv058.farc 86DE71C8 rom/2d/spr_sel_pv059.farc 231EAEEC rom/2d/spr_sel_pv060.farc 848F95D4 rom/2d/spr_sel_pv061.farc B6E3926B rom/2d/spr_sel_pv062.farc 0DC06C3B rom/2d/spr_sel_pv063.farc 3B6755A3 rom/2d/spr_sel_pv064.farc 772E4782 rom/2d/spr_sel_pv066.farc 37DC8976 rom/2d/spr_sel_pv079.farc 0162211B rom/2d/spr_sel_pv081.farc 9547577E rom/2d/spr_sel_pv082.farc F4980F2C rom/2d/spr_sel_pv083.farc 2445268F rom/2d/spr_sel_pv084.farc E1E2C923 rom/2d/spr_sel_pv085.farc 3B29FFC8 rom/2d/spr_sel_pv086.farc 99F8FEA5 rom/2d/spr_sel_pv087.farc 63ACE06E rom/2d/spr_sel_pv088.farc EEEEE1FE rom/2d/spr_sel_pv089.farc 6F6FA7FC rom/2d/spr_sel_pv090.farc BC2A33A4 rom/2d/spr_sel_pv091.farc 26240E5A rom/2d/spr_sel_pv092.farc 036104D1 rom/2d/spr_sel_pv093.farc 280B5809 rom/2d/spr_sel_pv094.farc 31867CFA rom/2d/spr_sel_pv096.farc BE2CAFD0 rom/2d/spr_sel_pv097.farc E883063A rom/2d/spr_sel_pv101.farc 2180585F rom/2d/spr_sel_pv102.farc D137ED22 rom/2d/spr_sel_pv103.farc 935967B8 rom/2d/spr_sel_pv104.farc 350DE770 rom/2d/spr_sel_pv201.farc 05A3B011 rom/2d/spr_sel_pv202.farc 1B4AC54F rom/2d/spr_sel_pv203.farc 895584C6 rom/2d/spr_sel_pv204.farc 4DC18373 rom/2d/spr_sel_pv205.farc 208DFF63 rom/2d/spr_sel_pv206.farc 68428D4F rom/2d/spr_sel_pv207.farc 02CA1629 rom/2d/spr_sel_pv208.farc 6E5E0B25 rom/2d/spr_sel_pv209.farc 3D71A758 rom/2d/spr_sel_pv210.farc C8E60F64 rom/2d/spr_sel_pv212.farc FB1E13D8 rom/2d/spr_sel_pv213.farc 6DA4821A rom/2d/spr_sel_pv214.farc A7212F65 rom/2d/spr_sel_pv215.farc 60E2FFF3 rom/2d/spr_sel_pv216.farc A7EC2D60 rom/2d/spr_sel_pv218.farc 1E683805 rom/2d/spr_sel_pv219.farc C80FBD72 rom/2d/spr_sel_pv220.farc 9B955F54 rom/2d/spr_sel_pv221.farc 17E5CBBE rom/2d/spr_sel_pv222.farc 221C9B5B rom/2d/spr_sel_pv223.farc 882B356D rom/2d/spr_sel_pv224.farc 7A623880 rom/2d/spr_sel_pv225.farc 54FCD8DC rom/2d/spr_sel_pv226.farc 6135244E rom/2d/spr_sel_pv227.farc F382C089 rom/2d/spr_sel_pv228.farc CD8F90E9 rom/2d/spr_sel_pv232.farc 68459057 rom/2d/spr_sel_pv233.farc 5A77A8C1 rom/2d/spr_sel_pv234.farc 43A601E9 rom/2d/spr_sel_pv235.farc 55E2309F rom/2d/spr_sel_pv236.farc 4871D2C2 rom/2d/spr_sel_pv238.farc 01085810 rom/2d/spr_sel_pv239.farc B5F3A07B rom/2d/spr_sel_pv240.farc C78AD4CD rom/2d/spr_sel_pv241.farc D6CAE408 rom/2d/spr_sel_pv242.farc 43E8FC59 rom/2d/spr_sel_pv243.farc 9971A3BF rom/2d/spr_sel_pv244.farc 79D4C878 rom/2d/spr_sel_pv246.farc 8710365C rom/2d/spr_sel_pv247.farc 1F2C7DB8 rom/2d/spr_sel_pv248.farc 7900EB10 rom/2d/spr_sel_pv249.farc F259DA9E rom/2d/spr_sel_pv251.farc 37A98829 rom/2d/spr_sel_pv253.farc 2C110128 rom/2d/spr_sel_pv255.farc 5C7FC3C8 rom/2d/spr_sel_pv257.farc 3E011A25 rom/2d/spr_sel_pv259.farc C70B7317 rom/2d/spr_sel_pv260.farc CD16C39A rom/2d/spr_sel_pv261.farc 457FE2D8 rom/2d/spr_sel_pv262.farc 1F766DE0 rom/2d/spr_sel_pv265.farc 1B7B2C85 rom/2d/spr_sel_pv401.farc D56CB113 rom/2d/spr_sel_pv402.farc 0002AF17 rom/2d/spr_sel_pv403.farc 6F0990EB rom/2d/spr_sel_pv404.farc 4E05F4F9 rom/2d/spr_sel_pv405.farc E0791BC8 rom/2d/spr_sel_pv406.farc 2B06C165 rom/2d/spr_sel_pv407.farc 07DB3D5E rom/2d/spr_sel_pv409.farc B1BD9D1B rom/2d/spr_sel_pv410.farc 2E1B78AD rom/2d/spr_sel_pv411.farc DB5BE3BA rom/2d/spr_sel_pv412.farc 93B9392F rom/2d/spr_sel_pv413.farc DBED2390 rom/2d/spr_sel_pv414.farc A506CD33 rom/2d/spr_sel_pv415.farc 9B655835 rom/2d/spr_sel_pv416.farc 270D5E9C rom/2d/spr_sel_pv417.farc BA0847E1 rom/2d/spr_sel_pv418.farc C691D619 rom/2d/spr_sel_pv419.farc B595653B rom/2d/spr_sel_pv420.farc 94A44FA3 rom/2d/spr_sel_pv421.farc F5E4C8B7 rom/2d/spr_sel_pv422.farc 91618229 rom/2d/spr_sel_pv423.farc 90C634C9 rom/2d/spr_sel_pv424.farc F342C15C rom/2d/spr_sel_pv426.farc 0DFDF8B4 rom/2d/spr_sel_pv427.farc DD47D4F2 rom/2d/spr_sel_pv428.farc 5DB83762 rom/2d/spr_sel_pv429.farc 5DE3702F rom/2d/spr_sel_pv430.farc 4A42A9FE rom/2d/spr_sel_pv431.farc EDC78E46 rom/2d/spr_sel_pv432.farc F8854AB5 rom/2d/spr_sel_pv433.farc 7C3D3C24 rom/2d/spr_sel_pv434.farc 7415972B rom/2d/spr_sel_pv435.farc 31566E71 rom/2d/spr_sel_pv436.farc BBE5846E rom/2d/spr_sel_pv437.farc 9FA1A231 rom/2d/spr_sel_pv438.farc EA769FE7 rom/2d/spr_sel_pv439.farc 2E7EAD02 rom/2d/spr_sel_pv440.farc 7F24C4ED rom/2d/spr_sel_pv441.farc 84B4250E rom/2d/spr_sel_pv443.farc D631E622 rom/2d/spr_sel_pv600.farc 1948E586 rom/2d/spr_sel_pv601.farc 5E73CFAC rom/2d/spr_sel_pv602.farc 6553A25A rom/2d/spr_sel_pv603.farc 989683FF rom/2d/spr_sel_pv604.farc 50D80BD3 rom/2d/spr_sel_pv605.farc 6BE37422 rom/2d/spr_sel_pv607.farc 1C8F9B24 rom/2d/spr_sel_pv608.farc 3BFAD4F4 rom/2d/spr_sel_pv609.farc F10A0DC4 rom/2d/spr_sel_pv610.farc C64EA504 rom/2d/spr_sel_pv611.farc 8101FB4A rom/2d/spr_sel_pv612.farc 9E2D8D1D rom/2d/spr_sel_pv613.farc 4B5B3AE1 rom/2d/spr_sel_pv614.farc 49A27804 rom/2d/spr_sel_pv615.farc 86210159 rom/2d/spr_sel_pv617.farc B714E3C6 rom/2d/spr_sel_pv618.farc F0A816A4 rom/2d/spr_sel_pv619.farc 6507AA67 rom/2d/spr_sel_pv620.farc A4AE47C9 rom/2d/spr_sel_pv621.farc CBA1E04B rom/2d/spr_sel_pv622.farc 855115CB rom/2d/spr_sel_pv623.farc 7CF97C75 rom/2d/spr_sel_pv624.farc 1192C3C7 rom/2d/spr_sel_pv625.farc 9AE951F8 rom/2d/spr_sel_pv626.farc B4B61FD0 rom/2d/spr_sel_pv627.farc 8C79AB6C rom/2d/spr_sel_pv628.farc 8D8F7EB2 rom/2d/spr_sel_pv629.farc 09EEBF00 rom/2d/spr_sel_pv630.farc 058645F6 rom/2d/spr_sel_pv631.farc 538EBD85 rom/2d/spr_sel_pv637.farc EA951BC4 rom/2d/spr_sel_pv639.farc 044B4B74 rom/2d/spr_sel_pv640.farc 2D019485 rom/2d/spr_sel_pv641.farc EBF6E9AF rom/2d/spr_sel_pv642.farc 923F6B17 rom/2d/spr_sel_pv710.farc D986D6B5 rom/2d/spr_sel_pv722.farc 2991CE7B rom/2d/spr_sel_pv723.farc 60460640 rom/2d/spr_sel_pv724.farc FA90CF20 rom/2d/spr_sel_pv725.farc 3B73F3F4 rom/2d/spr_sel_pv726.farc 951350DE rom/2d/spr_sel_pv727.farc 57822532 rom/2d/spr_sel_pv728.farc 3C7088B2 rom/2d/spr_sel_pv729.farc 3E756D05 rom/2d/spr_sel_pv730.farc 93EE4384 rom/2d/spr_sel_pv731.farc 34574138 rom/2d/spr_sel_pv732.farc 62100DF1 rom/2d/spr_sel_md409cmn.farc 90C681AF rom/2d/spr_sel_mdrsakcmn.farc E96A0882 rom/2d/spr_sel_pv010.farc BC1FC1A4 rom/2d/spr_sel_pv027.farc 41F01C2D rom/2d/spr_sel_pv048.farc 3D68DCF2 rom/2d/spr_sel_pv065.farc 5A009E24 rom/2d/spr_sel_pv095.farc F3F8E0BB rom/2d/spr_sel_pv211.farc 3D4276EF rom/2d/spr_sel_pv231.farc 4304049D rom/2d/spr_sel_pv250.farc 4B5E17D5 rom/2d/spr_sel_pv408.farc 1669E5FC rom/2d/spr_sel_pv425.farc 5C88A012 rom/2d/spr_sel_pv442.farc 32D68B8F rom/2d/spr_sel_pv616.farc 4852CE5C rom/2d/spr_sel_pv638.farc 6DC0263D rom/2d/spr_sel_pv733.farc 3F6E4868 rom/2d/spr_sel_pv734.farc 84765085 rom/2d/spr_sel_pv736.farc B41F59EA rom/2d/spr_sel_pv737.farc 3F785D0F rom/2d/spr_sel_pv738.farc E90D92C6 rom/2d/spr_sel_pv739.farc 86907E3A rom/2d/spr_sel_pv740.farc 98B6D24E rom/2d/spr_sel_pv832.farc 979FD4C7 rom/2d/spr_sel_qst.farc 0DE020E6 rom/2d/spr_sel_result.farc 1650912C rom/2d/spr_sel_sc.farc 935A6CF2 rom/2d/spr_sel_skin001.farc FAED1701 rom/2d/spr_sel_song.farc A39B458B rom/2d/spr_sel_songcmn.farc DB8E002C rom/2d/spr_sel_stamp.farc ECADE5C4 rom/2d/spr_sel_ticket.farc B859F8C6 rom/2d/spr_sel_vaccess.farc AE30643C rom/2d/spr_sel_watch.farc FF0EA620 rom/auth_3d/EFFCHRPV612KAI002.farc 99671723 rom/auth_3d/auth_3d_db.bin CAEFF330 rom/auth_3d/auth_3d_setting.bin 919ED660 rom/auth_3d/CAMPV001.farc A17C0C98 rom/auth_3d/CAMPV002.farc D3665CAF rom/auth_3d/CAMPV003.farc 59E28ED6 rom/auth_3d/CAMPV004.farc B2524665 rom/auth_3d/CAMPV005.farc 575FF6A6 rom/auth_3d/CAMPV006.farc D6B5BF51 rom/auth_3d/CAMPV007.farc 27FA06A6 rom/auth_3d/CAMPV008.farc 5BB7B7B9 rom/auth_3d/CAMPV009.farc 770134E5 rom/auth_3d/CAMPV010.farc 33D43661 rom/auth_3d/CAMPV011.farc DAE53599 rom/auth_3d/CAMPV012.farc 597B4733 rom/auth_3d/CAMPV013.farc E01EB1A6 rom/auth_3d/CAMPV014.farc C8EFD180 rom/auth_3d/CAMPV015.farc 0898C8B4 rom/auth_3d/CAMPV017.farc 17FE1C7A rom/auth_3d/CAMPV018.farc CE35B750 rom/auth_3d/CAMPV019.farc 7682AD09 rom/auth_3d/CAMPV020.farc 6CCE6914 rom/auth_3d/CAMPV021.farc F720FE88 rom/auth_3d/CAMPV0211.farc FFEFB0A8 rom/auth_3d/CAMPV022.farc 3E4D6251 rom/auth_3d/CAMPV023.farc 177D4FA8 rom/auth_3d/CAMPV024.farc 3341C7CD rom/auth_3d/CAMPV025.farc 26F0CC09 rom/auth_3d/CAMPV027.farc CF9AD56E rom/auth_3d/CAMPV028.farc 35435D13 rom/auth_3d/CAMPV029.farc A4336C7F rom/auth_3d/CAMPV030.farc DCAF0A42 rom/auth_3d/CAMPV031.farc 2BA20177 rom/auth_3d/CAMPV032.farc FCF4E988 rom/auth_3d/CAMPV037.farc 7BEB2878 rom/auth_3d/CAMPV039.farc 6F1C8497 rom/auth_3d/CAMPV040.farc FDB333C7 rom/auth_3d/CAMPV041.farc AA1EC6C2 rom/auth_3d/CAMPV042.farc 3E02A307 rom/auth_3d/CAMPV043.farc BE05DA83 rom/auth_3d/CAMPV044.farc B74F07D9 rom/auth_3d/CAMPV045.farc 1BDD253F rom/auth_3d/CAMPV046.farc FDF3CB83 rom/auth_3d/CAMPV047.farc E5748AA0 rom/auth_3d/CAMPV048.farc 52E11359 rom/auth_3d/CAMPV049.farc 6EB2D0BD rom/auth_3d/CAMPV050.farc 7A4F6F6A rom/auth_3d/CAMPV051.farc F12D737B rom/auth_3d/CAMPV052.farc 48B254A3 rom/auth_3d/CAMPV053.farc 7E9348E8 rom/auth_3d/CAMPV054.farc 5C707289 rom/auth_3d/CAMPV055.farc 2A005B3E rom/auth_3d/CAMPV057.farc 34AA78C9 rom/auth_3d/CAMPV058.farc AE48379C rom/auth_3d/CAMPV059.farc C130499A rom/auth_3d/CAMPV060.farc A7EF2D9C rom/auth_3d/CAMPV061.farc ACBC6DB2 rom/auth_3d/CAMPV062.farc 34B743B3 rom/auth_3d/CAMPV063.farc 13FAFC49 rom/auth_3d/CAMPV064.farc E8284036 rom/auth_3d/CAMPV065.farc 416C942A rom/auth_3d/CAMPV066.farc D884B667 rom/auth_3d/CAMPV067.farc AF10BDF8 rom/auth_3d/CAMPV068.farc BA528797 rom/auth_3d/CAMPV079.farc ADD29858 rom/auth_3d/CAMPV081.farc 54CC3FC0 rom/auth_3d/CAMPV082.farc EF3EF30F rom/auth_3d/CAMPV083.farc 6EA2F143 rom/auth_3d/CAMPV084.farc DB5FC262 rom/auth_3d/CAMPV016.farc A5286DBD rom/auth_3d/CAMPV038.farc 15A90F20 rom/auth_3d/CAMPV056.farc 08506229 rom/auth_3d/CAMPV085.farc 593D8569 rom/auth_3d/CAMPV204.farc 58412FB0 rom/auth_3d/CAMPV226.farc 5E3C3318 rom/auth_3d/CAMPV248.farc 1B1529B2 rom/auth_3d/CAMPV603.farc 38B7CEE8 rom/auth_3d/CAMPV622.farc 898E9E01 rom/auth_3d/CAMPV723.farc 5D2AE6FB rom/auth_3d/CAMPV832.farc 38913457 rom/auth_3d/EFFCHRPV262HAK001.farc B7B191A2 rom/auth_3d/EFFCHRPV262MIK100.farc 9B41ECCA rom/auth_3d/EFFCHRPV441MEI001.farc 95814B38 rom/auth_3d/EFFCHRPV605HAK001.farc F3F3F2AF rom/auth_3d/CAMPV086.farc 6EFF73AB rom/auth_3d/CAMPV087.farc 3FE2CB3E rom/auth_3d/CAMPV088.farc AE2A9BC9 rom/auth_3d/CAMPV089.farc E844A2B6 rom/auth_3d/CAMPV090.farc 1C0279AB rom/auth_3d/CAMPV091.farc 8373BBA6 rom/auth_3d/CAMPV092.farc 81B7EAAD rom/auth_3d/CAMPV093.farc CEFF6C7D rom/auth_3d/CAMPV094.farc 6ED5CEA3 rom/auth_3d/CAMPV095.farc 90833959 rom/auth_3d/CAMPV096.farc FB7CAF8A rom/auth_3d/CAMPV097.farc BDF113D5 rom/auth_3d/CAMPV102.farc 89583338 rom/auth_3d/CAMPV103.farc BDA6D4E5 rom/auth_3d/CAMPV104.farc 9CB50C53 rom/auth_3d/CAMPV201.farc 44544FBF rom/auth_3d/CAMPV202.farc 456CE270 rom/auth_3d/CAMPV205.farc 0B3A1508 rom/auth_3d/CAMPV206.farc 0F40C7AF rom/auth_3d/CAMPV207.farc 3ED9F519 rom/auth_3d/CAMPV208.farc 21D1E978 rom/auth_3d/CAMPV210.farc A955F032 rom/auth_3d/CAMPV211.farc A7711650 rom/auth_3d/CAMPV212.farc 8784367E rom/auth_3d/CAMPV213.farc AB48B193 rom/auth_3d/CAMPV214.farc 2EE942DB rom/auth_3d/CAMPV218.farc 905699EC rom/auth_3d/CAMPV219.farc 8ADC7EF4 rom/auth_3d/CAMPV220.farc EE090C7C rom/auth_3d/CAMPV221.farc FCE79E7E rom/auth_3d/CAMPV222.farc E7C02725 rom/auth_3d/CAMPV223.farc 956B2416 rom/auth_3d/CAMPV224.farc 08E24EBC rom/auth_3d/CAMPV225.farc 60921430 rom/auth_3d/CAMPV227.farc EF8CA9F7 rom/auth_3d/CAMPV228.farc 63021B09 rom/auth_3d/CAMPV231.farc 000DE946 rom/auth_3d/CAMPV232.farc 56E1BAFF rom/auth_3d/CAMPV233.farc 20138F7A rom/auth_3d/CAMPV234.farc F8913B0C rom/auth_3d/CAMPV235.farc D3B64B5E rom/auth_3d/CAMPV236.farc 06AB81C9 rom/auth_3d/CAMPV238.farc 4AA6A19A rom/auth_3d/CAMPV239.farc 9B9B08FD rom/auth_3d/CAMPV240.farc 7D3F1C76 rom/auth_3d/CAMPV241.farc 905C4BC6 rom/auth_3d/CAMPV242.farc 3B5BD39F rom/auth_3d/CAMPV243.farc 84851459 rom/auth_3d/CAMPV244.farc 26652501 rom/auth_3d/CAMPV246.farc 3BE59EA9 rom/auth_3d/CAMPV247.farc 2728A4A0 rom/auth_3d/CAMPV249.farc EA8B2721 rom/auth_3d/CAMPV250.farc 22CFA171 rom/auth_3d/CAMPV251.farc B1473A80 rom/auth_3d/CAMPV253.farc 218B5578 rom/auth_3d/CAMPV255.farc 70965058 rom/auth_3d/CAMPV257.farc 4329CB08 rom/auth_3d/CAMPV259.farc F54B2C7E rom/auth_3d/CAMPV260.farc 6E310078 rom/auth_3d/CAMPV261.farc 8C330967 rom/auth_3d/CAMPV262.farc 49B13727 rom/auth_3d/CAMPV432.farc 81E24223 rom/auth_3d/CAMPV433.farc 28C37489 rom/auth_3d/CAMPV434.farc AF0A2A7C rom/auth_3d/CAMPV435.farc EE95209A rom/auth_3d/CAMPV600.farc 16E77529 rom/auth_3d/CAMPV601.farc F9D597F8 rom/auth_3d/CAMPV602.farc 079F6FCB rom/auth_3d/CAMPV604.farc F6021B0A rom/auth_3d/CAMPV605.farc F8C827B6 rom/auth_3d/CAMPV607.farc 0A15735B rom/auth_3d/CAMPV608.farc AA2AF17D rom/auth_3d/CAMPV609.farc 5B68E2FE rom/auth_3d/CAMPV610.farc 73DE32AB rom/auth_3d/CAMPV611.farc 8FC15FC1 rom/auth_3d/CAMPV612.farc 7022DBDD rom/auth_3d/CAMPV613.farc 78B5B76C rom/auth_3d/CAMPV614.farc B7AAED11 rom/auth_3d/CAMPV615.farc B3FF7A29 rom/auth_3d/CAMPV616.farc 9DABD42E rom/auth_3d/CAMPV617.farc 50FBD4D0 rom/auth_3d/CAMPV618.farc 3254703F rom/auth_3d/CAMPV619.farc 1040CF3D rom/auth_3d/CAMPV620.farc EA120BBC rom/auth_3d/CAMPV621.farc 8CAD5A81 rom/auth_3d/CAMPV623.farc 020EA366 rom/auth_3d/CAMPV624.farc 3C60A120 rom/auth_3d/CAMPV625.farc 5F17AA9C rom/auth_3d/CAMPV626.farc DB0CC623 rom/auth_3d/CAMPV627.farc 0A32168B rom/auth_3d/CAMPV628.farc E0806ACD rom/auth_3d/CAMPV629.farc 4AB9E983 rom/auth_3d/CAMPV630.farc D7E9FEB5 rom/auth_3d/CAMPV631.farc 544C3223 rom/auth_3d/CAMPV637.farc E3E96BA9 rom/auth_3d/CAMPV638.farc 57771EDA rom/auth_3d/CAMPV639.farc F31ADC24 rom/auth_3d/CAMPV640.farc 26A0FB6E rom/auth_3d/CAMPV641.farc 80EADECB rom/auth_3d/CAMPV642.farc 9C73CF16 rom/auth_3d/CAMPV710.farc B1D29058 rom/auth_3d/CAMPV722.farc 84DC0FAF rom/auth_3d/CAMPV724.farc FF82C33E rom/auth_3d/CAMPV725.farc 4BDC92C3 rom/auth_3d/CAMPV726.farc E6157C20 rom/auth_3d/CAMPV727.farc F139C788 rom/auth_3d/CAMPV728.farc 776EE649 rom/auth_3d/CAMPV729.farc 3B54F09B rom/auth_3d/CAMPV730.farc 20E1FB85 rom/auth_3d/CAMPV731.farc 3275CD42 rom/auth_3d/CAMPV732.farc 694CAF6A rom/auth_3d/CAMPV733.farc 72F37F3B rom/auth_3d/CAMPV734.farc 05ADB091 rom/auth_3d/CAMPV736.farc 000FBFBD rom/auth_3d/CAMPV737.farc 796A42EA rom/auth_3d/CAMPV738.farc A341652D rom/auth_3d/CAMPV739.farc 8162DCDD rom/auth_3d/CAMPV740.farc 194AEE61 rom/auth_3d/CHRPV605.farc 88FCF752 rom/auth_3d/EFFCHRPV243HAK001.farc 14290C22 rom/auth_3d/EFFCHRPV243KAI001.farc A92BA963 rom/auth_3d/EFFCHRPV243LEN001.farc A6D7201A rom/auth_3d/EFFCHRPV243LUK001.farc A06F23B7 rom/auth_3d/EFFCHRPV243MEI001.farc CCDC6A89 rom/auth_3d/EFFCHRPV243MIK001.farc 42F16C54 rom/auth_3d/EFFCHRPV243NER001.farc C20F547B rom/auth_3d/EFFCHRPV243RIN001.farc 13A99A9B rom/auth_3d/EFFCHRPV243SAK001.farc 13CB2376 rom/auth_3d/EFFCHRPV243TET001.farc 58A7F437 rom/auth_3d/EFFCHRPV244KAI001.farc 413623CA rom/auth_3d/EFFCHRPV244KAI002.farc 4F64A70E rom/auth_3d/EFFCHRPV244LEN001.farc 1E938412 rom/auth_3d/EFFCHRPV244LEN002.farc B6F5E60C rom/auth_3d/EFFCHRPV262HAK002.farc 92FF9BA6 rom/auth_3d/EFFCHRPV262KAI001.farc 5CE06302 rom/auth_3d/EFFCHRPV262KAI002.farc 42622D2D rom/auth_3d/EFFCHRPV262KAI100.farc 318C29D6 rom/auth_3d/EFFCHRPV262KAI101.farc B5B3CBDD rom/auth_3d/EFFCHRPV262LEN001.farc D3BCB624 rom/auth_3d/EFFCHRPV262LEN002.farc 957E1770 rom/auth_3d/EFFCHRPV262LUK001.farc 77CF97A3 rom/auth_3d/EFFCHRPV262LUK002.farc CB409B26 rom/auth_3d/EFFCHRPV262MEI001.farc B6AAC873 rom/auth_3d/EFFCHRPV262MEI002.farc 8AB4C6C6 rom/auth_3d/EFFCHRPV262MEI100.farc A039B7C3 rom/auth_3d/EFFCHRPV262MEI101.farc 09086369 rom/auth_3d/EFFCHRPV262MIK001.farc E7E96ADD rom/auth_3d/EFFCHRPV262MIK002.farc 65E85D3E rom/auth_3d/EFFCHRPV262MIK101.farc 390C1AC0 rom/auth_3d/EFFCHRPV262NER001.farc D293CACA rom/auth_3d/EFFCHRPV262NER002.farc 8C01535F rom/auth_3d/EFFCHRPV262RIN001.farc 0409B8EB rom/auth_3d/EFFCHRPV262RIN002.farc 5A3F50ED rom/auth_3d/EFFCHRPV262RIN100.farc 1557FF55 rom/auth_3d/EFFCHRPV262RIN101.farc 137B4160 rom/auth_3d/EFFCHRPV262SAK001.farc 4CAB7162 rom/auth_3d/EFFCHRPV262SAK002.farc E43D47DE rom/auth_3d/EFFCHRPV262TET001.farc DDD43BA3 rom/auth_3d/EFFCHRPV262TET002.farc D4B62E47 rom/auth_3d/EFFCHRPV441HAK001.farc 5C671F95 rom/auth_3d/EFFCHRPV441KAI001.farc EAD57E16 rom/auth_3d/EFFCHRPV441LEN001.farc E15C682B rom/auth_3d/EFFCHRPV441LUK001.farc 3ACCBD31 rom/auth_3d/EFFCHRPV441MIK001.farc 667D6CEE rom/auth_3d/EFFCHRPV441NER001.farc F4F20658 rom/auth_3d/EFFCHRPV441RIN001.farc 21570A6A rom/auth_3d/EFFCHRPV441SAK001.farc 061FBDAA rom/auth_3d/EFFCHRPV441TET001.farc 26CEDB14 rom/auth_3d/EFFCHRPV602HAK001.farc 9D442247 rom/auth_3d/EFFCHRPV602KAI001.farc 027C89AC rom/auth_3d/EFFCHRPV602LEN001.farc 6CCBDB8E rom/auth_3d/EFFCHRPV602LUK001.farc 7D65E2CC rom/auth_3d/EFFCHRPV602MEI001.farc E821B024 rom/auth_3d/EFFCHRPV602MIK001.farc C54D340B rom/auth_3d/EFFCHRPV602NER001.farc 092BD6FA rom/auth_3d/EFFCHRPV602RIN001.farc 065E696B rom/auth_3d/EFFCHRPV602SAK001.farc DF7750D8 rom/auth_3d/EFFCHRPV602TET001.farc 45C05290 rom/auth_3d/EFFCHRPV605KAI001.farc 51F4A74B rom/auth_3d/EFFCHRPV605LEN001.farc E363BCB0 rom/auth_3d/EFFCHRPV605LUK001.farc DEA5A23C rom/auth_3d/EFFCHRPV605MEI001.farc 7F0461A3 rom/auth_3d/EFFCHRPV605MIK001.farc 86DC836F rom/auth_3d/EFFCHRPV605NER001.farc 292FCE85 rom/auth_3d/EFFCHRPV605RIN001.farc A82FF005 rom/auth_3d/EFFCHRPV605SAK001.farc 1B31B05F rom/auth_3d/EFFCHRPV605TET001.farc BCA3FBB7 rom/auth_3d/EFFCHRPV609LEN003.farc 4A30E18C rom/auth_3d/EFFCHRPV609LUK004.farc B3905482 rom/auth_3d/EFFCHRPV609MIK001.farc 23B6D0B6 rom/auth_3d/EFFCHRPV609RIN002.farc A93B4A0A rom/auth_3d/EFFCHRPV612HAK002.farc A421939D rom/auth_3d/EFFCHRPV612KAI001.farc 237151B0 rom/auth_3d/EFFCHRPV612LEN001.farc 341AA5B4 rom/auth_3d/EFFCHRPV612LEN002.farc 55932B20 rom/auth_3d/EFFCHRPV612LUK001.farc E7401294 rom/auth_3d/EFFCHRPV612LUK002.farc A88D1781 rom/auth_3d/EFFCHRPV612MEI001.farc 14284F24 rom/auth_3d/EFFCHRPV612MEI002.farc 201EBC8E rom/auth_3d/EFFCHRPV612MIK001.farc 7275DCBA rom/auth_3d/EFFCHRPV612MIK002.farc 969D6DA2 rom/auth_3d/EFFCHRPV612NER002.farc 08D61C5A rom/auth_3d/EFFCHRPV612RIN001.farc B2607E6D rom/auth_3d/EFFCHRPV612RIN002.farc 1F5429FC rom/auth_3d/EFFCHRPV612SAK001.farc C4940352 rom/auth_3d/EFFCHRPV612SAK002.farc 52624ACE rom/auth_3d/EFFCHRPV612TET002.farc 3C9BBCE9 rom/auth_3d/EFFCHRPV614KAI009.farc BCFD96BA rom/auth_3d/EFFCHRPV614LUK002.farc D44BB0E9 rom/auth_3d/EFFCHRPV614LUK003.farc 76D721A7 rom/auth_3d/EFFCHRPV614LUK004.farc 8D67B00A rom/auth_3d/EFFCHRPV614LUK005.farc 258B7011 rom/auth_3d/EFFCHRPV614LUK006.farc 1C5F9201 rom/auth_3d/EFFCHRPV614LUK007.farc FE5404F3 rom/auth_3d/EFFCHRPV614LUK008.farc 31F25333 rom/auth_3d/EFFCHRPV614LUK009.farc 199890CD rom/auth_3d/EFFCHRPV614LUK010.farc 1F0D4D1A rom/auth_3d/EFFCHRPV614MEI009.farc A7DBD981 rom/auth_3d/EFFCHRPV614MIK009.farc 5ACCA867 rom/auth_3d/EFFCHRPV614TET009.farc 24587A53 rom/auth_3d/EFFCHRPV617HAK001.farc 32EC0948 rom/auth_3d/EFFCHRPV617KAI001.farc 9A01A6B7 rom/auth_3d/EFFCHRPV617LEN001.farc 519D2509 rom/auth_3d/EFFCHRPV617MEI001.farc A72D97F8 rom/auth_3d/EFFCHRPV617MIK001.farc 58F773CD rom/auth_3d/EFFCHRPV617NER001.farc ADBCB01B rom/auth_3d/EFFCHRPV617RIN001.farc 41E91D03 rom/auth_3d/EFFCHRPV617SAK001.farc FC0E42EA rom/auth_3d/EFFCHRPV617TET001.farc 9CA9ADCE rom/auth_3d/EFFCHRPV624EXT001.farc 22B377ED rom/auth_3d/EFFCHRPV624EXT002.farc F9C198D1 rom/auth_3d/EFFCHRPV624HAK001.farc 3EA5DB1B rom/auth_3d/EFFCHRPV624HAK002.farc C41F0EAF rom/auth_3d/EFFCHRPV624KAI001.farc 54387144 rom/auth_3d/EFFCHRPV624KAI002.farc 8CB3DC01 rom/auth_3d/EFFCHRPV624LEN001.farc 0D656936 rom/auth_3d/EFFCHRPV624LEN002.farc C4986826 rom/auth_3d/EFFCHRPV624LUK001.farc 26114C9A rom/auth_3d/EFFCHRPV624MEI001.farc DDFC3D16 rom/auth_3d/EFFCHRPV624MEI002.farc 58196757 rom/auth_3d/EFFCHRPV624MIK001.farc 971A6440 rom/auth_3d/EFFCHRPV624MIK002.farc 41F5765C rom/auth_3d/EFFCHRPV624NER001.farc CB0D49DE rom/auth_3d/EFFCHRPV624NER002.farc 370E99E5 rom/auth_3d/EFFCHRPV624RIN001.farc CE4F052A rom/auth_3d/EFFCHRPV624RIN002.farc D34E520D rom/auth_3d/EFFCHRPV624SAK001.farc CEA0E988 rom/auth_3d/EFFCHRPV624SAK002.farc 3B9897C4 rom/auth_3d/EFFCHRPV624TET001.farc EF0AB355 rom/auth_3d/EFFCHRPV624TET002.farc 13D27B23 rom/auth_3d/EFFCHRPV630HAK001.farc 40F2AC88 rom/auth_3d/EFFCHRPV630HAK002.farc BE401C00 rom/auth_3d/EFFCHRPV630KAI001.farc 8F5723D4 rom/auth_3d/EFFCHRPV630LEN001.farc 9BD6713D rom/auth_3d/EFFCHRPV630LEN002.farc D0FD196F rom/auth_3d/EFFCHRPV630LUK001.farc 2BAE4517 rom/auth_3d/EFFCHRPV630LUK002.farc D70397B3 rom/auth_3d/EFFCHRPV630MEI001.farc 2F4CC925 rom/auth_3d/EFFCHRPV630MEI002.farc AFD16838 rom/auth_3d/EFFCHRPV630MIK001.farc A421F14E rom/auth_3d/EFFCHRPV630MIK002.farc 19936BBF rom/auth_3d/EFFCHRPV630NER001.farc 8F2053A9 rom/auth_3d/EFFCHRPV630NER002.farc 75A79608 rom/auth_3d/EFFCHRPV630RIN001.farc C6EAF079 rom/auth_3d/EFFCHRPV630RIN002.farc 4EEDEEBD rom/auth_3d/EFFCHRPV630SAK001.farc 28C1B15C rom/auth_3d/EFFCHRPV630SAK002.farc 1EF24B87 rom/auth_3d/EFFCHRPV630TET001.farc E89E4B7A rom/auth_3d/EFFCHRPV637KAI005.farc 131FE02C rom/auth_3d/EFFCHRPV637LEN002.farc 764A35DC rom/auth_3d/EFFCHRPV637LUK003.farc DFB5597C rom/auth_3d/EFFCHRPV637MEI004.farc 9FF0645B rom/auth_3d/EFFCHRPV637MIK001.farc 7ADE5BD2 rom/auth_3d/EFFCHRPV637MIK002.farc 2E487296 rom/auth_3d/EFFCHRPV637MIK003.farc 6E372AAB rom/auth_3d/EFFCHRPV637MIK004.farc 2C541DC2 rom/auth_3d/EFFCHRPV637MIK005.farc 0795EB26 rom/auth_3d/EFFCHRPV637RIN001.farc F7CDEFAE rom/auth_3d/EFFCHRPV641HAK002.farc 386FF542 rom/auth_3d/EFFCHRPV641HAK003.farc D093B9B7 rom/auth_3d/EFFCHRPV641KAI002.farc D8923AB7 rom/auth_3d/EFFCHRPV641KAI003.farc 3B6BF935 rom/auth_3d/EFFCHRPV641LEN002.farc 94EB4E03 rom/auth_3d/EFFCHRPV641LUK002.farc 3B4618F4 rom/auth_3d/EFFCHRPV641LUK003.farc DD090C6F rom/auth_3d/EFFCHRPV641MEI002.farc FB8C80EA rom/auth_3d/EFFCHRPV641MEI003.farc CF0AF161 rom/auth_3d/EFFCHRPV641MIK001.farc 289C1B41 rom/auth_3d/EFFCHRPV641MIK002.farc BA8EEB01 rom/auth_3d/EFFCHRPV641MIK003.farc 0D3569A9 rom/auth_3d/EFFCHRPV641NER002.farc A38E3256 rom/auth_3d/EFFCHRPV641NER003.farc C4BCB75A rom/auth_3d/EFFCHRPV641RIN002.farc 9E9DE037 rom/auth_3d/EFFCHRPV641RIN003.farc 489A53D5 rom/auth_3d/EFFCHRPV641SAK002.farc 66A7153E rom/auth_3d/EFFCHRPV641SAK003.farc AED2244F rom/auth_3d/EFFCHRPV641TET002.farc 5A583B37 rom/auth_3d/EFFCHRPV641TET003.farc AF8F8DD5 rom/auth_3d/EFFCHRPV722KAI100.farc C6A6AABB rom/auth_3d/EFFCHRPV722LEN100.farc 5B71EC8A rom/auth_3d/EFFCHRPV722LUK100.farc 75243F7F rom/auth_3d/EFFCHRPV722MEI100.farc 669E9430 rom/auth_3d/EFFCHRPV722MIK100.farc 35F55992 rom/auth_3d/EFFCHRPV722NER100.farc 26DBBA42 rom/auth_3d/EFFCHRPV722RIN100.farc F7146F91 rom/auth_3d/EFFCHRPV722SAK100.farc C5E6D14E rom/auth_3d/EFFCHRPV722TET100.farc 931939E5 rom/auth_3d/EFFCHRPV725HAK001.farc D22DF2B9 rom/auth_3d/EFFCHRPV725KAI001.farc 2AC6F0B3 rom/auth_3d/EFFCHRPV725LEN001.farc 86DB1336 rom/auth_3d/EFFCHRPV725LUK001.farc D53B5AD3 rom/auth_3d/EFFCHRPV725MEI001.farc AE641F2A rom/auth_3d/EFFCHRPV725MIK001.farc 5A306AB4 rom/auth_3d/EFFCHRPV725RIN001.farc 288FF10F rom/auth_3d/EFFCHRPV725SAK001.farc 5AF64D32 rom/auth_3d/EFFCHRPV725TET001.farc 826B8C74 rom/auth_3d/EFFCHRPV726HAK001.farc 6A7109EA rom/auth_3d/EFFCHRPV726HAK002.farc 709151FF rom/auth_3d/EFFCHRPV726KAI001.farc 071EE862 rom/auth_3d/EFFCHRPV726KAI002.farc D3380A31 rom/auth_3d/EFFCHRPV726LEN001.farc E8337FC9 rom/auth_3d/EFFCHRPV726LUK001.farc 14AAD090 rom/auth_3d/EFFCHRPV726LUK002.farc B77542F1 rom/auth_3d/EFFCHRPV726MEI001.farc EC342F94 rom/auth_3d/EFFCHRPV726MEI002.farc E737AD68 rom/auth_3d/EFFCHRPV726MIK001.farc 55E678D8 rom/auth_3d/EFFCHRPV726MIK002.farc 9B4DF05F rom/auth_3d/EFFCHRPV726NER001.farc 87A24376 rom/auth_3d/EFFCHRPV726SAK001.farc D57BF68B rom/auth_3d/EFFCHRPV726SAK002.farc 1D4E5076 rom/auth_3d/EFFCHRPV726TET001.farc 42A3F649 rom/auth_3d/EFFCHRPV726TET002.farc EEE3FE8C rom/auth_3d/EFFCHRPV730HAK001.farc 537BF140 rom/auth_3d/EFFCHRPV730HAK002.farc 7F2FD0B8 rom/auth_3d/EFFCHRPV730KAI001.farc FE19777F rom/auth_3d/EFFCHRPV730KAI002.farc 127A4AAA rom/auth_3d/EFFCHRPV730LEN001.farc 1305216A rom/auth_3d/EFFCHRPV730LEN002.farc 14F89B2D rom/auth_3d/EFFCHRPV730LUK001.farc 36972BD8 rom/auth_3d/EFFCHRPV730LUK002.farc AED4094F rom/auth_3d/EFFCHRPV730MEI001.farc CC525C27 rom/auth_3d/EFFCHRPV730MEI002.farc ABC1B507 rom/auth_3d/EFFCHRPV730MIK001.farc 57648548 rom/auth_3d/EFFCHRPV730NER001.farc DF1206B3 rom/auth_3d/EFFCHRPV730NER002.farc FDD5BF90 rom/auth_3d/EFFCHRPV730RIN001.farc 747EC171 rom/auth_3d/EFFCHRPV730RIN002.farc 3755A7BB rom/auth_3d/EFFCHRPV730SAK001.farc 33DE145B rom/auth_3d/EFFCHRPV730SAK002.farc 98F7B5CE rom/auth_3d/EFFCHRPV730TET001.farc C3E416B8 rom/auth_3d/EFFCHRPV730TET002.farc 2D14E03F rom/auth_3d/EFFCHRPV737HAK001.farc 294FBC2F rom/auth_3d/EFFCHRPV737HAK002.farc C9D88161 rom/auth_3d/EFFCHRPV737KAI001.farc BC26BCEA rom/auth_3d/EFFCHRPV737KAI002.farc D93EF807 rom/auth_3d/EFFCHRPV737LEN001.farc 14097056 rom/auth_3d/EFFCHRPV737LEN002.farc 383B4B95 rom/auth_3d/EFFCHRPV737LUK001.farc B9F78091 rom/auth_3d/EFFCHRPV737MEI001.farc EAF610A5 rom/auth_3d/EFFCHRPV737MEI002.farc 74FE4A7B rom/auth_3d/EFFCHRPV737MIK001.farc 9590D42F rom/auth_3d/EFFCHRPV737MIK002.farc D06C4FB6 rom/auth_3d/EFFCHRPV737NER001.farc 8AF3E413 rom/auth_3d/EFFCHRPV737NER002.farc BC44041D rom/auth_3d/EFFCHRPV737RIN001.farc FF3CF72E rom/auth_3d/EFFCHRPV737RIN002.farc 453C8197 rom/auth_3d/EFFCHRPV737SAK001.farc 6FC8AD87 rom/auth_3d/EFFCHRPV737SAK002.farc A36CD8C8 rom/auth_3d/EFFCHRPV737TET001.farc 8F8BF63F rom/auth_3d/EFFCHRPV737TET002.farc 5BEE5D3E rom/auth_3d/EFFCHRPV739HAK100.farc 730FA3A5 rom/auth_3d/EFFCHRPV739KAI100.farc D5B4C1CC rom/auth_3d/EFFCHRPV739LEN100.farc D5EE1C34 rom/auth_3d/EFFCHRPV739LUK100.farc 9CF0B074 rom/auth_3d/EFFCHRPV739MIK100.farc 1952C977 rom/auth_3d/EFFCHRPV739NER100.farc F4DC13E7 rom/auth_3d/EFFCHRPV739RIN100.farc B7254AB4 rom/auth_3d/EFFCHRPV739SAK100.farc 7F1B99D5 rom/auth_3d/EFFCHRPV739TET100.farc BA5312E5 rom/auth_3d/EFFSTGD2NS035.farc 56E7780B rom/auth_3d/EFFSTGD2NS036.farc 48F3CC15 rom/auth_3d/EFFSTGD2NS037.farc 97B98D05 rom/auth_3d/EFFSTGD2NS038.farc DD1D0848 rom/auth_3d/EFFSTGD2NS039.farc 89D7DD5D rom/auth_3d/EFFSTGD2NS040.farc D12C11DE rom/auth_3d/EFFSTGD2NS041.farc 7AAF8E1A rom/auth_3d/EFFSTGD2NS042.farc 76661BE3 rom/auth_3d/EFFSTGD2NS043.farc ACF8B360 rom/auth_3d/EFFSTGD2NS044.farc 6A3F9079 rom/auth_3d/EFFSTGD2NS045.farc EED96011 rom/auth_3d/EFFSTGD2NS047.farc 656FC964 rom/auth_3d/EFFSTGD2NS048.farc 5AC38C59 rom/auth_3d/EFFSTGD2NS049.farc 2E71BE98 rom/auth_3d/EFFSTGD2NS050.farc 38CEF718 rom/auth_3d/EFFSTGD2NS051.farc 3B0EAA02 rom/auth_3d/EFFSTGD2NS052.farc 81E60C01 rom/auth_3d/EFFSTGD2NS053.farc 261C53E3 rom/auth_3d/EFFSTGD2NS054.farc 04552910 rom/auth_3d/EFFSTGD2NS055.farc 3083D881 rom/auth_3d/EFFSTGD2NS056.farc A2D8A6E3 rom/auth_3d/EFFSTGD2NS057.farc 52E08FAD rom/auth_3d/EFFSTGD2NS058.farc 81A7B12B rom/auth_3d/EFFSTGD2NS059.farc C4D5A892 rom/auth_3d/EFFSTGD2NS060.farc 7127C843 rom/auth_3d/EFFSTGD2NS061.farc 06233586 rom/auth_3d/EFFSTGD2NS062.farc AE7802D0 rom/auth_3d/EFFSTGD2NS064.farc D8DDD32B rom/auth_3d/EFFSTGD2NS065.farc F43B3F58 rom/auth_3d/EFFSTGD2NS066.farc 776FC8F4 rom/auth_3d/EFFSTGD2NS067.farc FBEF8588 rom/auth_3d/EFFSTGD2NS068.farc 14C37277 rom/auth_3d/EFFSTGD2NS069.farc 51453E7B rom/auth_3d/EFFSTGD2NS070.farc 21A2BE9A rom/auth_3d/EFFSTGD2NS071.farc D5AD75A0 rom/auth_3d/EFFSTGD2NS072.farc 147AB236 rom/auth_3d/EFFSTGD2NS073.farc A4A69E7E rom/auth_3d/EFFSTGD2NS074.farc 5D00DBC7 rom/auth_3d/EFFSTGD2NS075.farc 87885D79 rom/auth_3d/EFFSTGD2NS076.farc 5FD5BF99 rom/auth_3d/EFFSTGD2NS077.farc FBA8CE5F rom/auth_3d/EFFSTGD2NS078.farc F04FCCD1 rom/auth_3d/EFFSTGD2NS079.farc 597328D7 rom/auth_3d/EFFSTGD2NS081.farc 99DE4F67 rom/auth_3d/EFFSTGD2NS082.farc 53AE74EE rom/auth_3d/EFFSTGD2PV037.farc 3834E510 rom/auth_3d/EFFSTGD2PV038.farc 43A89E70 rom/auth_3d/EFFSTGD2PV039.farc D33529C4 rom/auth_3d/EFFSTGD2PV040.farc E9B2E49C rom/auth_3d/EFFSTGD2PV041.farc 76FF7B08 rom/auth_3d/EFFSTGD2PV042.farc E31E04D8 rom/auth_3d/EFFSTGD2PV043.farc 5EFAEBEF rom/auth_3d/EFFSTGD2PV044.farc 363C03E1 rom/auth_3d/EFFSTGD2PV045.farc FF7F790B rom/auth_3d/EFFSTGD2PV046.farc 329B8AFE rom/auth_3d/EFFSTGD2PV047.farc 09FFD3BD rom/auth_3d/EFFSTGD2PV048.farc 9AB62769 rom/auth_3d/EFFSTGD2PV050.farc A9867640 rom/auth_3d/EFFSTGD2PV051.farc 03E5FC74 rom/auth_3d/EFFCHRPV614LUK001.farc 2EDB9186 rom/auth_3d/EFFCHRPV617LUK001.farc CEAE38A9 rom/auth_3d/EFFCHRPV624LUK002.farc CB9498B0 rom/auth_3d/EFFCHRPV630KAI002.farc DDBD7883 rom/auth_3d/EFFCHRPV630TET002.farc 3905A779 rom/auth_3d/EFFCHRPV641LEN003.farc 2A2CB4A1 rom/auth_3d/EFFCHRPV722HAK100.farc 3B7D1CA0 rom/auth_3d/EFFCHRPV725NER001.farc 6687BE37 rom/auth_3d/EFFCHRPV726RIN001.farc D77F4F98 rom/auth_3d/EFFCHRPV730MIK002.farc 5FB23E61 rom/auth_3d/EFFCHRPV737LUK002.farc 39D906EE rom/auth_3d/EFFCHRPV739MEI100.farc 447A1A16 rom/auth_3d/EFFSTGD2NS046.farc C99F2C50 rom/auth_3d/EFFSTGD2NS063.farc 3D57AC24 rom/auth_3d/EFFSTGD2NS080.farc 80E1CBC6 rom/auth_3d/EFFSTGD2PV052.farc 98E253A9 rom/auth_3d/EFFSTGNS001.farc B912AFB2 rom/auth_3d/EFFSTGNS018.farc 6F1F6348 rom/auth_3d/EFFSTGNS083.farc AFF6D169 rom/auth_3d/EFFSTGNS102.farc 853C28F7 rom/auth_3d/EFFSTGNS120.farc F81F7332 rom/auth_3d/EFFSTGPV005.farc C5A421FF rom/auth_3d/EFFSTGPV067.farc 3BC5F250 rom/auth_3d/EFFSTGPV096.farc 537B9369 rom/auth_3d/EFFSTGPV233.farc 776D1628 rom/auth_3d/EFFSTGPV253.farc FC8CC520 rom/auth_3d/EFFSTGPV604.farc 628B1393 rom/auth_3d/EFFSTGPV622.farc ECE35007 rom/auth_3d/EFFSTGPV723.farc 0E3A4028 rom/auth_3d/EFFSTGTST002.farc 07BDF62F rom/auth_3d/EFFSTGD2PV053.farc 68AB1053 rom/auth_3d/EFFSTGD2PV055.farc EFB3EBF6 rom/auth_3d/EFFSTGD2PV056.farc 375F78FA rom/auth_3d/EFFSTGD2PV057.farc C45DFC16 rom/auth_3d/EFFSTGD2PV058.farc 7D0A6D6D rom/auth_3d/EFFSTGD2PV060.farc 408CAA2D rom/auth_3d/EFFSTGD2PV061.farc 883F27BE rom/auth_3d/EFFSTGD2PV062.farc B25E5AF8 rom/auth_3d/EFFSTGD2PV063.farc A52C311B rom/auth_3d/EFFSTGD2PV064.farc 6BF97759 rom/auth_3d/EFFSTGD2PV065.farc 476F6EB4 rom/auth_3d/EFFSTGD2PV066.farc F7323A79 rom/auth_3d/EFFSTGD2PV208.farc 029246A8 rom/auth_3d/EFFSTGD2PV212.farc 8FB2FDCD rom/auth_3d/EFFSTGD2PV213.farc 3D509180 rom/auth_3d/EFFSTGD2PV214.farc 177EAEDC rom/auth_3d/EFFSTGNS002.farc 24F39D22 rom/auth_3d/EFFSTGNS003.farc 42A642B0 rom/auth_3d/EFFSTGNS004.farc E14182EF rom/auth_3d/EFFSTGNS005.farc E04A5403 rom/auth_3d/EFFSTGNS006.farc 68B054BE rom/auth_3d/EFFSTGNS007.farc 6E2AF236 rom/auth_3d/EFFSTGNS008.farc 35FB4883 rom/auth_3d/EFFSTGNS009.farc 1256742C rom/auth_3d/EFFSTGNS010.farc 7EDEB50B rom/auth_3d/EFFSTGNS011.farc 25D1312A rom/auth_3d/EFFSTGNS012.farc 416A58C1 rom/auth_3d/EFFSTGNS013.farc 87DBF99E rom/auth_3d/EFFSTGNS014.farc E9CC9AF1 rom/auth_3d/EFFSTGNS015.farc B3E33E14 rom/auth_3d/EFFSTGNS016.farc AA22A1C4 rom/auth_3d/EFFSTGNS017.farc 0A5350F2 rom/auth_3d/EFFSTGNS019.farc AA740CBD rom/auth_3d/EFFSTGNS020.farc D8E33D69 rom/auth_3d/EFFSTGNS021.farc 102CB3F6 rom/auth_3d/EFFSTGNS022.farc A0EB9514 rom/auth_3d/EFFSTGNS023.farc C2BAE832 rom/auth_3d/EFFSTGNS024.farc 284C217C rom/auth_3d/EFFSTGNS025.farc 1A2809C6 rom/auth_3d/EFFSTGNS026.farc 3AED2D27 rom/auth_3d/EFFSTGNS027.farc 63B8C81E rom/auth_3d/EFFSTGNS028.farc A27DC810 rom/auth_3d/EFFSTGNS029.farc 6E017704 rom/auth_3d/EFFSTGNS030.farc 97D0B447 rom/auth_3d/EFFSTGNS031.farc 982FDBA7 rom/auth_3d/EFFSTGNS032.farc 239AF751 rom/auth_3d/EFFSTGNS033.farc 0A5AF007 rom/auth_3d/EFFSTGNS034.farc D17D92FB rom/auth_3d/EFFSTGNS084.farc D09EE6E0 rom/auth_3d/EFFSTGNS085.farc 017DBEB1 rom/auth_3d/EFFSTGNS086.farc 781A37A5 rom/auth_3d/EFFSTGNS087.farc C8EE8274 rom/auth_3d/EFFSTGNS088.farc 6A24DC4B rom/auth_3d/EFFSTGNS089.farc C31F7676 rom/auth_3d/EFFSTGNS090.farc D19B2995 rom/auth_3d/EFFSTGNS091.farc 32FF1E89 rom/auth_3d/EFFSTGNS093.farc 83C4272C rom/auth_3d/EFFSTGNS094.farc 00ED62FC rom/auth_3d/EFFSTGNS095.farc 0066C3AD rom/auth_3d/EFFSTGNS096.farc 8B3B4116 rom/auth_3d/EFFSTGNS097.farc FEFC3C74 rom/auth_3d/EFFSTGNS099.farc 69DC3BFB rom/auth_3d/EFFSTGNS100.farc ED88B2AC rom/auth_3d/EFFSTGNS101.farc 207E2AD1 rom/auth_3d/EFFSTGNS103.farc 585411A4 rom/auth_3d/EFFSTGNS104.farc 19491CEF rom/auth_3d/EFFSTGNS105.farc 29DAE468 rom/auth_3d/EFFSTGNS106.farc D7444861 rom/auth_3d/EFFSTGNS107.farc 848ADD64 rom/auth_3d/EFFSTGNS108.farc 33716808 rom/auth_3d/EFFSTGNS109.farc 10E532B2 rom/auth_3d/EFFSTGNS111.farc 360B0E34 rom/auth_3d/EFFSTGNS112.farc 534D174C rom/auth_3d/EFFSTGNS113.farc A6986CC2 rom/auth_3d/EFFSTGNS114.farc AC8D2D58 rom/auth_3d/EFFSTGNS115.farc 2C80ED98 rom/auth_3d/EFFSTGNS116.farc D4A521B6 rom/auth_3d/EFFSTGNS117.farc 9849C734 rom/auth_3d/EFFSTGNS118.farc C17EE495 rom/auth_3d/EFFSTGNS119.farc F27D02A5 rom/auth_3d/EFFSTGNS121.farc E82C2B27 rom/auth_3d/EFFSTGNS122.farc 4A181157 rom/auth_3d/EFFSTGNS123.farc 20B16FB2 rom/auth_3d/EFFSTGNS124.farc D2873675 rom/auth_3d/EFFSTGNS125.farc 98828B4A rom/auth_3d/EFFSTGNS126.farc 063FE2A1 rom/auth_3d/EFFSTGNS210.farc 01B9D711 rom/auth_3d/EFFSTGNS221.farc B8EBCDB3 rom/auth_3d/EFFSTGNS249.farc E09AD874 rom/auth_3d/EFFSTGNS257.farc 6A640592 rom/auth_3d/EFFSTGNS266.farc 301867A1 rom/auth_3d/EFFSTGNS267.farc AE005E82 rom/auth_3d/EFFSTGNS272.farc E49D885A rom/auth_3d/EFFSTGPV001.farc F9FEB62C rom/auth_3d/EFFSTGPV003.farc 96845EAB rom/auth_3d/EFFSTGPV004.farc 5849E0A9 rom/auth_3d/EFFSTGPV006.farc 89F96B10 rom/auth_3d/EFFSTGPV007.farc 593E0B3A rom/auth_3d/EFFSTGPV008.farc 54EF4457 rom/auth_3d/EFFSTGPV009.farc 15840DD4 rom/auth_3d/EFFSTGPV011.farc B4E1D0AC rom/auth_3d/EFFSTGPV012.farc CC586711 rom/auth_3d/EFFSTGPV013.farc E40C05ED rom/auth_3d/EFFSTGPV014.farc E2E5AC21 rom/auth_3d/EFFSTGPV015.farc A4379211 rom/auth_3d/EFFSTGPV018.farc 146B786C rom/auth_3d/EFFSTGPV019.farc E77DE414 rom/auth_3d/EFFSTGPV020.farc F8B695AE rom/auth_3d/EFFSTGPV022.farc C6959A68 rom/auth_3d/EFFSTGPV024.farc D91051D8 rom/auth_3d/EFFSTGPV025.farc CAFEE286 rom/auth_3d/EFFSTGPV028.farc 3EADAEFC rom/auth_3d/EFFSTGPV079.farc D293E97C rom/auth_3d/EFFSTGPV081.farc B71827F1 rom/auth_3d/EFFSTGPV082.farc CE5FAECD rom/auth_3d/EFFSTGPV083.farc F0F7BFB1 rom/auth_3d/EFFSTGPV084.farc FDE8BE3C rom/auth_3d/EFFSTGPV085.farc 89C58918 rom/auth_3d/EFFSTGPV086.farc 7450135A rom/auth_3d/EFFSTGPV087.farc 68F2F90D rom/auth_3d/EFFSTGPV088.farc 92DF4B2B rom/auth_3d/EFFSTGPV089.farc EB0A3D25 rom/auth_3d/EFFSTGPV090.farc 05D6DC20 rom/auth_3d/EFFSTGPV091.farc 56FEBD4B rom/auth_3d/EFFSTGPV092.farc EEDCF405 rom/auth_3d/EFFSTGPV093.farc E5C7511B rom/auth_3d/EFFSTGPV094.farc 9D5614C9 rom/auth_3d/EFFSTGPV095.farc FABA15D0 rom/auth_3d/EFFSTGPV097.farc 8E420DF4 rom/auth_3d/EFFSTGPV103.farc F25E564C rom/auth_3d/EFFSTGPV104.farc C59723E6 rom/auth_3d/EFFSTGPV218.farc B2351797 rom/auth_3d/EFFSTGPV219.farc DFFBFEA6 rom/auth_3d/EFFSTGPV220.farc FCB28A14 rom/auth_3d/EFFSTGPV221.farc 62EBA54B rom/auth_3d/EFFSTGPV222.farc CF115598 rom/auth_3d/EFFSTGPV223.farc C69DC3CE rom/auth_3d/EFFSTGPV224.farc 7E468741 rom/auth_3d/EFFSTGPV225.farc F7D14238 rom/auth_3d/EFFSTGPV226.farc 89A43F57 rom/auth_3d/EFFSTGPV227.farc 6BD9D3EF rom/auth_3d/EFFSTGPV228.farc DA57FDA9 rom/auth_3d/EFFSTGPV231.farc 041ACC05 rom/auth_3d/EFFSTGPV232.farc 9F15B969 rom/auth_3d/EFFSTGPV234.farc E2CD691E rom/auth_3d/EFFSTGPV235.farc 82F20CB4 rom/auth_3d/EFFSTGPV236.farc B6004989 rom/auth_3d/EFFSTGPV238.farc 2DDE64B2 rom/auth_3d/EFFSTGPV239.farc B4DAF769 rom/auth_3d/EFFSTGPV240.farc DC7C0F72 rom/auth_3d/EFFSTGPV241.farc 7BFFA12F rom/auth_3d/EFFSTGPV242.farc 379CDADF rom/auth_3d/EFFSTGPV243.farc 668DBDF2 rom/auth_3d/EFFSTGPV244.farc A872E9BF rom/auth_3d/EFFSTGPV246.farc 55A9EAA4 rom/auth_3d/EFFSTGPV247.farc 030A5522 rom/auth_3d/EFFSTGPV248.farc D44BB66D rom/auth_3d/EFFSTGPV249.farc DD9FD30B rom/auth_3d/EFFSTGPV250.farc 8E6577F2 rom/auth_3d/EFFSTGPV251.farc FD6858EE rom/auth_3d/EFFSTGPV255.farc F09AFE08 rom/auth_3d/EFFSTGPV257.farc 5B7697F7 rom/auth_3d/EFFSTGPV259.farc 46687791 rom/auth_3d/EFFSTGPV260.farc 39776F5C rom/auth_3d/EFFSTGPV261.farc 604AC337 rom/auth_3d/EFFSTGPV262.farc F1CAE011 rom/auth_3d/EFFSTGPV432.farc 375F56EF rom/auth_3d/EFFSTGPV433.farc 235157D7 rom/auth_3d/EFFSTGPV434.farc 54F28967 rom/auth_3d/EFFSTGPV435.farc 223D7600 rom/auth_3d/EFFSTGPV440.farc 6CAA4160 rom/auth_3d/EFFSTGPV441.farc 3B53F7EA rom/auth_3d/EFFSTGPV600.farc A7A740A8 rom/auth_3d/EFFSTGPV601.farc 3F46E14F rom/auth_3d/EFFSTGPV602.farc ADE4E5D3 rom/auth_3d/EFFSTGPV603.farc EFF8CA4D rom/auth_3d/EFFSTGPV605.farc FEDCE396 rom/auth_3d/EFFSTGPV607.farc B44CCE0B rom/auth_3d/EFFSTGPV608.farc 35F0BEEF rom/auth_3d/EFFSTGPV609.farc 3AB7D8E3 rom/auth_3d/EFFSTGPV610.farc 29C067BA rom/auth_3d/EFFSTGPV611.farc 29E8D82E rom/auth_3d/EFFSTGPV612.farc 3245289F rom/auth_3d/EFFSTGPV613.farc 10A529B9 rom/auth_3d/EFFSTGPV614.farc C65D1288 rom/auth_3d/EFFSTGPV615.farc FFA78BA4 rom/auth_3d/EFFSTGPV616.farc D4A74294 rom/auth_3d/EFFSTGPV617.farc 547F5ED9 rom/auth_3d/EFFSTGPV618.farc 2F4EE7B5 rom/auth_3d/EFFSTGPV619.farc 2F5435F4 rom/auth_3d/EFFSTGPV620.farc 5CFA2E7D rom/auth_3d/EFFSTGPV621.farc 8C4A2812 rom/auth_3d/EFFSTGPV623.farc BC453A9F rom/auth_3d/EFFSTGPV624.farc F4F419CD rom/auth_3d/EFFSTGPV625.farc BC3DE62E rom/auth_3d/EFFSTGPV626.farc 4352E3BC rom/auth_3d/EFFSTGPV627.farc 69319D7F rom/auth_3d/EFFSTGPV628.farc 940EB82E rom/auth_3d/EFFSTGPV629.farc AD8891E0 rom/auth_3d/EFFSTGPV630.farc 0AF7FFA6 rom/auth_3d/EFFSTGPV631.farc C7354479 rom/auth_3d/EFFSTGPV637.farc FE437FCB rom/auth_3d/EFFSTGPV638.farc CC980E20 rom/auth_3d/EFFSTGPV639.farc 6DB65008 rom/auth_3d/EFFSTGPV640.farc EEC9A82B rom/auth_3d/EFFSTGPV641.farc 0F0AC200 rom/auth_3d/EFFSTGPV642.farc E488120F rom/auth_3d/EFFSTGPV710.farc C8FC43CB rom/auth_3d/EFFSTGPV724.farc 41FC0B93 rom/auth_3d/EFFSTGPV725.farc 6D9EE458 rom/auth_3d/EFFSTGPV726.farc D695C2C9 rom/auth_3d/EFFSTGPV727.farc 0B1962B3 rom/auth_3d/EFFSTGPV728.farc 6701B155 rom/auth_3d/EFFSTGPV729.farc ECA237BB rom/auth_3d/EFFSTGPV730.farc EFFBCBC4 rom/auth_3d/EFFSTGPV731.farc 620E1027 rom/auth_3d/EFFSTGPV732.farc 66059D52 rom/auth_3d/EFFSTGPV733.farc 5ACFC6F9 rom/auth_3d/EFFSTGPV734.farc 6896719B rom/auth_3d/EFFSTGPV736.farc AB987FA9 rom/auth_3d/EFFSTGPV737.farc 47461831 rom/auth_3d/EFFSTGPV738.farc AB1D04B7 rom/auth_3d/EFFSTGPV739.farc 92F6114C rom/auth_3d/EFFSTGPV740.farc B7D7A497 rom/auth_3d/EFFSTGPV832.farc 7225B509 rom/auth_3d/EFFSTGTST003.farc 02792A90 rom/auth_3d/HAK.farc EDC204A8 rom/auth_3d/ITMPV045.farc 766CF114 rom/auth_3d/ITMPV060.farc 524E43D3 rom/auth_3d/ITMPV084.farc E8A75380 rom/auth_3d/ITMPV085.farc 18147358 rom/auth_3d/ITMPV086.farc 5D916A9C rom/auth_3d/ITMPV088.farc AA2F99FA rom/auth_3d/ITMPV089.farc 8D879C00 rom/auth_3d/ITMPV103.farc 75B4D149 rom/auth_3d/ITMPV212.farc 8A8AF3A2 rom/auth_3d/ITMPV218.farc 487F7FB8 rom/auth_3d/ITMPV221.farc B054439E rom/auth_3d/ITMPV232.farc C98F818A rom/auth_3d/ITMPV233.farc 0302B8DD rom/auth_3d/ITMPV441.farc 68E2CD8A rom/auth_3d/ITMPV600.farc D785BF96 rom/auth_3d/ITMPV602.farc 10F7CA15 rom/auth_3d/ITMPV616.farc 4A6E050F rom/auth_3d/ITMPV618.farc D5FC3817 rom/auth_3d/ITMPV619.farc 4EB891A9 rom/auth_3d/ITMPV620.farc 51CB3A8F rom/auth_3d/ITMPV641.farc 809F2950 rom/auth_3d/ITMPV725.farc 4A6CA3D9 rom/auth_3d/ITMPV726.farc C3DDBD0D rom/auth_3d/ITMPV731.farc 6049B77C rom/auth_3d/ITMPV733.farc 6CECE044 rom/auth_3d/ITMPV737.farc 80AA4AD0 rom/auth_3d/KAI.farc 1294C976 rom/auth_3d/LEN.farc AF0C0D09 rom/auth_3d/LUK.farc 10639156 rom/auth_3d/MEI.farc 449CE2C3 rom/auth_3d/MIK.farc 8562956D rom/auth_3d/NER.farc E60D5926 rom/auth_3d/RIN.farc DD3600C5 rom/auth_3d/SAK.farc EE624919 rom/ibl/pv025s20.ibl 6D59850A rom/ibl/aetback.ibl 4178467F rom/ibl/d2ns035.ibl F330EC0B rom/ibl/d2ns036.ibl 503302CF rom/ibl/d2ns037.ibl DD958334 rom/ibl/d2ns038.ibl B7D4CF3F rom/ibl/d2ns039.ibl 13E036C5 rom/ibl/d2ns040.ibl 9F9A769B rom/ibl/d2ns041.ibl 4C386AEE rom/ibl/d2ns042.ibl 165B260C rom/ibl/d2ns043.ibl 990C33FF rom/ibl/d2ns044.ibl CDFFED70 rom/ibl/d2ns045.ibl 8F3ABF54 rom/ibl/d2ns046.ibl 78082BAF rom/ibl/d2ns047.ibl 460BA1BA rom/ibl/d2ns048.ibl 19C78219 rom/ibl/d2ns049.ibl 1E8E74DC rom/ibl/d2ns050.ibl 726E6414 rom/ibl/d2ns051.ibl 063DA2A6 rom/ibl/d2ns052.ibl BE924FBF rom/ibl/d2ns054.ibl BCD4D943 rom/ibl/d2ns055.ibl F63FBB71 rom/ibl/d2ns056.ibl 143B31E6 rom/ibl/d2ns057.ibl A82BBA43 rom/ibl/d2ns058.ibl DC84EACF rom/ibl/d2ns059.ibl 4614FECD rom/ibl/d2ns060.ibl 8B729A32 rom/ibl/d2ns062.ibl BF4590EA rom/ibl/d2ns063.ibl 73DC13B7 rom/ibl/d2ns064.ibl 9293C9B8 rom/ibl/d2ns065.ibl 3480CA8F rom/ibl/d2ns066.ibl 8F3F7EAC rom/ibl/d2ns067.ibl 16A45151 rom/ibl/d2ns068.ibl 385FF510 rom/ibl/d2ns069.ibl 1F13E300 rom/ibl/d2ns070.ibl 4D7AA345 rom/ibl/d2ns071.ibl 4C548CCD rom/ibl/d2ns072.ibl 407CC1AA rom/ibl/d2ns074.ibl 30E5657A rom/ibl/d2ns075.ibl 632323E5 rom/ibl/d2ns076.ibl 420FBF7D rom/ibl/d2ns077.ibl 1D181266 rom/ibl/d2ns078.ibl 794307DE rom/ibl/d2ns079.ibl 40D2798D rom/ibl/d2ns080.ibl F5C2396A rom/ibl/d2ns081.ibl 45D03C55 rom/ibl/d2ns082.ibl F4302F08 rom/ibl/d2pv037s01.ibl 47E91BF2 rom/ibl/d2pv037s02.ibl 8FC9A6F9 rom/ibl/d2pv037s03.ibl E99ABDC9 rom/ibl/d2pv038s01.ibl 893D99B7 rom/ibl/d2pv039s01.ibl 290C3E68 rom/ibl/d2pv039s02.ibl A36F52C5 rom/ibl/d2pv039s03.ibl FB7E1912 rom/ibl/d2pv040s01.ibl 5CF3D134 rom/ibl/d2pv041s01.ibl 195D505E rom/ibl/d2pv042s02.ibl 3954FBFF rom/ibl/d2pv042s03.ibl AD17327F rom/ibl/d2pv042s06.ibl 3A571E2D rom/ibl/d2pv043s01.ibl DBBF7280 rom/ibl/d2pv044s01.ibl ED1A7DD6 rom/ibl/d2pv044s02.ibl 393237A2 rom/ibl/d2pv044s03.ibl 722A185E rom/ibl/d2pv046s02.ibl E8119D7A rom/ibl/d2pv046s03.ibl CCB57F82 rom/ibl/d2pv046s04.ibl 1455877E rom/ibl/d2pv046s05.ibl E40F87BC rom/ibl/d2pv046s06.ibl 4AC87827 rom/ibl/d2pv047s01.ibl 42A0A909 rom/ibl/d2pv047s02.ibl FF2D1487 rom/ibl/d2pv047s03.ibl 98543059 rom/ibl/d2pv047s04.ibl 6C11F2A4 rom/ibl/d2pv047s05.ibl 80355BA9 rom/ibl/d2pv048s01.ibl B7AAD285 rom/ibl/d2pv050s01.ibl C4028165 rom/ibl/d2pv051s01.ibl EA8D7AE0 rom/ibl/d2pv051s02.ibl AC8759BB rom/ibl/d2pv051s03.ibl 957F396E rom/ibl/d2pv051s04.ibl 1BFA82AB rom/ibl/d2pv051s05.ibl 6307A52A rom/ibl/d2pv053s01.ibl 0C8C252C rom/ibl/d2pv053s02.ibl 7593B731 rom/ibl/d2pv053s03.ibl EBF1C978 rom/ibl/d2pv053s05.ibl 012EDF2B rom/ibl/d2pv053s06.ibl 60598563 rom/ibl/d2pv053s09.ibl 33D2AB84 rom/ibl/d2pv053s10.ibl 5A432033 rom/ibl/d2pv053s15.ibl F694F8B5 rom/ibl/d2pv055s01.ibl DAEF0705 rom/ibl/d2pv055s02.ibl ED5B320A rom/ibl/d2ns053.ibl 965B88E1 rom/ibl/d2ns073.ibl 7AAA540B rom/ibl/d2pv042s01.ibl 9C0E853D rom/ibl/d2pv047s06.ibl 2F671EDC rom/ibl/d2pv057s01.ibl 336753A6 rom/ibl/d2pv065s02.ibl 27F66309 rom/ibl/ns008.ibl CC2BAF9B rom/ibl/ns030.ibl 030F6C33 rom/ibl/ns099.ibl 3C1D8783 rom/ibl/ns119.ibl 8B8ABCA1 rom/ibl/pv001s04.ibl DAE1B0E2 rom/ibl/pv005s01.ibl D0B4F7F1 rom/ibl/pv008s07.ibl 96E03307 rom/ibl/pv013s04.ibl 347A0377 rom/ibl/pv020s01.ibl DF1E296C rom/ibl/pv025s02.ibl A0A33A61 rom/ibl/d2pv058s01.ibl 745B16AC rom/ibl/d2pv058s02.ibl 79C2D427 rom/ibl/d2pv060s01.ibl BF3B4E9D rom/ibl/d2pv061s01.ibl B87F0802 rom/ibl/d2pv061s02.ibl D0F1EC1A rom/ibl/d2pv062s01.ibl CBCB9363 rom/ibl/d2pv063s01.ibl BF601DC1 rom/ibl/d2pv063s02.ibl 11D2555B rom/ibl/d2pv063s03.ibl A0B090EA rom/ibl/d2pv063s04.ibl A4C02632 rom/ibl/d2pv063s09.ibl 24AD05CC rom/ibl/d2pv063s10.ibl 98EEA714 rom/ibl/d2pv063s11.ibl AF288BEB rom/ibl/d2pv063s12.ibl 384ACE2D rom/ibl/d2pv063s13.ibl 0D6EA06E rom/ibl/d2pv064s01.ibl F5247AC6 rom/ibl/d2pv064s02.ibl 354B70F7 rom/ibl/d2pv065s01.ibl 62536453 rom/ibl/d2pv065s03.ibl BF4BA866 rom/ibl/d2pv065s04.ibl 23668E45 rom/ibl/d2pv065s05.ibl 0EF19CBA rom/ibl/d2pv065s06.ibl EB0D126B rom/ibl/d2pv065s07.ibl 8190189D rom/ibl/d2pv065s08.ibl 7A4CE838 rom/ibl/d2pv066s01.ibl 95200790 rom/ibl/d2pv208s01.ibl F0275461 rom/ibl/d2pv212s01.ibl E5FA61ED rom/ibl/d2pv213s01.ibl A9A348FA rom/ibl/d2pv214s01.ibl B6C93B6A rom/ibl/ns001.ibl 01B5C60C rom/ibl/ns002.ibl F59E8432 rom/ibl/ns003.ibl 7C67340A rom/ibl/ns004.ibl 5B14D6DF rom/ibl/ns005.ibl B8FEE450 rom/ibl/ns006.ibl 803D2422 rom/ibl/ns007.ibl F8A9F675 rom/ibl/ns009.ibl A38117AD rom/ibl/ns010.ibl 8EE513AD rom/ibl/ns011.ibl 64786486 rom/ibl/ns012.ibl CC03E057 rom/ibl/ns013.ibl 8501C64E rom/ibl/ns014.ibl EAB24C2A rom/ibl/ns015.ibl 0EAE8CF0 rom/ibl/ns016.ibl FE8A5E0F rom/ibl/ns017.ibl 886A1757 rom/ibl/ns018.ibl 60B983FD rom/ibl/ns019.ibl 2320B965 rom/ibl/ns020.ibl B79C214C rom/ibl/ns021.ibl 4D8CD897 rom/ibl/ns022.ibl 1ACD1D49 rom/ibl/ns023.ibl 3F2EFB94 rom/ibl/ns024.ibl 0C74DB6C rom/ibl/ns025.ibl 7358CDF9 rom/ibl/ns026.ibl F2413E03 rom/ibl/ns029.ibl 70C6D602 rom/ibl/ns031.ibl 61A7993C rom/ibl/ns032.ibl B3E244EE rom/ibl/ns033.ibl 3579EEEF rom/ibl/ns034.ibl 08E6C1E1 rom/ibl/ns083.ibl 56E2BB24 rom/ibl/ns084.ibl D34EE900 rom/ibl/ns085.ibl 8E59CC9C rom/ibl/ns087.ibl 09A6730E rom/ibl/ns088.ibl E3F29B3D rom/ibl/ns089.ibl EF6064AA rom/ibl/ns090.ibl 37BD9F05 rom/ibl/ns091.ibl E3058650 rom/ibl/ns092.ibl 7A47728D rom/ibl/ns093.ibl BB9FA2EB rom/ibl/ns094.ibl 2661DF5B rom/ibl/ns095.ibl 9BAAC5CD rom/ibl/ns096.ibl F0EC7919 rom/ibl/ns097.ibl D21DF408 rom/ibl/ns098.ibl E4EB21C1 rom/ibl/ns100.ibl B37E1F0B rom/ibl/ns101.ibl 0A2E9C90 rom/ibl/ns102.ibl 7C829BD5 rom/ibl/ns103.ibl A8B6BF1E rom/ibl/ns104.ibl DA68D279 rom/ibl/ns105.ibl EF617C6D rom/ibl/ns106.ibl DDF925EB rom/ibl/ns107.ibl 39141DF9 rom/ibl/ns108.ibl C30D1834 rom/ibl/ns109.ibl 8AB9F507 rom/ibl/ns110.ibl 4EA3EA35 rom/ibl/ns111.ibl D968D94E rom/ibl/ns112.ibl B831D089 rom/ibl/ns113.ibl E91B47D3 rom/ibl/ns114.ibl 56100E59 rom/ibl/ns115.ibl 63CA6447 rom/ibl/ns116.ibl B9F9E318 rom/ibl/ns117.ibl 98532190 rom/ibl/ns118.ibl 7F7DFB12 rom/ibl/ns120.ibl EEC99B9B rom/ibl/ns121.ibl 9B3D6BAC rom/ibl/ns122.ibl CF23AFBB rom/ibl/ns123.ibl A45C4951 rom/ibl/ns124.ibl CB440E2D rom/ibl/ns125.ibl 1E625601 rom/ibl/ns126.ibl ED08ECA0 rom/ibl/ns221.ibl 4769E1B4 rom/ibl/ns249.ibl 03E17F63 rom/ibl/ns257.ibl CD7EC128 rom/ibl/ns263.ibl 977C7E76 rom/ibl/ns266.ibl 39386172 rom/ibl/ns267.ibl 59CAAB75 rom/ibl/ns272.ibl B44A688E rom/ibl/ns292.ibl CAC6CD31 rom/ibl/pv001s01.ibl 691FC482 rom/ibl/pv001s02.ibl 1EB98615 rom/ibl/pv001s03.ibl FCC5E524 rom/ibl/pv001s05.ibl FAB3AA48 rom/ibl/pv001s06.ibl 88D5BDDC rom/ibl/pv001s07.ibl 10274D6F rom/ibl/pv003s01.ibl 5D026EF1 rom/ibl/pv003s02.ibl CC463063 rom/ibl/pv003s03.ibl A0BCE0E4 rom/ibl/pv003s04.ibl 7C4369C9 rom/ibl/pv003s05.ibl 76A99791 rom/ibl/pv003s06.ibl 69969579 rom/ibl/pv003s07.ibl 637C6B21 rom/ibl/pv003s08.ibl 00BF6269 rom/ibl/pv003s09.ibl F4006D99 rom/ibl/pv004s01.ibl 3DE21683 rom/ibl/pv004s02.ibl 6D22FE25 rom/ibl/pv004s05.ibl EE84E6EF rom/ibl/pv004s06.ibl 8334906B rom/ibl/pv004s07.ibl 7C5553B4 rom/ibl/pv005s04.ibl 0028F5CE rom/ibl/pv005s06.ibl AFF2BDEF rom/ibl/pv006s02.ibl 510C0D80 rom/ibl/pv007s01.ibl 760A7672 rom/ibl/pv007s02.ibl F35207E1 rom/ibl/pv007s03.ibl 3FDF0959 rom/ibl/pv007s04.ibl 844A1925 rom/ibl/pv007s05.ibl 529A3DBD rom/ibl/pv007s06.ibl 3F2A4B39 rom/ibl/pv007s07.ibl 7CE33BA6 rom/ibl/pv007s08.ibl AD6A31AF rom/ibl/pv007s09.ibl 3F2AE1EC rom/ibl/pv007s10.ibl 83C98266 rom/ibl/pv007s11.ibl C8DC18B6 rom/ibl/pv007s12.ibl DFBF4015 rom/ibl/pv008s01.ibl ECBC7BC6 rom/ibl/pv008s03.ibl D2716AD6 rom/ibl/pv008s08.ibl 6A3851FF rom/ibl/pv008s09.ibl 802B7832 rom/ibl/pv008s10.ibl DFEF4C40 rom/ibl/pv009s02.ibl 0E3D9FD8 rom/ibl/pv009s03.ibl 50DA5340 rom/ibl/pv009s04.ibl 4ADDDE4F rom/ibl/pv009s05.ibl 5FC7BE5E rom/ibl/pv009s08.ibl 879DC276 rom/ibl/pv009s09.ibl F2CAA75B rom/ibl/pv011s01.ibl 4F58605C rom/ibl/pv011s02.ibl 048984D6 rom/ibl/pv011s03.ibl 5F8E8BCD rom/ibl/pv011s04.ibl 5FA0E001 rom/ibl/pv011s06.ibl 626BD044 rom/ibl/pv013s01.ibl 9AA582B2 rom/ibl/pv013s02.ibl FF10FDF1 rom/ibl/pv013s03.ibl C16D17BD rom/ibl/pv014s01.ibl F4F803EB rom/ibl/pv015s01.ibl AE0BD7CB rom/ibl/pv015s02.ibl 1E70B84F rom/ibl/pv015s03.ibl 6CAFCB4D rom/ibl/pv015s05.ibl FC0EFA3E rom/ibl/pv018s05.ibl FB7D9433 rom/ibl/pv018s06.ibl 95B7ADBB rom/ibl/pv018s07.ibl 354528C3 rom/ibl/pv018s08.ibl 01030A19 rom/ibl/pv018s09.ibl DBA6297C rom/ibl/pv019s03.ibl 259690FA rom/ibl/pv019s04.ibl 77AEF5FD rom/ibl/pv019s08.ibl 92F00BE8 rom/ibl/pv019s09.ibl 945EED0A rom/ibl/pv019s11.ibl 356C2F0E rom/ibl/pv019s13.ibl 510612DB rom/ibl/pv019s14.ibl E5F02D31 rom/ibl/pv020s02.ibl 280E1826 rom/ibl/pv020s03.ibl 7AFE08E0 rom/ibl/pv024s01.ibl D605A2CA rom/ibl/pv024s02.ibl 86C54A6C rom/ibl/pv024s03.ibl CC3FA259 rom/ibl/pv024s04.ibl 00412BCF rom/ibl/pv024s05.ibl CB5F6D91 rom/ibl/pv024s06.ibl 659C3CDD rom/ibl/pv024s07.ibl 1C04C752 rom/ibl/pv024s08.ibl C58C8FAE rom/ibl/pv024s09.ibl F5CCD7CC rom/ibl/pv024s10.ibl 843BBCEB rom/ibl/pv024s11.ibl 96E4C22E rom/ibl/pv024s12.ibl B5F22249 rom/ibl/pv024s13.ibl 4EE6EBF9 rom/ibl/pv024s14.ibl 5861B67E rom/ibl/pv025s01.ibl 170CA7C1 rom/ibl/pv025s03.ibl 7712E975 rom/ibl/pv025s04.ibl 9C87E303 rom/ibl/pv025s05.ibl 90B7B631 rom/ibl/pv025s06.ibl C4170889 rom/ibl/pv025s07.ibl E0360BFF rom/ibl/pv025s08.ibl 38806C27 rom/ibl/pv025s09.ibl 6A438782 rom/ibl/pv025s10.ibl 525462EE rom/ibl/pv025s11.ibl DF707781 rom/ibl/pv025s12.ibl 6D4DB340 rom/ibl/pv025s13.ibl 349CB2EB rom/ibl/pv025s14.ibl 87361514 rom/ibl/pv025s15.ibl 180284BF rom/ibl/pv025s16.ibl 09D05327 rom/ibl/pv025s17.ibl 00BCDEC0 rom/ibl/pv025s18.ibl AA60F7A2 rom/ibl/pv025s19.ibl A30C7A45 rom/ibl/pv025s21.ibl 2C89D977 rom/ibl/pv025s22.ibl 6E5F1471 rom/ibl/pv025s23.ibl 2E44CFA0 rom/ibl/pv025s24.ibl 002F03A0 rom/ibl/pv025s25.ibl 3335135B rom/ibl/pv025s26.ibl 23D10F5B rom/ibl/pv025s27.ibl 3CFBD290 rom/ibl/pv028s01.ibl 7BAC5C4F rom/ibl/pv079s01.ibl E427BF7B rom/ibl/pv081s01.ibl 828BEBFE rom/ibl/pv081s02.ibl E60A00BF rom/ibl/pv081s03.ibl 85B8E15C rom/ibl/pv081s04.ibl CE4C30FF rom/ibl/pv081s05.ibl 19ED185F rom/ibl/pv081s06.ibl EB4AD6E4 rom/ibl/pv081s07.ibl F93E8508 rom/ibl/pv081s08.ibl 8353B828 rom/ibl/pv081s10.ibl B8CD6269 rom/ibl/pv081s11.ibl 578A3293 rom/ibl/pv081s12.ibl 56DECB56 rom/ibl/pv082s61.ibl 4F263D28 rom/ibl/pv082s62.ibl 4F263D28 rom/ibl/pv082s63.ibl 4F263D28 rom/ibl/pv082s64.ibl 4F263D28 rom/ibl/pv082s65.ibl 4F263D28 rom/ibl/pv083s01.ibl C86AE535 rom/ibl/pv083s02.ibl F1644446 rom/ibl/pv083s03.ibl AB42A6B4 rom/ibl/pv083s04.ibl 499B52FA rom/ibl/pv083s05.ibl EC532123 rom/ibl/pv083s07.ibl D6CEDCBB rom/ibl/pv083s08.ibl 8EEDDB47 rom/ibl/pv083s14.ibl B3458652 rom/ibl/pv083s18.ibl 0EC2DE73 rom/ibl/pv083s25.ibl 7C10B814 rom/ibl/pv083s26.ibl D48DF4A6 rom/ibl/pv083s27.ibl DFBF1CCB rom/ibl/pv083s28.ibl A568745D rom/ibl/pv084s01.ibl 4DDE4A21 rom/ibl/pv085s01.ibl 18C33455 rom/ibl/pv086s01.ibl A2F85F3F rom/ibl/pv086s02.ibl 8C878A5D rom/ibl/pv087s01.ibl F4EEA3D6 rom/ibl/pv087s02.ibl C5B4AE8A rom/ibl/pv087s16.ibl A9B24BF8 rom/ibl/pv087s17.ibl 2EA753ED rom/ibl/pv088s01.ibl 59DC3A3B rom/ibl/pv088s02.ibl C34EFE27 rom/ibl/pv088s11.ibl E08D9A3B rom/ibl/pv088s12.ibl 466A850C rom/ibl/pv088s14.ibl D0D5BD23 rom/ibl/pv089s02.ibl ED8AC0AE rom/ibl/pv089s03.ibl 47CD1D4C rom/ibl/pv089s05.ibl 91AFAF4C rom/ibl/pv090s01.ibl 95982749 rom/ibl/pv090s02.ibl 9C939BAC rom/ibl/pv091s01.ibl A8C9AEFA rom/ibl/pv091s02.ibl CD538D96 rom/ibl/pv091s03.ibl 7504E667 rom/ibl/pv091s04.ibl E8801354 rom/ibl/pv091s09.ibl 76DADCFB rom/ibl/pv091s10.ibl 6507CB84 rom/ibl/pv091s13.ibl 69956DF7 rom/ibl/pv091s14.ibl BB22205E rom/ibl/pv091s15.ibl 217FA3E0 rom/ibl/pv092s01.ibl 57BFB9BF rom/ibl/pv092s02.ibl 1E0CCDF7 rom/ibl/pv092s05.ibl 916042D8 rom/ibl/pv092s09.ibl EEE38567 rom/ibl/pv092s10.ibl 92ECE857 rom/ibl/pv092s11.ibl 248A8732 rom/ibl/pv092s12.ibl 7B88A581 rom/ibl/pv094s01.ibl 6458303F rom/ibl/pv094s02.ibl F65A16D8 rom/ibl/pv094s16.ibl 97A9DCD0 rom/ibl/pv094s17.ibl 0215F42E rom/ibl/pv094s18.ibl 2A047020 rom/ibl/pv096s01.ibl C40E40BC rom/ibl/pv097s01.ibl 0FF5B432 rom/ibl/pv103s01.ibl DCD8A91D rom/ibl/pv104s01.ibl 5D38F454 rom/ibl/pv104s02.ibl 8D0E6E82 rom/ibl/pv104s03.ibl C2E3E730 rom/ibl/pv104s04.ibl F6125D6F rom/ibl/pv218s01.ibl 61EDD513 rom/ibl/pv218s03.ibl 127B5627 rom/ibl/pv218s04.ibl 8BADBCBC rom/ibl/pv219s01.ibl FF372483 rom/ibl/pv219s02.ibl BE70086B rom/ibl/pv219s03.ibl 76FCE3C1 rom/ibl/pv219s04.ibl 200F0A53 rom/ibl/pv219s05.ibl 0F204B9A rom/ibl/pv219s07.ibl BF4F72D0 rom/ibl/pv219s08.ibl 309DE29C rom/ibl/pv219s09.ibl 84E9ACD5 rom/ibl/pv219s10.ibl 78A8B2DC rom/ibl/pv219s11.ibl 160C7FA3 rom/ibl/pv219s12.ibl 244AE1EB rom/ibl/pv219s13.ibl 2A0BA6F4 rom/ibl/pv219s14.ibl 4E4BC50A rom/ibl/pv220s01.ibl DC9AE1F5 rom/ibl/pv220s02.ibl 118A5FAE rom/ibl/pv221s03.ibl CE3D4245 rom/ibl/pv221s04.ibl BBA303EB rom/ibl/pv221s05.ibl 657AC024 rom/ibl/pv221s06.ibl DD618234 rom/ibl/pv221s07.ibl E36112BA rom/ibl/pv221s08.ibl D549B691 rom/ibl/pv221s09.ibl 8326FCE5 rom/ibl/pv221s10.ibl DB73F806 rom/ibl/pv221s11.ibl 63E7974D rom/ibl/pv221s14.ibl 8ED52513 rom/ibl/pv222s01.ibl E207D031 rom/ibl/pv222s02.ibl 0B7BBF27 rom/ibl/pv223s01.ibl 9BF973A7 rom/ibl/pv223s02.ibl 7C96DA2B rom/ibl/pv223s03.ibl 825C5BB3 rom/ibl/pv223s04.ibl AA10C409 rom/ibl/pv223s05.ibl 30DA4868 rom/ibl/pv223s07.ibl AE61329E rom/ibl/pv223s08.ibl C9CD6BE8 rom/ibl/pv223s09.ibl 98A1B156 rom/ibl/pv223s10.ibl A52F6DD5 rom/ibl/pv224s01.ibl 9ECF3055 rom/ibl/pv224s02.ibl BC5B8562 rom/ibl/pv224s03.ibl 182DF716 rom/ibl/pv225s01.ibl B6F360EA rom/ibl/pv225s02.ibl 81AC64B0 rom/ibl/pv225s03.ibl 808759EF rom/ibl/pv226s01.ibl 3AD23A1B rom/ibl/pv227s01.ibl BC61F210 rom/ibl/pv228s01.ibl 6F36D651 rom/ibl/pv228s02.ibl BF004C87 rom/ibl/pv228s03.ibl FAC5F9BE rom/ibl/pv228s04.ibl C41C7F6A rom/ibl/pv231s01.ibl D84AD6E5 rom/ibl/pv231s03.ibl E77AFF48 rom/ibl/pv231s04.ibl 3822CF3D rom/ibl/pv231s05.ibl A62A85BF rom/ibl/pv231s06.ibl 0712E690 rom/ibl/pv231s07.ibl F5327166 rom/ibl/pv232s01.ibl B4DF48F9 rom/ibl/pv232s02.ibl F5B47CFD rom/ibl/pv232s03.ibl BE143D53 rom/ibl/pv233s01.ibl 3ACAD409 rom/ibl/pv233s02.ibl 52CB897E rom/ibl/pv233s03.ibl 50F52948 rom/ibl/pv233s04.ibl 6A2EA342 rom/ibl/pv233s05.ibl C4C0FB15 rom/ibl/pv233s06.ibl 921AC60F rom/ibl/pv233s07.ibl 62E850BC rom/ibl/pv233s08.ibl 358BEC4B rom/ibl/pv234s01.ibl 5F34ADE7 rom/ibl/pv235s01.ibl 9021B69F rom/ibl/pv235s02.ibl C99827E1 rom/ibl/pv235s03.ibl ED0ABC04 rom/ibl/pv235s04.ibl 57B5634C rom/ibl/pv235s05.ibl 99B53E7E rom/ibl/pv235s06.ibl EF7E859A rom/ibl/pv235s07.ibl 01E24004 rom/ibl/pv235s08.ibl 20507D21 rom/ibl/pv235s09.ibl 6A1DE306 rom/ibl/pv236s01.ibl B79CB1DC rom/ibl/pv236s02.ibl 45419B47 rom/ibl/pv236s03.ibl 2680CD6D rom/ibl/pv236s04.ibl FCED6E13 rom/ibl/pv236s05.ibl 5E7A48B6 rom/ibl/pv236s06.ibl CD367E6F rom/ibl/pv236s07.ibl 44426A17 rom/ibl/pv238s01.ibl 8D7237E7 rom/ibl/pv240s01.ibl B1BB4C0A rom/ibl/pv240s02.ibl B9DE6304 rom/ibl/pv240s03.ibl 41DF098A rom/ibl/pv241s01.ibl 74585D0F rom/ibl/pv241s02.ibl 458B5DB4 rom/ibl/pv243s01.ibl 954B1198 rom/ibl/pv244s01.ibl 9472F5DC rom/ibl/pv244s02.ibl 30775035 rom/ibl/pv246s01.ibl FE47545F rom/ibl/pv248s01.ibl A63D038E rom/ibl/pv248s05.ibl DC926F80 rom/ibl/pv250s01.ibl DEE405F6 rom/ibl/pv251s01.ibl 6D7FE7CD rom/ibl/pv251s02.ibl D59C6244 rom/ibl/pv251s03.ibl 16E93617 rom/ibl/pv251s04.ibl B78B44B5 rom/ibl/pv251s05.ibl 367990E1 rom/ibl/pv251s07.ibl E4A2901F rom/ibl/pv253s01.ibl C038EC2B rom/ibl/pv253s02.ibl E532575C rom/ibl/pv253s03.ibl 4F1B3C4E rom/ibl/pv253s04.ibl AF2721B2 rom/ibl/pv253s05.ibl 050E4AA0 rom/ibl/pv253s06.ibl 2004F1D7 rom/ibl/pv253s07.ibl 8A2D9AC5 rom/ibl/pv253s08.ibl 3B0DCC6E rom/ibl/pv253s09.ibl 9124A77C rom/ibl/pv255s01.ibl 2A2AE1E2 rom/ibl/pv257s01.ibl 905306A8 rom/ibl/pv262s03.ibl 0A13E161 rom/ibl/pv432s01.ibl 9D226B21 rom/ibl/pv432s02.ibl 05D27EF0 rom/ibl/pv432s03.ibl DB6CF1FD rom/ibl/pv433s01.ibl A171F2F3 rom/ibl/pv433s03.ibl CB74ED7B rom/ibl/pv433s04.ibl 81079625 rom/ibl/pv433s05.ibl CEDBF382 rom/ibl/pv433s06.ibl 48443D8F rom/ibl/pv434s01.ibl 3BEAC906 rom/ibl/pv435s01.ibl 2CEE71C4 rom/ibl/pv435s02.ibl 0273E43C rom/ibl/pv435s03.ibl A0230396 rom/ibl/pv435s04.ibl 45A96976 rom/ibl/pv435s05.ibl 76690D7A rom/ibl/pv435s06.ibl 2A05EAFE rom/ibl/pv435s07.ibl E5013828 rom/ibl/pv435s08.ibl CE9453CA rom/ibl/pv441s01.ibl 88D5E7CA rom/ibl/pv600s01.ibl 82617777 rom/ibl/pv600s02.ibl 1C878BB5 rom/ibl/pv600s03.ibl 1266BDBC rom/ibl/pv601s01.ibl 8B527E39 rom/ibl/pv601s02.ibl 8831F008 rom/ibl/pv601s03.ibl EACD0385 rom/ibl/pv601s04.ibl BFCC04C5 rom/ibl/pv602s01.ibl B5C21FE2 rom/ibl/pv602s02.ibl 10B71262 rom/ibl/pv602s03.ibl 3806149D rom/ibl/pv602s04.ibl 1D0A072B rom/ibl/pv603s01.ibl 3D3A4464 rom/ibl/pv604s07.ibl 01F745D0 rom/ibl/pv605s01.ibl 64B525BA rom/ibl/pv605s02.ibl 5B28E1B2 rom/ibl/pv605s05.ibl 5218794A rom/ibl/pv607s01.ibl 29D10A4F rom/ibl/pv608s01.ibl E737060F rom/ibl/pv609s01.ibl 732AC7BC rom/ibl/pv609s03.ibl D4257930 rom/ibl/pv610s02.ibl 597C61B5 rom/ibl/pv611s01.ibl 83DF7917 rom/ibl/pv612s01.ibl 9116DBD2 rom/ibl/pv612s02.ibl B2FFE574 rom/ibl/pv612s03.ibl 8714873C rom/ibl/pv612s04.ibl C72423EF rom/ibl/pv613s01.ibl 262148C0 rom/ibl/pv613s02.ibl B6B71FDF rom/ibl/pv613s03.ibl BBB5A3EB rom/ibl/pv614s01.ibl DDFC7E94 rom/ibl/pv614s05.ibl 4FD3CC59 rom/ibl/pv615s01.ibl 51B28006 rom/ibl/pv616s01.ibl 1DBAEA16 rom/ibl/pv616s02.ibl 764EE2DE rom/ibl/pv616s03.ibl 3D2F0E16 rom/ibl/pv617s01.ibl 3603F6BE rom/ibl/pv617s02.ibl 78D2DFA0 rom/ibl/pv619s02.ibl 3627A9C0 rom/ibl/pv619s03.ibl 6ADB5B66 rom/ibl/pv619s04.ibl 96C6F4DF rom/ibl/pv620s01.ibl BFF56741 rom/ibl/pv621s01.ibl A9C7FC11 rom/ibl/pv622s01.ibl 9948A050 rom/ibl/pv623s01.ibl 83336D5D rom/ibl/pv623s02.ibl 38232D43 rom/ibl/pv625s01.ibl 55E55F68 rom/ibl/pv625s03.ibl C18D6454 rom/ibl/pv626s01.ibl 36DE8126 rom/ibl/pv628s01.ibl A8B5873B rom/ibl/pv629s01.ibl C45F6B5F rom/ibl/pv630s01.ibl 133A2902 rom/ibl/pv630s02.ibl 0056192A rom/ibl/pv630s03.ibl 26CC207C rom/ibl/pv630s04.ibl 253DFCE5 rom/ibl/pv631s01.ibl F37A9DC1 rom/ibl/pv637s01.ibl E5828779 rom/ibl/pv637s02.ibl 16D7EECB rom/ibl/pv638s01.ibl 573DD586 rom/ibl/pv638s02.ibl 84F72534 rom/ibl/pv639s01.ibl CCA311FF rom/ibl/pv639s02.ibl 6A32EC1F rom/ibl/pv639s03.ibl B3284A7C rom/ibl/pv639s05.ibl B0C61271 rom/ibl/pv640s01.ibl 133F84BB rom/ibl/pv640s02.ibl 6EDBA192 rom/ibl/pv641s01.ibl 52C2E7FD rom/ibl/pv642s01.ibl 6187BE45 rom/ibl/pv722s01.ibl 9FDC5C51 rom/ibl/pv722s02.ibl 7078031B rom/ibl/pv723s01.ibl B4036EA7 rom/ibl/pv725s01.ibl 36AD7EB8 rom/ibl/pv725s02.ibl BC4490EA rom/ibl/pv727s02.ibl AD9D785A rom/ibl/pv728s03.ibl 1FA26273 rom/ibl/pv729s01.ibl 56732274 rom/ibl/pv729s03.ibl DF519FA9 rom/ibl/pv732s01.ibl 986ED4C9 rom/ibl/pv734s05.ibl 1C773267 rom/ibl/pv736s01.ibl E23A07F0 rom/ibl/pv737s01.ibl 49FFA7AC rom/ibl/pv737s02.ibl 78C02F78 rom/ibl/pv738s01.ibl 38049734 rom/ibl/pv739s01.ibl 51BD8906 rom/ibl/selpvback.ibl 0D56ED9E rom/ibl/tst.ibl 9BEEB7F4 rom/ibl/tst001.ibl 0039ACDB rom/ibl/tst002.ibl 743C9BF9 rom/ibl/tst006.ibl 2B73D816 rom/ibl/tst007.ibl 4CAFB5B2 rom/ibl/tst008.ibl 6683F6D0 rom/ibl/tst009.ibl 1B6BE303 rom/ibl/tst010.ibl ADFC5F79 rom/ibl/pv081s09.ibl 1DF3F015 rom/ibl/pv083s24.ibl BEC8FFEC rom/ibl/pv089s01.ibl 8D048949 rom/ibl/pv092s07.ibl 2698C5A1 rom/ibl/pv218s02.ibl 6C734D80 rom/ibl/pv220s03.ibl 21E1F90B rom/ibl/pv223s06.ibl E8D5C07D rom/ibl/pv231s02.ibl 155A68BE rom/ibl/pv234s02.ibl 55CB6435 rom/ibl/pv239s01.ibl 7D121032 rom/ibl/pv251s06.ibl 0FB25B5C rom/ibl/pv433s02.ibl CF20A228 rom/ibl/pv600s04.ibl AE33D397 rom/ibl/pv610s01.ibl 9FBB004E rom/ibl/pv619s01.ibl 35A1B1F8 rom/ibl/pv630s05.ibl 25ADB8D6 rom/ibl/pv726s01.ibl F6F6ACF3 rom/light_param/face_d2ns035.txt 4954B23E rom/light_param/face_d2ns036.txt 32376B86 rom/light_param/face_d2ns037.txt 32376B86 rom/light_param/face_d2ns038.txt C4F0D8F6 rom/light_param/face_d2ns039.txt F941342A rom/light_param/face_d2ns040.txt 4954B23E rom/light_param/face_d2ns041.txt C4F0D8F6 rom/light_param/face_d2ns042.txt 4954B23E rom/light_param/face_d2ns043.txt C4F0D8F6 rom/light_param/face_d2ns046.txt 32376B86 rom/light_param/face_d2ns047.txt 4954B23E rom/light_param/face_d2ns048.txt 4954B23E rom/light_param/face_d2ns049.txt 32376B86 rom/light_param/face_d2ns050.txt 4954B23E rom/light_param/face_d2ns051.txt C4F0D8F6 rom/light_param/face_d2ns052.txt 74E55EE2 rom/light_param/face_d2ns054.txt 4954B23E rom/light_param/face_d2ns055.txt F941342A rom/light_param/face_d2ns059.txt 4954B23E rom/light_param/face_d2ns060.txt 4954B23E rom/light_param/face_d2ns065.txt 74E55EE2 rom/light_param/face_d2ns067.txt F7EF1A95 rom/light_param/face_d2ns070.txt 74E55EE2 rom/light_param/face_d2ns071.txt F941342A rom/light_param/face_d2ns072.txt 4954B23E rom/light_param/face_d2ns073.txt C4F0D8F6 rom/light_param/face_d2ns079.txt C4F0D8F6 rom/light_param/face_d2ns080.txt 74E55EE2 rom/light_param/face_d2ns081.txt 4954B23E rom/light_param/face_d2ns082.txt C4F0D8F6 rom/light_param/face_d2pv037s01.txt 4954B23E rom/light_param/face_d2pv038s01.txt 78B73586 rom/light_param/face_d2pv043s01.txt 4954B23E rom/light_param/face_d2pv044s01.txt 32376B86 rom/light_param/face_d2pv044s02.txt 4954B23E rom/light_param/face_d2pv046s03.txt 4954B23E rom/light_param/face_d2pv046s04.txt 4954B23E rom/light_param/face_d2pv046s05.txt F941342A rom/light_param/face_d2pv047s01.txt 4954B23E rom/light_param/face_d2pv047s02.txt 4954B23E rom/light_param/face_d2pv047s03.txt F941342A rom/light_param/face_d2pv047s04.txt F941342A rom/light_param/face_d2pv047s05.txt F941342A rom/light_param/face_d2pv051s01.txt 4954B23E rom/light_param/face_d2pv051s02.txt 4954B23E rom/light_param/face_d2pv051s03.txt 74E55EE2 rom/light_param/face_d2pv051s04.txt 4954B23E rom/light_param/face_d2pv051s05.txt 4954B23E rom/light_param/face_d2pv057s01.txt F7EF1A95 rom/light_param/face_d2pv060s01.txt F941342A rom/light_param/face_d2pv061s01.txt 74E55EE2 rom/light_param/face_d2pv061s02.txt 4954B23E rom/light_param/face_d2pv063s11.txt 8222ED92 rom/light_param/face_d2pv064s01.txt 32376B86 rom/light_param/face_d2pv065s01.txt C4F0D8F6 rom/light_param/face_d2pv065s02.txt 74E55EE2 rom/light_param/face_d2pv065s03.txt 74E55EE2 rom/light_param/face_d2pv065s04.txt 74E55EE2 rom/light_param/face_d2pv065s06.txt C4F0D8F6 rom/light_param/face_d2pv065s07.txt 74E55EE2 rom/light_param/face_d2pv066s01.txt 74E55EE2 rom/light_param/face_ns002.txt 4954B23E rom/light_param/face_ns003.txt 4954B23E rom/light_param/face_ns005.txt 4954B23E rom/light_param/face_ns013.txt 3126AB93 rom/light_param/face_d2ns053.txt F941342A rom/light_param/face_d2pv039s03.txt C4F0D8F6 rom/light_param/face_d2pv055s01.txt 74E55EE2 rom/light_param/face_ns014.txt 4954B23E rom/light_param/face_ns120.txt CB9DFC3A rom/light_param/face_pv024s03.txt 74E55EE2 rom/light_param/face_pv025s12.txt F41D92CE rom/light_param/face_pv083s05.txt 3978E7FB rom/light_param/face_pv092s09.txt 4954B23E rom/light_param/face_pv233s03.txt EC708E31 rom/light_param/fog_d2ns036.txt 9EFBCC96 rom/light_param/fog_d2ns058.txt E2C8A858 rom/light_param/fog_d2ns080.txt DA510E7C rom/light_param/fog_d2pv047s01.txt 7C6F3887 rom/light_param/fog_d2pv058s01.txt A2B2A6AE rom/light_param/face_ns020.txt 3F91CF1F rom/light_param/face_ns024.txt 6B3194F5 rom/light_param/face_ns030.txt 36648A46 rom/light_param/face_ns033.txt 4954B23E rom/light_param/face_ns084.txt 4954B23E rom/light_param/face_ns088.txt 4954B23E rom/light_param/face_ns098.txt F9F69735 rom/light_param/face_ns099.txt 3978E7FB rom/light_param/face_ns101.txt EC581E7A rom/light_param/face_ns103.txt BF93014E rom/light_param/face_ns104.txt EC581E7A rom/light_param/face_ns105.txt EC581E7A rom/light_param/face_ns111.txt F941342A rom/light_param/face_ns112.txt 74E55EE2 rom/light_param/face_ns115.txt 74E55EE2 rom/light_param/face_ns116.txt 4954B23E rom/light_param/face_ns117.txt 4954B23E rom/light_param/face_ns123.txt 4954B23E rom/light_param/face_ns124.txt 4954B23E rom/light_param/face_ns125.txt BF93014E rom/light_param/face_ns249.txt 4954B23E rom/light_param/face_ns272.txt 3F91CF1F rom/light_param/face_pv004s05.txt 7EA4FEFA rom/light_param/face_pv004s07.txt 339902FD rom/light_param/face_pv007s07.txt C4F0D8F6 rom/light_param/face_pv009s01.txt C4F0D8F6 rom/light_param/face_pv009s02.txt 32376B86 rom/light_param/face_pv009s04.txt 4954B23E rom/light_param/face_pv009s10.txt 32376B86 rom/light_param/face_pv015s01.txt 32376B86 rom/light_param/face_pv020s01.txt 32376B86 rom/light_param/face_pv020s02.txt 32376B86 rom/light_param/face_pv020s03.txt 32376B86 rom/light_param/face_pv024s07.txt 34A81DEE rom/light_param/face_pv024s08.txt 32376B86 rom/light_param/face_pv024s11.txt 74E55EE2 rom/light_param/face_pv024s12.txt BFB5DBCD rom/light_param/face_pv024s13.txt A10F6766 rom/light_param/face_pv024s14.txt 92AD589E rom/light_param/face_pv025s01.txt 85544DBB rom/light_param/face_pv025s02.txt AE7CADAE rom/light_param/face_pv025s03.txt 698796CD rom/light_param/face_pv025s04.txt 63D49220 rom/light_param/face_pv025s06.txt 32376B86 rom/light_param/face_pv025s07.txt 58278C60 rom/light_param/face_pv025s08.txt 32376B86 rom/light_param/face_pv025s09.txt B53BABD6 rom/light_param/face_pv025s10.txt 4954B23E rom/light_param/face_pv025s11.txt BFE71ABB rom/light_param/face_pv025s14.txt E404C764 rom/light_param/face_pv025s15.txt 32376B86 rom/light_param/face_pv025s20.txt 32376B86 rom/light_param/face_pv025s21.txt F41D92CE rom/light_param/face_pv025s22.txt 32376B86 rom/light_param/face_pv025s23.txt 28448309 rom/light_param/face_pv025s24.txt 74E55EE2 rom/light_param/face_pv028s01.txt 3126AB93 rom/light_param/face_pv081s02.txt 4954B23E rom/light_param/face_pv081s08.txt 4954B23E rom/light_param/face_pv082s61.txt 32376B86 rom/light_param/face_pv082s62.txt 32376B86 rom/light_param/face_pv082s63.txt 32376B86 rom/light_param/face_pv082s64.txt 32376B86 rom/light_param/face_pv082s65.txt 32376B86 rom/light_param/face_pv083s04.txt 3978E7FB rom/light_param/face_pv083s07.txt 3978E7FB rom/light_param/face_pv083s18.txt EC581E7A rom/light_param/face_pv083s26.txt 3978E7FB rom/light_param/face_pv083s27.txt 3978E7FB rom/light_param/face_pv083s28.txt 3978E7FB rom/light_param/face_pv085s01.txt EC581E7A rom/light_param/face_pv086s01.txt BF93014E rom/light_param/face_pv086s02.txt F941342A rom/light_param/face_pv087s01.txt EC581E7A rom/light_param/face_pv087s02.txt EC581E7A rom/light_param/face_pv087s16.txt EC581E7A rom/light_param/face_pv087s17.txt EC581E7A rom/light_param/face_pv090s01.txt F941342A rom/light_param/face_pv090s02.txt F941342A rom/light_param/face_pv092s01.txt C4F0D8F6 rom/light_param/face_pv092s02.txt F941342A rom/light_param/face_pv092s10.txt 4954B23E rom/light_param/face_pv092s11.txt 4954B23E rom/light_param/face_pv092s12.txt 74E55EE2 rom/light_param/face_pv096s01.txt 4954B23E rom/light_param/face_pv096s09.txt 4954B23E rom/light_param/face_PV097s01.txt BF93014E rom/light_param/face_pv104s02.txt 25FEE193 rom/light_param/face_pv218s03.txt 74E55EE2 rom/light_param/face_pv218s04.txt 74E55EE2 rom/light_param/face_pv220s01.txt C4F0D8F6 rom/light_param/face_pv220s02.txt C4F0D8F6 rom/light_param/face_pv232s01.txt 32376B86 rom/light_param/face_pv232s02.txt 74E55EE2 rom/light_param/face_pv232s03.txt 74E55EE2 rom/light_param/face_pv233s01.txt EC708E31 rom/light_param/face_pv233s02.txt 272C5D94 rom/light_param/face_pv233s06.txt EC708E31 rom/light_param/face_pv233s07.txt EC708E31 rom/light_param/face_pv233s08.txt 4954B23E rom/light_param/face_pv236s07.txt EC581E7A rom/light_param/face_pv432s01.txt F941342A rom/light_param/face_pv432s03.txt F941342A rom/light_param/face_pv616s01.txt 6AE4FC9F rom/light_param/face_pv616s02.txt 6AE4FC9F rom/light_param/face_pv616s03.txt 6AE4FC9F rom/light_param/face_pv618s06.txt B79857BF rom/light_param/face_pv621s01.txt 6AE4FC9F rom/light_param/face_pv638s01.txt 6AE4FC9F rom/light_param/face_pv638s02.txt 6AE4FC9F rom/light_param/face_selpvback.txt 32376B86 rom/light_param/face_stgns105.txt EC581E7A rom/light_param/face_tst.txt 32376B86 rom/light_param/fog_d2ns035.txt 80A2537A rom/light_param/fog_d2ns037.txt 0C76633D rom/light_param/fog_d2ns040.txt 7A29FDB0 rom/light_param/fog_d2ns041.txt F1FA5B55 rom/light_param/fog_d2ns042.txt CC012757 rom/light_param/fog_d2ns043.txt A02BEC50 rom/light_param/fog_d2ns044.txt EABEDCEF rom/light_param/fog_d2ns045.txt 260DA633 rom/light_param/fog_d2ns046.txt 4549FB71 rom/light_param/fog_d2ns047.txt 19448185 rom/light_param/fog_d2ns048.txt 64CDFB79 rom/light_param/fog_d2ns049.txt 62C3A8BE rom/light_param/fog_d2ns050.txt E7FC1F34 rom/light_param/fog_d2ns052.txt 2071B6A0 rom/light_param/fog_d2ns053.txt 2ED5D727 rom/light_param/fog_d2ns054.txt 7C6F3887 rom/light_param/fog_d2ns056.txt 1FE6777B rom/light_param/fog_d2ns057.txt E17A2DA9 rom/light_param/fog_d2ns059.txt 4341A309 rom/light_param/fog_d2ns060.txt AD4B9A71 rom/light_param/fog_d2ns062.txt BE510447 rom/light_param/fog_d2ns063.txt DCCE96C5 rom/light_param/fog_d2ns064.txt 06A421B5 rom/light_param/fog_d2ns065.txt A00236B4 rom/light_param/fog_d2ns066.txt F8F5BACB rom/light_param/fog_d2ns068.txt A2B2A6AE rom/light_param/fog_d2ns069.txt 48DA3FD6 rom/light_param/fog_d2ns070.txt 3E837AC2 rom/light_param/fog_d2ns071.txt 28622FE4 rom/light_param/fog_d2ns072.txt C6E766F2 rom/light_param/fog_d2ns073.txt 1FE8E4A4 rom/light_param/fog_d2ns074.txt 27E7EDFF rom/light_param/fog_d2ns075.txt 612D7159 rom/light_param/fog_d2ns076.txt 73515276 rom/light_param/fog_d2ns079.txt E6CBAD5C rom/light_param/fog_d2ns081.txt 738D121C rom/light_param/fog_d2ns082.txt 4C1E47E4 rom/light_param/fog_d2pv037s01.txt 7A29FDB0 rom/light_param/fog_d2pv038s01.txt F1FA5B55 rom/light_param/fog_d2pv039s01.txt CC012757 rom/light_param/fog_d2pv039s02.txt E23F92A0 rom/light_param/fog_d2pv039s03.txt A02BEC50 rom/light_param/fog_d2pv040s01.txt EABEDCEF rom/light_param/fog_d2pv041s01.txt 260DA633 rom/light_param/fog_d2pv042s01.txt 4549FB71 rom/light_param/fog_d2pv042s02.txt D3F82A85 rom/light_param/fog_d2pv042s06.txt 4549FB71 rom/light_param/fog_d2pv043s01.txt 19448185 rom/light_param/fog_d2pv044s02.txt 64CDFB79 rom/light_param/fog_d2pv044s03.txt 0B740D10 rom/light_param/fog_d2pv046s04.txt 425ABE5B rom/light_param/fog_d2pv047s02.txt 7C6F3887 rom/light_param/fog_d2pv047s03.txt 2ED5D727 rom/light_param/fog_d2pv047s04.txt 2ED5D727 rom/light_param/fog_d2pv048s01.txt 1FE6777B rom/light_param/fog_d2pv050s01.txt E2C8A858 rom/light_param/fog_d2pv051s01.txt D489F4DB rom/light_param/fog_d2pv051s02.txt 4341A309 rom/light_param/fog_d2pv051s03.txt C52CC600 rom/light_param/fog_d2pv051s04.txt AD4B9A71 rom/light_param/fog_d2pv051s05.txt B3093C5E rom/light_param/fog_d2pv053s01.txt 73515276 rom/light_param/fog_d2pv053s02.txt 73515276 rom/light_param/fog_d2pv053s03.txt 014665C2 rom/light_param/fog_d2pv053s15.txt 014665C2 rom/light_param/fog_d2pv055s01.txt A00236B4 rom/light_param/fog_d2pv055s02.txt 65B16338 rom/light_param/fog_d2pv058s02.txt A2B2A6AE rom/light_param/fog_d2pv060s01.txt 28622FE4 rom/light_param/fog_d2pv061s01.txt 66F67955 rom/light_param/fog_d2pv061s02.txt C6E766F2 rom/light_param/fog_d2pv062s01.txt EB4FF2B3 rom/light_param/fog_d2pv063s01.txt 27E7EDFF rom/light_param/fog_d2pv063s02.txt 612D7159 rom/light_param/fog_d2pv063s03.txt 73515276 rom/light_param/fog_d2pv063s04.txt B3093C5E rom/light_param/fog_d2pv063s09.txt 27E7EDFF rom/light_param/fog_d2pv063s10.txt 27E7EDFF rom/light_param/fog_d2pv063s13.txt 27E7EDFF rom/light_param/fog_d2pv065s01.txt E6CBAD5C rom/light_param/fog_d2pv065s02.txt DA510E7C rom/light_param/fog_d2pv065s03.txt DA510E7C rom/light_param/fog_d2pv065s04.txt DA510E7C rom/light_param/fog_d2pv065s05.txt 37068FD7 rom/light_param/fog_d2pv065s08.txt A1D73B6F rom/light_param/fog_d2pv066s01.txt 3E837AC2 rom/light_param/fog_d2pv212s01.txt 87F98902 rom/light_param/fog_d2pv213s01.txt 63FAFAC8 rom/light_param/fog_d2pv214s01.txt 354BFD9C rom/light_param/fog_ns001.txt A5D1FBDA rom/light_param/fog_ns002.txt 15C18287 rom/light_param/fog_ns003.txt 15C18287 rom/light_param/fog_ns004.txt 2A96FD67 rom/light_param/fog_ns005.txt 5A119437 rom/light_param/fog_ns006.txt E4BE9E07 rom/light_param/fog_ns007.txt BBC3794B rom/light_param/fog_ns009.txt F9920EB3 rom/light_param/fog_ns010.txt F51FCA83 rom/light_param/fog_ns011.txt 99375DD2 rom/light_param/fog_ns012.txt 188F3467 rom/light_param/fog_ns013.txt C9470B27 rom/light_param/fog_ns015.txt 0A46E88B rom/light_param/fog_ns016.txt 2F08837D rom/light_param/fog_ns017.txt C135364D rom/light_param/fog_ns018.txt D1A1477D rom/light_param/fog_ns019.txt 02214CC3 rom/light_param/fog_ns020.txt 7B658476 rom/light_param/fog_ns021.txt 971FCF53 rom/light_param/fog_ns022.txt 6AC99917 rom/light_param/fog_ns023.txt 05E579B8 rom/light_param/fog_ns025.txt A5D1FBDA rom/light_param/fog_ns029.txt 08D266CF rom/light_param/fog_ns030.txt B3093C5E rom/light_param/fog_ns031.txt 3BBCC150 rom/light_param/fog_ns032.txt F06B94CA rom/light_param/fog_ns033.txt 8376F15E rom/light_param/fog_ns034.txt 15C18287 rom/light_param/fog_ns083.txt 6DB0DB8D rom/light_param/fog_ns085.txt 354BFD9C rom/light_param/fog_ns086.txt 2A96FD67 rom/light_param/fog_ns087.txt B5BC07C9 rom/light_param/fog_ns088.txt 64CDFB79 rom/light_param/fog_ns089.txt 87F98902 rom/light_param/fog_ns090.txt 354BFD9C rom/light_param/fog_ns091.txt 63FAFAC8 rom/light_param/fog_ns092.txt CB74A9E7 rom/light_param/fog_ns093.txt D461D7B5 rom/light_param/fog_ns094.txt EC81406F rom/light_param/fog_ns095.txt B3093C5E rom/light_param/fog_ns096.txt B3093C5E rom/light_param/fog_ns097.txt 829A181E rom/light_param/fog_ns098.txt B23FF877 rom/light_param/fog_ns099.txt A72395BE rom/light_param/fog_ns100.txt 53B0793C rom/light_param/fog_ns101.txt AC22BFFB rom/light_param/fog_ns103.txt C198E9E7 rom/light_param/fog_ns104.txt 3E6D2E8B rom/light_param/fog_ns105.txt D22F40B8 rom/light_param/fog_ns106.txt E4AE8ADE rom/light_param/fog_ns107.txt F7EBA028 rom/light_param/fog_ns108.txt 0935CE57 rom/light_param/fog_ns109.txt 173CEF48 rom/light_param/fog_ns110.txt DE7CF592 rom/light_param/fog_ns111.txt 4EAEE1BD rom/light_param/fog_ns112.txt E12A3431 rom/light_param/fog_ns113.txt 1EEEF240 rom/light_param/fog_ns114.txt 11CFA4B4 rom/light_param/fog_ns115.txt 15FF3E6D rom/light_param/fog_ns116.txt 425ABE5B rom/light_param/fog_ns117.txt 97B7F186 rom/light_param/fog_ns120.txt DCC8D242 rom/light_param/fog_ns121.txt F79A63F3 rom/light_param/fog_ns123.txt 86D189B1 rom/light_param/fog_ns124.txt D9064072 rom/light_param/fog_ns126.txt 24D3EA8C rom/light_param/fog_ns221.txt 6539951B rom/light_param/fog_ns249.txt 2A96FD67 rom/light_param/fog_ns257.txt C165DD2A rom/light_param/fog_ns263.txt 88680782 rom/light_param/fog_ns272.txt 7B658476 rom/light_param/fog_ns292.txt AE462596 rom/light_param/fog_pv001s01.txt 971FCF53 rom/light_param/fog_pv001s02.txt 971FCF53 rom/light_param/fog_pv001s03.txt 6AC99917 rom/light_param/fog_pv001s04.txt 6AC99917 rom/light_param/fog_pv001s05.txt 05E579B8 rom/light_param/fog_pv001s06.txt 05E579B8 rom/light_param/fog_pv001s07.txt 05E579B8 rom/light_param/fog_pv003s01.txt C165DD2A rom/light_param/fog_pv003s03.txt 9EFBCC96 rom/light_param/fog_pv003s04.txt C165DD2A rom/light_param/fog_pv003s05.txt C165DD2A rom/light_param/fog_pv003s06.txt B6BE0720 rom/light_param/fog_pv003s07.txt C165DD2A rom/light_param/fog_pv003s08.txt C165DD2A rom/light_param/fog_pv003s09.txt C165DD2A rom/light_param/fog_pv004s01.txt 4940EAE6 rom/light_param/fog_pv004s02.txt 4940EAE6 rom/light_param/fog_pv004s05.txt B0D60A1C rom/light_param/fog_pv004s06.txt 4940EAE6 rom/light_param/fog_pv005s01.txt 08D266CF rom/light_param/fog_pv005s04.txt 08D266CF rom/light_param/fog_pv005s06.txt 08D266CF rom/light_param/fog_pv008s01.txt 775CB91E rom/light_param/fog_pv008s03.txt 781FA916 rom/light_param/fog_pv008s10.txt 68301A00 rom/light_param/fog_pv009s04.txt E73BBC5E rom/light_param/fog_pv011s01.txt 0C76633D rom/light_param/fog_pv011s02.txt A88EA466 rom/light_param/fog_pv011s06.txt B6D8CC85 rom/light_param/fog_pv013s02.txt E04CE66E rom/light_param/fog_pv013s03.txt E04CE66E rom/light_param/fog_pv013s04.txt E04CE66E rom/light_param/fog_pv015s01.txt B6924E93 rom/light_param/fog_pv015s02.txt F9920EB3 rom/light_param/fog_pv015s03.txt 4CE8B892 rom/light_param/fog_pv015s05.txt 9ED78525 rom/light_param/fog_pv020s01.txt 8376F15E rom/light_param/fog_pv020s02.txt 8376F15E rom/light_param/fog_pv020s03.txt 8376F15E rom/light_param/fog_pv024s03.txt B28AC568 rom/light_param/fog_pv024s11.txt 68BB3F95 rom/light_param/fog_pv024s13.txt 3ED8A2BE rom/light_param/fog_pv025s02.txt 76138CC3 rom/light_param/fog_pv025s03.txt 11DDFBE1 rom/light_param/fog_pv025s08.txt 629FC93F rom/light_param/fog_pv025s18.txt 47739975 rom/light_param/fog_pv028s01.txt C9470B27 rom/light_param/fog_pv079s01.txt 56C2A87C rom/light_param/fog_pv081s01.txt CB74A9E7 rom/light_param/fog_pv081s02.txt 1A19FB72 rom/light_param/fog_pv081s03.txt EC81406F rom/light_param/fog_pv081s06.txt E1142721 rom/light_param/fog_pv081s09.txt D461D7B5 rom/light_param/fog_pv082s61.txt 612D7159 rom/light_param/fog_pv082s62.txt 612D7159 rom/light_param/fog_pv082s63.txt 612D7159 rom/light_param/fog_pv082s65.txt 612D7159 rom/light_param/fog_pv083s01.txt 60D9EE70 rom/light_param/fog_pv083s02.txt F3016AFB rom/light_param/fog_pv083s03.txt ECDC8637 rom/light_param/fog_pv083s04.txt 65299130 rom/light_param/fog_pv083s05.txt 27B0B0F0 rom/light_param/fog_pv083s07.txt A72395BE rom/light_param/fog_pv083s08.txt 53B0793C rom/light_param/fog_pv083s14.txt ECDC8637 rom/light_param/fog_pv083s18.txt A47578C6 rom/light_param/fog_pv083s24.txt 53B0793C rom/light_param/fog_pv083s25.txt 53B0793C rom/light_param/fog_pv083s26.txt 829A181E rom/light_param/fog_pv083s27.txt 829A181E rom/light_param/fog_pv083s28.txt A72395BE rom/light_param/fog_pv084s01.txt BC1C8A10 rom/light_param/fog_pv086s01.txt C198E9E7 rom/light_param/fog_pv086s02.txt C198E9E7 rom/light_param/fog_pv087s01.txt 3E6D2E8B rom/light_param/fog_pv087s02.txt D22F40B8 rom/light_param/fog_pv087s16.txt A5F49AB2 rom/light_param/fog_pv087s17.txt A5F49AB2 rom/light_param/fog_pv088s01.txt E4AE8ADE rom/light_param/fog_pv088s02.txt 0935CE57 rom/light_param/fog_pv088s11.txt F7EBA028 rom/light_param/fog_pv088s12.txt F7EBA028 rom/light_param/fog_pv088s14.txt F7EBA028 rom/light_param/fog_pv089s01.txt FF1B31C5 rom/light_param/fog_pv089s02.txt 9790153B rom/light_param/fog_pv089s03.txt DE7CF592 rom/light_param/fog_pv089s05.txt 9790153B rom/light_param/fog_pv090s01.txt 4EAEE1BD rom/light_param/fog_pv091s04.txt 1EEEF240 rom/light_param/fog_pv091s09.txt 1EEEF240 rom/light_param/fog_pv091s10.txt 1EEEF240 rom/light_param/fog_pv091s13.txt 11CFA4B4 rom/light_param/fog_pv091s14.txt 123E7F47 rom/light_param/fog_pv091s15.txt 1EEEF240 rom/light_param/fog_pv092s09.txt FC31ABA7 rom/light_param/fog_pv092s10.txt D3410096 rom/light_param/fog_pv092s11.txt 517423C4 rom/light_param/fog_pv092s12.txt D34690AF rom/light_param/fog_pv094s01.txt 51ABB18D rom/light_param/fog_pv094s02.txt C832FC03 rom/light_param/fog_pv094s16.txt C832FC03 rom/light_param/fog_pv094s17.txt C832FC03 rom/light_param/fog_pv094s18.txt C832FC03 rom/light_param/fog_pv096s01.txt D9064072 rom/light_param/fog_pv103s01.txt 97B1B19C rom/light_param/fog_pv103s02.txt 3D1E04DF rom/light_param/fog_pv103s03.txt B2A80C02 rom/light_param/fog_pv104s01.txt 41A74B27 rom/light_param/fog_pv104s02.txt EA68E740 rom/light_param/fog_pv104s03.txt 41A74B27 rom/light_param/fog_pv104s04.txt 1A9F17C6 rom/light_param/fog_pv218s01.txt ECC874ED rom/light_param/fog_pv218s02.txt ECC874ED rom/light_param/fog_pv218s03.txt 906992A1 rom/light_param/fog_pv218s04.txt 906992A1 rom/light_param/fog_pv219s01.txt 4EA02874 rom/light_param/fog_pv219s02.txt 372E30DB rom/light_param/fog_pv219s03.txt 593A6A3D rom/light_param/fog_pv219s04.txt BE1919F5 rom/light_param/fog_pv219s05.txt 76C20DC1 rom/light_param/fog_pv219s08.txt 006E601F rom/light_param/fog_pv219s09.txt 5F8F6F1A rom/light_param/fog_pv219s10.txt 4EA02874 rom/light_param/fog_pv219s11.txt 1D687DAC rom/light_param/fog_pv219s12.txt 5F8F6F1A rom/light_param/fog_pv219s13.txt 006E601F rom/light_param/fog_pv219s14.txt 372E30DB rom/light_param/fog_pv220s01.txt B3093C5E rom/light_param/fog_pv220s03.txt 06A421B5 rom/light_param/fog_pv221s03.txt A25966AC rom/light_param/fog_pv221s04.txt A25966AC rom/light_param/fog_pv221s05.txt A25966AC rom/light_param/fog_pv221s06.txt A25966AC rom/light_param/fog_pv221s07.txt F626C42F rom/light_param/fog_pv221s08.txt F626C42F rom/light_param/fog_pv221s09.txt F626C42F rom/light_param/fog_pv221s11.txt F626C42F rom/light_param/fog_pv221s14.txt F626C42F rom/light_param/fog_pv222s01.txt 99549F51 rom/light_param/fog_pv222s02.txt 73D73DF5 rom/light_param/fog_pv223s01.txt 5262D86F rom/light_param/fog_pv223s02.txt 5DB91F48 rom/light_param/fog_pv223s03.txt 5DB91F48 rom/light_param/fog_pv223s04.txt 93B690C5 rom/light_param/fog_pv223s05.txt FF1B31C5 rom/light_param/fog_pv223s07.txt 3F1FC84D rom/light_param/fog_pv223s09.txt 3F1FC84D rom/light_param/fog_pv223s10.txt 3F1FC84D rom/light_param/fog_pv224s01.txt 3814C17B rom/light_param/fog_pv224s02.txt 7F6B2A67 rom/light_param/fog_pv224s03.txt 7F6B2A67 rom/light_param/fog_pv225s01.txt 664AE47D rom/light_param/fog_pv225s03.txt 083390AF rom/light_param/fog_pv226s01.txt 944C30C4 rom/light_param/fog_pv227s01.txt F3936806 rom/light_param/fog_pv228s02.txt 030631FB rom/light_param/fog_pv231s01.txt 04E4D532 rom/light_param/fog_pv231s02.txt FBA98B41 rom/light_param/fog_pv231s03.txt 3CCABE14 rom/light_param/fog_pv231s04.txt EA117190 rom/light_param/fog_pv231s05.txt 00DF806D rom/light_param/fog_pv231s06.txt 9D4088A3 rom/light_param/fog_pv231s07.txt 1FF9696B rom/light_param/fog_pv232s01.txt FA8934D3 rom/light_param/fog_pv232s02.txt A00236B4 rom/light_param/fog_pv232s03.txt 871F3662 rom/light_param/fog_pv233s01.txt 2B6FFF9A rom/light_param/fog_pv233s02.txt A16150B4 rom/light_param/fog_pv233s04.txt C135364D rom/light_param/fog_pv233s05.txt 0476F900 rom/light_param/fog_pv233s06.txt CFDE4BC6 rom/light_param/fog_pv233s07.txt 54C2A537 rom/light_param/fog_pv233s08.txt 69396342 rom/light_param/fog_pv234s01.txt E11141E0 rom/light_param/fog_pv234s02.txt E11141E0 rom/light_param/fog_pv236s01.txt 8A0FB847 rom/light_param/fog_pv236s02.txt D91456A1 rom/light_param/fog_pv236s03.txt A9E134E2 rom/light_param/fog_pv236s04.txt 5309DD68 rom/light_param/fog_pv236s05.txt 0935CE57 rom/light_param/fog_pv236s06.txt 0935CE57 rom/light_param/fog_pv236s07.txt D22F40B8 rom/light_param/fog_pv238s01.txt 574491DD rom/light_param/fog_pv239s01.txt 6850F898 rom/light_param/fog_pv240s03.txt 22841C7C rom/light_param/fog_pv241s01.txt B67C072F rom/light_param/fog_pv241s02.txt A1BF3CE0 rom/light_param/fog_pv243s01.txt 34293887 rom/light_param/fog_pv244s01.txt FDA02678 rom/light_param/fog_pv249s01.txt A9186801 rom/light_param/fog_pv253s01.txt E4DB0F82 rom/light_param/fog_pv253s02.txt 49748921 rom/light_param/fog_pv253s03.txt 49748921 rom/light_param/fog_pv253s04.txt 49748921 rom/light_param/fog_pv253s05.txt 49748921 rom/light_param/fog_pv253s06.txt 49748921 rom/light_param/fog_pv253s07.txt 49748921 rom/light_param/fog_pv253s08.txt 49748921 rom/light_param/fog_pv253s09.txt 49748921 rom/light_param/fog_pv257s01.txt BE727026 rom/light_param/fog_ns014.txt A29D604B rom/light_param/fog_ns084.txt AAED72CA rom/light_param/fog_ns102.txt BC1C8A10 rom/light_param/fog_ns122.txt C832FC03 rom/light_param/fog_pv003s02.txt 9EFBCC96 rom/light_param/fog_pv008s07.txt 775CB91E rom/light_param/fog_pv024s04.txt B59EDE97 rom/light_param/fog_pv082s64.txt 612D7159 rom/light_param/fog_pv085s01.txt 90B65C41 rom/light_param/fog_pv090s02.txt E12A3431 rom/light_param/fog_pv096s09.txt 7D06FBB1 rom/light_param/fog_pv219s07.txt 07EB6D14 rom/light_param/fog_pv221s10.txt F626C42F rom/light_param/fog_pv225s02.txt 32F7754D rom/light_param/fog_pv233s03.txt CFDE4BC6 rom/light_param/fog_pv260s01.txt 0EA1FC60 rom/light_param/fog_pv261s01.txt F4B56DAB rom/light_param/fog_pv261s02.txt 0BF1021A rom/light_param/fog_pv262s02.txt AF704C6C rom/light_param/fog_pv262s03.txt 4A5ACE3B rom/light_param/fog_pv262s04.txt 8DB48BFC rom/light_param/fog_pv262s05.txt 5C84512B rom/light_param/fog_pv262s08.txt 24FF8415 rom/light_param/fog_pv262s12.txt 8EAE3C46 rom/light_param/fog_pv432s01.txt 4EAEE1BD rom/light_param/fog_pv432s03.txt 4EAEE1BD rom/light_param/fog_pv433s02.txt 0103A3A2 rom/light_param/fog_pv433s03.txt DB3AF5F3 rom/light_param/fog_pv433s04.txt C7C90309 rom/light_param/fog_pv433s05.txt 3B1E6D55 rom/light_param/fog_pv434s01.txt 22908AB3 rom/light_param/fog_pv435s05.txt 70720CA4 rom/light_param/fog_pv435s08.txt 6B9063FE rom/light_param/fog_pv600s01.txt 05AAF8CC rom/light_param/fog_pv600s02.txt 9A7D8A11 rom/light_param/fog_pv600s03.txt 640EFFB8 rom/light_param/fog_pv600s04.txt E8C2724E rom/light_param/fog_pv601s01.txt CC2CF6F9 rom/light_param/fog_pv601s02.txt 52246462 rom/light_param/fog_pv601s03.txt FAAF0E16 rom/light_param/fog_pv601s04.txt D39D660B rom/light_param/fog_pv602s01.txt 6F296DCB rom/light_param/fog_pv602s03.txt 32D0BABC rom/light_param/fog_pv603s01.txt 31ADD70F rom/light_param/fog_pv604s02.txt 7DFE97BC rom/light_param/fog_pv605s01.txt 702E04AA rom/light_param/fog_pv607s01.txt 7C98D253 rom/light_param/fog_pv611s01.txt 83120E57 rom/light_param/fog_pv613s01.txt D3A587B2 rom/light_param/fog_pv613s02.txt 4495F58A rom/light_param/fog_pv613s03.txt 724F1AF1 rom/light_param/fog_pv614s05.txt 66026DE8 rom/light_param/fog_pv615s01.txt 4FC6E6C7 rom/light_param/fog_pv616s01.txt 7C98D253 rom/light_param/fog_pv616s02.txt 182FB826 rom/light_param/fog_pv617s02.txt 4BB836ED rom/light_param/fog_pv618s01.txt 478C77AC rom/light_param/fog_pv618s02.txt F0575D77 rom/light_param/fog_pv618s03.txt 478C77AC rom/light_param/fog_pv618s05.txt 478C77AC rom/light_param/fog_pv619s02.txt 9E3984BA rom/light_param/fog_pv619s03.txt 778C13F9 rom/light_param/fog_pv619s04.txt 756CE00B rom/light_param/fog_pv622s01.txt BC019593 rom/light_param/fog_pv623s02.txt 91538729 rom/light_param/fog_pv625s03.txt 7934889C rom/light_param/fog_pv628s01.txt 329306D1 rom/light_param/fog_pv637s01.txt 4AC3BFF3 rom/light_param/fog_pv637s02.txt 1DD2FAC2 rom/light_param/fog_pv638s01.txt 98519900 rom/light_param/fog_pv639s01.txt B50E5BAD rom/light_param/fog_pv639s02.txt 9737CB7D rom/light_param/fog_pv639s03.txt AB37945E rom/light_param/fog_pv639s06.txt CA69D151 rom/light_param/fog_pv727s01.txt 2CE64BF2 rom/light_param/fog_pv728s01.txt 77FDB9DF rom/light_param/fog_pv728s03.txt A9B3EBCE rom/light_param/fog_pv728s04.txt 2DE83A69 rom/light_param/fog_pv729s01.txt D2BBF8BD rom/light_param/fog_pv731s01.txt 4A1B364D rom/light_param/fog_pv732s01.txt 0252ABFC rom/light_param/fog_pv734s01.txt C40C199E rom/light_param/fog_pv734s02.txt F36A602A rom/light_param/fog_pv736s01.txt 6321C3A5 rom/light_param/fog_pv738s01.txt 03EBACDD rom/light_param/fog_pv738s02.txt AA8DC2B4 rom/light_param/fog_pv740s02.txt 3282C398 rom/light_param/fog_pv740s04.txt F5495D17 rom/light_param/fog_pv832s01.txt 88F3D327 rom/light_param/fog_selpvback.txt 806DDF0F rom/light_param/fog_stgns105.txt D22F40B8 rom/light_param/fog_tst.txt 806DDF0F rom/light_param/glow_aetback.txt 7CCACFA9 rom/light_param/glow_d2ns035.txt CF0852A3 rom/light_param/glow_d2ns036.txt 25473B51 rom/light_param/glow_d2ns039.txt 7AB9D5C0 rom/light_param/glow_d2ns040.txt B6602592 rom/light_param/glow_d2ns041.txt D77DE296 rom/light_param/glow_d2ns042.txt 979BE3B5 rom/light_param/glow_d2ns043.txt 293E05F0 rom/light_param/glow_d2ns044.txt 67397301 rom/light_param/glow_d2ns045.txt 9F97FA5A rom/light_param/glow_d2ns046.txt E6CB2ED6 rom/light_param/glow_d2ns047.txt 545A4A6A rom/light_param/glow_d2ns048.txt 21616BF5 rom/light_param/glow_d2ns049.txt 3D19AF29 rom/light_param/glow_d2ns051.txt 86EED18D rom/light_param/glow_d2ns052.txt 08B8C6F5 rom/light_param/glow_d2ns053.txt 545A4A6A rom/light_param/glow_d2ns054.txt 8F0E8604 rom/light_param/glow_d2ns055.txt 1472930B rom/light_param/glow_d2ns057.txt 65225E68 rom/light_param/glow_d2ns058.txt E0AFC7E9 rom/light_param/glow_d2ns059.txt 8096CEC5 rom/light_param/glow_d2ns060.txt 8096CEC5 rom/light_param/glow_d2ns062.txt 1C60BCCC rom/light_param/glow_d2ns063.txt 6E4F3D1B rom/light_param/glow_d2ns064.txt 26FF9072 rom/light_param/glow_d2ns065.txt 545A4A6A rom/light_param/glow_d2ns066.txt 81FEA04C rom/light_param/glow_d2ns067.txt 42ED6779 rom/light_param/glow_d2ns068.txt 40A6C646 rom/light_param/glow_d2ns069.txt 44ECB53C rom/light_param/glow_d2ns070.txt 1D146B29 rom/light_param/glow_d2ns071.txt D40BF8A8 rom/light_param/glow_d2ns072.txt 8FF86BAB rom/light_param/glow_d2ns073.txt 0B381F43 rom/light_param/glow_d2ns075.txt 49895D44 rom/light_param/glow_d2ns076.txt 3CF51348 rom/light_param/glow_d2ns077.txt 2D291DEE rom/light_param/glow_d2ns078.txt 4C4AB6D9 rom/light_param/glow_d2ns079.txt AB29E57B rom/light_param/glow_d2ns081.txt 860904C9 rom/light_param/glow_d2ns082.txt 5352CE55 rom/light_param/glow_d2pv037s01.txt B6602592 rom/light_param/glow_d2pv037s02.txt B6602592 rom/light_param/glow_d2pv037s03.txt B6602592 rom/light_param/glow_d2pv038s01.txt 3A26418E rom/light_param/glow_d2pv039s01.txt 979BE3B5 rom/light_param/glow_d2pv039s02.txt 979BE3B5 rom/light_param/glow_d2pv039s03.txt 293E05F0 rom/light_param/glow_d2pv040s01.txt 67397301 rom/light_param/glow_d2pv041s01.txt 9F97FA5A rom/light_param/glow_d2pv043s01.txt 545A4A6A rom/light_param/glow_d2pv044s01.txt 3D19AF29 rom/light_param/glow_d2pv044s02.txt 21616BF5 rom/light_param/glow_d2pv044s03.txt 669A9C14 rom/light_param/glow_d2pv046s04.txt 825ADB5C rom/light_param/glow_d2pv046s05.txt A7972052 rom/light_param/glow_d2pv047s01.txt 8F0E8604 rom/light_param/glow_d2pv047s02.txt 8F0E8604 rom/light_param/glow_d2pv047s03.txt 545A4A6A rom/light_param/glow_d2pv047s04.txt 545A4A6A rom/light_param/glow_d2pv047s05.txt 1472930B rom/light_param/glow_d2pv048s01.txt 20E4B960 rom/light_param/glow_d2pv050s01.txt E0AFC7E9 rom/light_param/glow_d2pv051s01.txt 8096CEC5 rom/light_param/glow_d2pv051s02.txt 8096CEC5 rom/light_param/glow_d2pv051s03.txt 8096CEC5 rom/light_param/glow_d2pv051s05.txt DD6D008A rom/light_param/glow_d2pv053s01.txt 2F70889E rom/light_param/glow_d2pv053s02.txt A97BBF76 rom/light_param/glow_d2pv053s03.txt 91DBE829 rom/light_param/glow_d2pv053s04.txt 91B4FEF5 rom/light_param/glow_d2pv053s05.txt 2CAAD88B rom/light_param/glow_d2pv053s07.txt E6CB2ED6 rom/light_param/glow_d2pv053s10.txt 67EE4BF1 rom/light_param/glow_d2pv053s15.txt 253B3229 rom/light_param/glow_d2pv055s01.txt 545A4A6A rom/light_param/glow_d2pv055s02.txt F41FEDD0 rom/light_param/glow_d2pv057s01.txt 42ED6779 rom/light_param/glow_d2pv058s01.txt 40A6C646 rom/light_param/glow_d2pv058s02.txt 40A6C646 rom/light_param/glow_d2pv060s01.txt D40BF8A8 rom/light_param/glow_d2pv061s01.txt 8096CEC5 rom/light_param/glow_d2pv062s01.txt 674DB376 rom/light_param/glow_d2pv063s01.txt 25681560 rom/light_param/glow_d2pv063s02.txt 49895D44 rom/light_param/glow_d2pv063s03.txt 3CF51348 rom/light_param/glow_d2pv063s04.txt 2D291DEE rom/light_param/glow_d2pv063s09.txt 25681560 rom/light_param/glow_d2pv063s10.txt B2844CB3 rom/light_param/glow_d2pv063s11.txt BACBF54A rom/light_param/glow_d2pv063s12.txt C20822AF rom/light_param/glow_d2pv063s13.txt B2844CB3 rom/light_param/glow_d2pv064s01.txt 4C4AB6D9 rom/light_param/glow_d2pv064s02.txt 4C4AB6D9 rom/light_param/glow_d2pv065s01.txt 623676FA rom/light_param/glow_d2pv065s02.txt 979BE3B5 rom/light_param/glow_d2pv065s03.txt 979BE3B5 rom/light_param/glow_d2pv065s04.txt 979BE3B5 rom/light_param/glow_d2pv065s05.txt 3B5AFB7B rom/light_param/glow_d2pv065s07.txt 979BE3B5 rom/light_param/glow_d2pv065s08.txt E5B54B0A rom/light_param/glow_d2pv066s01.txt 1D146B29 rom/light_param/glow_d2pv208s01.txt 858EC2E2 rom/light_param/glow_d2pv212s01.txt 8079BE46 rom/light_param/glow_d2pv213s01.txt 545A4A6A rom/light_param/glow_d2pv214s01.txt 1D146B29 rom/light_param/glow_ns001.txt 08CED474 rom/light_param/glow_ns002.txt 55EB05E6 rom/light_param/glow_ns003.txt 2AAD8867 rom/light_param/glow_ns004.txt 597036D3 rom/light_param/glow_ns005.txt 597036D3 rom/light_param/glow_ns006.txt 734E4F12 rom/light_param/glow_ns007.txt 56A87A5F rom/light_param/glow_ns008.txt E7FCAF81 rom/light_param/glow_ns009.txt D9756692 rom/light_param/glow_ns010.txt 71830BB9 rom/light_param/glow_ns012.txt 3D7F3565 rom/light_param/glow_ns013.txt DE721C8E rom/light_param/glow_ns014.txt 597036D3 rom/light_param/glow_ns015.txt 597036D3 rom/light_param/glow_ns016.txt F41FEDD0 rom/light_param/glow_ns017.txt 08CED474 rom/light_param/glow_ns018.txt 08CED474 rom/light_param/glow_ns019.txt 08CED474 rom/light_param/glow_ns020.txt 99095D70 rom/light_param/glow_ns021.txt 8AF0849B rom/light_param/glow_ns022.txt 8AF0849B rom/light_param/glow_ns023.txt 8AF0849B rom/light_param/glow_ns024.txt BADD2F3B rom/light_param/glow_ns025.txt 08CED474 rom/light_param/glow_ns026.txt 517E8F25 rom/light_param/glow_ns029.txt 5608DFEE rom/light_param/glow_ns030.txt D3FFBE4F rom/light_param/glow_ns032.txt 597036D3 rom/light_param/glow_ns033.txt 103E1790 rom/light_param/glow_ns034.txt 659AF753 rom/light_param/glow_ns083.txt 3D7F3565 rom/light_param/glow_ns084.txt 597036D3 rom/light_param/glow_ns085.txt 1D146B29 rom/light_param/glow_ns086.txt 597036D3 rom/light_param/glow_ns087.txt 6986E4D5 rom/light_param/glow_ns088.txt 21616BF5 rom/light_param/glow_ns089.txt 164442FA rom/light_param/glow_ns090.txt 1D146B29 rom/light_param/glow_ns091.txt 545A4A6A rom/light_param/glow_ns093.txt 66ED59AC rom/light_param/glow_ns095.txt 2CBBC66E rom/light_param/glow_ns096.txt 2CBBC66E rom/light_param/glow_ns097.txt 07C2D937 rom/light_param/glow_ns098.txt 80039D79 rom/light_param/glow_ns101.txt CF265F65 rom/light_param/glow_ns102.txt CF265F65 rom/light_param/glow_ns103.txt 2FF9022E rom/light_param/glow_ns104.txt 85721F88 rom/light_param/glow_ns105.txt 85721F88 rom/light_param/glow_ns106.txt 10CB908D rom/light_param/glow_ns107.txt 6DB029CC rom/light_param/glow_ns108.txt 7A175D31 rom/light_param/glow_ns109.txt 4F77EDA7 rom/light_param/glow_ns111.txt 72F84BE8 rom/light_param/glow_ns112.txt E6CB2ED6 rom/light_param/glow_ns113.txt 6F8F98EF rom/light_param/glow_ns114.txt 26A7871E rom/light_param/glow_ns115.txt 08B8C6F5 rom/light_param/glow_ns116.txt 825ADB5C rom/light_param/glow_ns117.txt 825ADB5C rom/light_param/glow_ns118.txt 1472930B rom/light_param/glow_ns121.txt 979BE3B5 rom/light_param/glow_ns122.txt 9557F62C rom/light_param/glow_ns123.txt 72BD3EBF rom/light_param/glow_ns124.txt EED4F5CE rom/light_param/glow_ns125.txt FFA13A7E rom/light_param/glow_ns126.txt 2B61A28E rom/light_param/glow_ns221.txt FBDAE8B1 rom/light_param/glow_ns223.txt 2C0BEC0A rom/light_param/glow_ns249.txt 597036D3 rom/light_param/glow_ns257.txt 81DF38D0 rom/light_param/glow_ns263.txt 110A48E9 rom/light_param/glow_ns266.txt 0816B1A1 rom/light_param/glow_ns272.txt 99095D70 rom/light_param/glow_ns292.txt 8ACC8318 rom/light_param/glow_pv001s01.txt 8AF0849B rom/light_param/glow_pv001s02.txt 8AF0849B rom/light_param/glow_pv001s03.txt 8AF0849B rom/light_param/fog_pv259s01.txt 283ABA83 rom/light_param/fog_pv435s01.txt BDA6F228 rom/light_param/fog_pv608s01.txt E0AAC3B0 rom/light_param/fog_pv621s01.txt 4F1B2AA4 rom/light_param/fog_pv729s03.txt BD431557 rom/light_param/glow_d2ns037.txt 40EFA566 rom/light_param/glow_d2ns056.txt 20E4B960 rom/light_param/glow_d2ns074.txt 25681560 rom/light_param/glow_d2pv042s02.txt 5352CE55 rom/light_param/glow_d2pv051s04.txt 8096CEC5 rom/light_param/glow_d2pv061s02.txt 8FF86BAB rom/light_param/glow_d2pv065s06.txt 8041F635 rom/light_param/glow_ns011.txt 919DFF88 rom/light_param/glow_ns031.txt 5653C79A rom/light_param/glow_ns099.txt F33C6D0B rom/light_param/glow_pv001s05.txt 8AF0849B rom/light_param/glow_pv001s06.txt 8AF0849B rom/light_param/glow_pv001s07.txt 8AF0849B rom/light_param/glow_pv003s01.txt 81DF38D0 rom/light_param/glow_pv003s02.txt 81DF38D0 rom/light_param/glow_pv003s03.txt 81DF38D0 rom/light_param/glow_pv003s04.txt 81DF38D0 rom/light_param/glow_pv003s05.txt 81DF38D0 rom/light_param/glow_pv003s06.txt 81DF38D0 rom/light_param/glow_pv003s07.txt 81DF38D0 rom/light_param/glow_pv003s08.txt 81DF38D0 rom/light_param/glow_pv003s09.txt 81DF38D0 rom/light_param/glow_pv004s01.txt D40BF8A8 rom/light_param/glow_pv004s02.txt D40BF8A8 rom/light_param/glow_pv004s03.txt 26B24575 rom/light_param/glow_pv004s04.txt 26B24575 rom/light_param/glow_pv004s06.txt 7B2D0B41 rom/light_param/glow_pv004s07.txt 7B2D0B41 rom/light_param/glow_pv005s01.txt 5608DFEE rom/light_param/glow_pv005s04.txt 5608DFEE rom/light_param/glow_pv005s06.txt 4EBB437D rom/light_param/glow_pv007s01.txt F95E2B8D rom/light_param/glow_pv007s03.txt F95E2B8D rom/light_param/glow_pv007s05.txt 734423F8 rom/light_param/glow_pv007s06.txt F95E2B8D rom/light_param/glow_pv007s08.txt F95E2B8D rom/light_param/glow_pv007s09.txt F95E2B8D rom/light_param/glow_pv007s11.txt 07AF6690 rom/light_param/glow_pv007s12.txt 3107C13E rom/light_param/glow_pv008s01.txt CF145265 rom/light_param/glow_pv008s03.txt FD7C833B rom/light_param/glow_pv008s07.txt CF145265 rom/light_param/glow_pv008s10.txt 7F589994 rom/light_param/glow_pv009s01.txt E6CB2ED6 rom/light_param/glow_pv009s02.txt 58081E93 rom/light_param/glow_pv009s03.txt 67EE4BF1 rom/light_param/glow_pv009s04.txt 67EE4BF1 rom/light_param/glow_pv009s05.txt C8DB3B76 rom/light_param/glow_pv009s06.txt 67EE4BF1 rom/light_param/glow_pv009s08.txt 67EE4BF1 rom/light_param/glow_pv009s09.txt 67EE4BF1 rom/light_param/glow_pv009s10.txt FDEFAA8E rom/light_param/glow_pv011s01.txt 40EFA566 rom/light_param/glow_pv011s02.txt 204CF596 rom/light_param/glow_pv011s03.txt A97BBF76 rom/light_param/glow_pv011s04.txt A97BBF76 rom/light_param/glow_pv011s06.txt 46B5204C rom/light_param/glow_pv013s01.txt AF850F95 rom/light_param/glow_pv013s03.txt 2FD4BD57 rom/light_param/glow_pv013s04.txt A6E3F7B7 rom/light_param/glow_pv015s01.txt 4023CE41 rom/light_param/glow_pv015s05.txt 4023CE41 rom/light_param/glow_pv019s01.txt 8599CB3E rom/light_param/glow_pv019s02.txt C8DB3B76 rom/light_param/glow_pv019s03.txt D0EF6DF8 rom/light_param/glow_pv019s04.txt 58081E93 rom/light_param/glow_pv019s07.txt 67EE4BF1 rom/light_param/glow_pv019s08.txt 58081E93 rom/light_param/glow_pv019s11.txt 58081E93 rom/light_param/glow_pv019s13.txt 67EE4BF1 rom/light_param/glow_pv019s14.txt EAD10591 rom/light_param/glow_pv020s01.txt 103E1790 rom/light_param/glow_pv020s02.txt 103E1790 rom/light_param/glow_pv020s03.txt 103E1790 rom/light_param/glow_pv024s02.txt B05658DA rom/light_param/glow_pv024s03.txt CEAE9F27 rom/light_param/glow_pv024s04.txt 22F8BBD8 rom/light_param/glow_pv024s05.txt FA335059 rom/light_param/glow_pv024s06.txt ACEB6FE3 rom/light_param/glow_pv024s07.txt 85BD1D48 rom/light_param/glow_pv024s08.txt 0B6098EB rom/light_param/glow_pv024s09.txt 8F6F660A rom/light_param/glow_pv024s10.txt B711781D rom/light_param/glow_pv024s11.txt 04C5ED9B rom/light_param/glow_pv024s12.txt 9862727E rom/light_param/glow_pv024s13.txt BC4B98C5 rom/light_param/glow_pv024s14.txt D660EB52 rom/light_param/glow_pv025s01.txt 278F3095 rom/light_param/glow_pv025s02.txt C22204A5 rom/light_param/glow_pv025s03.txt F75909C7 rom/light_param/glow_pv025s05.txt F19D8903 rom/light_param/glow_pv025s06.txt ACFB6A49 rom/light_param/glow_pv025s07.txt 497BB868 rom/light_param/glow_pv025s08.txt 6FD640B4 rom/light_param/glow_pv025s09.txt 6F7AE641 rom/light_param/glow_pv025s10.txt 29ADC5F1 rom/light_param/glow_pv025s11.txt 4E14359F rom/light_param/glow_pv025s12.txt 2306B450 rom/light_param/glow_pv025s13.txt AB280D90 rom/light_param/glow_pv025s14.txt EF60CB91 rom/light_param/glow_pv025s15.txt EF517B32 rom/light_param/glow_pv025s16.txt 484A6F74 rom/light_param/glow_pv025s17.txt 6EA745F3 rom/light_param/glow_pv025s18.txt C5F0FDA8 rom/light_param/glow_pv025s19.txt 265B2258 rom/light_param/glow_pv025s20.txt BE11D086 rom/light_param/glow_pv025s22.txt FED42CFC rom/light_param/glow_pv025s23.txt 94511B3F rom/light_param/glow_pv025s24.txt CD1C4254 rom/light_param/glow_pv025s27.txt 359B5D7E rom/light_param/glow_pv028s01.txt DE721C8E rom/light_param/glow_pv079s01.txt C62AB0AE rom/light_param/glow_pv081s01.txt 407751A0 rom/light_param/glow_pv081s02.txt 76EF128F rom/light_param/glow_pv081s05.txt 46111585 rom/light_param/glow_pv081s06.txt 1378C705 rom/light_param/glow_pv081s07.txt 9C43A332 rom/light_param/glow_pv081s09.txt 1378C705 rom/light_param/glow_pv081s10.txt 1378C705 rom/light_param/glow_pv081s11.txt E6CB2ED6 rom/light_param/glow_pv082s61.txt 03F0EBC6 rom/light_param/glow_pv082s62.txt 03F0EBC6 rom/light_param/glow_pv082s64.txt 03F0EBC6 rom/light_param/glow_pv082s65.txt 03F0EBC6 rom/light_param/glow_pv083s01.txt 32C243A5 rom/light_param/glow_pv083s02.txt 39DED465 rom/light_param/glow_pv083s03.txt 468916EF rom/light_param/glow_pv083s04.txt 07C2D937 rom/light_param/glow_pv083s05.txt 942321C9 rom/light_param/glow_pv083s07.txt 919FFBB6 rom/light_param/glow_pv083s14.txt 4FC34D4F rom/light_param/glow_pv083s15.txt 4B5D22E4 rom/light_param/glow_pv083s18.txt 7FF06EE6 rom/light_param/glow_pv083s26.txt 40BCDB0C rom/light_param/glow_pv083s27.txt 07C2D937 rom/light_param/glow_pv083s28.txt F33C6D0B rom/light_param/glow_pv084s01.txt CF265F65 rom/light_param/glow_pv085s01.txt CF265F65 rom/light_param/glow_pv086s02.txt 2FF9022E rom/light_param/glow_pv087s01.txt 85721F88 rom/light_param/glow_pv087s02.txt 85721F88 rom/light_param/glow_pv087s16.txt 85721F88 rom/light_param/glow_pv087s17.txt 85721F88 rom/light_param/glow_pv088s01.txt 10CB908D rom/light_param/glow_pv088s02.txt 7A175D31 rom/light_param/glow_pv088s11.txt DB803A43 rom/light_param/glow_pv088s12.txt 6DB029CC rom/light_param/glow_pv088s14.txt 6DB029CC rom/light_param/glow_pv089s01.txt 4F77EDA7 rom/light_param/glow_pv089s03.txt 292A0DB4 rom/light_param/glow_pv090s01.txt 72F84BE8 rom/light_param/glow_pv090s02.txt E6CB2ED6 rom/light_param/glow_pv091s01.txt 590D0BF6 rom/light_param/glow_pv091s02.txt 67EE4BF1 rom/light_param/glow_pv091s04.txt 6F8F98EF rom/light_param/glow_pv091s09.txt 6F8F98EF rom/light_param/glow_pv091s10.txt 6F8F98EF rom/light_param/glow_pv091s13.txt 26A7871E rom/light_param/glow_pv091s14.txt 26A7871E rom/light_param/glow_pv091s15.txt 6F8F98EF rom/light_param/glow_pv092s01.txt 86EED18D rom/light_param/glow_pv092s02.txt 552E9D8F rom/light_param/glow_pv092s03.txt 979BE3B5 rom/light_param/glow_pv092s05.txt 979BE3B5 rom/light_param/glow_pv092s07.txt B9F69914 rom/light_param/glow_pv092s08.txt 8664BC84 rom/light_param/glow_pv092s09.txt 825ADB5C rom/light_param/glow_pv092s10.txt 48FD8AA1 rom/light_param/glow_pv092s11.txt 825ADB5C rom/light_param/glow_pv092s12.txt 08B8C6F5 rom/light_param/glow_pv094s02.txt 9557F62C rom/light_param/glow_pv094s16.txt 9557F62C rom/light_param/glow_pv094s17.txt 9557F62C rom/light_param/glow_pv094s18.txt 9557F62C rom/light_param/glow_pv096s01.txt EED4F5CE rom/light_param/glow_pv096s09.txt 83BE2E15 rom/light_param/glow_PV097s01.txt FFA13A7E rom/light_param/glow_pv103s01.txt 797F0584 rom/light_param/glow_pv103s02.txt B0EA8DD1 rom/light_param/glow_pv103s03.txt 35F93D1C rom/light_param/glow_pv104s01.txt C243B71D rom/light_param/glow_pv104s02.txt 634370B3 rom/light_param/glow_pv104s03.txt CAD0EB9B rom/light_param/glow_pv104s04.txt 35FDDB5F rom/light_param/glow_pv218s01.txt CCF1867A rom/light_param/glow_pv218s02.txt CCF1867A rom/light_param/glow_pv218s04.txt 1D146B29 rom/light_param/glow_pv219s01.txt 8096CEC5 rom/light_param/glow_pv219s02.txt 01B3ABE2 rom/light_param/glow_pv219s04.txt E6CB2ED6 rom/light_param/glow_pv219s05.txt 0E2BE323 rom/light_param/glow_pv219s07.txt E6CB2ED6 rom/light_param/glow_pv219s08.txt E6CB2ED6 rom/light_param/glow_pv219s09.txt 68760330 rom/light_param/glow_pv219s10.txt 8096CEC5 rom/light_param/glow_pv219s11.txt 68760330 rom/light_param/glow_pv219s12.txt 26F2FE9F rom/light_param/glow_pv219s13.txt E6CB2ED6 rom/light_param/glow_pv219s14.txt 01B3ABE2 rom/light_param/glow_pv220s01.txt 67EE4BF1 rom/light_param/glow_pv220s02.txt 67EE4BF1 rom/light_param/glow_pv220s03.txt 26FF9072 rom/light_param/glow_pv221s04.txt 08550B1E rom/light_param/glow_pv221s05.txt 08550B1E rom/light_param/glow_pv221s06.txt 08550B1E rom/light_param/glow_pv221s07.txt 08550B1E rom/light_param/glow_pv221s08.txt 08550B1E rom/light_param/glow_pv221s09.txt 08550B1E rom/light_param/glow_pv221s10.txt 08550B1E rom/light_param/glow_pv221s11.txt 08550B1E rom/light_param/glow_pv221s14.txt 08550B1E rom/light_param/glow_pv222s01.txt 0ADFE1F9 rom/light_param/glow_pv222s02.txt FAB5F6E6 rom/light_param/glow_pv223s01.txt 545A4A6A rom/light_param/glow_pv223s02.txt 3428E7A7 rom/light_param/glow_pv223s03.txt 1BCC87B4 rom/light_param/glow_pv223s04.txt C1A0EAEE rom/light_param/glow_pv223s05.txt C1A0EAEE rom/light_param/glow_pv223s08.txt 2CBBC66E rom/light_param/glow_pv223s09.txt 1472930B rom/light_param/glow_pv223s10.txt A511AD88 rom/light_param/glow_pv224s01.txt E6CB2ED6 rom/light_param/glow_pv224s02.txt 120A8C43 rom/light_param/glow_pv224s03.txt 120A8C43 rom/light_param/glow_pv225s01.txt 0CD6439A rom/light_param/glow_pv225s02.txt 802711F8 rom/light_param/glow_pv225s03.txt 1C9D8B48 rom/light_param/glow_pv226s01.txt 164442FA rom/light_param/glow_pv227s01.txt DD6D008A rom/light_param/glow_pv228s01.txt 0DF220B2 rom/light_param/glow_pv228s02.txt 51FBFE43 rom/light_param/glow_pv228s03.txt 6FFC6436 rom/light_param/glow_pv228s04.txt F5623766 rom/light_param/glow_pv231s01.txt 6E831D89 rom/light_param/glow_pv231s03.txt 6E831D89 rom/light_param/glow_pv231s04.txt 6E831D89 rom/light_param/glow_pv231s05.txt 6E831D89 rom/light_param/glow_pv231s06.txt 6E831D89 rom/light_param/glow_pv231s07.txt 6E831D89 rom/light_param/glow_pv232s01.txt EED90111 rom/light_param/glow_pv232s02.txt 4C4AB6D9 rom/light_param/glow_pv232s03.txt 7D994E36 rom/light_param/glow_pv233s01.txt 1E6A0EF5 rom/light_param/glow_pv233s03.txt 1E6A0EF5 rom/light_param/glow_pv233s04.txt B6B79BAE rom/light_param/glow_pv233s06.txt 1E6A0EF5 rom/light_param/glow_pv233s07.txt 1E6A0EF5 rom/light_param/glow_pv233s08.txt 3F9C4613 rom/light_param/glow_pv234s01.txt 67EE4BF1 rom/light_param/glow_pv234s02.txt 67EE4BF1 rom/light_param/glow_pv235s02.txt E9935327 rom/light_param/glow_pv235s03.txt FA2D2013 rom/light_param/glow_pv235s04.txt DD6D008A rom/light_param/glow_pv235s05.txt 1472930B rom/light_param/glow_pv235s06.txt 275B83ED rom/light_param/glow_pv235s07.txt 60A419C7 rom/light_param/glow_pv235s09.txt D40BF8A8 rom/light_param/glow_pv236s01.txt 86E7BC10 rom/light_param/glow_pv236s02.txt DB6937E3 rom/light_param/glow_pv236s03.txt 979BE3B5 rom/light_param/glow_pv236s04.txt 10CB908D rom/light_param/glow_pv236s05.txt 5DA8D52F rom/light_param/glow_pv236s06.txt 7A175D31 rom/light_param/glow_pv236s07.txt 85721F88 rom/light_param/glow_pv238s01.txt 8B44AF92 rom/light_param/glow_pv239s01.txt 86E5F7AE rom/light_param/glow_pv001s04.txt 8AF0849B rom/light_param/glow_pv004s05.txt 7B2D0B41 rom/light_param/glow_pv008s08.txt 4CD87617 rom/light_param/glow_pv013s02.txt 2FD4BD57 rom/light_param/glow_pv024s01.txt 3F22136F rom/light_param/glow_pv025s04.txt BEAC9A3F rom/light_param/glow_pv025s21.txt 71D76220 rom/light_param/glow_pv082s63.txt 03F0EBC6 rom/light_param/glow_pv086s01.txt 2FF9022E rom/light_param/glow_pv091s03.txt 67EE4BF1 rom/light_param/glow_pv094s01.txt 979BE3B5 rom/light_param/glow_pv218s03.txt 1D146B29 rom/light_param/glow_pv221s03.txt 08550B1E rom/light_param/glow_pv223s07.txt 1472930B rom/light_param/glow_pv231s02.txt 6E831D89 rom/light_param/fog_d2pv065s07.txt DA510E7C rom/light_param/fog_pv240s01.txt 22841C7C rom/light_param/glow_ns120.txt 2361B703 rom/light_param/glow_pv235s01.txt 60A419C7 rom/light_param/light_ns017.txt 759AEFA3 rom/light_param/glow_pv240s02.txt E71487C1 rom/light_param/glow_pv240s03.txt E71487C1 rom/light_param/glow_pv241s01.txt A1E1A178 rom/light_param/glow_pv241s02.txt 9FAF0F62 rom/light_param/glow_pv242s01.txt D44796F2 rom/light_param/glow_pv243s01.txt 03F0EBC6 rom/light_param/glow_pv247s01.txt A51F63DF rom/light_param/glow_pv247s02.txt 01BD98B0 rom/light_param/glow_pv249s01.txt E522F8B7 rom/light_param/glow_pv250s01.txt 83F91C5E rom/light_param/glow_pv253s01.txt 97F7B348 rom/light_param/glow_pv253s02.txt 97F7B348 rom/light_param/glow_pv253s03.txt 97F7B348 rom/light_param/glow_pv253s04.txt 97F7B348 rom/light_param/glow_pv253s05.txt FA2FB791 rom/light_param/glow_pv253s06.txt 97F7B348 rom/light_param/glow_pv253s08.txt 97F7B348 rom/light_param/glow_pv253s09.txt 97F7B348 rom/light_param/glow_pv257s01.txt B50A0188 rom/light_param/glow_pv259s01.txt F298EADA rom/light_param/glow_pv260s01.txt 28C38FB4 rom/light_param/glow_pv261s01.txt 8A6B0737 rom/light_param/glow_pv261s02.txt 8CC2FE94 rom/light_param/glow_pv262s01.txt DB8EF195 rom/light_param/glow_pv262s02.txt BBC5EA9F rom/light_param/glow_pv262s03.txt 55EA1341 rom/light_param/glow_pv262s04.txt 858E13DD rom/light_param/glow_pv262s05.txt 1097E035 rom/light_param/glow_pv262s06.txt E1171481 rom/light_param/glow_pv262s07.txt A2A8E8F5 rom/light_param/glow_pv262s08.txt FB01B27D rom/light_param/glow_pv262s11.txt E547FBE5 rom/light_param/glow_pv432s01.txt 1472930B rom/light_param/glow_pv432s03.txt 1472930B rom/light_param/glow_pv433s01.txt FE6C7300 rom/light_param/glow_pv433s02.txt CC39A5A1 rom/light_param/glow_pv433s03.txt A1E1A178 rom/light_param/glow_pv433s04.txt CC39A5A1 rom/light_param/glow_pv433s05.txt CC39A5A1 rom/light_param/glow_pv433s06.txt 185058D6 rom/light_param/glow_pv434s01.txt 03F0EBC6 rom/light_param/glow_pv435s01.txt 7E18FC67 rom/light_param/glow_pv435s02.txt 4667AA29 rom/light_param/glow_pv435s03.txt C555EB70 rom/light_param/glow_pv435s04.txt F6B78B72 rom/light_param/glow_pv435s05.txt 0E4A80BB rom/light_param/glow_pv435s06.txt 2C0BEC0A rom/light_param/glow_pv435s07.txt 86E5F7AE rom/light_param/glow_pv600s01.txt C7EB8415 rom/light_param/glow_pv600s02.txt 979BE3B5 rom/light_param/glow_pv600s03.txt 081847C7 rom/light_param/glow_pv600s04.txt 96DBAB51 rom/light_param/glow_pv601s01.txt 9E096F91 rom/light_param/glow_pv601s02.txt 039877B0 rom/light_param/glow_pv601s03.txt 3A664673 rom/light_param/glow_pv601s04.txt A1B96D3F rom/light_param/glow_pv602s01.txt F6B78B72 rom/light_param/glow_pv602s02.txt 67EE4BF1 rom/light_param/glow_pv602s03.txt 67EE4BF1 rom/light_param/glow_pv602s04.txt 4859BF68 rom/light_param/glow_pv603s01.txt B79BCCD8 rom/light_param/glow_pv604s01.txt F0EBBA68 rom/light_param/glow_pv604s02.txt FBC2899B rom/light_param/glow_pv604s06.txt 5DE5A485 rom/light_param/glow_pv605s01.txt D918A090 rom/light_param/glow_pv605s02.txt 50AE9055 rom/light_param/glow_pv605s03.txt DD9AA912 rom/light_param/glow_pv605s05.txt 50AE9055 rom/light_param/glow_pv607s01.txt 0F643210 rom/light_param/glow_pv608s01.txt A3160D36 rom/light_param/glow_pv610s01.txt CBFC29DF rom/light_param/glow_pv611s01.txt D55DEAEF rom/light_param/glow_pv613s01.txt 780EC51B rom/light_param/glow_pv613s02.txt B9EC3E48 rom/light_param/glow_pv614s01.txt E71487C1 rom/light_param/glow_pv615s01.txt A7D0592C rom/light_param/glow_pv616s01.txt 68A23778 rom/light_param/glow_pv616s02.txt DD9AA912 rom/light_param/glow_pv616s03.txt 4EE4A666 rom/light_param/glow_pv617s01.txt 432F066A rom/light_param/glow_pv618s01.txt 2E714436 rom/light_param/glow_pv618s02.txt 2C0BEC0A rom/light_param/glow_pv618s03.txt 2E714436 rom/light_param/glow_pv618s04.txt 2C0BEC0A rom/light_param/glow_pv618s05.txt 2C0BEC0A rom/light_param/glow_pv618s06.txt 2C0BEC0A rom/light_param/glow_pv619s01.txt 82FF44C8 rom/light_param/glow_pv619s03.txt A7303B3C rom/light_param/glow_pv619s04.txt E9C16772 rom/light_param/glow_pv620s01.txt 77CA361B rom/light_param/glow_pv621s01.txt 75885C0F rom/light_param/glow_pv622s01.txt 7CE412DE rom/light_param/glow_pv623s01.txt 8D43EF04 rom/light_param/glow_pv623s02.txt 24B94FEE rom/light_param/glow_pv623s03.txt DFFE4054 rom/light_param/glow_pv624s01.txt 29ACF2AB rom/light_param/glow_pv625s03.txt 705B294D rom/light_param/glow_pv625s04.txt 943DFBC9 rom/light_param/glow_pv625s05.txt F3C53FD1 rom/light_param/glow_pv626s01.txt 1D18F495 rom/light_param/glow_pv627s01.txt FE7DF610 rom/light_param/glow_pv627s02.txt E71487C1 rom/light_param/glow_pv627s03.txt 14ABBEB5 rom/light_param/glow_pv628s01.txt 41D18B6B rom/light_param/glow_pv629s01.txt 9746FB1D rom/light_param/glow_pv631s01.txt FAEF3140 rom/light_param/glow_pv637s01.txt 97F7B348 rom/light_param/glow_pv637s02.txt B8ECD4AF rom/light_param/glow_pv638s01.txt 5D53B186 rom/light_param/glow_pv638s02.txt 927F99DA rom/light_param/glow_pv639s03.txt 029FBAF5 rom/light_param/glow_pv639s04.txt E71487C1 rom/light_param/glow_pv641s01.txt E3FC7C0D rom/light_param/glow_pv642s01.txt 078FDB03 rom/light_param/glow_pv710s04.txt 387D60D5 rom/light_param/glow_pv723s01.txt 12C0D7A0 rom/light_param/glow_pv723s02.txt 4187AF60 rom/light_param/glow_pv726s01.txt 0CBBF826 rom/light_param/glow_pv727s01.txt 9E932657 rom/light_param/glow_pv727s02.txt AE1D51CD rom/light_param/glow_pv727s03.txt 6CECBBFA rom/light_param/glow_pv728s01.txt 47F1AFC2 rom/light_param/glow_pv728s03.txt 7761369D rom/light_param/glow_pv728s04.txt 417B361D rom/light_param/glow_pv729s01.txt FCCF02C8 rom/light_param/glow_pv729s03.txt FFC53534 rom/light_param/glow_pv730s01.txt 38B40B49 rom/light_param/glow_pv730s02.txt D937E095 rom/light_param/glow_pv731s02.txt A848ED95 rom/light_param/glow_pv732s01.txt 55384823 rom/light_param/glow_pv734s01.txt 743F0902 rom/light_param/glow_pv734s02.txt 795C79A0 rom/light_param/glow_pv734s04.txt E9ED0219 rom/light_param/glow_pv734s05.txt 869B474C rom/light_param/glow_pv736s01.txt D937E095 rom/light_param/glow_pv736s02.txt 3485647C rom/light_param/glow_pv738s01.txt 060652BC rom/light_param/glow_pv739s01.txt 34DEA988 rom/light_param/glow_pv740s01.txt 5504C316 rom/light_param/glow_pv740s02.txt BDCF8F8F rom/light_param/glow_pv740s03.txt 6D471E6D rom/light_param/glow_pv740s04.txt C1C63142 rom/light_param/glow_pv740s05.txt F99DF359 rom/light_param/glow_pv832s01.txt 3A224A54 rom/light_param/glow_stgns105.txt 85721F88 rom/light_param/glow_tst.txt D5BAB724 rom/light_param/glow_tst002.txt AE1D51CD rom/light_param/light_aetback.txt D97122DE rom/light_param/light_d2ns035.txt 15B85F7E rom/light_param/light_d2ns036.txt E5533ACC rom/light_param/light_d2ns037.txt 730BE619 rom/light_param/light_d2ns039.txt BA75FC0E rom/light_param/light_d2ns040.txt F35B2854 rom/light_param/light_d2ns042.txt FC0FBA5B rom/light_param/light_d2ns043.txt CF4C1A69 rom/light_param/light_d2ns044.txt 2178507C rom/light_param/light_d2ns045.txt 9B18A3B4 rom/light_param/light_d2ns046.txt DC3FECBD rom/light_param/light_d2ns047.txt 2B944338 rom/light_param/light_d2ns048.txt B82B9494 rom/light_param/light_d2ns053.txt 91ABC262 rom/light_param/light_d2ns054.txt E8FD0400 rom/light_param/light_d2ns055.txt 50049067 rom/light_param/light_d2ns056.txt 8EC82D64 rom/light_param/light_d2ns057.txt 82CB5F06 rom/light_param/light_d2ns058.txt C3040909 rom/light_param/light_d2ns059.txt C958DF67 rom/light_param/light_d2ns060.txt 1E9A56F6 rom/light_param/light_d2ns062.txt BF639F57 rom/light_param/light_d2ns063.txt 1D77619F rom/light_param/light_d2ns066.txt 3587A2A3 rom/light_param/light_d2ns067.txt A889EACD rom/light_param/light_d2ns068.txt 3CA35B4D rom/light_param/light_d2ns069.txt 7960ABC0 rom/light_param/light_d2ns071.txt 81B0EBC2 rom/light_param/light_d2ns073.txt 945C2DD8 rom/light_param/light_d2ns075.txt 89DCDB77 rom/light_param/light_d2ns076.txt F366B8A5 rom/light_param/light_d2ns077.txt 81735BD0 rom/light_param/light_d2ns078.txt DF4F8186 rom/light_param/light_d2ns079.txt 55CF6927 rom/light_param/light_d2ns081.txt 68150916 rom/light_param/light_d2ns082.txt E8D47EB8 rom/light_param/light_d2pv037s01.txt F35B2854 rom/light_param/light_d2pv039s01.txt FC0FBA5B rom/light_param/light_d2pv039s02.txt FC0FBA5B rom/light_param/light_d2pv039s03.txt CF4C1A69 rom/light_param/light_d2pv040s01.txt 2178507C rom/light_param/light_d2pv041s01.txt 9B18A3B4 rom/light_param/light_d2pv042s01.txt A6D5D469 rom/light_param/light_d2pv042s02.txt 650B6AE4 rom/light_param/light_d2pv043s01.txt FBE181A4 rom/light_param/light_d2pv044s01.txt 31301976 rom/light_param/light_d2pv044s02.txt B82B9494 rom/light_param/light_d2pv044s03.txt CF8978E8 rom/light_param/light_d2pv047s01.txt E8FD0400 rom/light_param/light_d2pv047s02.txt E8FD0400 rom/light_param/light_d2pv047s03.txt 91ABC262 rom/light_param/light_d2pv047s04.txt 7B75067D rom/light_param/light_d2pv047s05.txt 50049067 rom/light_param/light_d2pv048s01.txt 8EC82D64 rom/light_param/light_d2pv050s01.txt E60DD448 rom/light_param/light_d2pv051s01.txt 20A16AC3 rom/light_param/light_d2pv051s02.txt 767D5F55 rom/light_param/light_d2pv051s03.txt 0922A41B rom/light_param/light_d2pv051s04.txt 25F3653C rom/light_param/light_d2pv053s01.txt 85E85D27 rom/light_param/light_d2pv053s02.txt 92EADA40 rom/light_param/light_d2pv053s03.txt 160A35ED rom/light_param/light_d2pv053s04.txt 455C5059 rom/light_param/light_d2pv053s05.txt D645D2EE rom/light_param/light_d2pv053s06.txt 3A0387EA rom/light_param/light_d2pv053s10.txt 8561FDE7 rom/light_param/light_d2pv058s01.txt 3CA35B4D rom/light_param/light_d2pv058s02.txt 3CA35B4D rom/light_param/light_d2pv060s01.txt 81B0EBC2 rom/light_param/light_d2pv061s01.txt 5D050DC3 rom/light_param/light_d2pv062s01.txt DA516867 rom/light_param/light_d2pv063s01.txt FC05F792 rom/light_param/light_d2pv063s09.txt 15A8ADC7 rom/light_param/light_d2pv063s11.txt B07A8D82 rom/light_param/light_d2pv063s12.txt 36B9253C rom/light_param/light_d2pv064s02.txt 1FD957D4 rom/light_param/light_d2pv065s01.txt 55CF6927 rom/light_param/light_d2pv065s05.txt 45651D59 rom/light_param/light_d2pv065s06.txt A4D693DC rom/light_param/light_d2pv208s01.txt 5E2D09A0 rom/light_param/light_d2pv212s01.txt D5083538 rom/light_param/light_ns001.txt B882FA66 rom/light_param/light_ns002.txt 29F9B7BF rom/light_param/light_ns005.txt E12C833E rom/light_param/light_ns006.txt AB5FC82C rom/light_param/light_ns007.txt E32CD56E rom/light_param/light_ns008.txt DA988B86 rom/light_param/light_ns009.txt 13254912 rom/light_param/light_ns010.txt 3F195457 rom/light_param/light_ns011.txt 1BCEDFD7 rom/light_param/light_ns012.txt A5FDE2D8 rom/light_param/light_ns013.txt F581714A rom/light_param/light_ns024.txt 98A60494 rom/light_param/light_ns025.txt 8DFEE399 rom/light_param/light_ns031.txt CE79592A rom/light_param/light_ns032.txt D3E8B59B rom/light_param/light_ns083.txt A5FDE2D8 rom/light_param/light_ns084.txt 268E9C5D rom/light_param/light_ns087.txt 60B8DC34 rom/light_param/light_ns088.txt B82B9494 rom/light_param/light_ns089.txt D5083538 rom/light_param/light_ns090.txt 7C009BA2 rom/light_param/light_ns093.txt DBD3EDFB rom/light_param/light_ns095.txt 7272CE34 rom/light_param/light_ns096.txt 7272CE34 rom/light_param/light_ns097.txt 2BB51610 rom/light_param/light_ns098.txt DE64B7B1 rom/light_param/light_ns099.txt 1DCF624F rom/light_param/light_ns100.txt 022FB194 rom/light_param/glow_pv240s01.txt E71487C1 rom/light_param/glow_pv253s07.txt 97F7B348 rom/light_param/glow_pv262s12.txt 83F9C109 rom/light_param/glow_pv435s08.txt F6B78B72 rom/light_param/glow_pv604s07.txt ADEDC7C8 rom/light_param/glow_pv617s02.txt B6C224AE rom/light_param/glow_pv625s01.txt 9432392E rom/light_param/glow_pv639s06.txt E71487C1 rom/light_param/glow_pv731s01.txt C6C2617A rom/light_param/glow_selpvback.txt D5BAB724 rom/light_param/light_d2ns049.txt 31301976 rom/light_param/light_d2ns074.txt 89DCDB77 rom/light_param/light_d2pv042s06.txt A6D5D469 rom/light_param/light_d2pv051s05.txt E684B97F rom/light_param/light_d2pv064s01.txt DF4F8186 rom/light_param/light_ns102.txt B7EF611A rom/light_param/light_ns103.txt 832E76E4 rom/light_param/light_ns104.txt BBDF831E rom/light_param/light_ns105.txt 2BA42F73 rom/light_param/light_ns106.txt 6ABE9DEA rom/light_param/light_ns107.txt A856DFEE rom/light_param/light_ns108.txt 14C0BACD rom/light_param/light_ns109.txt FE8C1B98 rom/light_param/light_ns110.txt CD4B668D rom/light_param/light_ns111.txt E3CF0A5C rom/light_param/light_ns112.txt 82336249 rom/light_param/light_ns114.txt DE36F6CC rom/light_param/light_ns116.txt A58D8657 rom/light_param/light_ns117.txt 2A9F127A rom/light_param/light_ns118.txt 41FC8227 rom/light_param/light_ns119.txt CB753736 rom/light_param/light_ns120.txt 48CDCDA1 rom/light_param/light_ns122.txt A4604AC7 rom/light_param/light_ns123.txt B0E5FB31 rom/light_param/light_ns124.txt CF1F7B8D rom/light_param/light_ns125.txt 2F7F44F8 rom/light_param/light_ns126.txt 5BDF1B2B rom/light_param/light_ns221.txt F270AF4D rom/light_param/light_ns223.txt 0C84BE75 rom/light_param/light_ns249.txt E12C833E rom/light_param/light_ns257.txt 00FA0BCE rom/light_param/light_ns263.txt 590DE343 rom/light_param/light_ns266.txt 3BD3AE83 rom/light_param/light_ns292.txt 4F92F5DB rom/light_param/light_pv003s01.txt 00FA0BCE rom/light_param/light_pv003s02.txt 00FA0BCE rom/light_param/light_pv003s03.txt 00FA0BCE rom/light_param/light_pv003s04.txt 00FA0BCE rom/light_param/light_pv003s05.txt 00FA0BCE rom/light_param/light_pv003s07.txt 00FA0BCE rom/light_param/light_pv003s08.txt 00FA0BCE rom/light_param/light_pv003s09.txt 7A25FDBC rom/light_param/light_pv004s05.txt B455CA9B rom/light_param/light_pv004s07.txt 8A7ED6B6 rom/light_param/light_pv007s07.txt 8A01E8A3 rom/light_param/light_pv007s10.txt C044E882 rom/light_param/light_pv007s11.txt 5A55E8E9 rom/light_param/light_pv007s12.txt 95686F11 rom/light_param/light_pv008s01.txt 7F8CF682 rom/light_param/light_pv008s03.txt DE2BA916 rom/light_param/light_pv008s07.txt 218FF576 rom/light_param/light_pv008s08.txt 4C26E89F rom/light_param/light_pv008s09.txt F76CE7F4 rom/light_param/light_pv008s10.txt CAC4CF4A rom/light_param/light_pv009s01.txt D973098D rom/light_param/light_pv009s03.txt C9E73C21 rom/light_param/light_pv009s04.txt 4DDDBE28 rom/light_param/light_pv009s05.txt DC3C6EFD rom/light_param/light_pv009s06.txt E8DFFBBC rom/light_param/light_pv009s08.txt B2035A71 rom/light_param/light_pv009s10.txt 5624B9CC rom/light_param/light_pv011s01.txt 37ECE940 rom/light_param/light_pv011s02.txt 37ECE940 rom/light_param/light_pv011s06.txt 37ECE940 rom/light_param/light_pv013s01.txt E5998FAF rom/light_param/light_pv013s02.txt E5998FAF rom/light_param/light_pv013s03.txt E5998FAF rom/light_param/light_pv013s04.txt E5998FAF rom/light_param/light_pv015s01.txt 86609832 rom/light_param/light_pv015s02.txt 1AFA8812 rom/light_param/light_pv015s03.txt 33544282 rom/light_param/light_pv018s01.txt EA9F5D64 rom/light_param/light_pv018s02.txt 8135D09D rom/light_param/light_pv018s03.txt EA9F5D64 rom/light_param/light_pv018s04.txt E2A1ECBA rom/light_param/light_pv018s05.txt 73F4BF1E rom/light_param/light_pv018s06.txt BDFBB843 rom/light_param/light_pv018s07.txt 11FD9E8F rom/light_param/light_pv018s08.txt AFFFB14D rom/light_param/light_pv018s09.txt DB0F4203 rom/light_param/light_pv019s01.txt F6456C50 rom/light_param/light_pv019s04.txt E5D10A9C rom/light_param/light_pv019s07.txt C3F52114 rom/light_param/light_pv019s08.txt B13E2EC7 rom/light_param/light_pv019s13.txt C1E616F5 rom/light_param/light_pv024s01.txt 8E7618E4 rom/light_param/light_pv024s02.txt CBB24DAC rom/light_param/light_pv024s04.txt 9B04755D rom/light_param/light_pv024s05.txt C6992EAB rom/light_param/light_pv024s06.txt E29DC9DA rom/light_param/light_pv024s07.txt 6B755E1A rom/light_param/light_pv024s08.txt F9B11E15 rom/light_param/light_pv024s09.txt EAB231C1 rom/light_param/light_pv024s10.txt 1D25BF5D rom/light_param/light_pv024s11.txt DE140F7A rom/light_param/light_pv024s12.txt 6D5A3A1C rom/light_param/light_pv024s13.txt BE99CD56 rom/light_param/light_pv024s14.txt 6FE11862 rom/light_param/light_pv025s01.txt 32E08368 rom/light_param/light_pv025s02.txt EF8F5F4E rom/light_param/light_pv025s03.txt C65FD26C rom/light_param/light_pv025s04.txt 0F13AA21 rom/light_param/light_pv025s05.txt 6F57DC4D rom/light_param/light_pv025s07.txt AB99703E rom/light_param/light_pv025s08.txt E0185D2C rom/light_param/light_pv025s09.txt AA385D38 rom/light_param/light_pv025s10.txt DA61C28D rom/light_param/light_pv025s11.txt 2743BBDF rom/light_param/light_pv025s12.txt 696CCF0D rom/light_param/light_pv025s13.txt 9D31602B rom/light_param/light_pv025s14.txt D143B41C rom/light_param/light_pv025s15.txt 9D31602B rom/light_param/light_pv025s16.txt 3784C6F1 rom/light_param/light_pv025s17.txt 9D31602B rom/light_param/light_pv025s18.txt 58F408EB rom/light_param/light_pv025s19.txt B36DE240 rom/light_param/light_pv025s20.txt BAC30BF2 rom/light_param/light_pv025s21.txt BBBEA4EC rom/light_param/light_pv025s22.txt D7DF8FD5 rom/light_param/light_pv025s24.txt FF211B02 rom/light_param/light_pv025s27.txt 5130F163 rom/light_param/light_pv028s01.txt F581714A rom/light_param/light_pv079s01.txt 844B3FE4 rom/light_param/light_pv081s01.txt 995EF7C9 rom/light_param/light_pv081s06.txt 57C46D9A rom/light_param/light_pv081s09.txt D003D5DB rom/light_param/light_pv081s10.txt 0C455742 rom/light_param/light_pv081s11.txt F4E5CC92 rom/light_param/light_pv081s12.txt E7BB3C37 rom/light_param/light_pv082s61.txt A50DC64B rom/light_param/light_pv082s62.txt A50DC64B rom/light_param/light_pv082s63.txt A50DC64B rom/light_param/light_pv082s64.txt A50DC64B rom/light_param/light_pv082s65.txt A50DC64B rom/light_param/light_pv083s01.txt C43523CE rom/light_param/light_pv083s03.txt 6C69D429 rom/light_param/light_pv083s04.txt 29F07390 rom/light_param/light_pv083s05.txt B205AEA2 rom/light_param/light_pv083s07.txt 2E0F14D6 rom/light_param/light_pv083s08.txt 7B8E8CA1 rom/light_param/light_pv083s14.txt E70C7166 rom/light_param/light_pv083s15.txt 29016A21 rom/light_param/light_pv083s18.txt 655C68E2 rom/light_param/light_pv083s24.txt 7B8E8CA1 rom/light_param/light_pv083s25.txt 7B8E8CA1 rom/light_param/light_pv083s26.txt B79778B3 rom/light_param/light_pv083s27.txt 863B3F35 rom/light_param/light_pv083s28.txt 70E1A38F rom/light_param/light_pv084s01.txt B7EF611A rom/light_param/light_pv085s01.txt 1B283412 rom/light_param/light_pv086s01.txt 832E76E4 rom/light_param/light_pv087s01.txt BBDF831E rom/light_param/light_pv087s02.txt 2BA42F73 rom/light_param/light_pv087s16.txt BBDF831E rom/light_param/light_pv087s17.txt 2BA42F73 rom/light_param/light_pv088s01.txt 6ABE9DEA rom/light_param/light_pv088s02.txt 1E445F38 rom/light_param/light_pv088s11.txt B6DC1A4D rom/light_param/light_pv088s12.txt A856DFEE rom/light_param/light_pv088s14.txt 339B4533 rom/light_param/light_pv089s01.txt FE8C1B98 rom/light_param/light_pv089s02.txt 3B740327 rom/light_param/light_pv089s03.txt CD4B668D rom/light_param/light_pv089s05.txt 3B740327 rom/light_param/light_pv090s01.txt E3CF0A5C rom/light_param/light_pv090s02.txt 82336249 rom/light_param/light_pv091s01.txt C7B68F67 rom/light_param/light_pv091s14.txt DE36F6CC rom/light_param/light_pv092s01.txt 467042BF rom/light_param/light_pv092s02.txt F16CA678 rom/light_param/light_pv092s03.txt A1546980 rom/light_param/light_pv092s05.txt 033F2E99 rom/light_param/light_pv092s07.txt AD4D840F rom/light_param/light_pv092s09.txt 79F1E92F rom/light_param/light_pv092s10.txt 7549ADFA rom/light_param/light_pv092s11.txt 4BEC4C91 rom/light_param/light_pv092s12.txt 9FED3EAF rom/light_param/light_pv094s01.txt CF4DFE30 rom/light_param/light_pv094s02.txt A4604AC7 rom/light_param/light_pv094s16.txt A4604AC7 rom/light_param/light_pv094s17.txt A4604AC7 rom/light_param/light_pv094s18.txt A4604AC7 rom/light_param/light_pv096s01.txt CF1F7B8D rom/light_param/light_PV097s01.txt 2F7F44F8 rom/light_param/light_pv103s01.txt 2738F7E3 rom/light_param/light_pv103s02.txt DD898352 rom/light_param/light_pv103s03.txt 2177D2BA rom/light_param/light_pv104s01.txt EA5AA209 rom/light_param/light_pv104s02.txt B769A68C rom/light_param/light_pv104s04.txt CD130211 rom/light_param/light_pv218s01.txt 996BEC4C rom/light_param/light_pv218s02.txt 996BEC4C rom/light_param/light_pv218s04.txt 894A863C rom/light_param/light_pv219s01.txt 38084ED0 rom/light_param/light_pv219s02.txt 1F3BFC4E rom/light_param/light_pv219s04.txt 3FBDECF4 rom/light_param/light_pv219s05.txt D83FC140 rom/light_param/light_pv219s07.txt DCEAF0AF rom/light_param/light_pv219s08.txt DCEAF0AF rom/light_param/light_pv219s10.txt 08ACC8CC rom/light_param/light_pv219s11.txt 2509EE5E rom/light_param/light_pv219s12.txt E805FEA1 rom/light_param/light_pv219s13.txt 2D36E5F0 rom/light_param/light_pv219s14.txt BD0F9D9F rom/light_param/light_pv220s01.txt 52A76A97 rom/light_param/light_pv220s02.txt 52A76A97 rom/light_param/light_pv221s03.txt D824021E rom/light_param/light_pv221s04.txt D824021E rom/light_param/light_pv221s05.txt D824021E rom/light_param/light_pv221s06.txt D824021E rom/light_param/light_pv221s07.txt 4D839A59 rom/light_param/light_pv221s08.txt 4D839A59 rom/light_param/light_pv221s09.txt 8B55D7ED rom/light_param/light_pv221s10.txt A3265127 rom/light_param/light_pv221s11.txt 4D839A59 rom/light_param/light_pv222s01.txt D3AF9162 rom/light_param/light_pv222s02.txt 41214A0C rom/light_param/light_pv223s01.txt CA790620 rom/light_param/light_pv223s02.txt 15C2F85E rom/light_param/light_pv223s03.txt F9614B16 rom/light_param/light_pv223s04.txt 4D9E18A3 rom/light_param/light_pv223s05.txt 9BDCA7BF rom/light_param/light_pv223s07.txt 0E777AD4 rom/light_param/light_pv223s09.txt AC68E0E0 rom/light_param/light_pv223s10.txt 1AFE0B87 rom/light_param/light_pv224s01.txt A3C17A35 rom/light_param/light_pv224s02.txt 5687FC42 rom/light_param/light_pv224s03.txt 960C16A8 rom/light_param/light_pv225.farc 15D3132C rom/light_param/light_pv225s01.txt 90374CB2 rom/light_param/light_pv225s02.txt 30157C6D rom/light_param/light_pv226s01.txt A6C6CD41 rom/light_param/light_pv227s01.txt 0A082C30 rom/light_param/light_pv228s01.txt E523E843 rom/light_param/light_pv228s02.txt E523E843 rom/light_param/light_pv228s04.txt E523E843 rom/light_param/light_pv231s01.txt 819537FD rom/light_param/light_pv231s02.txt 23A2EA6F rom/light_param/light_pv231s03.txt 23A2EA6F rom/light_param/light_pv231s04.txt 23A2EA6F rom/light_param/light_pv231s05.txt 23A2EA6F rom/light_param/light_pv231s06.txt 819537FD rom/light_param/light_pv231s07.txt 23A2EA6F rom/light_param/light_pv232s01.txt EC1870C8 rom/light_param/light_pv232s02.txt DF4F8186 rom/light_param/light_pv232s03.txt E04FBC2D rom/light_param/light_pv233s01.txt 883A49C8 rom/light_param/light_pv233s03.txt 5CAC524E rom/light_param/light_pv233s04.txt 7CE6E436 rom/light_param/light_pv233s05.txt CBB40603 rom/light_param/light_pv233s06.txt 10A6F79B rom/light_param/light_pv233s07.txt 5CAC524E rom/light_param/light_pv233s08.txt 45DCA5F1 rom/light_param/light_pv235s01.txt B2353204 rom/light_param/light_pv235s02.txt 5C984FD2 rom/light_param/light_pv235s03.txt AA481C42 rom/light_param/light_pv235s04.txt AB34247D rom/light_param/light_pv235s06.txt C02D9C0F rom/light_param/light_pv235s07.txt B2353204 rom/light_param/light_pv235s10.txt B2353204 rom/light_param/light_pv236s01.txt BA701E38 rom/light_param/light_pv236s02.txt 2DE38E1C rom/light_param/light_pv236s04.txt 6ABE9DEA rom/light_param/light_ns101.txt 1B283412 rom/light_param/light_ns121.txt CF4DFE30 rom/light_param/light_pv003s06.txt 00FA0BCE rom/light_param/light_pv009s02.txt 8E4F4A74 rom/light_param/light_pv015s05.txt 86609832 rom/light_param/light_pv024s03.txt 9AAFEACA rom/light_param/light_pv025s06.txt B782F419 rom/light_param/light_pv025s23.txt 38AE5DCC rom/light_param/light_pv083s02.txt 061173F4 rom/light_param/light_pv086s02.txt 832E76E4 rom/light_param/light_pv091s13.txt DE36F6CC rom/light_param/light_pv096s09.txt C3282E5A rom/light_param/light_pv219s09.txt 2509EE5E rom/light_param/light_pv221s14.txt 4D839A59 rom/light_param/light_pv225s03.txt 5219FC5A rom/light_param/light_pv233s02.txt A1636426 rom/light_param/light_pv236s05.txt 3D596F5A rom/light_param/light_pv249.farc 6DAEB58A rom/light_param/light_pv259.farc 3A0466BA rom/light_param/light_pv432s01.txt 3EF815BE rom/light_param/light_pv601s03.txt 814A74CD rom/light_param/light_pv611s01.txt B39F8479 rom/light_param/light_pv619s01.txt 5DDD7C4F rom/light_param/light_pv629s01.txt 45BCB1F2 rom/light_param/light_pv710s04.txt 1CB1AA16 rom/light_param/light_pv728s04.txt 564609F2 rom/light_param/light_pv736s01.txt 45ED2C45 rom/light_param/light_tst.txt A50DC64B rom/light_param/wind_pv009s04.txt C7E97D72 rom/light_param/light_pv236s06.txt 14C0BACD rom/light_param/light_pv236s07.txt 2BA42F73 rom/light_param/light_pv238s01.txt 2D086F7A rom/light_param/light_pv240s01.txt 653C612E rom/light_param/light_pv240s02.txt 653C612E rom/light_param/light_pv240s03.txt 58AF187D rom/light_param/light_pv241s01.txt AA0BDFE5 rom/light_param/light_pv241s02.txt 6D5A0067 rom/light_param/light_pv242s01.txt 9CEA6FF5 rom/light_param/light_pv243.farc BD13A837 rom/light_param/light_pv243s01.txt 9277A430 rom/light_param/light_pv246s01.txt 5B279C36 rom/light_param/light_pv247.farc 68CBE534 rom/light_param/light_pv247s01.txt A2E203D2 rom/light_param/light_pv247s02.txt 21A5D525 rom/light_param/light_pv248.farc 18CC44CB rom/light_param/light_pv249s01.txt 0B0BA5A1 rom/light_param/light_pv250s01.txt 20F91E06 rom/light_param/light_pv251.farc 53E38825 rom/light_param/light_pv253.farc B3C16557 rom/light_param/light_pv253s01.txt 95672BA7 rom/light_param/light_pv253s02.txt 5A43DB7D rom/light_param/light_pv253s03.txt DBDE2999 rom/light_param/light_pv253s04.txt EC1643C3 rom/light_param/light_pv253s05.txt 59BCCB42 rom/light_param/light_pv253s06.txt CA675D56 rom/light_param/light_pv253s07.txt 11DA51D0 rom/light_param/light_pv253s08.txt 47365807 rom/light_param/light_pv253s09.txt 3099E0D9 rom/light_param/light_pv255.farc 2A59C9DF rom/light_param/light_pv257.farc 23B8B584 rom/light_param/light_pv257s01.txt ECFD410D rom/light_param/light_pv259s01.txt B9E335E0 rom/light_param/light_pv259_old.farc 6016B443 rom/light_param/light_pv260.farc D9FC2AFC rom/light_param/light_pv260s01.txt C3077983 rom/light_param/light_pv261.farc 613D2A53 rom/light_param/light_pv261s01.txt 0834B0FD rom/light_param/light_pv261s02.txt FE86DDB0 rom/light_param/light_pv262.farc DDC5E607 rom/light_param/light_pv262s01.txt D5CF6B79 rom/light_param/light_pv262s02.txt AF2B3B66 rom/light_param/light_pv262s03.txt 12871789 rom/light_param/light_pv262s04.txt C878429C rom/light_param/light_pv262s05.txt 2AEB9A10 rom/light_param/light_pv262s08.txt 1EFC5C6B rom/light_param/light_pv262s11.txt CE359570 rom/light_param/light_pv262s12.txt 9D8CFCFD rom/light_param/light_pv432s03.txt 3EF815BE rom/light_param/light_pv433s01.txt 5B2C4813 rom/light_param/light_pv433s02.txt CF7FD54B rom/light_param/light_pv433s03.txt 2E1F8DD6 rom/light_param/light_pv433s04.txt 249F1201 rom/light_param/light_pv433s05.txt 8CE9F45C rom/light_param/light_pv433s06.txt 25E19761 rom/light_param/light_pv434s01.txt 73D287D1 rom/light_param/light_pv435s08.txt E4D9BF15 rom/light_param/light_pv441s01.txt AC8A96CA rom/light_param/light_pv600s01.txt C9829F87 rom/light_param/light_pv600s02.txt A69D16A7 rom/light_param/light_pv600s03.txt 78253547 rom/light_param/light_pv600s04.txt 2996BDE1 rom/light_param/light_pv601s01.txt 538AC606 rom/light_param/light_pv601s02.txt 451BB430 rom/light_param/light_pv601s04.txt 1C638D13 rom/light_param/light_pv602s01.txt 6A8AC850 rom/light_param/light_pv602s02.txt 80AA95C9 rom/light_param/light_pv602s03.txt 8B5A8618 rom/light_param/light_pv602s04.txt E838A659 rom/light_param/light_pv603s01.txt DA77CEAD rom/light_param/light_pv604s02.txt D7E0BFB3 rom/light_param/light_pv604s04.txt 4819C0B2 rom/light_param/light_pv604s05.txt AD212AA0 rom/light_param/light_pv604s06.txt EFA06B99 rom/light_param/light_pv604s07.txt 90425ED4 rom/light_param/light_pv605s01.txt 98A6A1F3 rom/light_param/light_pv605s02.txt A0881CD3 rom/light_param/light_pv605s05.txt C7A926EC rom/light_param/light_pv607s01.txt CEF1B277 rom/light_param/light_pv610s01.txt 1AC4D936 rom/light_param/light_pv612s01.txt 38074868 rom/light_param/light_pv613s01.txt D0AC92A0 rom/light_param/light_pv613s02.txt 8957DD2C rom/light_param/light_pv613s03.txt A7BC78A2 rom/light_param/light_pv614s01.txt 0A9D42E0 rom/light_param/light_pv615s01.txt BFF9DFF3 rom/light_param/light_pv616s01.txt 2FCB01FA rom/light_param/light_pv616s02.txt 367732C0 rom/light_param/light_pv616s03.txt 3CDCEE1F rom/light_param/light_pv617s01.txt 6A7AC177 rom/light_param/light_pv617s02.txt 24F8D8EE rom/light_param/light_pv618s01.txt 32BF48FE rom/light_param/light_pv618s02.txt 38849A36 rom/light_param/light_pv618s03.txt 32BF48FE rom/light_param/light_pv618s04.txt 15BC0AC8 rom/light_param/light_pv618s05.txt C611E580 rom/light_param/light_pv619s02.txt 8C3FA444 rom/light_param/light_pv619s03.txt 37249108 rom/light_param/light_pv619s04.txt D68FEB53 rom/light_param/light_pv620s01.txt 0EB8361F rom/light_param/light_pv621s01.txt 2352065C rom/light_param/light_pv622s01.txt F839B087 rom/light_param/light_pv623s01.txt CAF3B48E rom/light_param/light_pv623s03.txt DEB2A3E3 rom/light_param/light_pv624s01.txt C740810B rom/light_param/light_pv625s01.txt 122F5EA1 rom/light_param/light_pv625s03.txt 949F2EB5 rom/light_param/light_pv626s01.txt 79D90960 rom/light_param/light_pv627s01.txt D86C6C82 rom/light_param/light_pv627s02.txt D3BDA31C rom/light_param/light_pv627s03.txt 503F62D3 rom/light_param/light_pv628s01.txt 69FA7CB7 rom/light_param/light_pv630s01.txt C4FCD73D rom/light_param/light_pv630s03.txt D88F0008 rom/light_param/light_pv631s01.txt 9EF90BF4 rom/light_param/light_pv637s01.txt E7216FF2 rom/light_param/light_pv637s02.txt 08F5AE4C rom/light_param/light_pv638s01.txt D9B94E8A rom/light_param/light_pv638s02.txt F977C3F6 rom/light_param/light_pv639s01.txt E996B036 rom/light_param/light_pv639s02.txt 37F0BE4D rom/light_param/light_pv639s03.txt 8A2D8714 rom/light_param/light_pv639s04.txt DC077308 rom/light_param/light_pv639s06.txt D7F2907B rom/light_param/light_pv642s01.txt C8B6B395 rom/light_param/light_pv710s01.txt E18790A8 rom/light_param/light_pv710s02.txt E287744B rom/light_param/light_pv710s03.txt 3E85D07F rom/light_param/light_pv722.farc 7B5BECAC rom/light_param/light_pv723.farc 65E6B547 rom/light_param/light_pv723s01.txt A69EC7F9 rom/light_param/light_pv723s02.txt B216ED1C rom/light_param/light_pv724s01.txt 1D11C969 rom/light_param/light_pv724s04.txt B3536D96 rom/light_param/light_pv724s05.txt 1DFC5560 rom/light_param/light_pv725.farc 5F9813A7 rom/light_param/light_pv726.farc 9751F138 rom/light_param/light_pv726s01.txt 526BA390 rom/light_param/light_pv727.farc 40344803 rom/light_param/light_pv727s01.txt EBF1D63D rom/light_param/light_pv727s02.txt D91D79DC rom/light_param/light_pv728.farc BF8C256A rom/light_param/light_pv728s01.txt 7588C344 rom/light_param/light_pv728s03.txt 7BE95C0C rom/light_param/light_pv729.farc 9C8AF095 rom/light_param/light_pv729s01.txt 9423F386 rom/light_param/light_pv729s03.txt DCA52979 rom/light_param/light_pv730s01.txt 84C7CE16 rom/light_param/light_pv730s02.txt E4915FD0 rom/light_param/light_pv731.farc ACAABAB9 rom/light_param/light_pv731s02.txt F30A42B0 rom/light_param/light_pv732.farc 8C434087 rom/light_param/light_pv732s01.txt 8FD3DEF7 rom/light_param/light_pv733.farc 36E83C91 rom/light_param/light_pv734.farc 56832524 rom/light_param/light_pv734s01.txt 7808C221 rom/light_param/light_pv734s02.txt 22036688 rom/light_param/light_pv734s04.txt 4E9A164B rom/light_param/light_pv734s05.txt 15D368D1 rom/light_param/light_pv736.farc 0F802CB9 rom/light_param/light_pv736s02.txt 2B9767C9 rom/light_param/light_pv737.farc 81134C4A rom/light_param/light_pv738.farc B49950D5 rom/light_param/light_pv738s01.txt F5822F31 rom/light_param/light_pv739.farc E939D2ED rom/light_param/light_pv739s01.txt 38858C0A rom/light_param/light_pv740.farc 10FE35E4 rom/light_param/light_pv740s01.txt F3DCA288 rom/light_param/light_pv740s02.txt 1BE69CC5 rom/light_param/light_pv740s03.txt 94BE8DD1 rom/light_param/light_pv740s04.txt 1633971C rom/light_param/light_pv740s05.txt D8AA0A0E rom/light_param/light_pv832.farc 75B0AC7D rom/light_param/light_pv832s01.txt F0D62BDB rom/light_param/light_selpvback.txt A50DC64B rom/light_param/light_stgns105.txt 2BA42F73 rom/light_param/wind_ns221.txt FB9BFC6A rom/light_param/wind_pv003s01.txt 79CDA669 rom/light_param/wind_pv003s03.txt 79CDA669 rom/light_param/wind_pv003s04.txt 79CDA669 rom/light_param/wind_pv003s05.txt 79CDA669 rom/light_param/wind_pv003s07.txt 726663C2 rom/light_param/wind_pv003s08.txt 79CDA669 rom/light_param/wind_pv003s09.txt 79CDA669 rom/light_param/wind_pv008s01.txt ECF2F934 rom/light_param/wind_pv008s03.txt F8CBE464 rom/light_param/wind_pv008s07.txt ECF2F934 rom/light_param/wind_pv008s08.txt 8F75D710 rom/light_param/wind_pv008s10.txt F8CBE464 rom/light_param/wind_pv009s01.txt 49967F2C rom/light_param/wind_pv009s02.txt E5604EE2 rom/light_param/wind_pv009s03.txt 782D8407 rom/light_param/wind_pv009s05.txt 27AC5046 rom/light_param/wind_pv009s08.txt 6AC3C4EE rom/light_param/wind_pv009s10.txt F6D068A8 rom/light_param/wind_pv024s06.txt 8766DF11 rom/light_param/wind_pv024s07.txt 990E3799 rom/light_param/wind_pv024s11.txt 8766DF11 rom/light_param/wind_pv211_d2ns048.txt 5F684B06 rom/light_param/wind_pv262s02.txt 14D64E99 rom/light_param/wind_pv262s11.txt 9F35BCFE rom/light_param/wind_pv262s12.txt 9F35BCFE rom/light_param/wind_pv601s03.txt B10BBEF0 rom/light_param/wind_pv604s01.txt 138446A9 rom/light_param/wind_pv604s02.txt 138446A9 rom/light_param/wind_pv604s03.txt BE797ADD rom/light_param/wind_pv604s05.txt 138446A9 rom/light_param/wind_pv612s01.txt FB9BFC6A rom/light_param/wind_pv612s02.txt FB9BFC6A rom/light_param/wind_pv612s04.txt FB9BFC6A rom/light_param/wind_pv613s01.txt 9B3F63C4 rom/light_param/wind_pv639s01_clone1.txt 6815807D rom/light_param/wind_pv722s01.txt BE7C3575 rom/light_param/wind_pv723s02_clone.txt 34AF0BAD rom/light_param/wind_pv732s02_clone1.txt 6D0A32C7 rom/light_param/wind_pv732s03.txt 4ED77038 rom/light_param/wind_selpvback.txt ECC8CF40 rom/light_param/wind_tst.txt ECC8CF40 rom/objset/cmnitm1001.farc 3AC0BECC rom/objset/cmnitm1002.farc A6077F93 rom/objset/cmnitm1003.farc 7A28B33C rom/objset/cmnitm1004.farc 20D722E2 rom/objset/cmnitm1005.farc 615AB983 rom/objset/cmnitm1006.farc 3F2C160D rom/objset/cmnitm1007.farc EFD85F7D rom/objset/cmnitm1008.farc D8CB821E rom/objset/cmnitm1009.farc 02FCDDD9 rom/objset/cmnitm1010.farc 2385110A rom/objset/cmnitm1011.farc 1AECF5B0 rom/objset/cmnitm1012.farc 00E300E5 rom/objset/cmnitm1013.farc D65B47CC rom/objset/cmnitm1014.farc 9CBAB236 rom/objset/cmnitm1015.farc 9B56A0A1 rom/objset/cmnitm1016.farc 0B886C08 rom/objset/cmnitm1017.farc 9DFF7B70 rom/objset/cmnitm1019.farc 0D7E0D5B rom/objset/cmnitm1020.farc 54039999 rom/objset/cmnitm1021.farc 3340EA5F rom/objset/cmnitm1022.farc 6C90769D rom/objset/cmnitm1023.farc 4F3ECA7E rom/objset/cmnitm1024.farc 77497753 rom/objset/cmnitm1025.farc D6913A7E rom/objset/cmnitm1026.farc A87AA2D9 rom/objset/cmnitm1027.farc 63721CB3 rom/objset/cmnitm1028.farc F2AE600F rom/objset/cmnitm1029.farc FB1614E7 rom/objset/cmnitm1030.farc 4A2C6087 rom/objset/cmnitm1031.farc C8AD6C3D rom/objset/cmnitm1032.farc 1C5E6B5B rom/objset/cmnitm1033.farc 5E660193 rom/objset/cmnitm1034.farc 91EE6871 rom/objset/cmnitm1035.farc 6E097297 rom/objset/cmnitm1037.farc 432F43D3 rom/objset/cmnitm1038.farc 9B088A14 rom/objset/cmnitm1039.farc 6B3790C7 rom/objset/cmnitm1040.farc 93661D0D rom/objset/cmnitm1041.farc 55F073D3 rom/objset/cmnitm1042.farc 3F39FFB7 rom/objset/cmnitm1043.farc 4A88D580 rom/objset/cmnitm1044.farc EAFD3380 rom/objset/cmnitm1047.farc 359AB27A rom/objset/cmnitm1048.farc 43C32086 rom/objset/cmnitm1049.farc 86215CB2 rom/objset/cmnitm1050.farc 071844B8 rom/objset/cmnitm1051.farc 1AC53204 rom/objset/cmnitm1101.farc DDD49B20 rom/objset/cmnitm1104.farc BA4BA418 rom/objset/cmnitm1105.farc B7601BF8 rom/objset/cmnitm1106.farc E5E2F40A rom/objset/cmnitm1108.farc 8460D428 rom/objset/cmnitm1109.farc B4353542 rom/objset/cmnitm1201.farc 111541BE rom/objset/cmnitm1202.farc E5E90343 rom/objset/cmnitm1203.farc 0CACEA19 rom/objset/cmnitm1204.farc 53DD2FA4 rom/objset/cmnitm1205.farc 034AB281 rom/objset/cmnitm1206.farc 2936650A rom/objset/cmnitm1207.farc 72496A6E rom/objset/cmnitm1208.farc 5BBC56C6 rom/objset/cmnitm1209.farc E85D9F3B rom/objset/cmnitm1210.farc F6CCA36B rom/objset/cmnitm1211.farc EA0DDE97 rom/objset/cmnitm1212.farc 8E044E02 rom/objset/cmnitm1213.farc 28D44CBC rom/objset/cmnitm1214.farc E0D8D76B rom/objset/cmnitm1215.farc C3B75AA1 rom/objset/cmnitm1018.farc E4AE8A2C rom/objset/cmnitm1036.farc 4EBE663D rom/objset/cmnitm1107.farc 675692DA rom/objset/cmnitm1216.farc 3C66F284 rom/objset/cmnitm1236.farc CA0C7EF3 rom/objset/cmnitm1254.farc 8A7EB92B rom/objset/cmnitm1272.farc A85DBC06 rom/objset/cmnitm1311.farc A65BDD11 rom/objset/cmnitm1415.farc A7707D47 rom/objset/cmnitm1514.farc 1EBE9DCA rom/objset/cmnitm1616.farc B8CC2C32 rom/objset/dbg.farc F376D064 rom/objset/effchrpv262hak002.farc A0DDE552 rom/objset/effchrpv262mik101.farc D96DC801 rom/objset/effchrpv441mik001.farc 7DA190A1 rom/objset/cmnitm1217.farc 2AABEC0A rom/objset/cmnitm1218.farc 13D727E3 rom/objset/cmnitm1219.farc 89D99C97 rom/objset/cmnitm1220.farc 5640A175 rom/objset/cmnitm1221.farc DA100ACC rom/objset/cmnitm1222.farc 7E76B02D rom/objset/cmnitm1223.farc 5A381833 rom/objset/cmnitm1224.farc E3629B78 rom/objset/cmnitm1227.farc 18A74243 rom/objset/cmnitm1228.farc 81E59BE0 rom/objset/cmnitm1229.farc 6217E310 rom/objset/cmnitm1230.farc 070914F5 rom/objset/cmnitm1231.farc BB8F5692 rom/objset/cmnitm1232.farc 21C3DA13 rom/objset/cmnitm1233.farc B6099D6F rom/objset/cmnitm1234.farc 7A935AD7 rom/objset/cmnitm1235.farc 55B79AEA rom/objset/cmnitm1237.farc 40A2CCDC rom/objset/cmnitm1238.farc 444E30D5 rom/objset/cmnitm1239.farc A94BCECA rom/objset/cmnitm1240.farc 28E56B29 rom/objset/cmnitm1241.farc BF924E89 rom/objset/cmnitm1242.farc 24A311CC rom/objset/cmnitm1243.farc FED89551 rom/objset/cmnitm1244.farc 05B6BE75 rom/objset/cmnitm1245.farc CE0909A6 rom/objset/cmnitm1246.farc BBBC6EC5 rom/objset/cmnitm1247.farc 4DC95176 rom/objset/cmnitm1248.farc C13B86F8 rom/objset/cmnitm1249.farc 65E9E12A rom/objset/cmnitm1250.farc 5C781BEB rom/objset/cmnitm1251.farc C62DB7D4 rom/objset/cmnitm1252.farc A81392C7 rom/objset/cmnitm1253.farc A64F1325 rom/objset/cmnitm1255.farc B08C0493 rom/objset/cmnitm1256.farc C683756B rom/objset/cmnitm1257.farc 4D09AF81 rom/objset/cmnitm1258.farc B1EC5690 rom/objset/cmnitm1259.farc 540BC3F3 rom/objset/cmnitm1260.farc 94A98CAF rom/objset/cmnitm1261.farc 2C5D1570 rom/objset/cmnitm1262.farc B45B57CA rom/objset/cmnitm1263.farc 188ECF42 rom/objset/cmnitm1264.farc 3EED4A12 rom/objset/cmnitm1265.farc 7ACFFF38 rom/objset/cmnitm1266.farc 30907A47 rom/objset/cmnitm1267.farc 4AB0809B rom/objset/cmnitm1268.farc EB4C2831 rom/objset/cmnitm1269.farc 52EB41F1 rom/objset/cmnitm1270.farc 6A315A12 rom/objset/cmnitm1271.farc E516B38B rom/objset/cmnitm1273.farc AA76218A rom/objset/cmnitm1274.farc F2C32681 rom/objset/cmnitm1275.farc ED4EE41C rom/objset/cmnitm1276.farc 40DD00A6 rom/objset/cmnitm1277.farc 7A51A8EA rom/objset/cmnitm1278.farc 981DB11F rom/objset/cmnitm1279.farc 808BE5CD rom/objset/cmnitm1301.farc FE0C9979 rom/objset/cmnitm1302.farc CC82D092 rom/objset/cmnitm1303.farc AE2535C2 rom/objset/cmnitm1304.farc F96E58B9 rom/objset/cmnitm1305.farc 6243AA63 rom/objset/cmnitm1306.farc 70D54CE4 rom/objset/cmnitm1307.farc AABC7641 rom/objset/cmnitm1308.farc ECA070A3 rom/objset/cmnitm1309.farc AE4122D1 rom/objset/cmnitm1310.farc 4FE94DA1 rom/objset/cmnitm1312.farc 8ADC7432 rom/objset/cmnitm1313.farc 42CB29BA rom/objset/cmnitm1314.farc FE4D1EA4 rom/objset/cmnitm1315.farc 1C2076F8 rom/objset/cmnitm1316.farc BF5281D3 rom/objset/cmnitm1317.farc 9DD09325 rom/objset/cmnitm1318.farc 99695CEE rom/objset/cmnitm1401.farc 59F930AC rom/objset/cmnitm1402.farc 22CBB752 rom/objset/cmnitm1403.farc CBEAC88D rom/objset/cmnitm1404.farc E703BDF4 rom/objset/cmnitm1405.farc 97B1E35D rom/objset/cmnitm1406.farc EAE07758 rom/objset/cmnitm1411.farc 67CA815D rom/objset/cmnitm1412.farc 9D0A7EB2 rom/objset/cmnitm1413.farc D232EEBE rom/objset/cmnitm1414.farc 8EA5A955 rom/objset/cmnitm1416.farc 1055AEDE rom/objset/cmnitm1417.farc D3B1475F rom/objset/cmnitm1418.farc FA36A129 rom/objset/cmnitm1419.farc 246ED6CF rom/objset/cmnitm1501.farc FDCE2D12 rom/objset/cmnitm1502.farc EF557EED rom/objset/cmnitm1503.farc D065C7FF rom/objset/cmnitm1504.farc 5598AE5C rom/objset/cmnitm1505.farc D10B864A rom/objset/cmnitm1506.farc 2DB72A94 rom/objset/cmnitm1507.farc 7BFA2D98 rom/objset/cmnitm1508.farc 24C51B85 rom/objset/cmnitm1509.farc 3705C7DB rom/objset/cmnitm1510.farc ADF4454E rom/objset/cmnitm1511.farc 08BEAA89 rom/objset/cmnitm1512.farc 04200F8F rom/objset/cmnitm1513.farc FBF2A16C rom/objset/cmnitm1515.farc 576F1EFB rom/objset/cmnitm1516.farc 10FEB048 rom/objset/cmnitm1601.farc 515CBE96 rom/objset/cmnitm1602.farc 7BE856B8 rom/objset/cmnitm1603.farc 063C5107 rom/objset/cmnitm1604.farc 44D50BF4 rom/objset/cmnitm1605.farc EC9F76D5 rom/objset/cmnitm1606.farc ABA1FB91 rom/objset/cmnitm1607.farc 42B18271 rom/objset/cmnitm1608.farc DC5064D0 rom/objset/cmnitm1609.farc 8F2DD783 rom/objset/cmnitm1610.farc 49FAF91E rom/objset/cmnitm1611.farc EF26FD9E rom/objset/cmnitm1612.farc 62E15386 rom/objset/cmnitm1613.farc BD4B964D rom/objset/cmnitm1614.farc 4B7F9E11 rom/objset/cmnitm1615.farc DD5AD6C4 rom/objset/cmnitm1617.farc 0B37905C rom/objset/cmnitm1618.farc 8B0DBA9B rom/objset/cmnitm1619.farc 46DC5FC5 rom/objset/cmnitm1620.farc 6F2DF164 rom/objset/cmnitm1621.farc 9A798FBF rom/objset/cmnitm1625.farc A82D1E8D rom/objset/cmnitm1626.farc EDBD89A9 rom/objset/cmnitm1627.farc 75217551 rom/objset/cmnitm1701.farc C949B0E7 rom/objset/cmnitm1702.farc 2A3B65B4 rom/objset/cmnitm1703.farc E3320CB4 rom/objset/cmnitm1704.farc 551272C3 rom/objset/cmnitm1705.farc 07319614 rom/objset/cmnitm1706.farc B59C118C rom/objset/cmnitm1707.farc 8C261D0A rom/objset/cmnitm1708.farc 89F9E1E5 rom/objset/effchrpv243hak001.farc 1A793F03 rom/objset/effchrpv243kai001.farc 4ECD73B1 rom/objset/effchrpv243len001.farc 315DA955 rom/objset/effchrpv243luk001.farc 78F0D856 rom/objset/effchrpv243mei001.farc 558B9A9C rom/objset/effchrpv243mik001.farc 66872E88 rom/objset/effchrpv243ner001.farc 366920CB rom/objset/effchrpv243rin001.farc 88B1C2AB rom/objset/effchrpv243sak001.farc 50E5CE31 rom/objset/effchrpv243tet001.farc 09EACCFB rom/objset/effchrpv244kai001.farc AE51B863 rom/objset/effchrpv244kai002.farc 4D0B7512 rom/objset/effchrpv244len001.farc C9E7F92E rom/objset/effchrpv244len002.farc 48E76BE2 rom/objset/effchrpv262hak001.farc BC51ADD2 rom/objset/effchrpv262kai001.farc E014F491 rom/objset/effchrpv262kai002.farc 567AA70B rom/objset/effchrpv262kai100.farc D4B763F4 rom/objset/effchrpv262kai101.farc 5E21AA8B rom/objset/effchrpv262len001.farc 5C0093FB rom/objset/effchrpv262len002.farc 7B900638 rom/objset/effchrpv262luk001.farc D9EDD24A rom/objset/effchrpv262luk002.farc 14FAC933 rom/objset/effchrpv262mei001.farc 96795824 rom/objset/effchrpv262mei002.farc D6B8F084 rom/objset/effchrpv262mei100.farc E8511F3C rom/objset/effchrpv262mei101.farc AD5E60E1 rom/objset/effchrpv262mik001.farc 58A6A988 rom/objset/effchrpv262mik002.farc 0F7EDB34 rom/objset/effchrpv262mik100.farc A5C88FF4 rom/objset/effchrpv262ner001.farc FE86B4E2 rom/objset/effchrpv262ner002.farc 811AE0D8 rom/objset/effchrpv262rin001.farc 27990A84 rom/objset/effchrpv262rin002.farc 5B457713 rom/objset/effchrpv262rin100.farc 76EC2370 rom/objset/effchrpv262rin101.farc CBCA04F6 rom/objset/effchrpv262sak001.farc 784DB625 rom/objset/effchrpv262sak002.farc A3C40232 rom/objset/effchrpv262tet001.farc 983EDDB2 rom/objset/effchrpv262tet002.farc 64205C99 rom/objset/effchrpv441hak001.farc 037918BC rom/objset/effchrpv441kai001.farc E7D93FD3 rom/objset/effchrpv441len001.farc 0CFBD83F rom/objset/effchrpv441luk001.farc 8558E4DA rom/objset/effchrpv441mei001.farc F718786C rom/objset/effchrpv441ner001.farc A04B2E61 rom/objset/effchrpv441rin001.farc 8B224B96 rom/objset/effchrpv441sak001.farc 18B0FAD5 rom/objset/effchrpv441tet001.farc 4B3DA725 rom/objset/effchrpv602hak001.farc 8734508E rom/objset/effchrpv602kai001.farc 6A6A6932 rom/objset/effchrpv602len001.farc 81C2F68D rom/objset/effchrpv602luk001.farc 33A06B54 rom/objset/effchrpv602mei001.farc B61A21E4 rom/objset/effchrpv602mik001.farc A8911AE6 rom/objset/effchrpv602ner001.farc E9ACC794 rom/objset/effchrpv602rin001.farc 15E98149 rom/objset/effchrpv602sak001.farc 94FA2D61 rom/objset/effchrpv602tet001.farc EB6DC0A8 rom/objset/effchrpv605hak001.farc 3ADA0CE0 rom/objset/effchrpv605len001.farc 8D912870 rom/objset/effchrpv605luk001.farc 834B6969 rom/objset/effchrpv605mei001.farc 2044ACBE rom/objset/effchrpv605mik001.farc 5B30A7CD rom/objset/effchrpv605ner001.farc DF22D055 rom/objset/effchrpv605rin001.farc 0C5E887F rom/objset/effchrpv605sak001.farc 3ED4FD5E rom/objset/effchrpv605tet001.farc FE84E378 rom/objset/effchrpv609kai001.farc 57A2D53C rom/objset/effchrpv609len001.farc CDBF1EB7 rom/objset/effchrpv609len003.farc 761CEA91 rom/objset/effchrpv609luk001.farc 10E90735 rom/objset/effchrpv609luk004.farc 6038124D rom/objset/effchrpv609mei001.farc A16C4B33 rom/objset/effchrpv609mik001.farc B869EEC0 rom/objset/effchrpv609mik003.farc 54057A67 rom/objset/effchrpv609mik004.farc 2FBD045E rom/objset/effchrpv609rin001.farc CF54B796 rom/objset/effchrpv609rin002.farc 5DF4A7B5 rom/objset/effchrpv609sak001.farc 374D5C73 rom/objset/effchrpv612hak001.farc 8A6FBF1D rom/objset/effchrpv612hak002.farc 137AE842 rom/objset/effchrpv612kai001.farc 6A5CF9F7 rom/objset/effchrpv612kai002.farc 9A58ECBC rom/objset/effchrpv612len001.farc 95CF1A21 rom/objset/effchrpv612len002.farc 0A6BA5ED rom/objset/effchrpv612luk001.farc 8C468557 rom/objset/effchrpv612luk002.farc CD731D20 rom/objset/effchrpv612mei001.farc 1349A72A rom/objset/effchrpv612mei002.farc D271BCF0 rom/objset/effchrpv612mik002.farc 9FC11599 rom/objset/effchrpv612ner001.farc 3BC1E810 rom/objset/effchrpv612ner002.farc 77C05610 rom/objset/effchrpv612rin001.farc C6C2AD81 rom/objset/effchrpv612rin002.farc 609C91D3 rom/objset/effchrpv612sak001.farc D43DD672 rom/objset/effchrpv612sak002.farc 87F3153B rom/objset/effchrpv612tet001.farc D5B4807D rom/objset/effchrpv612tet002.farc 30801E6B rom/objset/effchrpv614kai001.farc 72CF1709 rom/objset/effchrpv614kai002.farc 4120C2E5 rom/objset/effchrpv614kai003.farc A0261331 rom/objset/effchrpv614kai004.farc AA178E95 rom/objset/effchrpv614kai005.farc 7D9BD162 rom/objset/effchrpv614kai006.farc A4C67462 rom/objset/effchrpv614kai008.farc B7AAFE26 rom/objset/effchrpv614kai009.farc 05210761 rom/objset/effchrpv614kai010.farc 7FF67129 rom/objset/effchrpv614len001.farc 13A483C6 rom/objset/effchrpv614len002.farc 7F5EF8F8 rom/objset/effchrpv614len003.farc BF4756AF rom/objset/effchrpv614len004.farc FC7A74AB rom/objset/effchrpv614len005.farc CF497CF7 rom/objset/effchrpv614len006.farc A38548E7 rom/objset/effchrpv614len007.farc DCD5E6FB rom/objset/effchrpv614len008.farc 0D6AE9F2 rom/objset/effchrpv614len009.farc 3A9780B8 rom/objset/effchrpv614len010.farc C92CD693 rom/objset/effchrpv614luk001.farc AB5A9EA1 rom/objset/effchrpv614luk002.farc 3506293B rom/objset/effchrpv614luk004.farc F86DC096 rom/objset/effchrpv614luk005.farc FD87DC36 rom/objset/effchrpv614luk006.farc 097160C3 rom/objset/effchrpv614luk007.farc 92179BC5 rom/objset/effchrpv614luk008.farc 34AEAABF rom/objset/effchrpv614luk009.farc A642A4D2 rom/objset/effchrpv614luk010.farc EE96C201 rom/objset/effchrpv614mei001.farc 0F115BAF rom/objset/effchrpv614mei002.farc 12048ECC rom/objset/effchrpv614mei003.farc 4A5FB097 rom/objset/effchrpv614mei004.farc 274183C3 rom/objset/effchrpv614mei005.farc 49767333 rom/objset/effchrpv614mei006.farc E4389306 rom/objset/effchrpv614mei007.farc 697FD2BD rom/objset/effchrpv614mei008.farc 8E0E500A rom/objset/effchrpv614mei010.farc 2C400D99 rom/objset/effchrpv614mik001.farc 95280F2D rom/objset/effchrpv614mik002.farc 323AA4CE rom/objset/effchrpv614mik003.farc 2B2A25D6 rom/objset/effchrpv614mik004.farc 4FB900C4 rom/objset/effchrpv614mik005.farc CDFE8E8F rom/objset/effchrpv614mik006.farc 16F57493 rom/objset/effchrpv614mik007.farc 90F2D76B rom/objset/effchrpv614mik008.farc 537C0611 rom/objset/effchrpv614mik009.farc A18F2A89 rom/objset/effchrpv614mik010.farc 6486DCA7 rom/objset/effchrpv614rin001.farc 009C7DC3 rom/objset/effchrpv614rin002.farc F1D5F30E rom/objset/effchrpv614rin003.farc 2F0C9CBC rom/objset/effchrpv614rin004.farc F20557F9 rom/objset/effchrpv614rin006.farc 88106AC2 rom/objset/effchrpv614rin007.farc 29311150 rom/objset/effchrpv614rin008.farc 2FAA9390 rom/objset/effchrpv614rin009.farc 5ABC3980 rom/objset/effchrpv614rin010.farc BF6221E5 rom/objset/effchrpv614sak001.farc 02F75919 rom/objset/effchrpv614sak002.farc 92952A2D rom/objset/effchrpv614sak003.farc FA3FBD43 rom/objset/effchrpv614sak004.farc 6B21A752 rom/objset/effchrpv614sak005.farc 640C36B0 rom/objset/effchrpv614sak006.farc A904CFD6 rom/objset/effchrpv614sak007.farc 81372F74 rom/objset/effchrpv614sak008.farc 0E1BCFB2 rom/objset/effchrpv614sak009.farc AFAA6998 rom/objset/effchrpv614sak010.farc C2CBA5E2 rom/objset/effchrpv617hak001.farc CE2CDE6D rom/objset/effchrpv617kai001.farc 4A1ED1B7 rom/objset/effchrpv617len001.farc 52458EF3 rom/objset/effchrpv617luk001.farc 53ED3F49 rom/objset/effchrpv617mei001.farc 98F82D18 rom/objset/effchrpv617mik001.farc DA78DB0A rom/objset/effchrpv617ner001.farc 8CA5E6A7 rom/objset/effchrpv617rin001.farc 451DA6F0 rom/objset/effchrpv617sak001.farc 5EE035E3 rom/objset/effchrpv617tet001.farc 03B5778F rom/objset/effchrpv624ext001.farc 676CC5BC rom/objset/effchrpv624ext002.farc 3CDA00AE rom/objset/effchrpv624hak001.farc F48088BF rom/objset/effchrpv624hak002.farc 1F816D9A rom/objset/effchrpv624kai001.farc 6F4A2BE6 rom/objset/effchrpv624len001.farc 1F0E7C4B rom/objset/effchrpv624len002.farc 24CA7804 rom/objset/effchrpv624luk001.farc 64897A7C rom/objset/effchrpv624luk002.farc B04C168F rom/objset/effchrpv624mei001.farc 5F1DC511 rom/objset/effchrpv624mei002.farc 8FA52C05 rom/objset/effchrpv624mik001.farc 31F948C5 rom/objset/effchrpv624mik002.farc 6A140653 rom/objset/effchrpv624ner001.farc B69BAEE5 rom/objset/effchrpv624ner002.farc 45C95512 rom/objset/effchrpv624rin001.farc 15EE1E27 rom/objset/effchrpv624rin002.farc 65195CD6 rom/objset/effchrpv624sak001.farc 5C9EC9F4 rom/objset/effchrpv624sak002.farc F204B8D1 rom/objset/effchrpv624tet001.farc 7A323647 rom/objset/effchrpv630hak001.farc 67469B20 rom/objset/effchrpv630hak002.farc 70C7F7E8 rom/objset/effchrpv630kai001.farc 9E7B2E77 rom/objset/effchrpv630kai002.farc 9333F3A5 rom/objset/effchrpv630len001.farc 0A76EC9C rom/objset/effchrpv630len002.farc C3664D1E rom/objset/effchrpv630luk001.farc 25D1285E rom/objset/effchrpv630luk002.farc 42C1100E rom/objset/effchrpv630mei001.farc 951ABC4B rom/objset/effchrpv630mei002.farc 9FB81856 rom/objset/effchrpv630mik001.farc B32F3CBA rom/objset/effchrpv630mik002.farc D6DEAB36 rom/objset/effchrpv630ner001.farc 8781EB2E rom/objset/effchrpv630ner002.farc 9A7A2111 rom/objset/effchrpv630rin001.farc F4481ADA rom/objset/effchrpv630sak001.farc 58ED01F0 rom/objset/effchrpv630sak002.farc FD903EAD rom/objset/effchrpv630tet001.farc DE30C453 rom/objset/effchrpv630tet002.farc 24A112C7 rom/objset/effchrpv637kai005.farc D2128625 rom/objset/effchrpv637len002.farc 779FED05 rom/objset/effchrpv637luk003.farc 3C0AC7DE rom/objset/effchrpv637mei004.farc A16C192A rom/objset/effchrpv637mik001.farc A1039A8A rom/objset/effchrpv637mik002.farc 0F9A30D2 rom/objset/effchrpv637mik003.farc 833884B2 rom/objset/effchrpv637mik004.farc 1C04ADE1 rom/objset/effchrpv637mik005.farc D82A5B9B rom/objset/effchrpv637rin001.farc ABC75930 rom/objset/effchrpv641hak002.farc 45C4DA41 rom/objset/effchrpv641kai002.farc 41734855 rom/objset/effchrpv641kai003.farc 278F2A45 rom/objset/effchrpv641len002.farc 951F5D2C rom/objset/effchrpv641len003.farc 772E1D5C rom/objset/effchrpv641luk002.farc 7C0ADBA9 rom/objset/effchrpv641luk003.farc DDC929A6 rom/objset/effchrpv641mei002.farc 97A8D7A2 rom/objset/effchrpv641mei003.farc BDCA84CE rom/objset/effchrpv641mik001.farc 1045F858 rom/objset/effchrpv641mik002.farc 7491482F rom/objset/effchrpv641mik003.farc 02692CEC rom/objset/effchrpv641ner002.farc 9CAE03D9 rom/objset/effchrpv641ner003.farc 40FA199E rom/objset/effchrpv641rin002.farc 6C8D2C80 rom/objset/effchrpv641rin003.farc BAFF7ADA rom/objset/effchrpv641sak003.farc FA8D559D rom/objset/effchrpv641tet002.farc 8ADF16D6 rom/objset/effchrpv641tet003.farc 3677BD9A rom/objset/effchrpv722hak100.farc C6F909B8 rom/objset/effchrpv722kai100.farc 0806B0DF rom/objset/effchrpv722len100.farc FB524797 rom/objset/effchrpv722luk100.farc F2EE887D rom/objset/effchrpv722mei100.farc 6C46C972 rom/objset/effchrpv722mik100.farc 4B76E590 rom/objset/effchrpv722ner100.farc 7E876D18 rom/objset/effchrpv722rin100.farc 05744ED5 rom/objset/effchrpv722sak100.farc 048CA810 rom/objset/effchrpv722tet100.farc 7E36FA58 rom/objset/effchrpv725hak001.farc C4978C54 rom/objset/effchrpv725kai001.farc D9182FB1 rom/objset/effchrpv725luk001.farc 8B6A1FD2 rom/objset/effchrpv725mei001.farc 9137B20F rom/objset/effchrpv725mik001.farc 681F1D30 rom/objset/effchrpv725ner001.farc 6F51D0E1 rom/objset/effchrpv725rin001.farc 3C7B30CF rom/objset/effchrpv725sak001.farc 16D6152C rom/objset/effchrpv725tet001.farc F0B74EB5 rom/objset/effchrpv726hak001.farc 2ADC9F3A rom/objset/effchrpv726hak002.farc 24241A1A rom/objset/effchrpv726kai001.farc 82C55624 rom/objset/effchrpv726kai002.farc BE2A352C rom/objset/effchrpv726len001.farc 2A580FA9 rom/objset/effchrpv726len002.farc 96184D35 rom/objset/effchrpv726luk001.farc 7017CAD9 rom/objset/effchrpv726luk002.farc 1746D993 rom/objset/effchrpv726mei002.farc 0EAAE961 rom/objset/effchrpv726mik001.farc E249879A rom/objset/effchrpv726mik002.farc E426AE6F rom/objset/effchrpv726ner001.farc 5E87F657 rom/objset/effchrpv726ner002.farc 4E94E43A rom/objset/effchrpv726rin001.farc B9414D7E rom/objset/effchrpv726rin002.farc BE4DC07C rom/objset/effchrpv726sak001.farc B4DCF240 rom/objset/effchrpv726sak002.farc 6CE59D41 rom/objset/effchrpv726tet001.farc 843AB9CE rom/objset/effchrpv726tet002.farc 01403723 rom/objset/effchrpv730hak001.farc DEB2BF72 rom/objset/effchrpv730hak002.farc 5CC4B888 rom/objset/effchrpv730kai001.farc A43C7FE8 rom/objset/effchrpv730kai002.farc D9BD0C39 rom/objset/effchrpv730len002.farc ABAEBE87 rom/objset/effchrpv730luk001.farc 689F5626 rom/objset/effchrpv730luk002.farc 66D9ED6C rom/objset/effchrpv730mei001.farc 1DBDDEFE rom/objset/effchrpv730mei002.farc E847B080 rom/objset/effchrpv730mik001.farc 289FC989 rom/objset/effchrpv730mik002.farc 7039991F rom/objset/effchrpv730ner001.farc 8FF21EE9 rom/objset/effchrpv730ner002.farc 50487E8F rom/objset/effchrpv730rin001.farc 8A8A3B66 rom/objset/effchrpv730rin002.farc 07C3ED7F rom/objset/effchrpv730sak001.farc 2F7AAEDA rom/objset/effchrpv730sak002.farc 6354F0CE rom/objset/effchrpv730tet001.farc 1B9D7C2A rom/objset/effchrpv730tet002.farc 5B619583 rom/objset/effchrpv609mik002.farc 2BAAE390 rom/objset/effchrpv612mik001.farc 86924F29 rom/objset/effchrpv614kai007.farc 936673A1 rom/objset/effchrpv614luk003.farc 5954D613 rom/objset/effchrpv614mei009.farc 77D5BAD4 rom/objset/effchrpv614rin005.farc 38941A4A rom/objset/effchrpv614tet009.farc D69F12B0 rom/objset/effchrpv624kai002.farc 4B943137 rom/objset/effchrpv624tet002.farc AD0957BB rom/objset/effchrpv630rin002.farc 472E512F rom/objset/effchrpv641hak003.farc D62CA92B rom/objset/effchrpv641sak002.farc 1EA78917 rom/objset/effchrpv725len001.farc 6B144014 rom/objset/effchrpv726mei001.farc E9397C3C rom/objset/effchrpv730len001.farc B049406E rom/objset/effchrpv737hak002.farc 36029459 rom/objset/effchrpv737kai001.farc D3ADFA6C rom/objset/effchrpv737kai002.farc 517F27AA rom/objset/effchrpv737len001.farc C7D0600E rom/objset/effchrpv737len002.farc 719619B6 rom/objset/effchrpv737luk001.farc 5F98A594 rom/objset/effchrpv737luk002.farc 0CFC44B4 rom/objset/effchrpv737mei001.farc CBF77D60 rom/objset/effchrpv737mei002.farc 451DD0D2 rom/objset/effchrpv737mik001.farc 63275B4E rom/objset/effchrpv737mik002.farc B792E98D rom/objset/effchrpv737ner001.farc 5F8234E6 rom/objset/effchrpv737ner002.farc 38C7AB7E rom/objset/effchrpv737rin001.farc BA86F7B3 rom/objset/effchrpv737rin002.farc 5CD0C584 rom/objset/effchrpv737sak002.farc DB412E4A rom/objset/effchrpv737tet001.farc 3ED3C6D7 rom/objset/effchrpv737tet002.farc E25020B1 rom/objset/effchrpv739hak100.farc 5BA244D5 rom/objset/effchrpv739kai100.farc A6893363 rom/objset/effchrpv739len100.farc 35B46735 rom/objset/effchrpv739luk100.farc 8B1D51AF rom/objset/effchrpv739mei100.farc A2318941 rom/objset/effchrpv739mik100.farc 0577D485 rom/objset/effchrpv739ner100.farc 064C83E4 rom/objset/effchrpv739rin100.farc 33EC6A82 rom/objset/effchrpv739sak100.farc 051B4C4F rom/objset/effchrpv739tet100.farc 599CC0D7 rom/objset/effcmn.farc EB35DB87 rom/objset/effmodulemik149.farc 89A211A0 rom/objset/hakitm000.farc 350B067C rom/objset/hakitm002.farc 0A96B23D rom/objset/hakitm003.farc BC77DEDC rom/objset/hakitm004.farc 158EE201 rom/objset/hakitm301.farc 54E9F69B rom/objset/hakitm302.farc 20280872 rom/objset/hakitm304.farc 46928FA6 rom/objset/hakitm500.farc 0A0D7B29 rom/objset/hakitm501.farc 4CBFFCBA rom/objset/hakitm502.farc 631126BF rom/objset/hakitm700.farc DA1DF09B rom/objset/hakitm725.farc 2ED374B2 rom/objset/hnditm000.farc 555D606B rom/objset/hnditm001.farc 809F60A5 rom/objset/hnditm002.farc 6A98C76B rom/objset/hnditm003.farc 96EBC8ED rom/objset/hnditm004.farc B17B0E6D rom/objset/hnditm005.farc 1528B2F3 rom/objset/hnditm007.farc 55F8F2F1 rom/objset/hnditm008.farc 708A3D7A rom/objset/hnditm009.farc 35775C04 rom/objset/hnditm010.farc 64893EDA rom/objset/hnditm011.farc 7C5B8E3A rom/objset/hnditm012.farc 7146CFCD rom/objset/hnditm013.farc 7E842062 rom/objset/hnditm014.farc 8886A343 rom/objset/hnditm015.farc 89D58557 rom/objset/hnditm016.farc 602A548D rom/objset/hnditm017.farc 3E1F916E rom/objset/hnditm018.farc C8C01703 rom/objset/hnditm019.farc 0551B7D0 rom/objset/hnditm020.farc F73CFED9 rom/objset/hnditm021.farc 0E4EB221 rom/objset/hnditm022.farc 5A6C94B2 rom/objset/hnditm023.farc 092ED5F4 rom/objset/hnditm025.farc E31F230D rom/objset/hnditm026.farc 785482B7 rom/objset/hnditm027.farc 2037D2B2 rom/objset/hnditm028.farc 086C2D26 rom/objset/hnditm029.farc B4E03DC9 rom/objset/hnditm030.farc 0A604020 rom/objset/hnditm031.farc 285E95DD rom/objset/hnditm035.farc DFB97546 rom/objset/hnditm036.farc FDBEF3F2 rom/objset/hnditm054.farc 6238DBEE rom/objset/hnditm056.farc EEE32777 rom/objset/hnditm057.farc ECAC14B7 rom/objset/hnditm058.farc B19D9733 rom/objset/hnditm300.farc 1E7DC0E7 rom/objset/hnditm301.farc E3D4A24A rom/objset/hnditm302.farc A8E297A2 rom/objset/hnditm303.farc B69A1E58 rom/objset/hnditm400.farc BABAFE3F rom/objset/hnditm401.farc E5303B18 rom/objset/hnditm402.farc 066E5D63 rom/objset/hnditm403.farc EB682A36 rom/objset/hnditm404.farc C477EBC9 rom/objset/hnditm405.farc 92947F2F rom/objset/hnditm406.farc 271424C5 rom/objset/hnditm500.farc 15236AED rom/objset/hnditm501.farc 55B595B7 rom/objset/hnditm502.farc D22C4F6D rom/objset/hnditm600.farc 007D71F5 rom/objset/hnditm601.farc 9BA4CF55 rom/objset/hnditm603.farc CCC3E33D rom/objset/hnditm604.farc 74F192E7 rom/objset/hnditm605.farc 0CAD3503 rom/objset/itmpv045.farc E4E8C7C0 rom/objset/itmpv060.farc 2742BCC5 rom/objset/itmpv086.farc 62305A31 rom/objset/itmpv088.farc CABE0620 rom/objset/itmpv089.farc 1B890A11 rom/objset/itmpv103.farc CA683153 rom/objset/itmpv212.farc E6290FD1 rom/objset/itmpv218.farc 8BF86C25 rom/objset/itmpv221.farc 471B7B9F rom/objset/itmpv232.farc F2D62436 rom/objset/itmpv233.farc 5B056E18 rom/objset/itmpv435.farc 7E875712 rom/objset/itmpv441.farc 098EDCBF rom/objset/itmpv600.farc 4B10538B rom/objset/itmpv602.farc D53D2A52 rom/objset/itmpv603.farc F3ACA41B rom/objset/itmpv607.farc BCCB37F5 rom/objset/itmpv610.farc DEE7ED1C rom/objset/itmpv612.farc 95D04FCA rom/objset/itmpv618.farc B0EA3A00 rom/objset/itmpv619.farc 16B8B29A rom/objset/itmpv620.farc 08BA08F2 rom/objset/itmpv622.farc DB37FC7F rom/objset/itmpv630.farc 3F9E1892 rom/objset/itmpv641.farc 1397313E rom/objset/itmpv725.farc B8C5476C rom/objset/itmpv726.farc 9D069AA2 rom/objset/itmpv727.farc C74DBAC3 rom/objset/itmpv731.farc 729D6D24 rom/objset/itmpv733.farc D1DC7F43 rom/objset/itmpv737.farc D96D5803 rom/objset/kaiitm000.farc AD04DD42 rom/objset/kaiitm001.farc 97503A68 rom/objset/kaiitm002.farc 970B9183 rom/objset/kaiitm003.farc 6BB55349 rom/objset/kaiitm004.farc C5F2BCBC rom/objset/kaiitm006.farc BBE1E9A6 rom/objset/kaiitm008.farc 53249631 rom/objset/kaiitm009.farc 6C0C76E5 rom/objset/kaiitm010.farc 84A571CF rom/objset/kaiitm011.farc E06B0823 rom/objset/kaiitm012.farc F79DCADF rom/objset/kaiitm014.farc 92068332 rom/objset/kaiitm015.farc 777D2BDB rom/objset/kaiitm016.farc F5D6EC9C rom/objset/kaiitm017.farc 4703AC68 rom/objset/kaiitm018.farc 07EC8764 rom/objset/kaiitm019.farc 8ADE5675 rom/objset/kaiitm020.farc 3595AD75 rom/objset/kaiitm022.farc 9085916A rom/objset/kaiitm023.farc 028BAF06 rom/objset/kaiitm024.farc 0C3C759B rom/objset/kaiitm025.farc FF67F1D9 rom/objset/kaiitm027.farc 9BDFEBEF rom/objset/kaiitm028.farc 18BC2ADE rom/objset/kaiitm029.farc A62FD3C0 rom/objset/kaiitm030.farc D91F24A8 rom/objset/kaiitm031.farc 3DD19EAA rom/objset/kaiitm032.farc 29C380DE rom/objset/kaiitm033.farc 324DD25D rom/objset/kaiitm034.farc 6060D1B9 rom/objset/kaiitm036.farc D331BD8F rom/objset/kaiitm037.farc 0F27EA51 rom/objset/kaiitm038.farc 88C49D15 rom/objset/kaiitm041.farc EF5A819D rom/objset/kaiitm042.farc 156B06F0 rom/objset/kaiitm301.farc 328DB040 rom/objset/kaiitm304.farc CD19CB24 rom/objset/kaiitm310.farc C3247618 rom/objset/kaiitm311.farc ABF95FD8 rom/objset/kaiitm315.farc DA1240B4 rom/objset/kaiitm316.farc 223CBE7F rom/objset/kaiitm320.farc D69C3EE1 rom/objset/kaiitm322.farc 49D9DD64 rom/objset/kaiitm323.farc 2ACFC313 rom/objset/kaiitm324.farc D747D475 rom/objset/kaiitm325.farc EDC25B55 rom/objset/kaiitm327.farc 5B3AAEFE rom/objset/kaiitm328.farc 7566E5DC rom/objset/kaiitm329.farc B2E30115 rom/objset/kaiitm330.farc 5BBEEE45 rom/objset/kaiitm331.farc 1D1F51F1 rom/objset/kaiitm332.farc BFECD270 rom/objset/kaiitm334.farc 1E2C3C4C rom/objset/kaiitm337.farc 4E3B76E5 rom/objset/kaiitm341.farc 7C4AD92F rom/objset/kaiitm342.farc 9CB4C785 rom/objset/kaiitm501.farc 5BC446C5 rom/objset/kaiitm502.farc 4BF40691 rom/objset/kaiitm503.farc 23F29F71 rom/objset/kaiitm504.farc F51CB15E rom/objset/kaiitm505.farc 255BDDE2 rom/objset/kaiitm506.farc D4F1592B rom/objset/kaiitm507.farc 2B02AE43 rom/objset/kaiitm508.farc 12428A4B rom/objset/kaiitm509.farc 59288B2C rom/objset/kaiitm510.farc C22A451F rom/objset/kaiitm520.farc 4974F09E rom/objset/kaiitm522.farc 8FBCA7B5 rom/objset/kaiitm523.farc 2AB73916 rom/objset/kaiitm524.farc 0E68502A rom/objset/kaiitm527.farc 58EDBA2D rom/objset/kaiitm528.farc 546D2673 rom/objset/kaiitm529.farc D7A6F699 rom/objset/kaiitm532.farc 4584E91E rom/objset/kaiitm533.farc 9D5EBEC3 rom/objset/kaiitm534.farc 4281B5BF rom/objset/kaiitm536.farc D9839A39 rom/objset/kaiitm541.farc C86EE494 rom/objset/kaiitm542.farc 4936ACAC rom/objset/kaiitm700.farc 4AC8F842 rom/objset/kaiitm701.farc 49AE7D9E rom/objset/kaiitm702.farc 491BCD98 rom/objset/kaiitm703.farc 4A0448BB rom/objset/kaiitm705.farc 537E1759 rom/objset/kaiitm706.farc D7B2A52D rom/objset/kaiitm707.farc D4971344 rom/objset/kaiitm725.farc A955F752 rom/objset/kaiitm726.farc D241BF8A rom/objset/kaiitm727.farc 48DDFF75 rom/objset/kaiitm728.farc 25094570 rom/objset/kaiitm730.farc 58749A87 rom/objset/kaiitm750.farc 6FCB444B rom/objset/kaiitm751.farc BD8F2969 rom/objset/kaiitm775.farc 09473B99 rom/objset/kaiitm809.farc 18A540B4 rom/objset/kaiitm810.farc 54C9966D rom/objset/kaiitm815.farc 52BDEDA4 rom/objset/kaiitm820.farc C49DF631 rom/objset/kaiitm822.farc AB5130EC rom/objset/kaiitm824.farc 11188A57 rom/objset/kaiitm827.farc 679FD178 rom/objset/kaiitm828.farc CDF52575 rom/objset/kaiitm829.farc CAA90712 rom/objset/kaiitm831.farc 72DEDD37 rom/objset/kaiitm832.farc E6B88CD5 rom/objset/kaiitm834.farc 71FA5517 rom/objset/kaiitm837.farc E512AC5A rom/objset/kaiitm842.farc 9D989CA3 rom/objset/lenitm000.farc BC03D32B rom/objset/lenitm001.farc 88DF3A42 rom/objset/lenitm002.farc ACA6D39F rom/objset/lenitm003.farc 9429A238 rom/objset/lenitm004.farc 6C5E03B8 rom/objset/lenitm005.farc F7486CFA rom/objset/lenitm006.farc 35E79F73 rom/objset/lenitm007.farc 1DE6144A rom/objset/lenitm008.farc 69F64489 rom/objset/lenitm009.farc 4041494D rom/objset/lenitm010.farc FD174831 rom/objset/lenitm011.farc D97F5B5B rom/objset/lenitm012.farc 2F34C5BB rom/objset/lenitm013.farc C2D52F6E rom/objset/lenitm014.farc 4C2B8C6A rom/objset/lenitm015.farc EAC21180 rom/objset/lenitm017.farc 01371E35 rom/objset/lenitm018.farc 6C17E510 rom/objset/lenitm019.farc 3796AD39 rom/objset/lenitm021.farc F200613C rom/objset/lenitm022.farc 3CDFA92E rom/objset/lenitm023.farc 471373C1 rom/objset/lenitm024.farc F1647B68 rom/objset/lenitm025.farc 63DC2D1C rom/objset/lenitm026.farc E9903E49 rom/objset/lenitm027.farc 97115B58 rom/objset/lenitm028.farc 7A9E7B75 rom/objset/lenitm029.farc 9D7BCB8E rom/objset/lenitm030.farc F7B7A81D rom/objset/lenitm031.farc 114FF252 rom/objset/lenitm032.farc 95DFA68F rom/objset/lenitm033.farc D73D0313 rom/objset/lenitm034.farc 7F94ED68 rom/objset/lenitm036.farc D2CF6640 rom/objset/lenitm037.farc CB81DFAA rom/objset/lenitm038.farc 00FE2812 rom/objset/lenitm039.farc 701EC69A rom/objset/lenitm040.farc B7EA8D1E rom/objset/lenitm301.farc 77E5F4C2 rom/objset/lenitm309.farc 796080B0 rom/objset/lenitm310.farc 034AEC98 rom/objset/lenitm311.farc 82CC93E2 rom/objset/lenitm313.farc 7F955BF7 rom/objset/lenitm315.farc 200FB180 rom/objset/lenitm316.farc 476F5BDA rom/objset/lenitm321.farc 52771F8C rom/objset/lenitm322.farc 138C14EA rom/objset/lenitm324.farc B99F4DDD rom/objset/lenitm325.farc 0087DB02 rom/objset/lenitm326.farc E145EB67 rom/objset/effchrpv737sak001.farc 5C923267 rom/objset/hakitm001.farc 07F49BAF rom/objset/hnditm006.farc FD6DF5C7 rom/objset/hnditm024.farc 89CB58C2 rom/objset/hnditm304.farc 10603C0C rom/objset/itmpv085.farc 0C7803BE rom/objset/itmpv616.farc A148FD31 rom/objset/kaiitm005.farc 9D42AE25 rom/objset/kaiitm026.farc D7CC7471 rom/objset/kaiitm312.farc 594204EC rom/objset/kaiitm500.farc 58E2077A rom/objset/kaiitm531.farc 70098BBD rom/objset/kaiitm729.farc 655615E6 rom/objset/kaiitm841.farc C25C11D1 rom/objset/lenitm016.farc 264D17D5 rom/objset/lenitm035.farc 5EA71C98 rom/objset/lenitm328.farc B06C42A7 rom/objset/lenitm329.farc 6E077406 rom/objset/lenitm331.farc AE26F8E5 rom/objset/lenitm332.farc 3EE207BE rom/objset/lenitm334.farc F2EB12C4 rom/objset/lenitm336.farc 3CFB119A rom/objset/lenitm337.farc 4ED84AE9 rom/objset/lenitm339.farc F5093A00 rom/objset/lenitm340.farc 1485391B rom/objset/lenitm500.farc 69622C05 rom/objset/lenitm501.farc DFB07B31 rom/objset/lenitm502.farc 8594CA06 rom/objset/lenitm503.farc 5F4DCECE rom/objset/lenitm504.farc 4EB9316F rom/objset/lenitm505.farc BB72F9E0 rom/objset/lenitm506.farc BE7C48DC rom/objset/lenitm507.farc 221C1722 rom/objset/lenitm509.farc D035EAF4 rom/objset/lenitm511.farc C7BE590C rom/objset/lenitm519.farc 7C220BA9 rom/objset/lenitm521.farc 604C2777 rom/objset/lenitm522.farc 104377FF rom/objset/lenitm523.farc 36EEB6EF rom/objset/lenitm524.farc 387958DF rom/objset/lenitm525.farc A72D7061 rom/objset/lenitm526.farc A894FE56 rom/objset/lenitm528.farc ECBEEE33 rom/objset/lenitm529.farc AB657049 rom/objset/lenitm530.farc E48A97A9 rom/objset/lenitm531.farc F6693D0D rom/objset/lenitm532.farc 2F7198CA rom/objset/lenitm533.farc 0938C256 rom/objset/lenitm534.farc 27C09818 rom/objset/lenitm535.farc F2B9C424 rom/objset/lenitm537.farc 5A063B20 rom/objset/lenitm538.farc 103ECF12 rom/objset/lenitm540.farc 3A400C17 rom/objset/lenitm542.farc 9E732010 rom/objset/lenitm700.farc CFB96DEC rom/objset/lenitm701.farc 2475ADD2 rom/objset/lenitm702.farc 8E054423 rom/objset/lenitm703.farc F6D69189 rom/objset/lenitm704.farc CCC93C27 rom/objset/lenitm725.farc 2390F15F rom/objset/lenitm726.farc 7E4BEF83 rom/objset/lenitm729.farc 062DFCAF rom/objset/lenitm770.farc 086E9CDF rom/objset/lenitm771.farc D0D59BB0 rom/objset/lenitm775.farc 5D6223B1 rom/objset/lenitm807.farc CCF6CBB6 rom/objset/lenitm808.farc 4B40D638 rom/objset/lenitm810.farc 5D2DCE27 rom/objset/lenitm811.farc 377F97BB rom/objset/lenitm812.farc C92E0144 rom/objset/lenitm814.farc 93C239A5 rom/objset/lenitm815.farc A65D91F6 rom/objset/lenitm819.farc D90082EE rom/objset/lenitm822.farc 74FFE9AC rom/objset/lenitm824.farc 90E7EEF8 rom/objset/lenitm825.farc 6DED6625 rom/objset/lenitm826.farc 98401898 rom/objset/lenitm828.farc CA4F588D rom/objset/lenitm831.farc AB85F8AE rom/objset/lenitm832.farc 49A90D5F rom/objset/lenitm833.farc D8C432A2 rom/objset/lenitm834.farc A06D636B rom/objset/lenitm836.farc 4DAC4BCD rom/objset/lenitm837.farc 21A0A402 rom/objset/lenitm839.farc 87C923FA rom/objset/lenitm842.farc 76E14FAC rom/objset/lenitm997.farc 66EFCA85 rom/objset/lukitm000.farc BDF09DE9 rom/objset/lukitm001.farc F6ED6554 rom/objset/lukitm002.farc 247BD515 rom/objset/lukitm003.farc E6794AE1 rom/objset/lukitm004.farc EEE5441B rom/objset/lukitm005.farc F80C8961 rom/objset/lukitm006.farc 7FCCC616 rom/objset/lukitm007.farc 8407D57E rom/objset/lukitm008.farc EE4C2109 rom/objset/lukitm009.farc DA062526 rom/objset/lukitm010.farc D8906EC8 rom/objset/lukitm011.farc B0C68F45 rom/objset/lukitm012.farc 7B6AC699 rom/objset/lukitm013.farc D4C32B6F rom/objset/lukitm015.farc EFCB8709 rom/objset/lukitm017.farc B6C6F0B7 rom/objset/lukitm018.farc CE303EDD rom/objset/lukitm019.farc 523A2021 rom/objset/lukitm020.farc CDDEE1E4 rom/objset/lukitm021.farc D0F4CA55 rom/objset/lukitm022.farc 9D9784C8 rom/objset/lukitm023.farc BEEB40BF rom/objset/lukitm024.farc A0F39CA4 rom/objset/lukitm025.farc 3DE3478B rom/objset/lukitm026.farc 78B71347 rom/objset/lukitm027.farc 3F0F4618 rom/objset/lukitm028.farc B5D94677 rom/objset/lukitm029.farc 5AAA41A3 rom/objset/lukitm030.farc D9CF25AF rom/objset/lukitm031.farc B867130D rom/objset/lukitm032.farc 604B18B4 rom/objset/lukitm034.farc 9A34C501 rom/objset/lukitm035.farc 4100E6CB rom/objset/lukitm036.farc 89FEF43D rom/objset/lukitm037.farc BCF6672E rom/objset/lukitm038.farc 0C616433 rom/objset/lukitm039.farc 0F29E97A rom/objset/lukitm040.farc 04696E68 rom/objset/lukitm041.farc 0E298622 rom/objset/lukitm042.farc 9A0890B2 rom/objset/lukitm301.farc 23A816B9 rom/objset/lukitm304.farc 9C34BF40 rom/objset/lukitm305.farc 1C40D169 rom/objset/lukitm310.farc 4E62F733 rom/objset/lukitm311.farc DCB3DAB9 rom/objset/lukitm312.farc A834446D rom/objset/lukitm313.farc 3C8FA743 rom/objset/lukitm314.farc 5EE0B177 rom/objset/lukitm317.farc 1A521117 rom/objset/lukitm320.farc 09074878 rom/objset/lukitm324.farc CF80DC22 rom/objset/lukitm325.farc B6921830 rom/objset/lukitm326.farc BF7C9170 rom/objset/lukitm328.farc E937C3C1 rom/objset/lukitm329.farc 7EFF1451 rom/objset/lukitm330.farc F4C9D657 rom/objset/lukitm331.farc 9374D535 rom/objset/lukitm332.farc AF45DC59 rom/objset/lukitm334.farc 2DF95A42 rom/objset/lukitm335.farc 1EBB0461 rom/objset/lukitm336.farc 0D601C77 rom/objset/lukitm337.farc D85779F7 rom/objset/lukitm339.farc 9CC103B8 rom/objset/lukitm341.farc 31775ECF rom/objset/lukitm342.farc DAABB698 rom/objset/lukitm501.farc D87F7C55 rom/objset/lukitm502.farc E7EC8885 rom/objset/lukitm503.farc DB42E024 rom/objset/lukitm504.farc F67DFA56 rom/objset/lukitm505.farc FF987043 rom/objset/lukitm506.farc CF024DF1 rom/objset/lukitm507.farc 5D16B74F rom/objset/lukitm508.farc AE92AA21 rom/objset/lukitm509.farc 1BE7223E rom/objset/lukitm510.farc 600283A6 rom/objset/lukitm511.farc 47A421C8 rom/objset/lukitm512.farc 2B1C9AEC rom/objset/lukitm513.farc D552DAAA rom/objset/lukitm514.farc 12BF68A8 rom/objset/lukitm515.farc 9E368A0A rom/objset/lukitm516.farc 3A7B0E69 rom/objset/lukitm517.farc 68C9F8EF rom/objset/lukitm526.farc ADA92811 rom/objset/lukitm527.farc D748EA2C rom/objset/lukitm528.farc 67E61495 rom/objset/lukitm529.farc E1AF243F rom/objset/lukitm530.farc 4E04FCB6 rom/objset/lukitm531.farc 5CDF085F rom/objset/lukitm532.farc 183929D8 rom/objset/lukitm533.farc 8073A922 rom/objset/lukitm534.farc D589009B rom/objset/lukitm535.farc BF47D8D4 rom/objset/lukitm536.farc 33835164 rom/objset/lukitm537.farc 398DD10C rom/objset/lukitm538.farc 3906209F rom/objset/lukitm539.farc 83847DF8 rom/objset/lukitm540.farc E3998099 rom/objset/lukitm542.farc 0EF2EF73 rom/objset/lukitm700.farc 97D96F27 rom/objset/lukitm702.farc 847EF462 rom/objset/lukitm703.farc 37E213D4 rom/objset/lukitm704.farc 6357FAC6 rom/objset/lukitm705.farc 1F9ABC7F rom/objset/lukitm706.farc 17987E5B rom/objset/lukitm725.farc C47B9C98 rom/objset/lukitm726.farc 7C536EFA rom/objset/lukitm727.farc D50D3908 rom/objset/lukitm810.farc 9CC6D237 rom/objset/lukitm815.farc A3ED4FC0 rom/objset/lukitm817.farc ECAD1390 rom/objset/lukitm825.farc 930E9345 rom/objset/lukitm829.farc FF25F3F2 rom/objset/lukitm830.farc 27A08FDD rom/objset/lukitm833.farc 6C4AA5B9 rom/objset/lukitm836.farc 0F3E366B rom/objset/lukitm837.farc 7125A734 rom/objset/lukitm840.farc 5E5C0E80 rom/objset/lukitm841.farc 990BB0B8 rom/objset/meiitm000.farc 152C3041 rom/objset/meiitm001.farc FFCC4CE0 rom/objset/meiitm002.farc 0310CEFD rom/objset/meiitm003.farc 7DADEA34 rom/objset/meiitm004.farc 7D1B14E7 rom/objset/meiitm005.farc 9FF903B8 rom/objset/meiitm006.farc D4059F06 rom/objset/meiitm008.farc 615830AE rom/objset/meiitm009.farc 0792DF11 rom/objset/meiitm010.farc 32BB37F5 rom/objset/meiitm011.farc 5E24C453 rom/objset/meiitm012.farc 3600FAE4 rom/objset/meiitm013.farc B0645268 rom/objset/meiitm014.farc 02634DE8 rom/objset/meiitm015.farc B45A73E9 rom/objset/meiitm017.farc 29F85162 rom/objset/meiitm018.farc 3BD9484A rom/objset/meiitm019.farc 709066C2 rom/objset/meiitm020.farc A374F662 rom/objset/meiitm021.farc B3E70C4F rom/objset/meiitm022.farc AB4DE228 rom/objset/meiitm023.farc 03486835 rom/objset/meiitm024.farc 43447515 rom/objset/meiitm025.farc 3BD3455B rom/objset/meiitm026.farc 63251238 rom/objset/meiitm027.farc 779092B7 rom/objset/meiitm028.farc A1E169CE rom/objset/meiitm029.farc 7D722CCA rom/objset/meiitm030.farc B1DDDA67 rom/objset/meiitm031.farc 62B78DDF rom/objset/meiitm032.farc E18152E9 rom/objset/meiitm033.farc 282973D0 rom/objset/meiitm304.farc E98A4606 rom/objset/meiitm305.farc FE6405DF rom/objset/meiitm309.farc 0007DD54 rom/objset/meiitm311.farc C9AD02ED rom/objset/meiitm313.farc 15D8A8A8 rom/objset/meiitm314.farc A0EE30ED rom/objset/meiitm320.farc 9AE96ECD rom/objset/meiitm321.farc 7403C427 rom/objset/meiitm322.farc 5FE8B304 rom/objset/meiitm323.farc 1499EDA0 rom/objset/meiitm324.farc BB66C32A rom/objset/meiitm325.farc 92E4819A rom/objset/meiitm327.farc CA5295C5 rom/objset/meiitm330.farc 181F9CC9 rom/objset/meiitm331.farc 2FB9F6DF rom/objset/meiitm332.farc CCF8B84A rom/objset/meiitm333.farc EAAF1AD1 rom/objset/meiitm501.farc FEEF8E6C rom/objset/meiitm502.farc A77983F5 rom/objset/meiitm503.farc 31686271 rom/objset/meiitm504.farc BB48AC19 rom/objset/meiitm505.farc FA41751C rom/objset/meiitm506.farc 8B91A3D7 rom/objset/meiitm507.farc 756E61D9 rom/objset/meiitm508.farc 0618DB38 rom/objset/meiitm509.farc 148289D5 rom/objset/meiitm510.farc E927FD2C rom/objset/meiitm511.farc 6EBF8650 rom/objset/meiitm512.farc 782978AE rom/objset/meiitm513.farc 6986E9B5 rom/objset/meiitm514.farc C3E46A8A rom/objset/meiitm515.farc 3E2F8547 rom/objset/meiitm521.farc A265F17B rom/objset/meiitm522.farc 9060D7D9 rom/objset/meiitm524.farc 4D9E2B44 rom/objset/meiitm525.farc 71972678 rom/objset/meiitm526.farc 22F7F76C rom/objset/meiitm527.farc EEDB73D7 rom/objset/meiitm528.farc C7DE0927 rom/objset/meiitm529.farc 7EFE4BC2 rom/objset/meiitm530.farc 63F20C67 rom/objset/meiitm532.farc 0437A5AA rom/objset/meiitm533.farc 8053BA00 rom/objset/meiitm700.farc CD5BD6ED rom/objset/meiitm701.farc 1A42A3F9 rom/objset/meiitm702.farc FBC14CCD rom/objset/meiitm703.farc 0BF6C668 rom/objset/meiitm704.farc D8B2B8C2 rom/objset/meiitm705.farc 57219F39 rom/objset/meiitm706.farc ED10DDC6 rom/objset/meiitm707.farc 6F7577F1 rom/objset/meiitm725.farc C031D3CD rom/objset/meiitm775.farc EA932205 rom/objset/meiitm809.farc 699CB5A1 rom/objset/meiitm816.farc B4CE2C1B rom/objset/meiitm820.farc 9282AF83 rom/objset/meiitm821.farc C3FA51FD rom/objset/meiitm823.farc 5D84D0C1 rom/objset/meiitm827.farc 280B138A rom/objset/meiitm828.farc CCE32500 rom/objset/meiitm831.farc 857F0535 rom/objset/meiitm833.farc 1FEF1109 rom/objset/mikitm000.farc B71AFDBB rom/objset/mikitm001.farc 9228F624 rom/objset/mikitm002.farc FDD0B7C9 rom/objset/mikitm003.farc C92A9EFB rom/objset/mikitm004.farc 9017DCDF rom/objset/mikitm005.farc 51E47940 rom/objset/mikitm007.farc 0CCDFD4C rom/objset/mikitm008.farc FBCE7E60 rom/objset/mikitm009.farc 655BBD93 rom/objset/mikitm010.farc A9229387 rom/objset/mikitm011.farc 14074684 rom/objset/mikitm012.farc B3764052 rom/objset/mikitm013.farc A0EFADEF rom/objset/mikitm014.farc B09B3F64 rom/objset/mikitm015.farc 85A19A41 rom/objset/mikitm016.farc 351B7E5C rom/objset/mikitm017.farc A58F9A3C rom/objset/mikitm018.farc 369C1C2C rom/objset/mikitm019.farc 1E62E7D1 rom/objset/mikitm020.farc 826FBC6A rom/objset/mikitm021.farc 4CE67E64 rom/objset/mikitm022.farc D66941F4 rom/objset/mikitm023.farc 4B094E80 rom/objset/lenitm508.farc 21F6C7A6 rom/objset/lenitm536.farc FCC5C5F1 rom/objset/lenitm809.farc 420DDA61 rom/objset/lenitm838.farc 1A64EF09 rom/objset/lukitm014.farc FD7B8A61 rom/objset/lukitm033.farc 75559748 rom/objset/lukitm315.farc 47707E2A rom/objset/lukitm500.farc 817BA35F rom/objset/lukitm525.farc 64A86200 rom/objset/lukitm701.farc E32C4CAC rom/objset/lukitm839.farc D1066CC8 rom/objset/meiitm016.farc 03669C18 rom/objset/meiitm301.farc 936DF84B rom/objset/meiitm500.farc FF610886 rom/objset/meiitm523.farc E35A7E92 rom/objset/meiitm709.farc 2D8B80ED rom/objset/effchrpv605kai001.farc 73787B50 rom/objset/effchrpv737hak001.farc 1D5C1D6B rom/objset/lenitm327.farc E979D5FE rom/objset/mikitm006.farc 2507401E rom/objset/mikitm540.farc 92C76CD8 rom/objset/rinitm331.farc 6540997A rom/objset/stgns005.farc F9433B22 rom/objset/stgpv082s06.farc BE2D6D95 rom/objset/stgpv236s02.farc D4114C25 rom/objset/mikitm025.farc 47E1D494 rom/objset/mikitm026.farc 4019E726 rom/objset/mikitm027.farc 674B2DE3 rom/objset/mikitm028.farc E6AFB421 rom/objset/mikitm029.farc B38CCC2C rom/objset/mikitm030.farc A5191C41 rom/objset/mikitm031.farc 0E087FEB rom/objset/mikitm032.farc C7068FBB rom/objset/mikitm033.farc 7F104DC5 rom/objset/mikitm034.farc 1A8F2FB8 rom/objset/mikitm035.farc 901C7388 rom/objset/mikitm036.farc 0CE339AA rom/objset/mikitm037.farc 1623692D rom/objset/mikitm038.farc EC04A709 rom/objset/mikitm039.farc 2E870378 rom/objset/mikitm040.farc 161FFC3C rom/objset/mikitm041.farc F25F1C46 rom/objset/mikitm043.farc 7637B8C0 rom/objset/mikitm044.farc 4C0685AD rom/objset/mikitm045.farc B042F89E rom/objset/mikitm046.farc C557CF73 rom/objset/mikitm047.farc F216F29C rom/objset/mikitm048.farc CF969F2F rom/objset/mikitm049.farc 51589758 rom/objset/mikitm050.farc 59D5BA38 rom/objset/mikitm051.farc F0F49016 rom/objset/mikitm052.farc 803E572C rom/objset/mikitm053.farc 283BAE37 rom/objset/mikitm054.farc C329463E rom/objset/mikitm055.farc D1393A6C rom/objset/mikitm056.farc 9608786D rom/objset/mikitm057.farc ECBB6736 rom/objset/mikitm058.farc 48C7C088 rom/objset/mikitm059.farc B4143A22 rom/objset/mikitm061.farc 59E22D61 rom/objset/mikitm063.farc 706E43C1 rom/objset/mikitm064.farc 003AF401 rom/objset/mikitm065.farc 4F6FC1CB rom/objset/mikitm066.farc 9B59EDAA rom/objset/mikitm067.farc 388DA036 rom/objset/mikitm068.farc 633C9515 rom/objset/mikitm069.farc 7AB49FDF rom/objset/mikitm070.farc DD742B58 rom/objset/mikitm071.farc 08B83911 rom/objset/mikitm072.farc 7AB9401B rom/objset/mikitm073.farc 8C63D6DF rom/objset/mikitm074.farc E6A9BB85 rom/objset/mikitm075.farc AE875463 rom/objset/mikitm076.farc C9F460A3 rom/objset/mikitm077.farc E66946A0 rom/objset/mikitm078.farc 58C67305 rom/objset/mikitm080.farc C1F52281 rom/objset/mikitm081.farc 0991FA67 rom/objset/mikitm082.farc 348E41A3 rom/objset/mikitm083.farc 2DAEFB73 rom/objset/mikitm084.farc AE7A46CD rom/objset/mikitm085.farc 1B966DC8 rom/objset/mikitm087.farc 7BC72333 rom/objset/mikitm088.farc 90EF80B7 rom/objset/mikitm089.farc F47E21F6 rom/objset/mikitm090.farc 5E9552AC rom/objset/mikitm091.farc CC8EDC3F rom/objset/mikitm092.farc 2ED29B36 rom/objset/mikitm093.farc E488D083 rom/objset/mikitm094.farc 18833768 rom/objset/mikitm095.farc 3237B0DA rom/objset/mikitm096.farc 1F56BD82 rom/objset/mikitm097.farc 69B6344B rom/objset/mikitm099.farc 0DC873A6 rom/objset/mikitm100.farc 0417A9B3 rom/objset/mikitm101.farc EAC87B67 rom/objset/mikitm102.farc 14499C9B rom/objset/mikitm103.farc 1367714B rom/objset/mikitm104.farc 4FDD9395 rom/objset/mikitm105.farc F1510D44 rom/objset/mikitm106.farc D087925B rom/objset/mikitm107.farc 2FF754E9 rom/objset/mikitm108.farc 01E3AA2F rom/objset/mikitm109.farc 58C893DF rom/objset/mikitm110.farc F6923428 rom/objset/mikitm111.farc C81E2163 rom/objset/mikitm112.farc 9133A204 rom/objset/mikitm113.farc 4251D22A rom/objset/mikitm114.farc 7C093DA4 rom/objset/mikitm115.farc 9FD57660 rom/objset/mikitm118.farc 87FF95A6 rom/objset/mikitm119.farc 963B029E rom/objset/mikitm120.farc 5B542B86 rom/objset/mikitm123.farc BDC18C5F rom/objset/mikitm124.farc 15A1B1C2 rom/objset/mikitm125.farc B4B54995 rom/objset/mikitm126.farc 2C9F3BFE rom/objset/mikitm127.farc 5A2875BC rom/objset/mikitm128.farc 5D62E680 rom/objset/mikitm129.farc 88B9F242 rom/objset/mikitm130.farc 31975093 rom/objset/mikitm131.farc B86D5225 rom/objset/mikitm132.farc 0F05AB90 rom/objset/mikitm133.farc 6E9ED911 rom/objset/mikitm134.farc D1B862F1 rom/objset/mikitm135.farc 0FF38015 rom/objset/mikitm136.farc 6CBE6C9A rom/objset/mikitm138.farc DD16E75E rom/objset/mikitm139.farc 6248E592 rom/objset/mikitm140.farc 1F1DD7EA rom/objset/mikitm141.farc 52CC2B40 rom/objset/mikitm142.farc A8C9E341 rom/objset/mikitm143.farc DF2CAFDB rom/objset/mikitm144.farc C4177F84 rom/objset/mikitm145.farc EEA103BC rom/objset/mikitm146.farc 84D8E7DC rom/objset/mikitm147.farc C4D62BCC rom/objset/mikitm148.farc 75EE6C0E rom/objset/mikitm149.farc 0982F214 rom/objset/mikitm151.farc CB7EEC1D rom/objset/mikitm152.farc B8A195EF rom/objset/mikitm153.farc E3F54510 rom/objset/mikitm155.farc 3755C58A rom/objset/mikitm156.farc 6D95CC9D rom/objset/mikitm160.farc AEFFE1BA rom/objset/mikitm162.farc D25E3EB3 rom/objset/mikitm163.farc 65FF3A53 rom/objset/mikitm164.farc CAD10AC6 rom/objset/mikitm165.farc A1EB6A62 rom/objset/mikitm166.farc 952A446E rom/objset/mikitm167.farc F3CCA6C8 rom/objset/mikitm169.farc C0E50963 rom/objset/mikitm170.farc F453B03E rom/objset/mikitm173.farc 74E50383 rom/objset/mikitm301.farc 16006FAB rom/objset/mikitm302.farc 9ADB8498 rom/objset/mikitm303.farc 1A2CCFD3 rom/objset/mikitm304.farc 4138EF8E rom/objset/mikitm305.farc D19FE933 rom/objset/mikitm306.farc 9B1F87DE rom/objset/mikitm308.farc D8A7D764 rom/objset/mikitm311.farc 6D353D3B rom/objset/mikitm312.farc 91CEE3BB rom/objset/mikitm313.farc 0574E2C7 rom/objset/mikitm314.farc B9B28BE4 rom/objset/mikitm315.farc 0A1FF1F0 rom/objset/mikitm316.farc 5C1C3BF8 rom/objset/mikitm317.farc 605B222A rom/objset/mikitm318.farc 5FDE142F rom/objset/mikitm319.farc 745E3572 rom/objset/mikitm321.farc 3F83F266 rom/objset/mikitm322.farc 4993A479 rom/objset/mikitm323.farc 0DABD6B9 rom/objset/mikitm325.farc 4B65DF5A rom/objset/mikitm326.farc 8F8303BE rom/objset/mikitm327.farc 43E0896E rom/objset/mikitm329.farc D414FC41 rom/objset/mikitm332.farc D387471C rom/objset/mikitm334.farc 9050E21B rom/objset/mikitm335.farc 4EC0A18C rom/objset/mikitm336.farc 4E152ABC rom/objset/mikitm337.farc 952F96D1 rom/objset/mikitm338.farc C3B61A9A rom/objset/mikitm339.farc AEEDD735 rom/objset/mikitm340.farc 46A0703C rom/objset/mikitm341.farc 03F51231 rom/objset/mikitm342.farc 9D2950DF rom/objset/mikitm343.farc 58F97A14 rom/objset/mikitm345.farc 3F64CE5C rom/objset/mikitm349.farc 4CADE578 rom/objset/mikitm350.farc 911621E6 rom/objset/mikitm353.farc 6C2CAE41 rom/objset/mikitm357.farc A5EB9D25 rom/objset/mikitm360.farc A29AD23E rom/objset/mikitm361.farc 46174A6A rom/objset/mikitm364.farc 696E7B3C rom/objset/mikitm365.farc 94F48D45 rom/objset/mikitm366.farc 0F9EB996 rom/objset/mikitm368.farc 06067408 rom/objset/mikitm369.farc 6E524598 rom/objset/mikitm370.farc 559015D7 rom/objset/mikitm371.farc 70700CB6 rom/objset/mikitm372.farc 732BC0FC rom/objset/mikitm373.farc A46F17AA rom/objset/mikitm374.farc F60788E5 rom/objset/mikitm375.farc 989E6BC2 rom/objset/mikitm376.farc DA8026AC rom/objset/mikitm377.farc AE0F9205 rom/objset/mikitm379.farc A510D4B0 rom/objset/mikitm380.farc EAD562F9 rom/objset/mikitm381.farc 54C9A61D rom/objset/mikitm382.farc D0081913 rom/objset/mikitm384.farc 73F2DE50 rom/objset/mikitm387.farc 811087EF rom/objset/mikitm388.farc 1F94CB80 rom/objset/mikitm389.farc D71976AB rom/objset/mikitm392.farc E721925A rom/objset/mikitm393.farc BB091700 rom/objset/mikitm394.farc E85E51DF rom/objset/mikitm395.farc 76ED6E8C rom/objset/mikitm396.farc CC1CEA25 rom/objset/mikitm397.farc 7F895B22 rom/objset/mikitm398.farc 129677CA rom/objset/mikitm399.farc 285BD9E4 rom/objset/mikitm400.farc 4A0CE6A1 rom/objset/mikitm401.farc 93B8F0FE rom/objset/mikitm402.farc 5040A113 rom/objset/mikitm404.farc 25926846 rom/objset/mikitm405.farc 0A78FE20 rom/objset/mikitm410.farc D897A840 rom/objset/mikitm411.farc 943AA5C8 rom/objset/mikitm412.farc C7ECCC38 rom/objset/mikitm413.farc 6B0C9C77 rom/objset/mikitm414.farc AC428A9A rom/objset/mikitm415.farc 4950F297 rom/objset/mikitm416.farc F73271F0 rom/objset/mikitm418.farc 1D1078B4 rom/objset/mikitm419.farc 9A62D4AA rom/objset/mikitm420.farc 47792C02 rom/objset/mikitm423.farc F45B0A39 rom/objset/mikitm424.farc 6BD8C0FB rom/objset/mikitm427.farc 3443E8F0 rom/objset/mikitm428.farc 7D49F95B rom/objset/mikitm429.farc 56504321 rom/objset/mikitm431.farc 28138E7C rom/objset/mikitm432.farc 0BA33D05 rom/objset/mikitm434.farc DBE7B9AD rom/objset/mikitm435.farc 15C88414 rom/objset/mikitm436.farc 80335E80 rom/objset/mikitm437.farc E53660D1 rom/objset/mikitm438.farc B43DDBE8 rom/objset/mikitm439.farc B68177D3 rom/objset/mikitm441.farc 91626E81 rom/objset/mikitm443.farc DEA5908C rom/objset/mikitm444.farc C05DBB9E rom/objset/mikitm445.farc E72B5FB1 rom/objset/mikitm446.farc ACD8DEA4 rom/objset/mikitm447.farc 70860107 rom/objset/mikitm448.farc DDC6E471 rom/objset/mikitm449.farc 8D235998 rom/objset/mikitm450.farc AE9C2BEF rom/objset/mikitm451.farc 37679019 rom/objset/mikitm455.farc DB3BB0A0 rom/objset/mikitm460.farc B02E5457 rom/objset/mikitm462.farc 95BB60A6 rom/objset/mikitm463.farc 7018F8BA rom/objset/mikitm464.farc 9603679A rom/objset/mikitm466.farc 94C57E60 rom/objset/mikitm467.farc 2E2301CD rom/objset/mikitm469.farc 73FBB644 rom/objset/mikitm470.farc 669E4CD7 rom/objset/mikitm473.farc C62C3172 rom/objset/mikitm500.farc 09CF1D97 rom/objset/mikitm501.farc 2D92DA28 rom/objset/mikitm502.farc A3869AD1 rom/objset/mikitm503.farc F931993B rom/objset/mikitm504.farc 5F6558E2 rom/objset/mikitm505.farc 1060C24E rom/objset/mikitm506.farc 91A1A468 rom/objset/mikitm507.farc 57B4B228 rom/objset/mikitm509.farc A4BB2AB2 rom/objset/mikitm520.farc 8D22E624 rom/objset/mikitm522.farc 4165CC00 rom/objset/mikitm524.farc 71E03CCF rom/objset/mikitm525.farc 327D9BFA rom/objset/mikitm526.farc F52F8CCE rom/objset/mikitm527.farc 9B74CAB7 rom/objset/mikitm528.farc 05BC6291 rom/objset/mikitm530.farc 8655753F rom/objset/mikitm531.farc 1A8088CC rom/objset/mikitm532.farc 1BEE70AC rom/objset/mikitm533.farc 9E44215F rom/objset/mikitm534.farc 0924C91B rom/objset/mikitm536.farc 0812A009 rom/objset/mikitm537.farc 0CA04FF4 rom/objset/mikitm538.farc 03584362 rom/objset/mikitm539.farc BD9DB0AB rom/objset/mikitm541.farc FF57B581 rom/objset/mikitm542.farc 34C3F5C9 rom/objset/mikitm543.farc 856E3FF0 rom/objset/mikitm544.farc B7F02E6E rom/objset/mikitm545.farc 49763991 rom/objset/mikitm546.farc D1996B5C rom/objset/mikitm547.farc F0B1D868 rom/objset/mikitm548.farc B5130814 rom/objset/mikitm549.farc E8C882BE rom/objset/mikitm550.farc 53613BA8 rom/objset/mikitm551.farc 48EE91AB rom/objset/mikitm552.farc 1475F7CE rom/objset/mikitm553.farc BF1DD1C8 rom/objset/mikitm554.farc CD492A4B rom/objset/mikitm555.farc 6915ECE3 rom/objset/mikitm556.farc CBC3172A rom/objset/mikitm557.farc EDE8DA31 rom/objset/mikitm024.farc FA8B29CE rom/objset/mikitm042.farc 65FB603E rom/objset/mikitm060.farc 149ED2D9 rom/objset/mikitm079.farc 9D725FAD rom/objset/mikitm098.farc EE0C1683 rom/objset/mikitm116.farc C08ACC09 rom/objset/mikitm137.farc A10CFDDB rom/objset/mikitm158.farc F30CB8D4 rom/objset/mikitm310.farc 071AA5FD rom/objset/mikitm333.farc F6F0CE03 rom/objset/mikitm363.farc D6AF368B rom/objset/mikitm383.farc 4D039E70 rom/objset/mikitm409.farc 6D3EB314 rom/objset/mikitm433.farc D37F7288 rom/objset/mikitm458.farc 53B4266F rom/objset/mikitm508.farc 8523A13B rom/objset/mikitm559.farc 6BCDE904 rom/objset/mikitm560.farc 72FAE8C7 rom/objset/mikitm593.farc 4616915F rom/objset/mikitm594.farc 58F3898B rom/objset/mikitm595.farc 9E645555 rom/objset/mikitm596.farc A4EF49E6 rom/objset/mikitm597.farc 6D2429E1 rom/objset/mikitm598.farc F11754DA rom/objset/mikitm599.farc 265F1550 rom/objset/mikitm600.farc 2A4ED93D rom/objset/mikitm601.farc 7BB60107 rom/objset/mikitm602.farc E9662AF6 rom/objset/mikitm603.farc 6E500446 rom/objset/mikitm604.farc 27DEE52A rom/objset/mikitm605.farc 3AB954C1 rom/objset/mikitm606.farc 46AE2171 rom/objset/mikitm607.farc A4FD9318 rom/objset/mikitm609.farc A2C2F074 rom/objset/mikitm610.farc 443219A6 rom/objset/mikitm611.farc 05C03047 rom/objset/mikitm612.farc B3CCBDEE rom/objset/mikitm613.farc 6669C8CA rom/objset/mikitm614.farc A7070249 rom/objset/mikitm615.farc 24C1CB80 rom/objset/mikitm616.farc 2973A69B rom/objset/mikitm617.farc AB68CC80 rom/objset/mikitm618.farc 125F3398 rom/objset/mikitm619.farc 7862642B rom/objset/mikitm620.farc CA2C7BC7 rom/objset/mikitm621.farc A850CF16 rom/objset/mikitm623.farc 4D94C7C2 rom/objset/mikitm624.farc 35251573 rom/objset/mikitm625.farc 2BB26977 rom/objset/mikitm626.farc 0E1B2C48 rom/objset/mikitm628.farc 1E0DE9B1 rom/objset/mikitm630.farc 7C5A521D rom/objset/mikitm631.farc 2DE3A24C rom/objset/mikitm632.farc 1247AA5F rom/objset/mikitm633.farc 57B2E169 rom/objset/mikitm634.farc 5B4D67C1 rom/objset/mikitm635.farc D0E44734 rom/objset/mikitm636.farc 4DCA1214 rom/objset/mikitm637.farc DB19812B rom/objset/mikitm638.farc 78C359A3 rom/objset/mikitm639.farc 9FD36630 rom/objset/mikitm640.farc BD05BC10 rom/objset/mikitm641.farc 34972A17 rom/objset/mikitm642.farc 9754D491 rom/objset/mikitm643.farc 5EF742F6 rom/objset/mikitm644.farc 4D7E11B0 rom/objset/mikitm645.farc 422CE108 rom/objset/mikitm647.farc AA623120 rom/objset/mikitm648.farc 29C18BC8 rom/objset/mikitm649.farc ECB342F3 rom/objset/mikitm651.farc 7FFD7668 rom/objset/mikitm652.farc D160DB6E rom/objset/mikitm653.farc 7DB80864 rom/objset/mikitm655.farc 48DE5866 rom/objset/mikitm656.farc FE344BB2 rom/objset/mikitm658.farc F1D20094 rom/objset/mikitm660.farc 0043F524 rom/objset/mikitm662.farc 8D9FA2FF rom/objset/mikitm663.farc E90C628F rom/objset/mikitm664.farc 2CF8D22B rom/objset/mikitm665.farc 33D8BD9E rom/objset/mikitm667.farc 8E34273A rom/objset/mikitm669.farc 61662789 rom/objset/mikitm670.farc 1CE515EC rom/objset/mikitm700.farc 6F4B7693 rom/objset/mikitm701.farc 430FC56F rom/objset/mikitm702.farc 924C79B3 rom/objset/mikitm703.farc 9E777CE7 rom/objset/mikitm704.farc 45A3B4AB rom/objset/mikitm705.farc AAAD819D rom/objset/mikitm706.farc 04952BEB rom/objset/mikitm707.farc 8690BEB5 rom/objset/mikitm708.farc 337CB546 rom/objset/mikitm709.farc 3DF5E995 rom/objset/mikitm710.farc 1D19E08B rom/objset/mikitm711.farc 8401DFC1 rom/objset/mikitm712.farc 3D47BE3B rom/objset/mikitm713.farc 1F14A684 rom/objset/mikitm714.farc 37F746CA rom/objset/mikitm715.farc 4452A815 rom/objset/mikitm716.farc 089EE724 rom/objset/mikitm718.farc E7D2D960 rom/objset/mikitm719.farc CD36FD26 rom/objset/mikitm720.farc DCD1C228 rom/objset/mikitm721.farc D1C0EAD4 rom/objset/mikitm722.farc C293777C rom/objset/mikitm723.farc 62F60662 rom/objset/mikitm724.farc 51DA502C rom/objset/mikitm725.farc 85176F44 rom/objset/mikitm726.farc B410CB1D rom/objset/mikitm727.farc BBC3CA9F rom/objset/mikitm728.farc 598DEC85 rom/objset/mikitm729.farc 8E9C28DB rom/objset/mikitm730.farc ED7347FF rom/objset/mikitm740.farc 81499AD7 rom/objset/mikitm741.farc 6491BCD6 rom/objset/mikitm742.farc 246E149E rom/objset/mikitm743.farc B2B1652A rom/objset/mikitm745.farc 26519FC5 rom/objset/mikitm746.farc 55CE74EC rom/objset/mikitm747.farc D792862D rom/objset/mikitm748.farc 24F6738E rom/objset/mikitm749.farc 2B7E3BE8 rom/objset/mikitm750.farc E7C52899 rom/objset/mikitm751.farc DD40DBBC rom/objset/mikitm752.farc 2FA84B1F rom/objset/mikitm770.farc F63CAD54 rom/objset/mikitm771.farc 285FC6C2 rom/objset/mikitm772.farc 4EB3D5ED rom/objset/mikitm773.farc 9D37278D rom/objset/mikitm775.farc 4CB11BE9 rom/objset/mikitm776.farc CA91EE7E rom/objset/mikitm777.farc AE484F0F rom/objset/mikitm778.farc 08033A19 rom/objset/mikitm779.farc 65E21C97 rom/objset/mikitm781.farc FBB9A967 rom/objset/mikitm782.farc 0F398C30 rom/objset/mikitm783.farc 501A478D rom/objset/mikitm784.farc AC783F47 rom/objset/mikitm790.farc 92CE9F3F rom/objset/mikitm791.farc 04A7E7D7 rom/objset/mikitm804.farc 3E1CDB7F rom/objset/mikitm833.farc 33871CDE rom/objset/mikitm834.farc BA392F88 rom/objset/mikitm835.farc 24B975E8 rom/objset/mikitm836.farc 5EEE900F rom/objset/mikitm837.farc 6A929893 rom/objset/mikitm838.farc 4EE73D1D rom/objset/mikitm839.farc C8ADA16F rom/objset/mikitm840.farc 8C476ABC rom/objset/mikitm841.farc C57F9C19 rom/objset/mikitm842.farc 95641DEB rom/objset/mikitm851.farc 3AECB942 rom/objset/mikitm852.farc DE326E4F rom/objset/mikitm856.farc D80AA0D5 rom/objset/mikitm857.farc DF2B675B rom/objset/mikitm863.farc 02DCFADB rom/objset/mikitm865.farc 4B216772 rom/objset/mikitm866.farc B5EE20CE rom/objset/mikitm868.farc C5D6C3E3 rom/objset/mikitm869.farc 0D600A54 rom/objset/mikitm873.farc 665A2873 rom/objset/mikitm874.farc 29B0037B rom/objset/mikitm876.farc 7B7860ED rom/objset/mikitm878.farc D905214C rom/objset/mikitm879.farc AF5CF234 rom/objset/mikitm880.farc BD25E12A rom/objset/mikitm882.farc 2D5C44EC rom/objset/mikitm884.farc 84AE3F8B rom/objset/mikitm893.farc 732FB880 rom/objset/mikitm894.farc 3D68729F rom/objset/mikitm895.farc DE59D2B2 rom/objset/mikitm896.farc 40BF261D rom/objset/mikitm897.farc F02579CD rom/objset/mikitm899.farc E0AC15A8 rom/objset/mikitm900.farc D844244E rom/objset/mikitm901.farc BBF01633 rom/objset/mikitm902.farc 79313676 rom/objset/mikitm904.farc 73ACF530 rom/objset/mikitm905.farc 59CD1E41 rom/objset/mikitm910.farc C786A361 rom/objset/mikitm913.farc 88C84963 rom/objset/mikitm914.farc DC02F2CC rom/objset/mikitm915.farc A72FFA2E rom/objset/mikitm916.farc 6D439E9C rom/objset/mikitm917.farc 0E00402F rom/objset/mikitm924.farc AB92DC71 rom/objset/mikitm926.farc F0A8FF49 rom/objset/mikitm927.farc 2DCEBA22 rom/objset/mikitm928.farc 1399C69A rom/objset/mikitm931.farc E788325F rom/objset/mikitm932.farc 321ED787 rom/objset/mikitm933.farc 18CAF8EA rom/objset/mikitm934.farc F1958BCA rom/objset/mikitm935.farc 065E870F rom/objset/mikitm936.farc E1E69ADD rom/objset/mikitm937.farc 8E3A3AF2 rom/objset/mikitm938.farc E5D89E28 rom/objset/mikitm939.farc B62594EC rom/objset/mikitm940.farc 4066820C rom/objset/mikitm941.farc D2FA9161 rom/objset/mikitm942.farc DDD270BB rom/objset/mikitm943.farc 32D5A0F2 rom/objset/mikitm945.farc 493A57ED rom/objset/mikitm946.farc 12C99809 rom/objset/mikitm947.farc 142B0E72 rom/objset/mikitm948.farc 95580409 rom/objset/mikitm949.farc 53BA6727 rom/objset/mikitm951.farc 610977BF rom/objset/mikitm956.farc E4917E44 rom/objset/mikitm958.farc BE5C881B rom/objset/mikitm962.farc 3AD277AA rom/objset/mikitm963.farc 839AE1FB rom/objset/mikitm965.farc 0F77BE8A rom/objset/mikitm966.farc 26E126FC rom/objset/mikitm967.farc 65499467 rom/objset/mikitm970.farc AFCECA41 rom/objset/mikitm973.farc 8007F3CA rom/objset/mikitm997.farc 8F55F15C rom/objset/mikitm998.farc 0FF31604 rom/objset/neritm000.farc B2521BF0 rom/objset/neritm001.farc 98BD582B rom/objset/neritm002.farc 099AC413 rom/objset/neritm003.farc A09AF96C rom/objset/neritm004.farc 3B12B64A rom/objset/neritm301.farc 99F68089 rom/objset/neritm302.farc 1BBEE36F rom/objset/neritm500.farc 35915FF1 rom/objset/neritm501.farc 4D7EA659 rom/objset/obj_db.bin E445FB3A rom/objset/rinitm000.farc 1CE0BA13 rom/objset/rinitm001.farc 8EF3C634 rom/objset/rinitm002.farc 25CF3A26 rom/objset/rinitm003.farc CE11B8D4 rom/objset/rinitm004.farc A545AED9 rom/objset/rinitm005.farc 1A8289E9 rom/objset/rinitm006.farc 25770111 rom/objset/rinitm008.farc 7C10142E rom/objset/rinitm009.farc 4498EA1A rom/objset/rinitm010.farc E8B9BB8C rom/objset/rinitm011.farc C553C65C rom/objset/rinitm012.farc 6B635934 rom/objset/rinitm013.farc CBCC58A8 rom/objset/rinitm014.farc 1E34D443 rom/objset/rinitm015.farc 2EC776FB rom/objset/rinitm016.farc 9DD6C751 rom/objset/rinitm017.farc 00B4CC05 rom/objset/rinitm018.farc 045B3AB0 rom/objset/rinitm019.farc BD448D91 rom/objset/rinitm020.farc 9491A5BE rom/objset/rinitm021.farc A5AB6C2C rom/objset/rinitm022.farc BB933C22 rom/objset/rinitm023.farc 76CB3914 rom/objset/rinitm024.farc 4D94208A rom/objset/rinitm026.farc A125FD8F rom/objset/rinitm027.farc 086E8CDC rom/objset/rinitm028.farc B0433515 rom/objset/rinitm029.farc 25B9792F rom/objset/rinitm030.farc 68CDB199 rom/objset/rinitm031.farc 31CC787B rom/objset/rinitm032.farc 6B537AE2 rom/objset/rinitm033.farc 64D24FBD rom/objset/rinitm034.farc 882BDBD1 rom/objset/rinitm035.farc 53610E4A rom/objset/rinitm036.farc FFA195E5 rom/objset/rinitm037.farc 73CE4AC3 rom/objset/rinitm038.farc 81586E09 rom/objset/rinitm039.farc 82DB878B rom/objset/rinitm040.farc E360C83B rom/objset/rinitm041.farc F2BB0DB4 rom/objset/rinitm043.farc 3CF6C350 rom/objset/rinitm045.farc C0868F84 rom/objset/rinitm046.farc 5F5119DD rom/objset/rinitm047.farc 7C846571 rom/objset/rinitm048.farc 815EDA6D rom/objset/rinitm301.farc 55B5F00F rom/objset/rinitm304.farc F70E650A rom/objset/rinitm309.farc A0A84AD1 rom/objset/rinitm311.farc 4B6C0436 rom/objset/rinitm312.farc 79792C3A rom/objset/rinitm313.farc 191D2241 rom/objset/rinitm314.farc 6FF3D9D3 rom/objset/rinitm315.farc E47D2F58 rom/objset/rinitm316.farc A3E3E8A4 rom/objset/rinitm320.farc 781BEAF5 rom/objset/rinitm326.farc A3EC3C94 rom/objset/rinitm329.farc B34CEAA8 rom/objset/rinitm330.farc 27AA7F45 rom/objset/rinitm333.farc 36142224 rom/objset/rinitm334.farc C4C11667 rom/objset/rinitm336.farc 5AF2510C rom/objset/rinitm337.farc 9D0993A4 rom/objset/rinitm339.farc A30B3C83 rom/objset/rinitm340.farc C9251B61 rom/objset/rinitm343.farc 3832E2B7 rom/objset/rinitm346.farc F80A12D3 rom/objset/rinitm347.farc 98C3313E rom/objset/rinitm348.farc 600A61E4 rom/objset/rinitm500.farc 14438C2C rom/objset/rinitm501.farc 3AE32A2B rom/objset/rinitm502.farc 56B4E20F rom/objset/rinitm503.farc A69F6657 rom/objset/rinitm504.farc B4D9E880 rom/objset/rinitm505.farc 9B4AAE98 rom/objset/rinitm506.farc 67BFFFED rom/objset/mikitm558.farc FC3AD288 rom/objset/mikitm608.farc BBB8CCEB rom/objset/mikitm627.farc 2615E3CF rom/objset/mikitm646.farc 3269FCC8 rom/objset/mikitm673.farc 8A6921B4 rom/objset/mikitm717.farc 25706199 rom/objset/mikitm744.farc C4C6D7E0 rom/objset/mikitm780.farc 4AFDD1BD rom/objset/mikitm843.farc 7F9422BB rom/objset/mikitm892.farc FB733C73 rom/objset/mikitm919.farc 412067BB rom/objset/mikitm944.farc 5CD005A9 rom/objset/mikitm999.farc 4983B4A8 rom/objset/rinitm007.farc 1FDB6829 rom/objset/rinitm025.farc CA540957 rom/objset/rinitm044.farc 328B5A0E rom/objset/rinitm508.farc 3380255A rom/objset/rinitm509.farc 6996CDB4 rom/objset/rinitm510.farc 58706165 rom/objset/rinitm511.farc 3273E6E7 rom/objset/rinitm512.farc A5F62E40 rom/objset/rinitm513.farc D3A5CF60 rom/objset/rinitm514.farc FAAF3BBE rom/objset/rinitm515.farc C38EC5FF rom/objset/rinitm516.farc D76A9E9D rom/objset/rinitm517.farc F5BD5DCF rom/objset/rinitm518.farc 4C02B1F8 rom/objset/rinitm519.farc E2F0A509 rom/objset/rinitm520.farc 9166D7B2 rom/objset/rinitm526.farc C27F4366 rom/objset/rinitm527.farc 3ACBE2E1 rom/objset/rinitm528.farc DC9A6A20 rom/objset/rinitm529.farc C2DE1675 rom/objset/rinitm531.farc EF24A005 rom/objset/rinitm532.farc 427C9835 rom/objset/rinitm533.farc B0F0EBF4 rom/objset/rinitm534.farc 2BA6EEA2 rom/objset/rinitm535.farc A0C8D1D2 rom/objset/rinitm536.farc 44DEC7A3 rom/objset/rinitm537.farc 3FF5BEC1 rom/objset/rinitm538.farc FB4407B6 rom/objset/rinitm539.farc 0180FB00 rom/objset/rinitm540.farc 344E1613 rom/objset/rinitm541.farc 11703356 rom/objset/rinitm543.farc 993D68F7 rom/objset/rinitm544.farc 4F973C32 rom/objset/rinitm545.farc DDF6BEDD rom/objset/rinitm547.farc E69EF14A rom/objset/rinitm548.farc 17412A63 rom/objset/rinitm550.farc C64AC124 rom/objset/rinitm701.farc 51433086 rom/objset/rinitm702.farc 38BCEF81 rom/objset/rinitm703.farc 48C373D8 rom/objset/rinitm704.farc 26B92109 rom/objset/rinitm705.farc 39E445FA rom/objset/rinitm706.farc 0EAD22ED rom/objset/rinitm707.farc E4233961 rom/objset/rinitm708.farc 076335B3 rom/objset/rinitm709.farc 8DEB87D9 rom/objset/rinitm710.farc D416B464 rom/objset/rinitm711.farc A4A60504 rom/objset/rinitm712.farc E66A0BE9 rom/objset/rinitm713.farc 90B357B3 rom/objset/rinitm714.farc BD14B675 rom/objset/rinitm715.farc 8F5D8D0C rom/objset/rinitm716.farc 9C1D997F rom/objset/rinitm717.farc ABA563EB rom/objset/rinitm719.farc D89C5C3D rom/objset/rinitm720.farc 6999DC14 rom/objset/rinitm721.farc 5648C4A6 rom/objset/rinitm725.farc F0DCA04B rom/objset/rinitm726.farc CD0464DC rom/objset/rinitm750.farc ACCBC303 rom/objset/rinitm770.farc C70ED662 rom/objset/rinitm771.farc DCB94ED0 rom/objset/rinitm775.farc 9A80B5E7 rom/objset/rinitm776.farc 224B9E1D rom/objset/rinitm777.farc FCE2D252 rom/objset/rinitm810.farc BF52DF52 rom/objset/rinitm811.farc 8788B336 rom/objset/rinitm814.farc 36B881BF rom/objset/rinitm815.farc 0CF0A778 rom/objset/rinitm816.farc CA1A5E50 rom/objset/rinitm817.farc ABFCE4D8 rom/objset/rinitm829.farc 4D29D6FA rom/objset/rinitm831.farc BF1CC690 rom/objset/rinitm836.farc F9B9D38B rom/objset/rinitm837.farc D9C5A3FA rom/objset/rinitm838.farc 4CA16471 rom/objset/rinitm839.farc 5BD047F8 rom/objset/rinitm840.farc 908CE3E0 rom/objset/rinitm843.farc 32ED10C0 rom/objset/rinitm844.farc 14EC1FF0 rom/objset/rinitm845.farc 00CC6D8D rom/objset/rinitm846.farc C3ACD73A rom/objset/rinitm848.farc 2E57C456 rom/objset/rinitm850.farc B0582774 rom/objset/rinitm997.farc C8404EE8 rom/objset/rinitm998.farc EFBEA440 rom/objset/rinitm999.farc 1878C802 rom/objset/sakitm000.farc F4408539 rom/objset/sakitm002.farc A88270E6 rom/objset/sakitm003.farc AC794199 rom/objset/sakitm005.farc 76BF43A9 rom/objset/sakitm301.farc A20D3D0F rom/objset/sakitm302.farc 67A42192 rom/objset/sakitm303.farc 7E6B0AFC rom/objset/sakitm305.farc 1BDD5E83 rom/objset/sakitm500.farc FC7E29DA rom/objset/sakitm501.farc B294F6B3 rom/objset/sakitm700.farc 49E97891 rom/objset/sakitm701.farc 73A2D211 rom/objset/sakitm775.farc BAE39E35 rom/objset/selcmn.farc 6C00B17E rom/objset/stgd2ns035.farc 192E7574 rom/objset/stgd2ns036.farc C2A4EA77 rom/objset/stgd2ns037.farc B6223EAE rom/objset/stgd2ns038.farc 6354DE96 rom/objset/stgd2ns040.farc B803364A rom/objset/stgd2ns041.farc F4391C78 rom/objset/stgd2ns042.farc D77D64BE rom/objset/stgd2ns043.farc FC31239E rom/objset/stgd2ns044.farc 8FE28DF7 rom/objset/stgd2ns045.farc 74826230 rom/objset/stgd2ns046.farc 7B05D485 rom/objset/stgd2ns047.farc B7651613 rom/objset/stgd2ns048.farc 6EC72C6F rom/objset/stgd2ns049.farc 7ABB1CA6 rom/objset/stgd2ns050.farc C6ACF03F rom/objset/stgd2ns051.farc 02ECEE08 rom/objset/stgd2ns052.farc 108EE903 rom/objset/stgd2ns053.farc 778CB975 rom/objset/stgd2ns054.farc F802E54A rom/objset/stgd2ns055.farc 4C1E9780 rom/objset/stgd2ns056.farc C0DDBADD rom/objset/stgd2ns058.farc 782FEB2E rom/objset/stgd2ns059.farc B661D221 rom/objset/stgd2ns060.farc D19481E8 rom/objset/stgd2ns061.farc 6507C843 rom/objset/stgd2ns062.farc 26AB1742 rom/objset/stgd2ns063.farc 144F61D1 rom/objset/stgd2ns064.farc A1E07BF3 rom/objset/stgd2ns065.farc 0CEFC703 rom/objset/stgd2ns066.farc E93F0FA5 rom/objset/stgd2ns067.farc F4F36FA4 rom/objset/stgd2ns068.farc 857A072E rom/objset/stgd2ns069.farc 26E6A104 rom/objset/stgd2ns070.farc 2D1BB5CE rom/objset/stgd2ns071.farc AFF194B1 rom/objset/stgd2ns072.farc 393A6D91 rom/objset/stgd2ns073.farc 54B39A54 rom/objset/stgd2ns074.farc CA461E37 rom/objset/stgd2ns076.farc 1C9278DF rom/objset/stgd2ns077.farc 57CDB479 rom/objset/stgd2ns078.farc 8737EDED rom/objset/stgd2ns079.farc 196E017B rom/objset/stgd2ns080.farc ED587020 rom/objset/stgd2ns081.farc F2316A87 rom/objset/stgd2ns082.farc C55471C9 rom/objset/stgd2pv037.farc DF6A193B rom/objset/stgd2pv037s01.farc 3690E013 rom/objset/stgd2pv037s02.farc 63E5AEE7 rom/objset/stgd2pv037s03.farc BC73DAF5 rom/objset/stgd2pv038.farc 2FFE01D9 rom/objset/stgd2pv038s01.farc C62AFB2C rom/objset/stgd2pv039.farc 162DA7D9 rom/objset/stgd2pv039s01.farc C176212B rom/objset/stgd2pv039s02.farc 37601119 rom/objset/stgd2pv039s03.farc 5A442439 rom/objset/stgd2pv040s01.farc E0ED60F2 rom/objset/stgd2pv041.farc 796290A3 rom/objset/stgd2pv041s01.farc 4304487D rom/objset/stgd2pv042.farc BC8C4561 rom/objset/stgd2pv042s01.farc 0F562225 rom/objset/stgd2pv042s02.farc 52E7CABA rom/objset/stgd2pv042s03.farc 69385D4A rom/objset/stgd2pv042s04.farc 1FA30703 rom/objset/stgd2pv042s05.farc 316C5756 rom/objset/stgd2pv042s06.farc 594CDB29 rom/objset/stgd2pv042s07.farc 6B0944CF rom/objset/stgd2pv042s08.farc 9507950A rom/objset/stgd2pv042s09.farc 9962FC3F rom/objset/stgd2pv042s10.farc D09F1AEE rom/objset/stgd2pv043.farc 9C2210D4 rom/objset/stgd2pv043s01.farc ADC105B6 rom/objset/stgd2pv044s01.farc 11F30596 rom/objset/stgd2pv044s02.farc AEF86750 rom/objset/stgd2pv044s03.farc CD7451AE rom/objset/stgd2pv045.farc B1035DCF rom/objset/stgd2pv045s01.farc 2DAAE3B7 rom/objset/stgd2pv046.farc 0252EA42 rom/objset/stgd2pv046s01.farc 86DFC96D rom/objset/stgd2pv046s02.farc F7343FA3 rom/objset/stgd2pv046s03.farc 801A0C09 rom/objset/stgd2pv046s04.farc 828F389D rom/objset/stgd2pv046s05.farc 12BD8CE7 rom/objset/stgd2pv046s06.farc C40A36E0 rom/objset/stgd2pv047.farc 69FF5869 rom/objset/stgd2pv047s01.farc 578165BD rom/objset/stgd2pv047s02.farc 1C47D717 rom/objset/stgd2pv047s03.farc D2A7E36B rom/objset/stgd2pv047s04.farc 7185A48C rom/objset/stgd2pv047s06.farc 884267CD rom/objset/stgd2pv048.farc DA31FF6F rom/objset/stgd2pv048s01.farc D091EED4 rom/objset/stgd2pv048s02.farc 3C00E521 rom/objset/stgd2pv048s03.farc 06A14ED5 rom/objset/stgd2pv050.farc 0E24AAA4 rom/objset/stgd2pv050s01.farc F4484287 rom/objset/stgd2pv051.farc AF63F638 rom/objset/stgd2pv051s01.farc 9860F37E rom/objset/stgd2pv051s02.farc 12ACF80D rom/objset/stgd2pv051s03.farc C8DB7769 rom/objset/stgd2pv051s04.farc EC8976FA rom/objset/stgd2pv051s05.farc BD7728F8 rom/objset/stgd2pv052.farc A7C391ED rom/objset/stgd2pv052s01.farc 8350FBDA rom/objset/stgd2pv053.farc 9D69353D rom/objset/stgd2pv053s02.farc 1F1A3812 rom/objset/stgd2pv053s03.farc C1D27418 rom/objset/stgd2pv053s04.farc A62E350D rom/objset/stgd2pv053s05.farc 5A9327AC rom/objset/stgd2pv053s06.farc 42EA6B6B rom/objset/stgd2pv053s07.farc 1D8D8B1D rom/objset/stgd2pv053s08.farc 3E512365 rom/objset/stgd2pv053s09.farc AD35FC25 rom/objset/stgd2pv053s10.farc D340BE87 rom/objset/stgd2pv053s11.farc E0970649 rom/objset/stgd2pv053s12.farc 1B5F4413 rom/objset/stgd2pv053s13.farc A31883FE rom/objset/stgd2pv053s14.farc EB0B3B6C rom/objset/stgd2pv053s15.farc 4F2A89C8 rom/objset/stgd2pv055.farc 90900533 rom/objset/stgd2pv055s01.farc 52DFC25D rom/objset/stgd2pv055s02.farc ABD50611 rom/objset/stgd2pv056s01.farc 5B5BCB0A rom/objset/stgd2pv057.farc BC848743 rom/objset/stgd2pv057s01.farc 21015E53 rom/objset/stgd2pv058.farc A21EBEE7 rom/objset/stgd2pv058s01.farc 90ACD9B9 rom/objset/stgd2pv058s02.farc 2AB4379C rom/objset/stgd2pv060.farc 0B47096A rom/objset/stgd2pv060s01.farc 4A8E52A6 rom/objset/stgd2pv061.farc 8ECB5EA9 rom/objset/stgd2pv061s01.farc 6143E33A rom/objset/stgd2pv061s02.farc 76091D7D rom/objset/stgd2pv062.farc 8F695143 rom/objset/stgd2pv062s01.farc 027CFAA0 rom/objset/stgd2pv063.farc CC98434A rom/objset/stgd2pv063s01.farc B7937063 rom/objset/stgd2pv063s02.farc 12CBC12E rom/objset/stgd2pv063s03.farc AC5BBC2B rom/objset/stgd2pv063s05.farc 92677306 rom/objset/stgd2pv063s06.farc 5A365509 rom/objset/stgd2pv063s07.farc 5204B987 rom/objset/stgd2pv063s08.farc DE01BFF1 rom/objset/stgd2pv063s09.farc EDE51263 rom/objset/stgd2pv063s10.farc E2DB5378 rom/objset/stgd2pv063s11.farc E9FF96E4 rom/objset/stgd2pv063s12.farc F7D0763C rom/objset/stgd2pv063s13.farc D99CF534 rom/objset/stgd2pv064.farc CFC4D04A rom/objset/stgd2pv064s01.farc 9D3E5508 rom/objset/stgd2pv064s02.farc 2D4869EB rom/objset/stgd2pv065.farc 56054511 rom/objset/stgd2pv065s01.farc 1929C59F rom/objset/stgd2pv065s02.farc 5DCDD44C rom/objset/stgd2pv065s03.farc D37F5858 rom/objset/stgd2pv065s04.farc A8FF53C9 rom/objset/stgd2pv065s06.farc 5031426F rom/objset/stgd2pv065s07.farc E0FF8121 rom/objset/stgd2pv065s08.farc 63E68070 rom/objset/stgd2pv066.farc A23CC0CE rom/objset/stgd2pv066s01.farc E2B855C0 rom/objset/stgd2pv208.farc 070EE827 rom/objset/stgd2pv208s01.farc ECBE7E9C rom/objset/stgd2pv212.farc A5CA8F17 rom/objset/stgd2pv212s01.farc 97072FFD rom/objset/stgd2pv213.farc A9332CE5 rom/objset/stgd2pv213s01.farc 3DFC5286 rom/objset/stgd2pv214.farc 7DE72A09 rom/objset/stgd2pv214s01.farc CD36227F rom/objset/stgns001.farc 73EFFE7A rom/objset/stgns002.farc 29739158 rom/objset/stgns003.farc DB5C8621 rom/objset/stgns004.farc 5B06483B rom/objset/stgns006.farc D44E3887 rom/objset/stgns007.farc D8D98DC4 rom/objset/stgns008.farc 5D382574 rom/objset/stgns009.farc D13F40A9 rom/objset/stgns010.farc 58B6A548 rom/objset/stgns011.farc 2928F893 rom/objset/stgns012.farc 9F972D06 rom/objset/stgns013.farc 3EA04FA7 rom/objset/stgns014.farc D337F3E3 rom/objset/stgns015.farc B4DFDB6A rom/objset/stgns016.farc 4C31DD9B rom/objset/stgns017.farc 0EF68401 rom/objset/stgns018.farc EB32FCE2 rom/objset/stgns019.farc A346BFA1 rom/objset/stgns020.farc E47F3C35 rom/objset/stgns021.farc 0D063125 rom/objset/stgns022.farc 7D6D7392 rom/objset/rinitm507.farc CE40F900 rom/objset/rinitm530.farc 01459399 rom/objset/rinitm700.farc 5ED9D417 rom/objset/rinitm718.farc 095354BF rom/objset/rinitm826.farc 49AB3C2C rom/objset/sakitm001.farc F082F642 rom/objset/stgd2ns039.farc 943DF5B0 rom/objset/stgd2ns057.farc F1A347A9 rom/objset/stgd2ns075.farc F4D2EBF0 rom/objset/stgd2pv040.farc 15FCCDD6 rom/objset/stgd2pv044.farc 8E9A8894 rom/objset/stgd2pv047s05.farc 880A2F90 rom/objset/stgd2pv053s01.farc FDD48050 rom/objset/stgd2pv056.farc FC144AFF rom/objset/stgd2pv063s04.farc 66011330 rom/objset/stgd2pv065s05.farc 510CED24 rom/objset/stgns024.farc A684597E rom/objset/stgns025.farc 8C482FA9 rom/objset/stgns026.farc A12F59ED rom/objset/stgns027.farc C5E801A6 rom/objset/stgns028.farc 9ACADB79 rom/objset/stgns029.farc 7A24AAE9 rom/objset/stgns030.farc BF8B7CB9 rom/objset/stgns031.farc F4069CF6 rom/objset/stgns032.farc 1AE2EFBB rom/objset/stgns033.farc 07862A2E rom/objset/stgns034.farc BB12D554 rom/objset/stgns083.farc FDDF12F9 rom/objset/stgns084.farc 271BD899 rom/objset/stgns085.farc C0EE1418 rom/objset/stgns086.farc 9347AF5E rom/objset/stgns087.farc 895B9479 rom/objset/stgns088.farc 8C5D579F rom/objset/stgns090.farc 883A442F rom/objset/stgns091.farc 7DC1A43F rom/objset/stgns092.farc B02C7186 rom/objset/stgns093.farc 14746DF1 rom/objset/stgns094.farc EAB3A7BB rom/objset/stgns095.farc 576EE392 rom/objset/stgns096.farc 976A7766 rom/objset/stgns097.farc C42CC276 rom/objset/stgns098.farc 31CBA5C9 rom/objset/stgns099.farc 8ACB21EA rom/objset/stgns100.farc F2FCBE3A rom/objset/stgns101.farc C450796E rom/objset/stgns102.farc 600E45A6 rom/objset/stgns103.farc 13CF066A rom/objset/stgns104.farc 7E991874 rom/objset/stgns105.farc DF4870C5 rom/objset/stgns106.farc 66AB1F98 rom/objset/stgns108.farc 9A27F58D rom/objset/stgns109.farc 91CF3488 rom/objset/stgns110.farc 3CB15441 rom/objset/stgns111.farc ECE121F6 rom/objset/stgns112.farc D6790738 rom/objset/stgns113.farc DF5CAB3B rom/objset/stgns114.farc E2209BF9 rom/objset/stgns115.farc 4322C430 rom/objset/stgns116.farc 8E8231BD rom/objset/stgns117.farc E272C107 rom/objset/stgns118.farc 9A7CF904 rom/objset/stgns119.farc DF7CB28B rom/objset/stgns120.farc 07912045 rom/objset/stgns121.farc 2E12A7C2 rom/objset/stgns122.farc 26310387 rom/objset/stgns123.farc DEFABFA5 rom/objset/stgns124.farc 8E3CFA46 rom/objset/stgns126.farc 7986F9FF rom/objset/stgns210.farc D0EE4193 rom/objset/stgns221.farc DEDFAB1E rom/objset/stgns223.farc 343CF37B rom/objset/stgns249.farc 4838F241 rom/objset/stgns257.farc 8302D3CE rom/objset/stgns263.farc 6844F88A rom/objset/stgns266.farc C08898D5 rom/objset/stgns267.farc DFD31347 rom/objset/stgns272.farc 62B18556 rom/objset/stgns292.farc AF2B51C6 rom/objset/stgpv001.farc EBF2C5B7 rom/objset/stgpv001s01.farc 0FE4EB4F rom/objset/stgpv001s02.farc FD3469FC rom/objset/stgpv001s03.farc 9722374D rom/objset/stgpv001s04.farc C3F75754 rom/objset/stgpv001s05.farc CB19F4AF rom/objset/stgpv001s07.farc F5A70622 rom/objset/stgpv003.farc DDDF3CEB rom/objset/stgpv003s01.farc EDD9B3C6 rom/objset/stgpv003s02.farc F69C199C rom/objset/stgpv003s03.farc 1FA74B5A rom/objset/stgpv003s04.farc 58F7DB04 rom/objset/stgpv003s05.farc 6FF6E7DC rom/objset/stgpv003s06.farc A2F3C633 rom/objset/stgpv003s07.farc 01B9C494 rom/objset/stgpv003s08.farc BCB5AC25 rom/objset/stgpv003s09.farc 6D0C1711 rom/objset/stgpv004.farc 1DA326F9 rom/objset/stgpv004s01.farc 48F57E1D rom/objset/stgpv004s02.farc CB29B914 rom/objset/stgpv004s03.farc D40D2772 rom/objset/stgpv004s04.farc 4B79D864 rom/objset/stgpv004s06.farc F69D15D8 rom/objset/stgpv004s07.farc 4DCDB6D9 rom/objset/stgpv005.farc AE6D1261 rom/objset/stgpv005s01.farc 45CC64F2 rom/objset/stgpv005s02.farc 0E965C02 rom/objset/stgpv005s03.farc 3852E18C rom/objset/stgpv005s04.farc 023C5B2A rom/objset/stgpv005s05.farc 41B3D0C2 rom/objset/stgpv005s06.farc 245501C1 rom/objset/stgpv006.farc 92CF117C rom/objset/stgpv006s01.farc 876341E5 rom/objset/stgpv006s02.farc 45946A4C rom/objset/stgpv007.farc 967AA88E rom/objset/stgpv007s01.farc 2581CABD rom/objset/stgpv007s02.farc 78A5E978 rom/objset/stgpv007s03.farc 3F908B3F rom/objset/stgpv007s05.farc E75A9D06 rom/objset/stgpv007s06.farc 430A1778 rom/objset/stgpv007s07.farc 8DFB74C8 rom/objset/stgpv007s08.farc C1AD54C9 rom/objset/stgpv007s09.farc 4C37785B rom/objset/stgpv007s10.farc E684E3BF rom/objset/stgpv007s11.farc 6A66CE42 rom/objset/stgpv007s12.farc 8DB69FE0 rom/objset/stgpv008.farc A1A26D7C rom/objset/stgpv008s01.farc 6C4EFB5B rom/objset/stgpv008s02.farc 61E5E8D0 rom/objset/stgpv008s03.farc 83ABB89E rom/objset/stgpv008s04.farc A3F92CC5 rom/objset/stgpv008s05.farc 1402146F rom/objset/stgpv008s06.farc 4035E52A rom/objset/stgpv008s07.farc 9A3DE83D rom/objset/stgpv008s09.farc 46A7F163 rom/objset/stgpv008s10.farc C9A532C7 rom/objset/stgpv009.farc 9EBC77A1 rom/objset/stgpv009s01.farc 49415531 rom/objset/stgpv009s02.farc F2685E17 rom/objset/stgpv009s03.farc 12FAC66C rom/objset/stgpv009s04.farc 316817F0 rom/objset/stgpv009s05.farc 8CD2C417 rom/objset/stgpv009s06.farc CA224973 rom/objset/stgpv009s07.farc CDE0594D rom/objset/stgpv009s08.farc 0A3DB351 rom/objset/stgpv009s09.farc E90A7F95 rom/objset/stgpv009s10.farc 0EC1D0A8 rom/objset/stgpv011.farc 29494693 rom/objset/stgpv011s01.farc 3A6BD311 rom/objset/stgpv011s02.farc A8012ECA rom/objset/stgpv011s04.farc B4AC6EF1 rom/objset/stgpv011s05.farc C443174C rom/objset/stgpv011s06.farc 1FC609F7 rom/objset/stgpv012.farc A0418F37 rom/objset/stgpv012s01.farc B2CB13CD rom/objset/stgpv013.farc 13282652 rom/objset/stgpv013s01.farc A5F5C46F rom/objset/stgpv013s02.farc 7D261DEA rom/objset/stgpv013s03.farc 9E9346DA rom/objset/stgpv013s04.farc 4957BD7C rom/objset/stgpv014.farc B85CF8A1 rom/objset/stgpv014s01.farc 6AADEFC3 rom/objset/stgpv015.farc D7A88233 rom/objset/stgpv015s01.farc 9D70F347 rom/objset/stgpv015s02.farc 74BA51BF rom/objset/stgpv015s03.farc E94673B3 rom/objset/stgpv015s05.farc DDA6FF50 rom/objset/stgpv015s06.farc 23BC306A rom/objset/stgpv018.farc 7086F28E rom/objset/stgpv018s01.farc 5F4784EF rom/objset/stgpv018s02.farc 39F59A99 rom/objset/stgpv018s03.farc A7611176 rom/objset/stgpv018s04.farc FD195A55 rom/objset/stgpv018s05.farc 0FF20572 rom/objset/stgpv018s06.farc 882BF896 rom/objset/stgpv018s07.farc 33A31B09 rom/objset/stgpv018s08.farc 8D431390 rom/objset/stgpv018s09.farc 99142B14 rom/objset/stgpv019.farc AD680973 rom/objset/stgpv019s01.farc E9AE7B5F rom/objset/stgpv019s02.farc 35A75F25 rom/objset/stgpv019s03.farc E549256B rom/objset/stgpv019s05.farc DD68DDA5 rom/objset/stgpv019s06.farc F2EDDA03 rom/objset/stgpv019s07.farc 3CFBB806 rom/objset/stgpv019s08.farc 2122B2EE rom/objset/stgpv019s09.farc 4DF1EBEC rom/objset/stgpv019s10.farc A61D0E4F rom/objset/stgpv019s11.farc 3B51BF46 rom/objset/stgpv019s12.farc 50574425 rom/objset/stgpv019s13.farc AA0B25EA rom/objset/stgpv019s14.farc DE4FD4C5 rom/objset/stgpv020.farc 029320AA rom/objset/stgpv020s01.farc 569AFC50 rom/objset/stgpv020s02.farc 55363F06 rom/objset/stgpv020s03.farc 5B80EB80 rom/objset/stgpv022.farc D981A69E rom/objset/stgpv022s01.farc F86203A8 rom/objset/stgpv024s01.farc 14AF99EE rom/objset/stgpv024s02.farc D8287422 rom/objset/stgpv024s03.farc 217B373E rom/objset/stgpv024s04.farc A2984D8D rom/objset/stgpv024s05.farc 86EE91DA rom/objset/stgpv024s06.farc 0632E285 rom/objset/stgpv024s07.farc E343899E rom/objset/stgpv024s08.farc 62DB9D2B rom/objset/stgpv024s09.farc AE7EF34E rom/objset/stgpv024s10.farc 413976E7 rom/objset/stgpv024s11.farc 09F00655 rom/objset/stgpv024s12.farc F0A4E1F5 rom/objset/stgpv024s13.farc 4FD6707E rom/objset/stgpv024s14.farc E1516EE9 rom/objset/stgpv025.farc AD4EA59D rom/objset/stgpv025s01.farc 96FE5889 rom/objset/stgpv025s03.farc B29C886A rom/objset/stgpv025s04.farc 9289D8C9 rom/objset/stgpv025s05.farc DEE9930C rom/objset/stgpv025s06.farc FA8BD2E6 rom/objset/stgpv025s07.farc A497ABC3 rom/objset/stgpv025s08.farc 4990AE3D rom/objset/stgpv025s09.farc BBF2320D rom/objset/stgpv025s10.farc 6C550C6A rom/objset/stgpv025s11.farc 7FA3A3CE rom/objset/stgpv025s12.farc C08C1E3D rom/objset/stgpv025s13.farc 6CA49377 rom/objset/stgpv025s14.farc C0DFE306 rom/objset/stgpv025s15.farc 0F7856C1 rom/objset/stgpv025s16.farc 7E78E16D rom/objset/stgpv025s17.farc 151ABB5A rom/objset/stgpv025s18.farc A9F9DEED rom/objset/stgpv025s20.farc 2A0100D8 rom/objset/stgpv025s21.farc E777345C rom/objset/stgpv025s22.farc A462C04A rom/objset/stgpv025s23.farc BA7FC070 rom/objset/stgpv025s24.farc F8B57620 rom/objset/stgpv025s25.farc ACC34D9C rom/objset/stgpv025s26.farc 97968573 rom/objset/stgpv025s27.farc 4A9151D6 rom/objset/stgpv028.farc 6FB06A5E rom/objset/stgpv028s01.farc 2C9CF20D rom/objset/stgpv067.farc DDA50BB4 rom/objset/stgpv067s01.farc B71B0643 rom/objset/stgpv079.farc 8DA2EB92 rom/objset/stgpv079s01.farc 15C7E440 rom/objset/stgpv081.farc E28A4535 rom/objset/stgpv081s01.farc 78B7F9A1 rom/objset/stgpv081s03.farc 188C3CB7 rom/objset/stgpv081s04.farc 9E89978B rom/objset/stgpv081s05.farc 8C420931 rom/objset/stgpv081s06.farc 16BD8E96 rom/objset/stgpv081s07.farc 09B48724 rom/objset/stgpv081s08.farc 3183CEBE rom/objset/stgpv081s09.farc 17A2A95D rom/objset/stgpv081s10.farc DEB2B466 rom/objset/stgpv081s11.farc A7F15B15 rom/objset/stgpv081s12.farc 4B50C00E rom/objset/stgpv082.farc 5FC14B81 rom/objset/stgpv082s01.farc 67C75C62 rom/objset/stgpv082s02.farc 2129E0FD rom/objset/stgpv082s03.farc 140F7A7A rom/objset/stgpv082s04.farc 266C4B6F rom/objset/stgpv082s05.farc 8780E911 rom/objset/stgpv082s07.farc E9D550CE rom/objset/stgpv082s10.farc A3FC1F77 rom/objset/stgpv082s11.farc B56FBB94 rom/objset/stgpv082s12.farc FE047BA3 rom/objset/stgpv082s21.farc 60A7E352 rom/objset/stgpv082s22.farc 96795893 rom/objset/stgpv082s23.farc 2F63AF5D rom/objset/stgpv082s24.farc D626C28F rom/objset/stgpv082s27.farc 48391A00 rom/objset/stgpv082s28.farc 3C35FCF5 rom/objset/stgpv082s29.farc 4CF1F94A rom/objset/stgpv082s41.farc 57AAED20 rom/objset/stgpv082s42.farc D03781D5 rom/objset/stgpv082s51.farc 0D5A1236 rom/objset/stgpv082s52.farc 5298C00F rom/objset/stgpv082s53.farc B2A5E65D rom/objset/stgns023.farc 4FCAD8FF rom/objset/stgns089.farc A8E44D91 rom/objset/stgns107.farc F21BD4FF rom/objset/stgns125.farc D04B0FAA rom/objset/stgpv001s06.farc D55815E2 rom/objset/stgpv004s05.farc 3B6EE581 rom/objset/stgpv007s04.farc 38BA2388 rom/objset/stgpv008s08.farc 31481898 rom/objset/stgpv011s03.farc 2B17D991 rom/objset/stgpv015s04.farc 7B54AEB2 rom/objset/stgpv019s04.farc C5F5B04D rom/objset/stgpv024.farc CE896299 rom/objset/stgpv025s02.farc B718F0DA rom/objset/stgpv025s19.farc AF500F13 rom/objset/stgpv081s02.farc 0D09B08C rom/objset/stgpv082s55.farc 9EB1DD14 rom/objset/stgpv082s61.farc 87F1450C rom/objset/stgpv083.farc A3549EA4 rom/objset/stgpv083s01.farc F34755D4 rom/objset/stgpv083s02.farc 0D146F33 rom/objset/stgpv083s03.farc 766E7855 rom/objset/stgpv083s04.farc 94E75C03 rom/objset/stgpv083s05.farc ACE36A9A rom/objset/stgpv083s06.farc 45481EFE rom/objset/stgpv083s07.farc 4F7ECEEC rom/objset/stgpv083s08.farc 596906BF rom/objset/stgpv083s09.farc C3C03641 rom/objset/stgpv083s10.farc 55F2CA0E rom/objset/stgpv083s11.farc E5A6AFA2 rom/objset/stgpv083s12.farc 8C53B2BD rom/objset/stgpv083s13.farc 169216A0 rom/objset/stgpv083s15.farc 282CF4CE rom/objset/stgpv083s16.farc 4EB6C353 rom/objset/stgpv083s17.farc 8B088318 rom/objset/stgpv083s18.farc 6BB35252 rom/objset/stgpv083s19.farc 046A6A43 rom/objset/stgpv083s20.farc B2472113 rom/objset/stgpv083s21.farc 987DD224 rom/objset/stgpv083s22.farc 44E590D8 rom/objset/stgpv083s23.farc A5AD552A rom/objset/stgpv083s24.farc 34D4BC71 rom/objset/stgpv083s25.farc D65C215E rom/objset/stgpv083s26.farc 5C166AB8 rom/objset/stgpv083s27.farc CD691D7E rom/objset/stgpv083s28.farc CDF17BB1 rom/objset/stgpv084.farc A391A09C rom/objset/stgpv084s01.farc BDD27F44 rom/objset/stgpv085s01.farc 8E34F4AB rom/objset/stgpv086.farc F0BB0EB6 rom/objset/stgpv086s01.farc 930A0EAD rom/objset/stgpv086s02.farc F70B177C rom/objset/stgpv087.farc DC76C888 rom/objset/stgpv087s01.farc 0BD3BF01 rom/objset/stgpv087s02.farc 9B4167CE rom/objset/stgpv087s03.farc 3871740F rom/objset/stgpv087s04.farc C44F85DE rom/objset/stgpv087s05.farc 2B91F1A8 rom/objset/stgpv087s06.farc 21BBF314 rom/objset/stgpv087s07.farc E67AA90D rom/objset/stgpv087s08.farc 89EAC56A rom/objset/stgpv087s09.farc 1A704605 rom/objset/stgpv087s10.farc A1D7FAAA rom/objset/stgpv087s11.farc 5DDDAA01 rom/objset/stgpv087s13.farc 627D5297 rom/objset/stgpv087s14.farc 27DB066E rom/objset/stgpv087s15.farc 0A1A3EE8 rom/objset/stgpv087s16.farc B2BD27DF rom/objset/stgpv087s17.farc 79D2D0CC rom/objset/stgpv088.farc AE611093 rom/objset/stgpv088s01.farc 38D58245 rom/objset/stgpv088s02.farc 250276F4 rom/objset/stgpv088s03.farc 5B763B19 rom/objset/stgpv088s04.farc 7C8A5158 rom/objset/stgpv088s05.farc 32AC5615 rom/objset/stgpv088s06.farc F12691A4 rom/objset/stgpv088s07.farc D4FC411C rom/objset/stgpv088s08.farc 2EE09285 rom/objset/stgpv088s09.farc 15267007 rom/objset/stgpv088s10.farc 0DE3D3EE rom/objset/stgpv088s12.farc 14E9F0EA rom/objset/stgpv088s13.farc 37C20FA9 rom/objset/stgpv088s14.farc 1994BBBB rom/objset/stgpv089.farc ECE8FD21 rom/objset/stgpv089s01.farc 9E26DD4C rom/objset/stgpv089s02.farc C98E4169 rom/objset/stgpv089s03.farc DC483DC0 rom/objset/stgpv089s04.farc 0303C129 rom/objset/stgpv089s05.farc 19E0D04D rom/objset/stgpv090.farc 4C60DACA rom/objset/stgpv090s01.farc C86D177B rom/objset/stgpv090s02.farc 6D597282 rom/objset/stgpv091.farc 018EE225 rom/objset/stgpv091s01.farc 4E5361CB rom/objset/stgpv091s02.farc D5D4EFDE rom/objset/stgpv091s03.farc FAB590C0 rom/objset/stgpv091s05.farc 2C7FFD4E rom/objset/stgpv091s06.farc A0966630 rom/objset/stgpv091s07.farc 22E3F0B4 rom/objset/stgpv091s08.farc AF4F59AD rom/objset/stgpv091s09.farc 9AD1FEF7 rom/objset/stgpv091s10.farc C7DE3F3F rom/objset/stgpv091s11.farc 329EAA7A rom/objset/stgpv091s12.farc EDDC038E rom/objset/stgpv091s13.farc 9D5074FC rom/objset/stgpv091s14.farc FE6E698D rom/objset/stgpv092.farc 9FA47105 rom/objset/stgpv092s01.farc 7CCB0256 rom/objset/stgpv092s02.farc 5D3C2353 rom/objset/stgpv092s03.farc 3F7E1DAA rom/objset/stgpv092s04.farc 36BA4951 rom/objset/stgpv092s05.farc 4791FF19 rom/objset/stgpv092s07.farc 2A430550 rom/objset/stgpv092s08.farc 5DE4A184 rom/objset/stgpv092s09.farc A8344A11 rom/objset/stgpv092s10.farc 36DBD025 rom/objset/stgpv092s11.farc 4B8391D9 rom/objset/stgpv092s12.farc 5737C3E6 rom/objset/stgpv093.farc 7E691E78 rom/objset/stgpv093s01.farc D78E9A20 rom/objset/stgpv094.farc 11C27E49 rom/objset/stgpv094s01.farc 8CA15851 rom/objset/stgpv094s02.farc BBAC66BE rom/objset/stgpv094s03.farc 6BA6F110 rom/objset/stgpv094s04.farc 0200A32B rom/objset/stgpv094s05.farc 8DE7E8C7 rom/objset/stgpv094s06.farc 6E540B78 rom/objset/stgpv094s07.farc 70DF9799 rom/objset/stgpv094s09.farc 47BD74DE rom/objset/stgpv094s10.farc 3AE3BCF0 rom/objset/stgpv094s11.farc 091D30BC rom/objset/stgpv094s12.farc 30F3B729 rom/objset/stgpv094s13.farc DAAD9701 rom/objset/stgpv094s14.farc 13B586D9 rom/objset/stgpv094s15.farc C709B99D rom/objset/stgpv094s16.farc DF975A46 rom/objset/stgpv094s17.farc CE74F9DE rom/objset/stgpv094s18.farc BCEBFFDA rom/objset/stgpv094s19.farc 735103DA rom/objset/stgpv094s20.farc 5AEE0018 rom/objset/stgpv095.farc 96082727 rom/objset/stgpv095s02.farc A7C97F96 rom/objset/stgpv096.farc AF432F1D rom/objset/stgpv096s01.farc 61C95D3B rom/objset/stgpv096s03.farc 4C9E8AAF rom/objset/stgpv096s04.farc 38298F35 rom/objset/stgpv096s05.farc 528434A1 rom/objset/stgpv096s06.farc 61AA32A0 rom/objset/stgpv096s07.farc EF302965 rom/objset/stgpv096s08.farc 3A71860A rom/objset/stgpv096s09.farc 281DFB5A rom/objset/stgpv097.farc 2D493896 rom/objset/stgpv097s01.farc B376F787 rom/objset/stgpv103.farc A20BF7B5 rom/objset/stgpv103s01.farc 7DD23A95 rom/objset/stgpv103s02.farc 43A3873B rom/objset/stgpv103s03.farc 1F408085 rom/objset/stgpv104.farc B83F1A3D rom/objset/stgpv104s01.farc 841CA9E5 rom/objset/stgpv104s02.farc 0510390B rom/objset/stgpv104s04.farc BDAA27D7 rom/objset/stgpv218.farc B0F7E81F rom/objset/stgpv218s01.farc 9A245EBA rom/objset/stgpv218s02.farc 6ED03836 rom/objset/stgpv218s03.farc 8A4B3A1A rom/objset/stgpv218s04.farc 3D8AA481 rom/objset/stgpv219.farc 614AD732 rom/objset/stgpv219s01.farc 9B633EDD rom/objset/stgpv219s02.farc 5FD797AE rom/objset/stgpv219s03.farc 92D19D10 rom/objset/stgpv219s04.farc 6C931898 rom/objset/stgpv219s05.farc CCA7D2C2 rom/objset/stgpv219s07.farc 8F20B8D7 rom/objset/stgpv219s08.farc D92F59F8 rom/objset/stgpv219s09.farc 47593985 rom/objset/stgpv219s10.farc 5B7FD750 rom/objset/stgpv219s12.farc B25B7A2C rom/objset/stgpv219s13.farc EB5847A0 rom/objset/stgpv219s14.farc 642E6E4F rom/objset/stgpv220.farc B2E20500 rom/objset/stgpv220s01.farc 9441A959 rom/objset/stgpv220s02.farc D728D4F3 rom/objset/stgpv220s03.farc 3BFC02C4 rom/objset/stgpv221.farc 0FD00FF7 rom/objset/stgpv221s01.farc 61BF8CF9 rom/objset/stgpv221s02.farc F8D4BE6E rom/objset/stgpv221s03.farc 752C6DF4 rom/objset/stgpv221s04.farc 86B9DD2B rom/objset/stgpv221s05.farc 7463C9C8 rom/objset/stgpv221s06.farc C716DF30 rom/objset/stgpv221s07.farc 8EFCBB6D rom/objset/stgpv221s08.farc A0A776F8 rom/objset/stgpv221s10.farc 72F624A0 rom/objset/stgpv221s11.farc 82E8BD82 rom/objset/stgpv221s12.farc BFB9C189 rom/objset/stgpv221s14.farc F1ED4365 rom/objset/stgpv222.farc 690DF608 rom/objset/stgpv222s01.farc CFFF240F rom/objset/stgpv222s02.farc CED33175 rom/objset/stgpv223.farc 2EB588E4 rom/objset/stgpv223s01.farc 403AA958 rom/objset/stgpv223s02.farc 0FF4A78F rom/objset/stgpv223s03.farc A9AEDD81 rom/objset/stgpv223s04.farc FA4DB857 rom/objset/stgpv223s05.farc 79A436EF rom/objset/stgpv223s06.farc E09FD6D4 rom/objset/stgpv223s07.farc 3BD180D9 rom/objset/stgpv223s08.farc 2AC4712A rom/objset/stgpv223s10.farc 48FAD9DB rom/objset/stgpv224.farc 96AF6C49 rom/objset/stgpv224s01.farc 412E0D56 rom/objset/stgpv224s02.farc 17BC0525 rom/objset/stgpv224s03.farc 6D000A42 rom/objset/stgpv224s04.farc 3899F51B rom/objset/stgpv225.farc 422B9651 rom/objset/stgpv225s01.farc 84D391BA rom/objset/stgpv225s02.farc 9CB01FB7 rom/objset/stgpv225s03.farc 520DACEE rom/objset/stgpv226.farc E1F0E028 rom/objset/stgpv226s01.farc A033F805 rom/objset/stgpv227.farc 5C270E53 rom/objset/stgpv227s01.farc E4D52DFD rom/objset/stgpv228.farc 82F681F9 rom/objset/stgpv228s01.farc 0CCE35A9 rom/objset/stgpv228s02.farc 50576918 rom/objset/stgpv228s04.farc 64669F50 rom/objset/stgpv231.farc BF0FEF19 rom/objset/stgpv231s01.farc DC726698 rom/objset/stgpv231s02.farc 82712A68 rom/objset/stgpv231s03.farc 078CDF4B rom/objset/stgpv231s04.farc 0A9CD94E rom/objset/stgpv231s05.farc 24FC27BD rom/objset/stgpv231s06.farc 2790BE61 rom/objset/stgpv231s07.farc 05D197DB rom/objset/stgpv232.farc B883855C rom/objset/stgpv232s01.farc 24BE73EE rom/objset/stgpv232s02.farc F77CBAD2 rom/objset/stgpv232s03.farc 90784CBE rom/objset/stgpv233.farc 26CC4838 rom/objset/stgpv233s01.farc 4C1837A8 rom/objset/stgpv233s02.farc 7161A703 rom/objset/stgpv233s04.farc 5D8B1D97 rom/objset/stgpv233s05.farc 41F2DF2D rom/objset/stgpv233s06.farc 789C3CCA rom/objset/stgpv233s07.farc 94C0B432 rom/objset/stgpv233s08.farc B904DD8F rom/objset/stgpv234.farc 80B190F6 rom/objset/stgpv234s01.farc B26DA687 rom/objset/stgpv234s02.farc 347FB783 rom/objset/stgpv235.farc 6ECD940E rom/objset/stgpv235s01.farc 048928EF rom/objset/stgpv235s02.farc 6591F112 rom/objset/stgpv235s06.farc B4411CAD rom/objset/stgpv235s07.farc 3D0485BE rom/objset/stgpv235s08.farc 3B735CE9 rom/objset/stgpv236.farc 15EF72FB rom/objset/stgpv236s01.farc 75794A55 rom/objset/stgpv236s03.farc E2C33611 rom/objset/stgpv236s04.farc 68FE7FE8 rom/objset/stgpv236s05.farc C5637520 rom/objset/stgpv236s06.farc 721490C0 rom/objset/stgpv236s07.farc 5F3740ED rom/objset/stgpv238.farc ACCBC1F3 rom/objset/stgpv238s01.farc D5FB5B46 rom/objset/stgpv239.farc 04B609CC rom/objset/stgpv239s01.farc D11A433F rom/objset/stgpv240.farc 4712F822 rom/objset/stgpv240s01.farc CED51C46 rom/objset/stgpv240s02.farc A006678B rom/objset/stgpv240s03.farc 52378BDD rom/objset/stgpv241.farc 9EC40C93 rom/objset/stgpv241s01.farc 36DCEE0E rom/objset/stgpv241s02.farc 626DF33A rom/objset/stgpv241s03.farc DC2762D7 rom/objset/stgpv082s54.farc C21EE95E rom/objset/stgpv083s14.farc 3074AE33 rom/objset/stgpv085.farc 3B72BA85 rom/objset/stgpv087s12.farc B71CC499 rom/objset/stgpv088s11.farc 37518A10 rom/objset/stgpv091s04.farc F85FB3AE rom/objset/stgpv092s06.farc 8CC7DE3E rom/objset/stgpv094s08.farc 7C6F9349 rom/objset/stgpv096s02.farc E4895988 rom/objset/stgpv104s03.farc 805F3C9D rom/objset/stgpv219s11.farc 9C77E7BC rom/objset/stgpv221s09.farc 47FCBBB4 rom/objset/stgpv223s09.farc 019453BC rom/objset/stgpv228s03.farc 24B82FD0 rom/objset/stgpv233s03.farc 9D2A3C3D rom/objset/stgpv242.farc 817FCBE0 rom/objset/stgpv242s01.farc 8C59CE72 rom/objset/stgpv243.farc 0C291F38 rom/objset/stgpv243hrc.farc 950A0962 rom/objset/stgpv243s01.farc 99BCABFB rom/objset/stgpv243s02.farc 351FED71 rom/objset/stgpv243s04.farc E26BE3AE rom/objset/stgpv243s05.farc E201FACF rom/objset/stgpv243s08.farc 6C941C49 rom/objset/stgpv244.farc 7470CB2A rom/objset/stgpv244s01.farc 174CD654 rom/objset/stgpv244s02.farc B8EECF39 rom/objset/stgpv246.farc C4FC0338 rom/objset/stgpv246s01.farc 7C642F5C rom/objset/stgpv247.farc FDA02199 rom/objset/stgpv247s01.farc 8500E68D rom/objset/stgpv248.farc D9F4F099 rom/objset/stgpv248s02.farc 37C0677E rom/objset/stgpv248s03.farc F16DD404 rom/objset/stgpv248s04.farc E24A692C rom/objset/stgpv248s05.farc F7D3A09A rom/objset/stgpv249.farc 57767856 rom/objset/stgpv249s01.farc 93051CE5 rom/objset/stgpv250.farc 98CC1938 rom/objset/stgpv250s01.farc FA289B43 rom/objset/stgpv251.farc 3599E849 rom/objset/stgpv251s01.farc 17813E66 rom/objset/stgpv251s02.farc CAAFF8BD rom/objset/stgpv251s03.farc 9B96CDDE rom/objset/stgpv251s04.farc D1ED45D7 rom/objset/stgpv251s05.farc 3D1EF987 rom/objset/stgpv251s06.farc 808A3DD5 rom/objset/stgpv251s07.farc 07788E2A rom/objset/stgpv253.farc 0AB566E9 rom/objset/stgpv253hrc.farc 8AF3BB25 rom/objset/stgpv253s01.farc DD628ABD rom/objset/stgpv253s02.farc DF0309DE rom/objset/stgpv253s03.farc CF86EE7A rom/objset/stgpv253s04.farc 844D4F54 rom/objset/stgpv253s05.farc 1E19F868 rom/objset/stgpv253s06.farc 27D60F3B rom/objset/stgpv253s07.farc DA92E6DA rom/objset/stgpv253s08.farc 16A31706 rom/objset/stgpv253s09.farc 1F08EB2F rom/objset/stgpv255.farc 88C775A0 rom/objset/stgpv255hrc.farc 3C3EBBD1 rom/objset/stgpv255s01.farc 89612465 rom/objset/stgpv257.farc 666EA6C6 rom/objset/stgpv257s01.farc CAA1D231 rom/objset/stgpv259s01.farc 393221FE rom/objset/stgpv260.farc 8DF11578 rom/objset/stgpv260s01.farc B65F9CAF rom/objset/stgpv261.farc 3B8F49AC rom/objset/stgpv261hrc.farc 920030BC rom/objset/stgpv261s01.farc 3D41618E rom/objset/stgpv261s02.farc BC43A10F rom/objset/stgpv262.farc D9B87FDC rom/objset/stgpv262hrc.farc 4A97C01F rom/objset/stgpv262s01.farc 78AE10EC rom/objset/stgpv262s02.farc A715CA68 rom/objset/stgpv262s03.farc 0D420C74 rom/objset/stgpv262s04.farc 7E4483A4 rom/objset/stgpv262s05.farc F51B9B39 rom/objset/stgpv262s06.farc 39F0592C rom/objset/stgpv262s07.farc 510747B6 rom/objset/stgpv262s09.farc 172D8ED1 rom/objset/stgpv262s10.farc 6519D9D7 rom/objset/stgpv262s11.farc CD3DFC6B rom/objset/stgpv262s12.farc 80F1EE2C rom/objset/stgpv262s13.farc B5FC81A2 rom/objset/stgpv432.farc 9AF0E224 rom/objset/stgpv432hrc.farc 4ED38649 rom/objset/stgpv432s01.farc 7AAE5FA0 rom/objset/stgpv432s02.farc B4FB55D1 rom/objset/stgpv432s03.farc A7DAE049 rom/objset/stgpv433.farc 238AEEFF rom/objset/stgpv433hrc.farc 74C72299 rom/objset/stgpv433s01.farc 48C4DAF9 rom/objset/stgpv433s02.farc 40E77A38 rom/objset/stgpv433s03.farc 627C20F6 rom/objset/stgpv433s04.farc 31B1E42F rom/objset/stgpv433s06.farc 4B50C4D6 rom/objset/stgpv434.farc 2DCA8E33 rom/objset/stgpv434hrc.farc 2D2C2916 rom/objset/stgpv434s01.farc CB461532 rom/objset/stgpv435.farc E2172782 rom/objset/stgpv435hrc.farc 9F411703 rom/objset/stgpv435s01.farc 94655AF5 rom/objset/stgpv435s02.farc 473F7F98 rom/objset/stgpv435s03.farc E6B19297 rom/objset/stgpv435s04.farc FC5295AB rom/objset/stgpv435s05.farc 2B161381 rom/objset/stgpv435s06.farc F904788B rom/objset/stgpv435s07.farc 6AF35D0C rom/objset/stgpv435s08.farc 9701FBBD rom/objset/stgpv441.farc 07BFAFD8 rom/objset/stgpv441s01.farc 3C336321 rom/objset/stgpv600hrc.farc B6459E31 rom/objset/stgpv600s01.farc 35AC4CA7 rom/objset/stgpv600s02.farc 82D85A32 rom/objset/stgpv600s03.farc 4CB27C12 rom/objset/stgpv600s04.farc F2EABB9E rom/objset/stgpv601.farc 96C81CB8 rom/objset/stgpv601hrc.farc 3803B707 rom/objset/stgpv601s01.farc 1D3AD2BF rom/objset/stgpv601s02.farc 4DC4924C rom/objset/stgpv601s03.farc 1D346705 rom/objset/stgpv601s04.farc F8A5DC9A rom/objset/stgpv602.farc 64887D19 rom/objset/stgpv602hrc.farc BA919573 rom/objset/stgpv602s01.farc 2C7DFC6A rom/objset/stgpv602s02.farc 7FDF92BB rom/objset/stgpv602s03.farc 46AD7224 rom/objset/stgpv603.farc 5A61DF90 rom/objset/stgpv603s01.farc 992622E1 rom/objset/stgpv604.farc C2410CA6 rom/objset/stgpv604s01.farc E3FAF3E0 rom/objset/stgpv604s02.farc 991C23E3 rom/objset/stgpv604s03.farc CF7264DC rom/objset/stgpv604s04.farc BE102077 rom/objset/stgpv604s05.farc D839924D rom/objset/stgpv604s07.farc A9C9FBDF rom/objset/stgpv605.farc D05F1A62 rom/objset/stgpv605s01.farc 3EA05211 rom/objset/stgpv605s02.farc 2FB0189F rom/objset/stgpv605s03.farc DD7C370D rom/objset/stgpv605s04.farc 6913D6FA rom/objset/stgpv605s05.farc 1D46DF64 rom/objset/stgpv607.farc 4B4AC09C rom/objset/stgpv607hrc.farc 60054582 rom/objset/stgpv608.farc 4986621E rom/objset/stgpv608hrc.farc 6C6B3A9D rom/objset/stgpv608s01.farc C5AEBB5F rom/objset/stgpv609.farc 12CF11D6 rom/objset/stgpv609hrc.farc 4774C11D rom/objset/stgpv609s01.farc 6A82B12E rom/objset/stgpv609s02.farc 9631FF53 rom/objset/stgpv609s03.farc D6597FA1 rom/objset/stgpv610.farc AD4506D4 rom/objset/stgpv610s01.farc 2F082C46 rom/objset/stgpv610s02.farc 5D09CFFD rom/objset/stgpv610s03.farc 09BA15A1 rom/objset/stgpv611.farc C62D6FB1 rom/objset/stgpv611s01.farc 165B9CD0 rom/objset/stgpv612.farc 150E314D rom/objset/stgpv612hrc.farc 41731EDB rom/objset/stgpv612s01.farc 37FA723B rom/objset/stgpv612s03.farc 1A1F1337 rom/objset/stgpv612s04.farc 85D5437E rom/objset/stgpv613.farc 91DD5156 rom/objset/stgpv613hrc.farc F34515A7 rom/objset/stgpv613s01.farc 308CC486 rom/objset/stgpv613s02.farc 4D3CB881 rom/objset/stgpv613s03.farc FEEA5773 rom/objset/stgpv614.farc AD44D044 rom/objset/stgpv614hrc.farc 8D587D4A rom/objset/stgpv614s01.farc 2DAE1AFE rom/objset/stgpv614s02.farc D2CFF316 rom/objset/stgpv614s03.farc 01066417 rom/objset/stgpv614s04.farc 06F3A59F rom/objset/stgpv614s05.farc 14126D13 rom/objset/stgpv614s06.farc BD315EEE rom/objset/stgpv615.farc 3F0FE1FA rom/objset/stgpv615s01.farc 6A215A76 rom/objset/stgpv616.farc 438CDBF0 rom/objset/stgpv616s01.farc 328B77ED rom/objset/stgpv616s02.farc A623F607 rom/objset/stgpv616s03.farc D67C7F66 rom/objset/stgpv617.farc 8DBB570E rom/objset/stgpv617hrc.farc 1A3EFCF3 rom/objset/stgpv617s01.farc 09B52782 rom/objset/stgpv617s02.farc BF0C36CA rom/objset/stgpv617s03.farc 101C211A rom/objset/stgpv617s04.farc 30F65AC6 rom/objset/stgpv618.farc B95D7FC2 rom/objset/stgpv618s01.farc 6479FDEA rom/objset/stgpv618s02.farc D7396598 rom/objset/stgpv618s03.farc 755EAA86 rom/objset/stgpv618s04.farc 22751984 rom/objset/stgpv618s05.farc 8012D69A rom/objset/stgpv619.farc 8CF9F5F5 rom/objset/stgpv619s01.farc 80F7B129 rom/objset/stgpv619s02.farc 6998F423 rom/objset/stgpv619s03.farc EAB7F601 rom/objset/stgpv619s04.farc EB4ABF38 rom/objset/stgpv620.farc 44C8FC9D rom/objset/stgpv620s01.farc 056B3595 rom/objset/stgpv621.farc E9690906 rom/objset/stgpv621s01.farc 517A5A10 rom/objset/stgpv622.farc 4FFC0634 rom/objset/stgpv622hrc.farc 4E956CB6 rom/objset/stgpv622s01.farc 16AFC7D4 rom/objset/stgpv623.farc 05BBFFF1 rom/objset/stgpv623hrc.farc D7DABADA rom/objset/stgpv623s01.farc 617B25D5 rom/objset/stgpv623s02.farc 12996043 rom/objset/stgpv623s03.farc 14F6C0A1 rom/objset/stgpv624s01.farc C680EFDF rom/objset/stgpv624s02.farc A05D9717 rom/objset/stgpv625.farc C153FA5E rom/objset/stgpv625hrc.farc 38E4EFC5 rom/objset/stgpv625s01.farc C780B0A9 rom/objset/stgpv625s02.farc E38C5B44 rom/objset/stgpv625s03.farc AA3F0C3E rom/objset/stgpv625s04.farc DDF3A127 rom/objset/stgpv625s05.farc 08366732 rom/objset/stgpv626.farc D39FC1FC rom/objset/stgpv626s01.farc E74218E4 rom/objset/stgpv626s02.farc D17EA453 rom/objset/stgpv627.farc 458C1D17 rom/objset/stgpv627s01.farc 4E3F9EB6 rom/objset/stgpv627s02.farc 0E065857 rom/objset/stgpv627s03.farc 1F5F8B2E rom/objset/stgpv628.farc 93649855 rom/objset/stgpv628s01.farc C3BBFC3A rom/objset/stgpv628s02.farc 145F2308 rom/objset/stgpv629.farc AC36EAF2 rom/objset/stgpv629s01.farc 25E82286 rom/objset/stgpv630.farc D4D21AB5 rom/objset/stgpv630hrc.farc C4B622F6 rom/objset/stgpv630s01.farc 1A57C691 rom/objset/stgpv630s02.farc 7EC3245A rom/objset/stgpv630s03.farc DCC57C8E rom/objset/stgpv630s04.farc DCCD13DE rom/objset/stgpv630s05.farc CC15C745 rom/objset/stgpv631.farc 2B2C5ED9 rom/objset/stgpv631s01.farc 557CC7BA rom/objset/stgpv631s02.farc 5F1C063A rom/objset/stgpv637.farc C2D00193 rom/objset/stgpv637hrc.farc F4F06B38 rom/objset/stgpv637s01.farc C9E44B61 rom/objset/stgpv638.farc BB2D7F0D rom/objset/stgpv638s01.farc 4F1854B9 rom/objset/stgpv638s02.farc 20681E61 rom/objset/stgpv639.farc 5D53F5EC rom/objset/stgpv639hrc.farc 9B931037 rom/objset/stgpv639s01.farc 75E076B2 rom/objset/stgpv639s02.farc 13B7FFBE rom/objset/stgpv639s03.farc F077B1CA rom/objset/stgpv639s04.farc 69B6EF42 rom/objset/stgpv639s05.farc 60D7E060 rom/objset/stgpv639s06.farc D27E95D0 rom/objset/stgpv640.farc B8886FD2 rom/objset/stgpv640hrc.farc 82BEF2D0 rom/objset/stgpv640s01.farc 33088DC1 rom/objset/stgpv640s02.farc A8125B6F rom/objset/stgpv641.farc 091ABDBA rom/objset/stgpv641hrc.farc A32EE0D9 rom/objset/stgpv642.farc C24DA152 rom/objset/stgpv642hrc.farc AB88F674 rom/objset/stgpv642s01.farc F7CF314E rom/objset/stgpv642s02.farc 1686DB3F rom/objset/stgpv642s03.farc 86E8F40F rom/objset/stgpv642s04.farc 7242F2E0 rom/objset/stgpv710.farc E2A19A98 rom/objset/stgpv710hrc.farc 5A4494BF rom/objset/stgpv710s01.farc 61EC9BA2 rom/objset/stgpv710s02.farc 37897009 rom/objset/stgpv710s03.farc EE6FDCF4 rom/objset/stgpv710s04.farc FA63D3C3 rom/objset/stgpv722.farc 90BF4B87 rom/objset/stgpv722s01.farc 62729687 rom/objset/stgpv723.farc D8568046 rom/objset/stgpv723s01.farc 230CEF9B rom/objset/stgpv723s02.farc BD56709A rom/objset/stgpv241s04.farc DF46AF91 rom/objset/stgpv248s01.farc 3A86FBF1 rom/objset/stgpv251s08.farc BC4EF310 rom/objset/stgpv259.farc 214B1EE4 rom/objset/stgpv262s08.farc 528BFEEC rom/objset/stgpv433s05.farc 93BD1B31 rom/objset/stgpv600.farc E5F5E545 rom/objset/stgpv602s04.farc 36B92245 rom/objset/stgpv607s01.farc 61E8B23C rom/objset/stgpv612s02.farc 2F6BE588 rom/objset/stgpv615hrc.farc D0E3BC6F rom/objset/stgpv618s06.farc 5E1462F3 rom/objset/stgpv624.farc 4234FFA1 rom/objset/stgpv628hrc.farc 511DA91D rom/objset/stgpv637s02.farc E5F5D33A rom/objset/stgpv641s01.farc 6670E2B1 rom/objset/stgpv724.farc 187AECCA rom/objset/stgpv727hrc.farc 647DA044 rom/objset/stgpv731s03.farc 282B2D80 rom/objset/stgpv736.farc C8EB0A8B rom/objset/stgpv740s03.farc DE2DA0F8 rom/objset/stgpv724hrc.farc 893FFFBF rom/objset/stgpv724s01.farc 3AECB5C5 rom/objset/stgpv724s02.farc 8F4A2BFF rom/objset/stgpv724s03.farc FD01A35D rom/objset/stgpv724s04.farc A4AFEB3C rom/objset/stgpv724s05.farc D0523DCF rom/objset/stgpv725.farc F3E323EE rom/objset/stgpv725hrc.farc AD79F954 rom/objset/stgpv725s01.farc 73451BA9 rom/objset/stgpv725s02.farc 2243F4E9 rom/objset/stgpv725s03.farc E57AAB27 rom/objset/stgpv725s04.farc 0F449245 rom/objset/stgpv726.farc 58D66E3B rom/objset/stgpv726hrc.farc DBB246BE rom/objset/stgpv726s01.farc A1D8823B rom/objset/stgpv727.farc D3FA57A7 rom/objset/stgpv727s01.farc 45975746 rom/objset/stgpv728.farc B84D9BE8 rom/objset/stgpv728s01.farc E0CF56B8 rom/objset/stgpv728s03.farc BEBA316A rom/objset/stgpv728s04.farc 4B2C848E rom/objset/stgpv729.farc 04F9BF08 rom/objset/stgpv729hrc.farc EDBB0721 rom/objset/stgpv729s01.farc 661B7041 rom/objset/stgpv729s03.farc DAD9DBD1 rom/objset/stgpv730.farc 670817E4 rom/objset/stgpv730hrc.farc 21ACF89E rom/objset/stgpv730s01.farc 68DF9598 rom/objset/stgpv730s02.farc A6D83322 rom/objset/stgpv731.farc 98CCD4B3 rom/objset/stgpv731s01.farc 54FFBD44 rom/objset/stgpv731s02.farc 37345393 rom/objset/stgpv732.farc E532676B rom/objset/stgpv732hrc.farc FE51FCDC rom/objset/stgpv732s01.farc 29D6CB49 rom/objset/stgpv732s02.farc CD3BB463 rom/objset/stgpv732s03.farc C1AD5442 rom/objset/stgpv733.farc 8B3D5A32 rom/objset/stgpv733hrc.farc A173BEB5 rom/objset/stgpv733s01.farc 662360B5 rom/objset/stgpv733s02.farc 45D6D7AD rom/objset/stgpv733s03.farc 31C93118 rom/objset/stgpv733s04.farc 4D798069 rom/objset/stgpv733s05.farc 8208FE83 rom/objset/stgpv734.farc FBD8DCF9 rom/objset/stgpv734s01.farc 43DB9322 rom/objset/stgpv734s02.farc 42786730 rom/objset/stgpv734s04.farc FFA59366 rom/objset/stgpv734s05.farc 1DDCF9BA rom/objset/stgpv736hrc.farc A4751A79 rom/objset/stgpv736s01.farc F07DA220 rom/objset/stgpv736s02.farc 4B0C74DF rom/objset/stgpv737.farc 086046A5 rom/objset/stgpv737hrc.farc 85336A38 rom/objset/stgpv737s01.farc 892878F4 rom/objset/stgpv737s02.farc 0837A799 rom/objset/stgpv738.farc 5644AE84 rom/objset/stgpv738hrc.farc 19C48FF9 rom/objset/stgpv738s01.farc CBC78A80 rom/objset/stgpv738s02.farc B7B1D12B rom/objset/stgpv739.farc 3852BE48 rom/objset/stgpv739hrc.farc 9AC568BC rom/objset/stgpv739s01.farc CC99C379 rom/objset/stgpv740.farc 63866FE4 rom/objset/stgpv740s01.farc EF8C6D77 rom/objset/stgpv740s02.farc F17836A3 rom/objset/stgpv740s04.farc 79070A0C rom/objset/stgpv740s05.farc E436D275 rom/objset/stgpv832.farc 1F471E6F rom/objset/stgpv832s01.farc 04323691 rom/objset/stgtst.farc 13D3DD97 rom/objset/stgtst001.farc 738E3F47 rom/objset/stgtst002.farc 038372CB rom/objset/stgtst003.farc 23CCF07C rom/objset/stgtst004.farc 0ACDF94C rom/objset/stgtst005.farc 92A73550 rom/objset/stgtst006.farc 9B919C6E rom/objset/stgtst007.farc A375642C rom/objset/stgtst008.farc 08A12951 rom/objset/stgtst009.farc A6F31112 rom/objset/stgtst010.farc A8B713F7 rom/objset/tetitm000.farc 850B51A6 rom/objset/tetitm001.farc 0F01B480 rom/objset/tetitm002.farc 3B4B9AC6 rom/objset/tetitm003.farc 9DC7A41F rom/objset/tetitm301.farc 437D4CE9 rom/objset/tetitm303.farc 6895AFC0 rom/objset/tetitm500.farc CDBEE21C rom/objset/tetitm502.farc D2DC77B2 rom/objset/tetitm503.farc 29E193B8 rom/objset/tetitm700.farc 73B8A7DB rom/objset/tex_db.bin DA00A0FE rom/osage_play_data/lukitm022_joha_outer_22__divskn.farc D7E69092 rom/osage_play_data/mikitm032_joha_outer_32__divskn.farc 5E5EDFD8 rom/osage_play_data/mikitm546_atam_atama_46__divskn.farc 3498E4B1 rom/osage_play_data/hakitm001_joha_outer_01__divskn.farc 64AEFF71 rom/osage_play_data/hakitm002_joha_outer_02__divskn.farc 71AE9692 rom/osage_play_data/hakitm003_joha_outer_03__divskn.farc 3607899C rom/osage_play_data/hakitm004_joha_outer_04__divskn.farc 5C629601 rom/osage_play_data/hakitm500_atam_atama_00__divskn.farc 974DC87A rom/osage_play_data/hakitm501_atam_atama_01__divskn.farc D2CBB816 rom/osage_play_data/hakitm502_atam_atama_02__divskn.farc AAFC6244 rom/osage_play_data/hakitm700_atam_zujo_00__divskn.farc 034F53B8 rom/osage_play_data/kaiitm001_joha_outer_01__divskn.farc CF61EE4D rom/osage_play_data/kaiitm002_joha_outer_02__divskn.farc 0F4CEB52 rom/osage_play_data/kaiitm003_joha_outer_03__divskn.farc DC79AC9B rom/osage_play_data/kaiitm004_joha_outer_04__divskn.farc 144B7C17 rom/osage_play_data/kaiitm008_joha_outer_08__divskn.farc 43B24B1F rom/osage_play_data/kaiitm009_joha_outer_09__divskn.farc 4EEF9EDE rom/osage_play_data/kaiitm010_joha_outer_10__divskn.farc 5BC902D6 rom/osage_play_data/kaiitm011_joha_outer_11__divskn.farc 45447E2A rom/osage_play_data/kaiitm012_joha_outer_12__divskn.farc 65140DBF rom/osage_play_data/kaiitm015_joha_outer_15__divskn.farc F3268750 rom/osage_play_data/kaiitm016_joha_outer_16__divskn.farc C1F8F59B rom/osage_play_data/kaiitm018_joha_outer_18__divskn.farc 4B312420 rom/osage_play_data/kaiitm019_joha_outer_19__divskn.farc 08727917 rom/osage_play_data/kaiitm020_joha_outer_20__divskn.farc 0F216CB9 rom/osage_play_data/kaiitm022_joha_outer_22__divskn.farc 17BB3CB8 rom/osage_play_data/kaiitm024_joha_outer_24__divskn.farc 71F86E86 rom/osage_play_data/kaiitm027_joha_outer_27__divskn.farc 4E9C4EC6 rom/osage_play_data/kaiitm028_joha_outer_28__divskn.farc 149BB47A rom/osage_play_data/kaiitm029_joha_outer_29__divskn.farc EE4D9633 rom/osage_play_data/kaiitm030_joha_outer_30__divskn.farc 948F8761 rom/osage_play_data/kaiitm031_joha_outer_31__divskn.farc B834DCBD rom/osage_play_data/kaiitm032_joha_outer_32__divskn.farc 68F29348 rom/osage_play_data/kaiitm033_joha_outer_33__divskn.farc C4F75DCF rom/osage_play_data/kaiitm034_joha_outer_34__divskn.farc 307E29B8 rom/osage_play_data/kaiitm036_joha_outer_36__divskn.farc AB9E0049 rom/osage_play_data/kaiitm041_joha_outer_41__divskn.farc 9D4A3EEB rom/osage_play_data/kaiitm042_joha_outer_42__divskn.farc E821B5C9 rom/osage_play_data/kaiitm500_atam_atama_00__divskn.farc 61FFD070 rom/osage_play_data/kaiitm502_atam_atama_02__divskn.farc 85C85453 rom/osage_play_data/kaiitm503_atam_atama_03__divskn.farc 194280CB rom/osage_play_data/kaiitm504_atam_atama_04__divskn.farc 7C148EBC rom/osage_play_data/kaiitm505_atam_atama_05__divskn.farc 9AAA1DE4 rom/osage_play_data/kaiitm506_atam_atama_06__divskn.farc EBEF609D rom/osage_play_data/kaiitm507_atam_atama_07__divskn.farc 3B51590A rom/osage_play_data/kaiitm508_atam_atama_08__divskn.farc 2486990E rom/osage_play_data/kaiitm509_atam_atama_09__divskn.farc 8B972A3C rom/osage_play_data/kaiitm510_atam_atama_10__divskn.farc 145F7482 rom/osage_play_data/kaiitm520_atam_atama_20__divskn.farc 7550BF43 rom/osage_play_data/kaiitm522_atam_atama_22__divskn.farc FEC3EC71 rom/osage_play_data/kaiitm523_atam_atama_23__divskn.farc 690AA4EA rom/osage_play_data/kaiitm527_atam_atama_27__divskn.farc 6E724AA5 rom/osage_play_data/kaiitm528_atam_atama_28__divskn.farc 20AC855E rom/osage_play_data/kaiitm529_atam_atama_29__divskn.farc E5299721 rom/osage_play_data/kaiitm531_atam_atama_31__divskn.farc 7E19DAF7 rom/osage_play_data/kaiitm532_atam_atama_32__divskn.farc E3E763FA rom/osage_play_data/kaiitm533_atam_atama_33__divskn.farc 67B70CC3 rom/osage_play_data/kaiitm534_atam_atama_34__divskn.farc 6A4F180A rom/osage_play_data/kaiitm536_atam_atama_36__divskn.farc 9C80A5B5 rom/osage_play_data/kaiitm541_atam_atama_41__divskn.farc CF0D893A rom/osage_play_data/kaiitm542_atam_atama_42__divskn.farc D750CCCC rom/osage_play_data/kaiitm701_atam_zujo_01__divskn.farc 8C98294F rom/osage_play_data/kaiitm705_atam_zujo_05__divskn.farc 51EE6584 rom/osage_play_data/kaiitm750_joha_neck_50__divskn.farc 83146C6E rom/osage_play_data/kaiitm751_joha_neck_51__divskn.farc AA5F1674 rom/osage_play_data/kaiitm775_joha_ushiro_75__divskn.farc BDFF3443 rom/osage_play_data/lenitm001_joha_outer_01__divskn.farc 1B50547F rom/osage_play_data/lenitm002_joha_outer_02__divskn.farc BA22379E rom/osage_play_data/lenitm003_joha_outer_03__divskn.farc 831A6143 rom/osage_play_data/lenitm004_joha_outer_04__divskn.farc B8E4D760 rom/osage_play_data/lenitm005_joha_outer_05__divskn.farc FF86DC43 rom/osage_play_data/lenitm007_joha_outer_07__divskn.farc FD324705 rom/osage_play_data/lenitm008_joha_outer_08__divskn.farc 3778AD15 rom/osage_play_data/lenitm009_joha_outer_09__divskn.farc 0E9DED8E rom/osage_play_data/lenitm010_joha_outer_10__divskn.farc 7925001B rom/osage_play_data/kaiitm006_joha_outer_06__divskn.farc 6B159016 rom/osage_play_data/kaiitm025_joha_outer_25__divskn.farc DE17F460 rom/osage_play_data/kaiitm501_atam_atama_01__divskn.farc 02FB87B2 rom/osage_play_data/kaiitm524_atam_atama_24__divskn.farc DE956A3E rom/osage_play_data/kaiitm706_atam_zujo_06__divskn.farc 913EA944 rom/osage_play_data/lenitm011_joha_outer_11__divskn.farc 2A7E6421 rom/osage_play_data/lenitm025_joha_outer_25__divskn.farc 95D04766 rom/osage_play_data/lenitm040_joha_outer_40__divskn.farc 6234792C rom/osage_play_data/lenitm522_atam_atama_22__divskn.farc FF4C4623 rom/osage_play_data/lenitm536_atam_atama_36__divskn.farc 253D84D2 rom/osage_play_data/lukitm008_joha_outer_08__divskn.farc 3D3AC86A rom/osage_play_data/lenitm012_joha_outer_12__divskn.farc 500A29DA rom/osage_play_data/lenitm013_joha_outer_13__divskn.farc A80701F9 rom/osage_play_data/lenitm014_joha_outer_14__divskn.farc DB459114 rom/osage_play_data/lenitm015_joha_outer_15__divskn.farc BFF3FAA7 rom/osage_play_data/lenitm016_joha_outer_16__divskn.farc CB0E6533 rom/osage_play_data/lenitm017_joha_outer_17__divskn.farc 6720F16A rom/osage_play_data/lenitm018_joha_outer_18__divskn.farc 27A42D7F rom/osage_play_data/lenitm019_joha_outer_19__divskn.farc 2DDC5D5A rom/osage_play_data/lenitm021_joha_outer_21__divskn.farc 4ED1C934 rom/osage_play_data/lenitm022_joha_outer_22__divskn.farc F6FB0707 rom/osage_play_data/lenitm023_joha_outer_23__divskn.farc 03EE190F rom/osage_play_data/lenitm024_joha_outer_24__divskn.farc C2990A92 rom/osage_play_data/lenitm026_joha_outer_26__divskn.farc 220DD19C rom/osage_play_data/lenitm027_joha_outer_27__divskn.farc EC7B11B9 rom/osage_play_data/lenitm028_joha_outer_28__divskn.farc 435C0675 rom/osage_play_data/lenitm029_joha_outer_29__divskn.farc CF311AED rom/osage_play_data/lenitm030_joha_outer_30__divskn.farc 386BD654 rom/osage_play_data/lenitm031_joha_outer_31__divskn.farc 5E6463AC rom/osage_play_data/lenitm032_joha_outer_32__divskn.farc 711D2859 rom/osage_play_data/lenitm033_joha_outer_33__divskn.farc 15575657 rom/osage_play_data/lenitm034_joha_outer_34__divskn.farc 57131694 rom/osage_play_data/lenitm035_joha_outer_35__divskn.farc 57211AA5 rom/osage_play_data/lenitm036_joha_outer_36__divskn.farc 4513DE58 rom/osage_play_data/lenitm038_joha_outer_38__divskn.farc 4FD59F2D rom/osage_play_data/lenitm500_atam_atama_00__divskn.farc AA447887 rom/osage_play_data/lenitm501_atam_atama_01__divskn.farc E5B2F460 rom/osage_play_data/lenitm502_atam_atama_02__divskn.farc 324622B1 rom/osage_play_data/lenitm503_atam_atama_03__divskn.farc D99263F3 rom/osage_play_data/lenitm504_atam_atama_04__divskn.farc 4BA676F4 rom/osage_play_data/lenitm505_atam_atama_05__divskn.farc 71590B5C rom/osage_play_data/lenitm506_atam_atama_06__divskn.farc B8E35CF2 rom/osage_play_data/lenitm508_atam_atama_08__divskn.farc DA1DA3A3 rom/osage_play_data/lenitm509_atam_atama_09__divskn.farc BAD3485E rom/osage_play_data/lenitm511_atam_atama_11__divskn.farc 958AECEB rom/osage_play_data/lenitm519_atam_atama_19__divskn.farc 5067DAA4 rom/osage_play_data/lenitm521_atam_atama_21__divskn.farc 9B7D56A7 rom/osage_play_data/lenitm523_atam_atama_23__divskn.farc 57E11D55 rom/osage_play_data/lenitm524_atam_atama_24__divskn.farc A38AF304 rom/osage_play_data/lenitm525_atam_atama_25__divskn.farc AB1BF7F8 rom/osage_play_data/lenitm526_atam_atama_26__divskn.farc 797D9806 rom/osage_play_data/lenitm528_atam_atama_28__divskn.farc F230740B rom/osage_play_data/lenitm529_atam_atama_29__divskn.farc 42E070B6 rom/osage_play_data/lenitm530_atam_atama_30__divskn.farc 9DF5C72C rom/osage_play_data/lenitm531_atam_atama_31__divskn.farc 517ADA9F rom/osage_play_data/lenitm532_atam_atama_32__divskn.farc A3679EE8 rom/osage_play_data/lenitm533_atam_atama_33__divskn.farc B1460C49 rom/osage_play_data/lenitm534_atam_atama_34__divskn.farc 56EFC33A rom/osage_play_data/lenitm535_atam_atama_35__divskn.farc CC492770 rom/osage_play_data/lenitm537_atam_atama_37__divskn.farc 9FD5E3FD rom/osage_play_data/lenitm538_atam_atama_38__divskn.farc 5AA01BB7 rom/osage_play_data/lenitm540_atam_atama_40__divskn.farc 8001863C rom/osage_play_data/lenitm700_atam_zujo_00__divskn.farc E4EBE2A4 rom/osage_play_data/lenitm775_joha_ushiro_75__divskn.farc C931DE39 rom/osage_play_data/lukitm001_joha_outer_01_zzc__divskn.farc 9EC00EBF rom/osage_play_data/lukitm002_joha_outer_02__divskn.farc 27451C7D rom/osage_play_data/lukitm003_joha_outer_03__divskn.farc 89FECDF1 rom/osage_play_data/lukitm004_joha_outer_04__divskn.farc 576075CA rom/osage_play_data/lukitm005_joha_outer_05__divskn.farc 0E79BD88 rom/osage_play_data/lukitm006_joha_outer_06__divskn.farc 80E7D2C1 rom/osage_play_data/lukitm007_joha_outer_07__divskn.farc 20E3C626 rom/osage_play_data/lukitm009_joha_outer_09__divskn.farc D1F2D067 rom/osage_play_data/lukitm010_joha_outer_10__divskn.farc D1978128 rom/osage_play_data/lukitm011_joha_outer_11__divskn.farc 41F10151 rom/osage_play_data/lukitm012_joha_outer_12__divskn.farc 52DB825D rom/osage_play_data/lukitm013_joha_outer_13__divskn.farc F5AB4873 rom/osage_play_data/lukitm014_joha_outer_14__divskn.farc 3312B4FE rom/osage_play_data/lukitm015_joha_outer_15__divskn.farc 48599601 rom/osage_play_data/lukitm017_joha_outer_17_zzc__divskn.farc A36F194B rom/osage_play_data/lukitm018_joha_outer_18__divskn.farc 90D2A4F8 rom/osage_play_data/lukitm019_joha_outer_19__divskn.farc 1FF5B626 rom/osage_play_data/lukitm020_joha_outer_20__divskn.farc A7D8D876 rom/osage_play_data/lukitm021_joha_outer_21__divskn.farc 66C72D30 rom/osage_play_data/lukitm023_joha_outer_23__divskn.farc A640EAA3 rom/osage_play_data/lukitm024_joha_outer_24__divskn.farc 8CC3E344 rom/osage_play_data/lukitm025_joha_outer_25__divskn.farc 082E866D rom/osage_play_data/lukitm026_joha_outer_26__divskn.farc 61226C12 rom/osage_play_data/lukitm027_joha_outer_27__divskn.farc A31B5E9E rom/osage_play_data/lukitm028_joha_outer_28__divskn.farc ADE33F01 rom/osage_play_data/lukitm029_joha_outer_29__divskn.farc F26ABE41 rom/osage_play_data/lukitm030_joha_outer_30__divskn.farc 9186E7D3 rom/osage_play_data/lukitm031_joha_outer_31__divskn.farc 898DF20F rom/osage_play_data/lukitm032_joha_outer_32__divskn.farc 6CFF0097 rom/osage_play_data/lukitm033_joha_outer_33__divskn.farc A0620DC1 rom/osage_play_data/lukitm034_joha_outer_34__divskn.farc 9C1C718A rom/osage_play_data/lukitm036_joha_outer_36__divskn.farc 289EB73C rom/osage_play_data/lukitm037_joha_outer_37__divskn.farc 3C46660A rom/osage_play_data/lukitm038_joha_outer_38__divskn.farc B7C279FF rom/osage_play_data/lukitm039_joha_outer_39__divskn.farc AB39B9F8 rom/osage_play_data/lukitm040_joha_outer_40__divskn.farc CD3A4673 rom/osage_play_data/lukitm042_joha_outer_42__divskn.farc B6067176 rom/osage_play_data/lukitm311_ude_hand_11__divskn.farc F30F7C07 rom/osage_play_data/lukitm500_atam_atama_00__divskn.farc B93882CD rom/osage_play_data/lukitm501_atam_atama_01__divskn.farc 22E19FD4 rom/osage_play_data/lukitm502_atam_atama_02__divskn.farc 0EFD4EF1 rom/osage_play_data/lukitm503_atam_atama_03__divskn.farc A428D8AC rom/osage_play_data/lukitm504_atam_atama_04__divskn.farc 502FF1E8 rom/osage_play_data/lukitm506_atam_atama_06__divskn.farc ABA03C37 rom/osage_play_data/lukitm507_atam_atama_07__divskn.farc B4B910BB rom/osage_play_data/lukitm508_atam_atama_08__divskn.farc 5B4878EF rom/osage_play_data/lukitm509_atam_atama_09__divskn.farc 23ECEFBA rom/osage_play_data/lukitm510_atam_atama_10__divskn.farc D7F48472 rom/osage_play_data/lukitm511_atam_atama_11__divskn.farc 5EC35074 rom/osage_play_data/lukitm512_atam_atama_12__divskn.farc F9C0BD3A rom/osage_play_data/lukitm513_atam_atama_13__divskn.farc AD85B2D9 rom/osage_play_data/lukitm514_atam_atama_14__divskn.farc 5DC53DBC rom/osage_play_data/lukitm515_atam_atama_15__divskn.farc B77BC644 rom/osage_play_data/lukitm516_atam_atama_16__divskn.farc 78F796C8 rom/osage_play_data/lukitm517_atam_atama_17__divskn.farc 1334B801 rom/osage_play_data/lukitm526_atam_atama_26__divskn.farc 10701210 rom/osage_play_data/lukitm527_atam_atama_27__divskn.farc 510BAE78 rom/osage_play_data/lukitm528_atam_atama_28__divskn.farc F0CE548A rom/osage_play_data/lukitm529_atam_atama_29__divskn.farc 735912DC rom/osage_play_data/lukitm530_atam_atama_30__divskn.farc F61681E8 rom/osage_play_data/lukitm531_atam_atama_31__divskn.farc 17CB5F4F rom/osage_play_data/lukitm532_atam_atama_32__divskn.farc 3692483B rom/osage_play_data/lukitm533_atam_atama_33__divskn.farc 87BE804A rom/osage_play_data/lukitm534_atam_atama_34__divskn.farc 029E700A rom/osage_play_data/lukitm535_atam_atama_35__divskn.farc F533A71C rom/osage_play_data/lukitm536_atam_atama_36__divskn.farc 4B0FFF58 rom/osage_play_data/lukitm537_atam_atama_37__divskn.farc E9150E91 rom/osage_play_data/lukitm539_atam_atama_39__divskn.farc B47F2386 rom/osage_play_data/lukitm540_atam_atama_40__divskn.farc 4982FCCE rom/osage_play_data/lukitm542_atam_atama_42__divskn.farc 6D5E6886 rom/osage_play_data/lukitm700_atam_zujo_00__divskn.farc 20CF1FA6 rom/osage_play_data/lukitm702_atam_zujo_02__divskn.farc 049F536F rom/osage_play_data/lukitm703_atam_zujo_03__divskn.farc B581C99C rom/osage_play_data/lukitm705_atam_zujo_05__divskn.farc 4291C268 rom/osage_play_data/meiitm001_joha_outer_01__divskn.farc 26448548 rom/osage_play_data/meiitm002_joha_outer_02__divskn.farc FAC58C8F rom/osage_play_data/meiitm003_joha_outer_03__divskn.farc 1AE37773 rom/osage_play_data/meiitm004_joha_outer_04__divskn.farc 1C4323D9 rom/osage_play_data/meiitm005_joha_outer_05__divskn.farc E8061B41 rom/osage_play_data/meiitm008_joha_outer_08__divskn.farc 2EE259D7 rom/osage_play_data/meiitm009_joha_outer_09__divskn.farc B70281DB rom/osage_play_data/meiitm010_joha_outer_10__divskn.farc 00CF376D rom/osage_play_data/meiitm011_joha_outer_11__divskn.farc 9341CE80 rom/osage_play_data/meiitm012_joha_outer_12__divskn.farc A903C356 rom/osage_play_data/meiitm013_joha_outer_13__divskn.farc 1D9EE80A rom/osage_play_data/meiitm014_joha_outer_14__divskn.farc 7F707696 rom/osage_play_data/meiitm015_joha_outer_15__divskn.farc 97AD5888 rom/osage_play_data/meiitm016_joha_outer_16__divskn.farc B785D526 rom/osage_play_data/meiitm017_joha_outer_17_zzc__divskn.farc 214A6C72 rom/osage_play_data/meiitm018_joha_outer_18__divskn.farc BABB429A rom/osage_play_data/meiitm019_joha_outer_19__divskn.farc 18FF17BD rom/osage_play_data/meiitm021_joha_outer_21__divskn.farc 63D2B778 rom/osage_play_data/meiitm022_joha_outer_22__divskn.farc 03284D3C rom/osage_play_data/meiitm023_joha_outer_23__divskn.farc E8E2284E rom/osage_play_data/meiitm024_joha_outer_24__divskn.farc 535209FD rom/osage_play_data/meiitm025_joha_outer_25__divskn.farc EBE5FD42 rom/osage_play_data/meiitm026_joha_outer_26__divskn.farc C82F0BBC rom/osage_play_data/meiitm027_joha_outer_27__divskn.farc 47A83F07 rom/osage_play_data/meiitm028_joha_outer_28__divskn.farc D7AFA076 rom/osage_play_data/meiitm029_joha_outer_29__divskn.farc 955328A5 rom/osage_play_data/meiitm030_joha_outer_30__divskn.farc 818A75C0 rom/osage_play_data/meiitm032_joha_outer_32__divskn.farc 2B2610AE rom/osage_play_data/meiitm033_joha_outer_33__divskn.farc 93416601 rom/osage_play_data/meiitm501_atam_atama_01__divskn.farc A01F8116 rom/osage_play_data/meiitm502_atam_atama_02__divskn.farc 93811BBD rom/osage_play_data/meiitm503_atam_atama_03__divskn.farc 315CE597 rom/osage_play_data/meiitm504_atam_atama_04__divskn.farc 607B7750 rom/osage_play_data/meiitm505_atam_atama_05__divskn.farc 73CD4DDD rom/osage_play_data/meiitm506_atam_atama_06__divskn.farc E5391999 rom/osage_play_data/meiitm507_atam_atama_07__divskn.farc 6CBA2C59 rom/osage_play_data/meiitm508_atam_atama_08__divskn.farc CB11E181 rom/osage_play_data/meiitm509_atam_atama_09__divskn.farc 3DE95A18 rom/osage_play_data/meiitm510_atam_atama_10__divskn.farc 8838128F rom/osage_play_data/meiitm511_atam_atama_11__divskn.farc D2494F49 rom/osage_play_data/meiitm512_atam_atama_12__divskn.farc 91D4BFE1 rom/osage_play_data/meiitm514_atam_atama_14__divskn.farc 6AED8734 rom/osage_play_data/meiitm515_atam_atama_15__divskn.farc 10950E6F rom/osage_play_data/meiitm521_atam_atama_21__divskn.farc F64FB0B2 rom/osage_play_data/meiitm522_atam_atama_22__divskn.farc 013464C0 rom/osage_play_data/meiitm523_atam_atama_23__divskn.farc B2BDDAA8 rom/osage_play_data/meiitm524_atam_atama_24__divskn.farc B482DCA9 rom/osage_play_data/meiitm525_atam_atama_25__divskn.farc 127ABE78 rom/osage_play_data/meiitm526_atam_atama_26__divskn.farc 26B9C99B rom/osage_play_data/meiitm527_atam_atama_27__divskn.farc 16A53B64 rom/osage_play_data/meiitm528_atam_atama_28__divskn.farc F2DEB01D rom/osage_play_data/meiitm529_atam_atama_29__divskn.farc D481FA1F rom/osage_play_data/meiitm530_atam_atama_30__divskn.farc C4DAC604 rom/osage_play_data/meiitm533_atam_atama_33__divskn.farc EA0C50A6 rom/osage_play_data/meiitm700_atam_zujo_00__divskn.farc 5FAFFE8A rom/osage_play_data/meiitm701_atam_zujo_01__divskn.farc 8EB2F430 rom/osage_play_data/meiitm702_atam_zujo_02__divskn.farc 996F7E3A rom/osage_play_data/meiitm704_atam_zujo_04__divskn.farc EAE3B369 rom/osage_play_data/meiitm705_atam_zujo_05__divskn.farc 9761AFEB rom/osage_play_data/meiitm709_atam_zujo_09__divskn.farc F8E140C9 rom/osage_play_data/meiitm775_joha_ushiro_75__divskn.farc 5BBFA38C rom/osage_play_data/mikitm001_joha_outer_01__divskn.farc 8AA0BD3B rom/osage_play_data/mikitm002_joha_outer_02__divskn.farc 1C51ADDA rom/osage_play_data/mikitm003_joha_outer_03__divskn.farc E345AE9F rom/osage_play_data/mikitm004_joha_outer_04__divskn.farc 1A3B7FFA rom/osage_play_data/mikitm006_joha_outer_06__divskn.farc 9FBA6840 rom/osage_play_data/mikitm007_joha_outer_07__divskn.farc CD3BA417 rom/osage_play_data/mikitm008_joha_outer_08__divskn.farc 9EBC93E6 rom/osage_play_data/mikitm009_joha_outer_09__divskn.farc 4C5E3BC9 rom/osage_play_data/mikitm010_joha_outer_10__divskn.farc A8990329 rom/osage_play_data/mikitm011_joha_outer_11__divskn.farc 01E4F878 rom/osage_play_data/mikitm012_joha_outer_12__divskn.farc 01C1C04C rom/osage_play_data/mikitm013_joha_outer_13__divskn.farc 33B25816 rom/osage_play_data/mikitm014_joha_outer_14__divskn.farc 098B18D7 rom/osage_play_data/mikitm015_joha_outer_15__divskn.farc 1EB35AC8 rom/osage_play_data/mikitm016_joha_outer_16__divskn.farc 0FA1EF0B rom/osage_play_data/mikitm017_joha_outer_17__divskn.farc 85008DF8 rom/osage_play_data/mikitm019_joha_outer_19__divskn.farc 1EC5C7F4 rom/osage_play_data/mikitm020_joha_outer_20__divskn.farc 1B8D0328 rom/osage_play_data/mikitm021_joha_outer_21__divskn.farc B27EE29D rom/osage_play_data/mikitm022_joha_outer_22_zzc__divskn.farc 831FC1B8 rom/osage_play_data/mikitm023_joha_outer_23__divskn.farc 0159AD1F rom/osage_play_data/mikitm024_joha_outer_24__divskn.farc F61DAC00 rom/osage_play_data/mikitm025_joha_outer_25__divskn.farc 6F831948 rom/osage_play_data/mikitm026_joha_outer_26__divskn.farc 05F1DF6C rom/osage_play_data/mikitm027_joha_outer_27__divskn.farc 16E99A66 rom/osage_play_data/mikitm029_joha_outer_29__divskn.farc 7BC24413 rom/osage_play_data/mikitm030_joha_outer_30__divskn.farc 8C98CBE8 rom/osage_play_data/mikitm031_joha_outer_31__divskn.farc C2AC4C60 rom/osage_play_data/mikitm038_joha_outer_38__divskn.farc AF1A36BA rom/osage_play_data/mikitm040_joha_outer_40__divskn.farc 45B5D69B rom/osage_play_data/mikitm041_joha_outer_41__divskn.farc 9C88D37E rom/osage_play_data/mikitm042_joha_outer_42__divskn.farc 57413F5E rom/osage_play_data/mikitm043_joha_outer_43__divskn.farc E54EF068 rom/osage_play_data/mikitm044_joha_outer_44__divskn.farc 0E387407 rom/osage_play_data/mikitm045_joha_outer_45__divskn.farc 57A8D472 rom/osage_play_data/mikitm046_joha_outer_46__divskn.farc C8DC72F5 rom/osage_play_data/mikitm047_joha_outer_47__divskn.farc 98E98AD7 rom/osage_play_data/mikitm048_joha_outer_48__divskn.farc E275A656 rom/osage_play_data/mikitm049_joha_outer_49__divskn.farc 9984E42E rom/osage_play_data/mikitm050_joha_outer_50__divskn.farc 1A199C59 rom/osage_play_data/lukitm035_joha_outer_35__divskn.farc 61AE0C7D rom/osage_play_data/lukitm505_atam_atama_05__divskn.farc A1E3DC27 rom/osage_play_data/lukitm525_atam_atama_25__divskn.farc 74A84CF1 rom/osage_play_data/lukitm538_atam_atama_38__divskn.farc 51D834DD rom/osage_play_data/meiitm006_joha_outer_06__divskn.farc FD057958 rom/osage_play_data/meiitm020_joha_outer_20__divskn.farc AE0A0557 rom/osage_play_data/meiitm500_atam_atama_00__divskn.farc D5A33305 rom/osage_play_data/meiitm513_atam_atama_13__divskn.farc 6EAA0661 rom/osage_play_data/meiitm532_atam_atama_32__divskn.farc B092B134 rom/osage_play_data/mikitm005_joha_outer_05__divskn.farc 652574DB rom/osage_play_data/mikitm018_joha_outer_18__divskn.farc 86DBB4E8 rom/osage_play_data/mikitm052_joha_outer_52__divskn.farc 5B5E678F rom/osage_play_data/mikitm053_joha_outer_53__divskn.farc 868CA7C4 rom/osage_play_data/mikitm054_joha_outer_54__divskn.farc 877477C0 rom/osage_play_data/mikitm055_joha_outer_55__divskn.farc 75042FD0 rom/osage_play_data/mikitm056_joha_outer_56__divskn.farc 0F4B4CDA rom/osage_play_data/mikitm057_joha_outer_57__divskn.farc 2758996C rom/osage_play_data/mikitm058_joha_outer_58__divskn.farc 3EF56380 rom/osage_play_data/mikitm059_joha_outer_59__divskn.farc 5B9261A4 rom/osage_play_data/mikitm060_joha_outer_60__divskn.farc 2611B024 rom/osage_play_data/mikitm061_joha_outer_61__divskn.farc 67AE1670 rom/osage_play_data/mikitm063_joha_outer_63__divskn.farc 0476390A rom/osage_play_data/mikitm064_joha_outer_64__divskn.farc 249613F5 rom/osage_play_data/mikitm066_joha_outer_66__divskn.farc C7B3CCD2 rom/osage_play_data/mikitm067_joha_outer_67__divskn.farc 25CD8AAC rom/osage_play_data/mikitm068_joha_outer_68__divskn.farc 49755D54 rom/osage_play_data/mikitm069_joha_outer_69__divskn.farc 9B8B27BD rom/osage_play_data/mikitm070_joha_outer_70__divskn.farc ECF8248C rom/osage_play_data/mikitm071_joha_outer_71__divskn.farc D21C7CB1 rom/osage_play_data/mikitm072_joha_outer_72__divskn.farc 00EE13D9 rom/osage_play_data/mikitm073_joha_outer_73__divskn.farc E8DE271C rom/osage_play_data/mikitm074_joha_outer_74__divskn.farc AA2AC555 rom/osage_play_data/mikitm075_joha_outer_75__divskn.farc 4EFB3558 rom/osage_play_data/mikitm076_joha_outer_76__divskn.farc 001EF92D rom/osage_play_data/mikitm077_joha_outer_77__divskn.farc 1907316D rom/osage_play_data/mikitm079_joha_outer_79__divskn.farc 93DE36C9 rom/osage_play_data/mikitm080_joha_outer_80__divskn.farc 78696628 rom/osage_play_data/mikitm081_joha_outer_81__divskn.farc CCB13F20 rom/osage_play_data/mikitm082_joha_outer_82__divskn.farc 23439E59 rom/osage_play_data/mikitm083_joha_outer_83__divskn.farc 20FEFA06 rom/osage_play_data/mikitm084_joha_outer_84__divskn.farc FF6B41CB rom/osage_play_data/mikitm085_joha_outer_85__divskn.farc DA1BF7D5 rom/osage_play_data/mikitm087_joha_outer_87__divskn.farc 351D4947 rom/osage_play_data/mikitm088_joha_outer_88__divskn.farc 52068901 rom/osage_play_data/mikitm089_joha_outer_89__divskn.farc 962B382B rom/osage_play_data/mikitm090_joha_outer_90__divskn.farc C8B1C14E rom/osage_play_data/mikitm091_joha_outer_91__divskn.farc 1BFFCA25 rom/osage_play_data/mikitm093_joha_outer_93__divskn.farc 2809A570 rom/osage_play_data/mikitm094_joha_outer_94__divskn.farc F36C9D1A rom/osage_play_data/mikitm095_joha_outer_95__divskn.farc 85F95FC6 rom/osage_play_data/mikitm096_joha_outer_96__divskn.farc 0971AF0C rom/osage_play_data/mikitm097_joha_outer_97__divskn.farc 9C8B69A3 rom/osage_play_data/mikitm098_joha_outer_98__divskn.farc 5D84105E rom/osage_play_data/mikitm099_joha_outer_99__divskn.farc 08F3AE2E rom/osage_play_data/mikitm100_joha_outer_100__divskn.farc 5096F736 rom/osage_play_data/mikitm101_joha_outer_101__divskn.farc 07E4FA05 rom/osage_play_data/mikitm102_joha_outer_102__divskn.farc 8E0625D1 rom/osage_play_data/mikitm103_joha_outer_103__divskn.farc 82048ED0 rom/osage_play_data/mikitm104_joha_outer_104__divskn.farc 4AD804AA rom/osage_play_data/mikitm106_joha_outer_106__divskn.farc 58D41A53 rom/osage_play_data/mikitm107_joha_outer_107__divskn.farc FAAACC87 rom/osage_play_data/mikitm108_joha_outer_108__divskn.farc 5FA1E91A rom/osage_play_data/mikitm109_joha_outer_109__divskn.farc D0524124 rom/osage_play_data/mikitm110_joha_outer_110__divskn.farc D9CD475F rom/osage_play_data/mikitm111_joha_outer_111__divskn.farc B6FC2D48 rom/osage_play_data/mikitm112_joha_outer_112__divskn.farc CBB35A82 rom/osage_play_data/mikitm113_joha_outer_113__divskn.farc A079FBBA rom/osage_play_data/mikitm114_joha_outer_114__divskn.farc C5360D75 rom/osage_play_data/mikitm115_joha_outer_115__divskn.farc BCF9C091 rom/osage_play_data/mikitm116_joha_outer_116__divskn.farc 47F74740 rom/osage_play_data/mikitm118_joha_outer_118__divskn.farc B37C71F0 rom/osage_play_data/mikitm120_joha_outer_120__divskn.farc 0B5E8483 rom/osage_play_data/mikitm123_joha_outer_123__divskn.farc E0A97A46 rom/osage_play_data/mikitm124_joha_outer_124__divskn.farc FB90FD8B rom/osage_play_data/mikitm125_joha_outer_125__divskn.farc CAD247FB rom/osage_play_data/mikitm126_joha_outer_126__divskn.farc 37F5EC84 rom/osage_play_data/mikitm127_joha_outer_127__divskn.farc D9AD6D88 rom/osage_play_data/mikitm128_joha_outer_128__divskn.farc 843501FC rom/osage_play_data/mikitm129_joha_outer_129__divskn.farc 68B818B2 rom/osage_play_data/mikitm130_joha_outer_130__divskn.farc 443D87F4 rom/osage_play_data/mikitm131_joha_outer_131__divskn.farc 7A6BCFC9 rom/osage_play_data/mikitm132_joha_outer_132__divskn.farc 7FC69252 rom/osage_play_data/mikitm133_joha_outer_133__divskn.farc E52CA6C1 rom/osage_play_data/mikitm135_joha_outer_135__divskn.farc 50B26D77 rom/osage_play_data/mikitm136_joha_outer_136__divskn.farc D3BA12F0 rom/osage_play_data/mikitm137_joha_outer_137__divskn.farc 92FBD8A7 rom/osage_play_data/mikitm138_joha_outer_138__divskn.farc AA660E98 rom/osage_play_data/mikitm139_joha_outer_139__divskn.farc 42532DED rom/osage_play_data/mikitm140_joha_outer_140__divskn.farc A05B9808 rom/osage_play_data/mikitm141_joha_outer_141__divskn.farc 64F7D8FD rom/osage_play_data/mikitm142_joha_outer_142__divskn.farc 630FA76E rom/osage_play_data/mikitm143_joha_outer_143__divskn.farc 393F018F rom/osage_play_data/mikitm144_joha_outer_144__divskn.farc 66BBFB4B rom/osage_play_data/mikitm145_joha_outer_145__divskn.farc 792C5F7F rom/osage_play_data/mikitm146_joha_outer_146__divskn.farc AB9A1D42 rom/osage_play_data/mikitm148_joha_outer_148__divskn.farc 047F98A3 rom/osage_play_data/mikitm149_joha_outer_149__divskn.farc E731FE1D rom/osage_play_data/mikitm151_joha_outer_151__divskn.farc 37EAF8E1 rom/osage_play_data/mikitm152_joha_outer_152__divskn.farc 98D68B26 rom/osage_play_data/mikitm153_joha_outer_153__divskn.farc 4241B513 rom/osage_play_data/mikitm155_joha_outer_155__divskn.farc C764ABE0 rom/osage_play_data/mikitm156_joha_outer_156__divskn.farc AE2F50C1 rom/osage_play_data/mikitm158_joha_outer_158__divskn.farc 6DF1511D rom/osage_play_data/mikitm160_joha_outer_160__divskn.farc 062C06C4 rom/osage_play_data/mikitm162_joha_outer_162__divskn.farc 691E633B rom/osage_play_data/mikitm163_joha_outer_163__divskn.farc 7553FF13 rom/osage_play_data/mikitm164_joha_outer_164__divskn.farc 91730035 rom/osage_play_data/mikitm167_joha_outer_167__divskn.farc 2C31A4B4 rom/osage_play_data/mikitm169_joha_outer_169__divskn.farc 122F66AF rom/osage_play_data/mikitm170_joha_outer_170__divskn.farc 4683BF35 rom/osage_play_data/mikitm173_joha_outer_173__divskn.farc E69262EC rom/osage_play_data/mikitm431_ude_hand_131__divskn.farc 2F796BC4 rom/osage_play_data/mikitm438_ude_hand_138__divskn.farc 9A04ED95 rom/osage_play_data/mikitm467_ude_hand_167__divskn.farc 249487EA rom/osage_play_data/mikitm500_atam_atama_00__divskn.farc 5D433A5C rom/osage_play_data/mikitm501_atam_atama_01__divskn.farc 7143B409 rom/osage_play_data/mikitm502_atam_atama_02__divskn.farc 68CFB014 rom/osage_play_data/mikitm504_atam_atama_04__divskn.farc 2696CABA rom/osage_play_data/mikitm505_atam_atama_05__divskn.farc 1D20B96C rom/osage_play_data/mikitm507_atam_atama_07__divskn.farc 7001A379 rom/osage_play_data/mikitm508_atam_atama_08__divskn.farc A1A3F964 rom/osage_play_data/mikitm509_atam_atama_09__divskn.farc 6668BCF4 rom/osage_play_data/mikitm520_atam_atama_20__divskn.farc 036F9253 rom/osage_play_data/mikitm522_atam_atama_22__divskn.farc 02365F27 rom/osage_play_data/mikitm524_atam_atama_24__divskn.farc 7ECC284E rom/osage_play_data/mikitm525_atam_atama_25__divskn.farc EE93390D rom/osage_play_data/mikitm526_atam_atama_26__divskn.farc 5FB8ED33 rom/osage_play_data/mikitm527_atam_atama_27__divskn.farc 7295A73F rom/osage_play_data/mikitm528_atam_atama_28__divskn.farc FE546E3F rom/osage_play_data/mikitm530_atam_atama_30__divskn.farc 6F9FABC8 rom/osage_play_data/mikitm531_atam_atama_31__divskn.farc 2B44DFC3 rom/osage_play_data/mikitm533_atam_atama_33__divskn.farc E9076770 rom/osage_play_data/mikitm534_atam_atama_34__divskn.farc A1996671 rom/osage_play_data/mikitm536_atam_atama_36__divskn.farc 43AD5E68 rom/osage_play_data/mikitm537_atam_atama_37__divskn.farc 715E94B4 rom/osage_play_data/mikitm538_atam_atama_38__divskn.farc FF0BAAFB rom/osage_play_data/mikitm539_atam_atama_39__divskn.farc FF764FD2 rom/osage_play_data/mikitm540_atam_atama_40__divskn.farc C9A89F46 rom/osage_play_data/mikitm541_atam_atama_41__divskn.farc ED32CF9D rom/osage_play_data/mikitm542_atam_atama_42__divskn.farc BBFAC916 rom/osage_play_data/mikitm543_atam_atama_43__divskn.farc F3012E36 rom/osage_play_data/mikitm544_atam_atama_44__divskn.farc 5F074B24 rom/osage_play_data/mikitm545_atam_atama_45__divskn.farc 03F251CE rom/osage_play_data/mikitm547_atam_atama_47__divskn.farc 0A9D4670 rom/osage_play_data/mikitm548_atam_atama_48__divskn.farc 0363257C rom/osage_play_data/mikitm549_atam_atama_49__divskn.farc 08125A39 rom/osage_play_data/mikitm550_atam_atama_50__divskn.farc 3B9B0149 rom/osage_play_data/mikitm551_atam_atama_51__divskn.farc A6A313F0 rom/osage_play_data/mikitm552_atam_atama_52__divskn.farc 644BEFA2 rom/osage_play_data/mikitm553_atam_atama_53__divskn.farc 138906F6 rom/osage_play_data/mikitm554_atam_atama_54__divskn.farc D692EE39 rom/osage_play_data/mikitm555_atam_atama_55__divskn.farc 6345309B rom/osage_play_data/mikitm556_atam_atama_56__divskn.farc 3328C03E rom/osage_play_data/mikitm557_atam_atama_57__divskn.farc 178C1C9E rom/osage_play_data/mikitm558_atam_atama_58__divskn.farc 7758BDE1 rom/osage_play_data/mikitm051_joha_outer_51__divskn.farc 24075F80 rom/osage_play_data/mikitm065_joha_outer_65__divskn.farc C124A2CE rom/osage_play_data/mikitm078_joha_outer_78__divskn.farc BB7D4CD4 rom/osage_play_data/mikitm092_joha_outer_92__divskn.farc C461B197 rom/osage_play_data/mikitm105_joha_outer_105__divskn.farc 9CDF642A rom/osage_play_data/mikitm119_joha_outer_119__divskn.farc 732DF778 rom/osage_play_data/mikitm134_joha_outer_134__divskn.farc 24E5C749 rom/osage_play_data/mikitm147_joha_outer_147__divskn.farc D29F40E4 rom/osage_play_data/mikitm165_joha_outer_165__divskn.farc 4D9F3AD9 rom/osage_play_data/mikitm506_atam_atama_06__divskn.farc FD4F5EC9 rom/osage_play_data/mikitm532_atam_atama_32__divskn.farc C3938517 rom/osage_play_data/mikitm560_atam_atama_60__divskn.farc 08566814 rom/osage_play_data/mikitm593_atam_atama_93__divskn.farc 16D2262C rom/osage_play_data/mikitm594_atam_atama_94__divskn.farc 71B045D7 rom/osage_play_data/mikitm595_atam_atama_95__divskn.farc 54091089 rom/osage_play_data/mikitm596_atam_atama_96__divskn.farc 7CAB0678 rom/osage_play_data/mikitm597_atam_atama_97__divskn.farc 5700C167 rom/osage_play_data/mikitm598_atam_atama_98__divskn.farc 8986BF0A rom/osage_play_data/mikitm599_atam_atama_99__divskn.farc E4587445 rom/osage_play_data/mikitm600_atam_atama_100__divskn.farc 59ABE7A0 rom/osage_play_data/mikitm601_atam_atama_101__divskn.farc 3D37F970 rom/osage_play_data/mikitm602_atam_atama_102__divskn.farc 41BD39D5 rom/osage_play_data/mikitm603_atam_atama_103__divskn.farc 2A7940E6 rom/osage_play_data/mikitm605_atam_atama_105__divskn.farc 1BA8826D rom/osage_play_data/mikitm606_atam_atama_106__divskn.farc 816FE5AC rom/osage_play_data/mikitm607_atam_atama_107__divskn.farc CFBD2571 rom/osage_play_data/mikitm608_atam_atama_108__divskn.farc 2B56B76F rom/osage_play_data/mikitm609_atam_atama_109__divskn.farc 32E06A44 rom/osage_play_data/mikitm610_atam_atama_110__divskn.farc 9E02E15B rom/osage_play_data/mikitm611_atam_atama_111__divskn.farc 85F14AF4 rom/osage_play_data/mikitm612_atam_atama_112__divskn.farc 7F07D1A2 rom/osage_play_data/mikitm613_atam_atama_113__divskn.farc F0BB2270 rom/osage_play_data/mikitm614_atam_atama_114__divskn.farc AAF58313 rom/osage_play_data/mikitm615_atam_atama_115__divskn.farc 8FF7539D rom/osage_play_data/mikitm616_atam_atama_116__divskn.farc 669106D9 rom/osage_play_data/mikitm619_atam_atama_119__divskn.farc BB5C4569 rom/osage_play_data/mikitm620_atam_atama_120__divskn.farc CFC99CAD rom/osage_play_data/mikitm621_atam_atama_121__divskn.farc 33BFEFFC rom/osage_play_data/mikitm623_atam_atama_123__divskn.farc F5381E60 rom/osage_play_data/mikitm624_atam_atama_124__divskn.farc E2125EB5 rom/osage_play_data/mikitm625_atam_atama_125__divskn.farc BCCC2F27 rom/osage_play_data/mikitm626_atam_atama_126__divskn.farc 8DB4A3BB rom/osage_play_data/mikitm627_atam_atama_127__divskn.farc 3FEDB426 rom/osage_play_data/mikitm628_atam_atama_128__divskn.farc 4622D8C5 rom/osage_play_data/mikitm630_atam_atama_130__divskn.farc 6CCD49EF rom/osage_play_data/mikitm631_atam_atama_131__divskn.farc F7939C97 rom/osage_play_data/mikitm632_atam_atama_132__divskn.farc 637BA830 rom/osage_play_data/mikitm634_atam_atama_134__divskn.farc AD9B29B8 rom/osage_play_data/mikitm635_atam_atama_135__divskn.farc 0FE4C76E rom/osage_play_data/mikitm636_atam_atama_136__divskn.farc 45EF3994 rom/osage_play_data/mikitm637_atam_atama_137__divskn.farc A690BA96 rom/osage_play_data/mikitm638_atam_atama_138__divskn.farc 3225F835 rom/osage_play_data/mikitm639_atam_atama_139__divskn.farc 771C5442 rom/osage_play_data/mikitm640_atam_atama_140__divskn.farc 773ADCC7 rom/osage_play_data/mikitm641_atam_atama_141__divskn.farc 415CE3B9 rom/osage_play_data/mikitm642_atam_atama_142__divskn.farc A41AC77D rom/osage_play_data/mikitm643_atam_atama_143__divskn.farc 17003D44 rom/osage_play_data/mikitm644_atam_atama_144__divskn.farc 924FC03B rom/osage_play_data/mikitm645_atam_atama_145__divskn.farc 9BC1D7BC rom/osage_play_data/mikitm647_atam_atama_147__divskn.farc DB838E7C rom/osage_play_data/mikitm648_atam_atama_148__divskn.farc 1E45B96B rom/osage_play_data/mikitm649_atam_atama_149__divskn.farc F2C31356 rom/osage_play_data/mikitm651_atam_atama_151__divskn.farc 249BD040 rom/osage_play_data/mikitm652_atam_atama_152__divskn.farc 1C519B79 rom/osage_play_data/mikitm653_atam_atama_153__divskn.farc 2A12631D rom/osage_play_data/mikitm655_atam_atama_155__divskn.farc 416937C2 rom/osage_play_data/mikitm656_atam_atama_156__divskn.farc DA344261 rom/osage_play_data/mikitm658_atam_atama_158__divskn.farc 7DB98357 rom/osage_play_data/mikitm660_atam_atama_160__divskn.farc FFC127E8 rom/osage_play_data/mikitm662_atam_atama_162__divskn.farc 852317AE rom/osage_play_data/mikitm663_atam_atama_163__divskn.farc 0AFB1800 rom/osage_play_data/mikitm665_atam_atama_165__divskn.farc E62EC854 rom/osage_play_data/mikitm667_atam_atama_167__divskn.farc 7FC1CDED rom/osage_play_data/mikitm669_atam_atama_169__divskn.farc 63730994 rom/osage_play_data/mikitm670_atam_atama_170__divskn.farc 12C4364D rom/osage_play_data/mikitm673_atam_atama_173__divskn.farc 4AA191D7 rom/osage_play_data/mikitm700_atam_zujo_00__divskn.farc 7F183636 rom/osage_play_data/mikitm702_atam_zujo_02__divskn.farc 067E368F rom/osage_play_data/mikitm709_atam_zujo_09__divskn.farc 0658BE2B rom/osage_play_data/mikitm711_atam_zujo_11__divskn.farc 7C49BED9 rom/osage_play_data/mikitm715_atam_zujo_15__divskn.farc 3C551435 rom/osage_play_data/mikitm718_atam_zujo_18__divskn.farc BF298B9C rom/osage_play_data/mikitm721_atam_zujo_21__divskn.farc 38DBF2D9 rom/osage_play_data/mikitm722_atam_zujo_22__divskn.farc 8C72D2C9 rom/osage_play_data/mikitm746_atam_zujo_46__divskn.farc 8ED3D73B rom/osage_play_data/mikitm748_atam_zujo_48__divskn.farc DD421265 rom/osage_play_data/mikitm749_atam_zujo_49__divskn.farc 88A9C55E rom/osage_play_data/mikitm751_joha_neck_51__divskn.farc 8F5C1569 rom/osage_play_data/mikitm752_joha_neck_52__divskn.farc 4B2561CD rom/osage_play_data/mikitm775_joha_ushiro_75__divskn.farc 17843906 rom/osage_play_data/mikitm776_joha_ushiro_76__divskn.farc E74561CD rom/osage_play_data/mikitm777_joha_ushiro_77__divskn.farc 9F7A665A rom/osage_play_data/mikitm780_joha_ushiro_80__divskn.farc 799DC471 rom/osage_play_data/mikitm781_joha_ushiro_81__divskn.farc 3E30C1AE rom/osage_play_data/mikitm782_joha_ushiro_82__divskn.farc 958CE7B8 rom/osage_play_data/mikitm783_joha_ushiro_83__divskn.farc 531D9F32 rom/osage_play_data/mikitm784_joha_ushiro_84__divskn.farc 610FF50F rom/osage_play_data/neritm001_joha_outer_01__divskn.farc EDE6196B rom/osage_play_data/neritm002_joha_outer_02__divskn.farc DCD3F39E rom/osage_play_data/neritm003_joha_outer_03__divskn.farc EEF96C79 rom/osage_play_data/neritm004_joha_outer_04__divskn.farc A194AAEF rom/osage_play_data/neritm500_atam_atama_00__divskn.farc 39110BFC rom/osage_play_data/neritm501_atam_atama_01__divskn.farc 1713D600 rom/osage_play_data/opd_db.txt 496925BF rom/osage_play_data/rinitm001_joha_outer_01__divskn.farc 0A839D9A rom/osage_play_data/rinitm002_joha_outer_02__divskn.farc 342E8B00 rom/osage_play_data/rinitm003_joha_outer_03__divskn.farc 9CDBE4A1 rom/osage_play_data/rinitm004_joha_outer_04__divskn.farc ED69FCAD rom/osage_play_data/rinitm006_joha_outer_06__divskn.farc 1EDF33B9 rom/osage_play_data/rinitm007_joha_outer_07__divskn.farc 86734AF4 rom/osage_play_data/rinitm009_joha_outer_09__divskn.farc D603D8BB rom/osage_play_data/rinitm010_joha_outer_10__divskn.farc 2A5B34A4 rom/osage_play_data/rinitm011_joha_outer_11__divskn.farc 2E2615F1 rom/osage_play_data/rinitm012_joha_outer_12__divskn.farc 86522A15 rom/osage_play_data/rinitm013_joha_outer_13__divskn.farc 608BB838 rom/osage_play_data/rinitm014_joha_outer_14__divskn.farc EE763F94 rom/osage_play_data/rinitm015_joha_outer_15__divskn.farc 10357546 rom/osage_play_data/rinitm016_joha_outer_16__divskn.farc C71CABDC rom/osage_play_data/rinitm017_joha_outer_17__divskn.farc EEBE3EAB rom/osage_play_data/rinitm018_joha_outer_18__divskn.farc 9BF404C7 rom/osage_play_data/rinitm020_joha_outer_20__divskn.farc 42B4FFC3 rom/osage_play_data/rinitm021_joha_outer_21__divskn.farc 87FDCD8E rom/osage_play_data/rinitm023_joha_outer_23__divskn.farc 265E6647 rom/osage_play_data/rinitm024_joha_outer_24__divskn.farc 8F703E04 rom/osage_play_data/rinitm025_joha_outer_25__divskn.farc E6D952F5 rom/osage_play_data/rinitm026_joha_outer_26_zzc__divskn.farc DF8E5555 rom/osage_play_data/rinitm027_joha_outer_27__divskn.farc C03EEB1F rom/osage_play_data/rinitm028_joha_outer_28__divskn.farc 51993096 rom/osage_play_data/rinitm029_joha_outer_29__divskn.farc F0150CE8 rom/osage_play_data/rinitm030_joha_outer_30__divskn.farc 3B09D19A rom/osage_play_data/rinitm031_joha_outer_31__divskn.farc EBCA9776 rom/osage_play_data/rinitm032_joha_outer_32__divskn.farc E90D4627 rom/osage_play_data/rinitm034_joha_outer_34__divskn.farc 707247E4 rom/osage_play_data/rinitm035_joha_outer_35__divskn.farc EB79F191 rom/osage_play_data/rinitm036_joha_outer_36__divskn.farc 64B77D04 rom/osage_play_data/rinitm037_joha_outer_37__divskn.farc 48D54336 rom/osage_play_data/rinitm038_joha_outer_38__divskn.farc C40F6C04 rom/osage_play_data/rinitm039_joha_outer_39__divskn.farc 9C553581 rom/osage_play_data/rinitm040_joha_outer_40__divskn.farc 0F977FD0 rom/osage_play_data/rinitm041_joha_outer_41__divskn.farc B523E7ED rom/osage_play_data/rinitm043_joha_outer_43__divskn.farc 9465BA07 rom/osage_play_data/rinitm044_joha_outer_44__divskn.farc F50DF47D rom/osage_play_data/rinitm045_joha_outer_45__divskn.farc F9116755 rom/osage_play_data/rinitm047_joha_outer_47__divskn.farc 7FFE1197 rom/osage_play_data/rinitm500_atam_atama_00__divskn.farc C08C30E4 rom/osage_play_data/rinitm501_atam_atama_01__divskn.farc 5D2FCD92 rom/osage_play_data/rinitm502_atam_atama_02__divskn.farc A9E6648E rom/osage_play_data/rinitm503_atam_atama_03__divskn.farc C8FE0B4B rom/osage_play_data/rinitm504_atam_atama_04__divskn.farc 040CEFA3 rom/osage_play_data/rinitm505_atam_atama_05__divskn.farc CC750AE3 rom/osage_play_data/rinitm506_atam_atama_06__divskn.farc 9E7AF4E6 rom/osage_play_data/rinitm507_atam_atama_07__divskn.farc F0644ADE rom/osage_play_data/rinitm508_atam_atama_08__divskn.farc 9E79ABA4 rom/osage_play_data/rinitm509_atam_atama_09__divskn.farc D38DF128 rom/osage_play_data/rinitm510_atam_atama_10__divskn.farc 25471C50 rom/osage_play_data/rinitm511_atam_atama_11__divskn.farc D7CC70D3 rom/osage_play_data/mikitm559_atam_atama_59__divskn.farc ABBABD95 rom/osage_play_data/mikitm604_atam_atama_104__divskn.farc B39217A9 rom/osage_play_data/mikitm618_atam_atama_118__divskn.farc 14C10AC9 rom/osage_play_data/mikitm633_atam_atama_133__divskn.farc EF72925D rom/osage_play_data/mikitm646_atam_atama_146__divskn.farc 43B53A4A rom/osage_play_data/mikitm664_atam_atama_164__divskn.farc 2F682199 rom/osage_play_data/mikitm745_atam_zujo_45__divskn.farc D925013A rom/osage_play_data/mikitm790_atam_zujo_90__divskn.farc 814FFB3F rom/osage_play_data/rinitm005_joha_outer_05__divskn.farc F727E78D rom/osage_play_data/rinitm019_joha_outer_19__divskn.farc 709CCC66 rom/osage_play_data/rinitm033_joha_outer_33__divskn.farc CBB6B94A rom/osage_play_data/rinitm048_joha_outer_48__divskn.farc FFB47632 rom/osage_play_data/rinitm512_atam_atama_12__divskn.farc F9CA0EC6 rom/osage_play_data/rinitm530_atam_atama_30__divskn.farc AE5BD7CF rom/osage_play_data/rinitm544_atam_atama_44__divskn.farc 71095016 rom/osage_play_data/rinitm711_atam_zujo_11__divskn.farc D74DB1B9 rom/osage_play_data/rinitm999_atam_zujo_99__divskn.farc B01B3026 rom/osage_play_data/rinitm513_atam_atama_13__divskn.farc 44AB9FB9 rom/osage_play_data/rinitm514_atam_atama_14__divskn.farc A5B4A9E7 rom/osage_play_data/rinitm515_atam_atama_15__divskn.farc ADA34A75 rom/osage_play_data/rinitm516_atam_atama_16__divskn.farc CC734CBF rom/osage_play_data/rinitm517_atam_atama_17__divskn.farc 4B50C1B7 rom/osage_play_data/rinitm518_atam_atama_18__divskn.farc 2028605F rom/osage_play_data/rinitm519_atam_atama_19__divskn.farc CFAC51ED rom/osage_play_data/rinitm520_atam_atama_20__divskn.farc 5F780E73 rom/osage_play_data/rinitm526_atam_atama_26__divskn.farc 8F7DF1C2 rom/osage_play_data/rinitm527_atam_atama_27__divskn.farc 67FD4629 rom/osage_play_data/rinitm528_atam_atama_28__divskn.farc 4C131B53 rom/osage_play_data/rinitm529_atam_atama_29__divskn.farc 16F1FAC1 rom/osage_play_data/rinitm531_atam_atama_31__divskn.farc 9EFEC507 rom/osage_play_data/rinitm532_atam_atama_32__divskn.farc C8259187 rom/osage_play_data/rinitm533_atam_atama_33__divskn.farc 8A99533D rom/osage_play_data/rinitm534_atam_atama_34__divskn.farc D405935D rom/osage_play_data/rinitm535_atam_atama_35__divskn.farc EE9D84AA rom/osage_play_data/rinitm536_atam_atama_36__divskn.farc CC858F46 rom/osage_play_data/rinitm537_atam_atama_37__divskn.farc EB48FEDA rom/osage_play_data/rinitm538_atam_atama_38__divskn.farc 77388B1B rom/osage_play_data/rinitm539_atam_atama_39__divskn.farc 28D88FD6 rom/osage_play_data/rinitm540_atam_atama_40__divskn.farc EC80C27A rom/osage_play_data/rinitm541_atam_atama_41__divskn.farc A4A779BA rom/osage_play_data/rinitm543_atam_atama_43__divskn.farc D1437206 rom/osage_play_data/rinitm545_atam_atama_45__divskn.farc 5DC8AEFD rom/osage_play_data/rinitm547_atam_atama_47__divskn.farc A07E3090 rom/osage_play_data/rinitm548_atam_atama_48__divskn.farc 1D3B4160 rom/osage_play_data/rinitm701_atam_zujo_01__divskn.farc C0CDDB3D rom/osage_play_data/rinitm702_atam_zujo_02__divskn.farc 08A5586A rom/osage_play_data/rinitm703_atam_zujo_03__divskn.farc F58FE49C rom/osage_play_data/rinitm704_atam_zujo_04__divskn.farc 76A70934 rom/osage_play_data/rinitm705_atam_zujo_05__divskn.farc 91A61EA4 rom/osage_play_data/rinitm706_atam_zujo_06__divskn.farc 0327B644 rom/osage_play_data/rinitm707_atam_zujo_07__divskn.farc 83F761CF rom/osage_play_data/rinitm708_atam_zujo_08__divskn.farc E47311C5 rom/osage_play_data/rinitm709_atam_zujo_09__divskn.farc 90192DBF rom/osage_play_data/rinitm710_atam_zujo_10__divskn.farc 969C10D7 rom/osage_play_data/rinitm712_atam_zujo_12__divskn.farc F3CE52FB rom/osage_play_data/rinitm714_atam_zujo_14__divskn.farc 919DA24B rom/osage_play_data/rinitm715_atam_zujo_15__divskn.farc 57A2615D rom/osage_play_data/rinitm716_atam_zujo_16__divskn.farc B9B12F6B rom/osage_play_data/rinitm717_atam_zujo_17__divskn.farc 0E689172 rom/osage_play_data/rinitm718_atam_zujo_18__divskn.farc 874FE32A rom/osage_play_data/rinitm719_atam_zujo_19__divskn.farc 080F6CDA rom/osage_play_data/rinitm720_atam_zujo_20__divskn.farc 4931CFDA rom/osage_play_data/rinitm721_atam_zujo_21__divskn.farc 2A8AC623 rom/osage_play_data/rinitm775_joha_ushiro_75__divskn.farc 715D3878 rom/osage_play_data/rinitm776_joha_ushiro_76__divskn.farc 23FFA255 rom/osage_play_data/rinitm777_joha_ushiro_77__divskn.farc 0FB16EAE rom/osage_play_data/sakitm001_joha_outer_01__divskn.farc C8B39E86 rom/osage_play_data/sakitm002_joha_outer_02__divskn.farc 5C006629 rom/osage_play_data/sakitm003_joha_outer_03__divskn.farc 9EE55756 rom/osage_play_data/sakitm005_joha_outer_05__divskn.farc 963013B5 rom/osage_play_data/sakitm500_atam_atama_00__divskn.farc 0330E51D rom/osage_play_data/sakitm501_atam_atama_01__divskn.farc 3109EE48 rom/osage_play_data/sakitm775_joha_ushiro_75__divskn.farc 75E21C3F rom/osage_play_data/tetitm001_joha_outer_01__divskn.farc E3B1B8B0 rom/osage_play_data/tetitm002_joha_outer_02__divskn.farc C603ACFD rom/osage_play_data/tetitm003_joha_outer_03__divskn.farc DADC11B4 rom/osage_play_data/tetitm500_atam_atama_00__divskn.farc 20FB6DC0 rom/osage_play_data/tetitm502_atam_atama_02__divskn.farc CDF2D3FD rom/osage_play_data/tetitm503_atam_atama_03__divskn.farc 46CF6C76 rom/particle/eff_pv247_cookie.farc AD331A6F rom/particle/eff_pv247_offset_test.farc ECC8E673 rom/particle/eff_pv247_star.farc 8BA13F52 rom/particle/eff_pv249_kirakira.farc 49BA60C2 rom/particle/eff_pv250_burneer.farc DD994371 rom/particle/eff_pv250_taxi.farc 62C6BB64 rom/particle/eff_pv250_yuge.farc 8613517D rom/particle/eff_pv253_hanabi.farc FC0799D3 rom/particle/eff_pv253_hanabi_test.farc 789FA432 rom/particle/eff_pv253_konpei.farc 61CFDBED rom/particle/eff_pv253_light_glow.farc 96F5ACE1 rom/particle/eff_pv253_light_glow_test.farc BCA9DDD4 rom/particle/eff_pv253_moyasmoke.farc BD686C99 rom/particle/eff_pv253_s05_coaster.farc 4390D9AE rom/particle/eff_pv253_smoke.farc 6321C589 rom/particle/eff_pv255_onpu.farc 05FD9CA2 rom/particle/eff_pv262_light_glow.farc D7AD18F9 rom/particle/eff_pv604_main.farc 039427CF rom/particle/eff_pv604_tail.farc C7F01C93 rom/particle/eff_pv710_main.farc 29975A9C rom/particle/eff_pv710_success.farc 48A29F53 rom/particle/eff_pv717_rain.farc 50A5B268 rom/particle/eff_PV722_main.farc 269D0B2D rom/particle/eff_pv723_main.farc E69562A8 rom/particle/eff_pv723_success.farc F556D355 rom/particle/eff_PV724_main.farc E0D538F6 rom/particle/eff_PV726_main.farc D307DE16 rom/particle/eff_pv726_success.farc 44C4012E rom/particle/eff_PV727_cut042.farc CDD163DD rom/particle/eff_PV727_main.farc 43BA1D29 rom/particle/eff_PV728_cut050.farc D7D45504 rom/particle/eff_PV728_cut051.farc 8E0CD34D rom/particle/eff_pv728_cut127.farc 80E1408E rom/particle/eff_PV728_lightbar.farc 4B835109 rom/particle/eff_PV728_lightbar_climax.farc 61303E05 rom/particle/eff_PV728_lightbar_nomalmax.farc BAD64A35 rom/particle/eff_PV728_smoke.farc DCE25A30 rom/particle/eff_pv729_gimmick.farc 260833BF rom/particle/eff_pv729_main.farc 2F0401E7 rom/particle/eff_pv729_reef.farc 39B91E39 rom/particle/eff_pv729_steam_1f.farc 5131DE23 rom/particle/eff_pv729_steam_2f.farc EED55FD5 rom/particle/eff_pv729_steam_3f.farc 8FBD08FD rom/particle/eff_pv731_ayasaki.farc E3C0B3FD rom/particle/eff_pv731_katana_aura_p1.farc 52CD9A22 rom/particle/eff_pv731_main.farc 58F0EB90 rom/particle/eff_pv731_miku.farc D3869868 rom/particle/eff_pv731_miku_delete.farc 73C7979F rom/particle/eff_pv731_reef.farc 3FA00C66 rom/particle/eff_pv731_stop.farc AA54274D rom/particle/eff_pv731_sword_p1.farc 80E51364 rom/particle/eff_PV732_main.farc 7097AD25 rom/particle/eff_pv733_main.farc BCC29B48 rom/particle/eff_pv733_rain.farc FFB3C9E3 rom/particle/eff_PV734_hibana.farc A890D639 rom/particle/eff_PV734_hibana_n.farc 07C98142 rom/particle/eff_PV734_hibana_s.farc C105F8B5 rom/particle/eff_PV734_hibana_success.farc ED50AF6F rom/particle/eff_pv734_hinoko.farc 76DED1C3 rom/particle/eff_pv734_hokori.farc 80AA3722 rom/particle/eff_pv253_smoke_cloud.farc 0FF52EF6 rom/particle/eff_pv728_cut011.farc 4D39835A rom/particle/eff_pv731_katana_aura_p2.farc 5CCDB57A rom/particle/eff_pv734_main.farc C8DF196E rom/particle/eff_PV736_lightchip.farc 3B515D80 rom/particle/eff_pv734_nor.farc 9E2E4094 rom/particle/eff_pv734_nor_hinoko.farc C31746C6 rom/particle/eff_pv734_spark.farc 86587705 rom/particle/eff_pv734_suc.farc 16EAA6F7 rom/particle/eff_pv734_suc_hinoko.farc 4E6179C8 rom/particle/eff_PV734_thunder.farc 9B852225 rom/particle/eff_PV736_barbroken.farc 7C81276D rom/particle/eff_PV736_bubble.farc 2D79A719 rom/particle/eff_PV736_bubble01.farc 3C66B156 rom/particle/eff_PV736_chip.farc B6E8E311 rom/particle/eff_PV736_crushball.farc 5A33971C rom/particle/eff_PV736_crushball01.farc 0EA7492F rom/particle/eff_PV736_cubebird.farc C7B890E2 rom/particle/eff_PV736_dustchip01.farc B401A1B3 rom/particle/eff_PV736_guitar.farc C54F59ED rom/particle/eff_PV736_whitechip.farc 3C88D673 rom/particle/eff_pv737_breath.farc ED8C676E rom/particle/eff_pv737_main.farc 2B130795 rom/particle/eff_PV737_shitsunai.farc 817168E3 rom/particle/eff_pv738_card_particle.farc 79A767E7 rom/particle/eff_pv738_success.farc ED39D61D rom/particle/eff_pv738_success_start.farc 90E25B1F rom/particle/eff_PV739_daiza.farc CF96C5EC rom/particle/eff_PV739_fireworks.farc A2544915 rom/particle/eff_PV739_hover.farc F4CA4CC9 rom/particle/eff_pv739_kirakira.farc 63253521 rom/particle/eff_pv739_kirakira_hand.farc DAC91901 rom/particle/eff_pv739_kirakira_line.farc 027F428A rom/particle/eff_pv739_kirakira_line_jikki.farc 674C5109 rom/particle/eff_pv739_light.farc 9D14C47F rom/particle/eff_pv739_main.farc F8E7371D rom/particle/eff_pv739_main_jikki.farc 4E13C1AB rom/particle/eff_PV739_monitor.farc 08B71967 rom/particle/eff_pv739_smoke.farc 24194B15 rom/particle/eff_pv739_star.farc E7BD497F rom/particle/eff_pv739_star_down.farc 441FCB2E rom/particle/eff_pv739_star_jikki.farc CE3ACA0B rom/particle/eff_pv740_main.farc 52410870 rom/particle/eff_pv740_mik_foot.farc 00F21438 rom/particle/eff_pv740_mik_room.farc AD77D666 rom/particle/eff_pv740_mik_sky.farc C2E5E591 rom/particle/eff_pv740_skyonpu.farc F2854B53 rom/particle/eff_pv740_success.farc 14B6BA93 rom/particle/eff_stgpv832_cream_snow.farc 3CFA8004 rom/particle/eff_stgpv832_main.farc 0E3AB30C rom/photo_print/aime_frame.tga 86B3E9F3 rom/photo_print/header01.jpg 25C555EC rom/photo_print/header02.jpg 2B0C8913 rom/photo_print/ic_img01.jpg 0EF317F6 rom/photo_print/ic_img02.jpg 8450F97F rom/photo_print/ic_img03_01.jpg 811672C7 rom/photo_print/ic_img04_01.jpg 10AF68C5 rom/photo_print/ic_pity01.jpg E248C663 rom/photo_print/ic_pity02.jpg 758B7F24 rom/photo_print/ic_pity03.jpg A3C41D70 rom/photo_print/ic_pity04.jpg F99DF5BE rom/photo_print/ic_pity05.jpg A62C1CB0 rom/photo_print/img01_sample.jpg 67775A6A rom/photo_print/img02_sample.jpg E9B4DA0E rom/photo_print/img03_01.jpg 4586644D rom/photo_print/img04_01.jpg B88876B1 rom/photo_print/pity01.jpg 3B7A2A55 rom/photo_print/pity02.jpg 6CD6913D rom/photo_print/pity03.jpg D84B88F3 rom/photo_print/pity04.jpg 7BDDC3CC rom/photo_print/pity05.jpg 1AD3763B rom/photo_print/ss_rights01.tga 5ED59C1D rom/photo_print/ss_rights01_ic.tga 59DE8C6D rom/photo_print/ss_rights02.tga 8027905B rom/photo_print/ss_rights02_ic.tga A246F183 rom/photo_print/ss_rights03.tga 2EF36550 rom/photo_print/ss_rights03_ic.tga 4D1EAE49 rom/photo_print/ss_rights04_l.tga F4BCCBA4 rom/photo_print/ss_rights04_l_ic.tga 3DB31DA1 rom/photo_print/ss_rights04_r.tga 1905A8A2 rom/photo_print/ss_rights04_r_ic.tga 6A9D3C62 rom/photo_print/ss_rights05.tga 5D076B55 rom/pv_expression/exp_PV206.bin 2A283830 rom/pv_expression/exp_PV219.bin C0A2FC9C rom/pv_expression/exp_PV238.bin 21C775E2 rom/pv_expression/exp_PV239.bin 00E1D3FE rom/pv_expression/exp_PV240.bin 49B5D1F9 rom/pv_expression/exp_PV241.bin 0FE653C1 rom/pv_expression/exp_PV242.bin 342DDE5B rom/pv_expression/exp_PV243.bin 0FD6AB88 rom/pv_expression/exp_PV244.bin 5E9DC803 rom/pv_expression/exp_PV246.bin E42BDE6B rom/pv_expression/exp_PV247.bin 717E0FFB rom/pv_expression/exp_PV248.bin 0D39046F rom/pv_expression/exp_PV249.bin 8BF61673 rom/pv_expression/exp_PV250.bin 3C211D2E rom/pv_expression/exp_PV251.bin AC51996D rom/pv_expression/exp_PV253.bin E96058D0 rom/pv_expression/exp_PV255.bin 54393F48 rom/pv_expression/exp_PV259.bin 2520BA14 rom/pv_expression/exp_PV260.bin 1A44D4B9 rom/pv_expression/exp_PV261.bin 7C4EB670 rom/pv_expression/exp_PV262.bin 31F3B9F0 rom/pv_expression/exp_PV432.bin 51BDED3A rom/pv_expression/exp_PV433.bin 9791CBC2 rom/pv_expression/exp_PV434.bin D9C76514 rom/pv_expression/exp_PV435.bin E59705CA rom/pv_expression/exp_PV600.bin D38B105D rom/pv_expression/exp_PV601.bin 184B934B rom/pv_expression/exp_PV602.bin 9AFB8045 rom/pv_expression/exp_PV603.bin EDBED130 rom/pv_expression/exp_PV604.bin ABAB85DF rom/pv_expression/exp_PV605.bin 8E0B2351 rom/pv_expression/exp_PV607.bin F1F80366 rom/pv_expression/exp_PV608.bin CD08EE40 rom/pv_expression/exp_PV609.bin 7E79571A rom/pv_expression/exp_PV611.bin F272A78C rom/pv_expression/exp_PV612.bin DF247F48 rom/pv_expression/exp_PV613.bin E4CF5BC7 rom/pv_expression/exp_PV614.bin 590E3DEB rom/pv_expression/exp_PV615.bin 5157E68D rom/pv_expression/exp_PV616.bin 732DFF4A rom/pv_expression/exp_PV617.bin FD1F9A90 rom/pv_expression/exp_PV618.bin 2DD6700F rom/pv_expression/exp_PV619.bin 25828064 rom/pv_expression/exp_PV620.bin 305377B5 rom/pv_expression/exp_PV621.bin F6D467C2 rom/pv_expression/exp_PV622.bin A13589EF rom/pv_expression/exp_PV623.bin 51A708A8 rom/pv_expression/exp_PV624.bin 6FB635A5 rom/pv_expression/exp_PV625.bin 0CA7989C rom/pv_expression/exp_PV626.bin 2FB449FE rom/pv_expression/exp_PV627.bin D689E5C9 rom/pv_expression/exp_PV629.bin 8C0D1E03 rom/pv_expression/exp_PV630.bin 3CF1B314 rom/pv_expression/exp_PV631.bin D29D9934 rom/pv_expression/exp_PV637.bin 6558D09D rom/pv_expression/exp_PV638.bin 66B36A3B rom/pv_expression/exp_PV639.bin 2FEB93DB rom/pv_expression/exp_PV640.bin C07AC05D rom/pv_expression/exp_PV641.bin 1162840E rom/pv_expression/exp_PV642.bin 35092553 rom/pv_expression/exp_PV710.bin 49D838C5 rom/pv_expression/exp_PV722.bin 9139DD7B rom/pv_expression/exp_PV723.bin 096D50DA rom/pv_expression/exp_PV724.bin 7E67C971 rom/pv_expression/exp_PV725.bin 25A1C4DD rom/pv_expression/exp_PV726.bin 9F5B394F rom/pv_expression/exp_PV727.bin 7E66AE5D rom/pv_expression/exp_PV728.bin 4054ED6C rom/pv_expression/exp_PV729.bin B2DBDF2B rom/pv_expression/exp_PV730.bin B3AB20AB rom/pv_expression/exp_PV731.bin 4740AD26 rom/pv_expression/exp_PV732.bin 021B7BAE rom/pv_expression/exp_PV733.bin C92D29F5 rom/pv_expression/exp_PV734.bin 8A65B959 rom/pv_expression/exp_PV736.bin C2316A4C rom/pv_expression/exp_PV737.bin 77785185 rom/pv_expression/exp_PV738.bin B0826499 rom/pv_expression/exp_PV739.bin 4D168904 rom/pv_expression/exp_PV740.bin 44D2C17F rom/pv_expression/exp_PV832.bin 3FDEF7C1 rom/pv_expression/exp_PV257.bin 7F5B6F34 rom/pv_expression/exp_PV610.bin DA21FE7D rom/pv_expression/exp_PV628.bin DA4B1889 rom/ranking/dummy_thumb.jpg 4CDAA935 rom/rob/mot_PV029_FACE_NER.farc BFD4CCF9 rom/rob/mothead_AUTH_HAK.bin 28571485 rom/rob/mothead_AUTH_KAI.bin E78CAC79 rom/rob/mothead_AUTH_LEN.bin A38F5693 rom/rob/mothead_AUTH_LUK.bin 8597EFF4 rom/rob/mothead_AUTH_MEI.bin D8B4FEB2 rom/rob/mothead_AUTH_MIK.bin C614E78F rom/rob/mothead_AUTH_NER.bin CFC38663 rom/rob/mothead_AUTH_RIN.bin AA543CCB rom/rob/mothead_AUTH_SAK.bin C5594550 rom/rob/mothead_CMN.bin A9AC3C98 rom/rob/mothead_EDT.bin 1C2CB8B3 rom/rob/mothead_EDT2.bin 2D941FE6 rom/rob/mothead_EDTF1.bin CF3F09C1 rom/rob/mothead_PV001.bin 862484C2 rom/rob/mothead_PV002.bin 8EF54CF2 rom/rob/mothead_PV003.bin 4FF9277B rom/rob/mothead_PV005.bin 4082775E rom/rob/mothead_PV006.bin 8FA10C2E rom/rob/mothead_PV007.bin BC64B5FF rom/rob/mothead_PV008.bin 740E0E3E rom/rob/mothead_PV009.bin A162B9C4 rom/rob/mothead_PV010.bin B632502C rom/rob/mothead_PV011.bin 6BE16818 rom/rob/mothead_PV012.bin FCA63D95 rom/rob/mothead_PV013.bin 53DE0A31 rom/rob/mothead_PV014.bin 9062BF06 rom/rob/mothead_PV015.bin E780E0AA rom/rob/mothead_PV016.bin F265CC85 rom/rob/mothead_PV017.bin 618D4351 rom/rob/mothead_PV018.bin 3A1C9EA8 rom/rob/mothead_PV019.bin 9136094F rom/rob/mothead_PV020.bin 45E5B032 rom/rob/mothead_PV022.bin A4C6C7C8 rom/rob/mothead_PV023.bin C4AC97C0 rom/rob/mothead_PV024.bin B4489779 rom/rob/mothead_PV025.bin DA135C5F rom/rob/mothead_PV027.bin 31E02C70 rom/rob/mothead_PV028.bin 504E0F2D rom/rob/mothead_PV029.bin BCF26BFF rom/rob/mothead_PV030.bin 7C88CFEE rom/rob/mothead_PV031.bin 39AF33C4 rom/rob/mothead_PV032.bin EC4390B0 rom/rob/mothead_PV037.bin 55D65577 rom/rob/mothead_PV038.bin 21CB698B rom/rob/mothead_PV039.bin 970635DC rom/rob/mothead_PV040.bin C76CF362 rom/rob/mothead_PV041.bin D836A057 rom/rob/mothead_PV042.bin 83809182 rom/rob/mothead_PV044.bin 0111ADF0 rom/rob/mothead_PV045.bin 2D87EB5C rom/rob/mothead_PV046.bin 2A3C9D46 rom/rob/mothead_PV047.bin F3884670 rom/rob/mothead_PV048.bin 1FFE60BC rom/rob/mothead_PV049.bin 7B6A950A rom/rob/mothead_PV050.bin E4DA3236 rom/rob/mothead_PV051.bin 413127E5 rom/rob/mothead_PV052.bin DABF952D rom/rob/mothead_PV053.bin 1C2D75A0 rom/rob/mothead_PV054.bin 0116A225 rom/rob/mothead_PV055.bin D634319E rom/rob/mothead_PV056.bin EE06BE93 rom/rob/mothead_PV057.bin 44E7EF21 rom/rob/mothead_PV058.bin 3F8D9581 rom/rob/mothead_PV059.bin C2DD284B rom/rob/mothead_PV004.bin 93BC6611 rom/rob/mothead_PV021.bin B65ECB1F rom/rob/mothead_PV043.bin 3A162295 rom/rob/mothead_PV060.bin B09EE39D rom/rob/mothead_PV090.bin E9D38868 rom/rob/mothead_PV208.bin 59200449 rom/rob/mothead_PV231.bin C8A48CF8 rom/rob/mothead_PV250.bin 8C2BACF9 rom/rob/mothead_PV604.bin 09595E47 rom/rob/mothead_PV622.bin 4560D379 rom/rob/mothead_PV722.bin EE85A47C rom/rob/mothead_PV740.bin 4B01DE0B rom/rob/mot_HAK.farc AA0412C9 rom/rob/mot_PV012.farc AD3EA805 rom/rob/mot_PV027_FACE_LEN.farc ABF0594D rom/rob/mothead_PV061.bin 56D7207D rom/rob/mothead_PV062.bin 1852F643 rom/rob/mothead_PV063.bin 5F6BD13D rom/rob/mothead_PV064.bin CE157258 rom/rob/mothead_PV065.bin 859793DB rom/rob/mothead_PV066.bin 00C4A54D rom/rob/mothead_PV079.bin B4A31CD8 rom/rob/mothead_PV081.bin BD0C5DCD rom/rob/mothead_PV082.bin E735BDDA rom/rob/mothead_PV083.bin E217DC74 rom/rob/mothead_PV084.bin 431C85A9 rom/rob/mothead_PV085.bin FA64792D rom/rob/mothead_PV086.bin 1389A49D rom/rob/mothead_PV087.bin B5EF9185 rom/rob/mothead_PV088.bin 36D7CFB7 rom/rob/mothead_PV089.bin 69326BE8 rom/rob/mothead_PV091.bin 7DA63EFF rom/rob/mothead_PV092.bin A441C861 rom/rob/mothead_PV093.bin 6A018296 rom/rob/mothead_PV094.bin 3062873F rom/rob/mothead_PV095.bin F177223F rom/rob/mothead_PV096.bin D02218C8 rom/rob/mothead_PV097.bin 0B644940 rom/rob/mothead_PV102.bin 26BD22CF rom/rob/mothead_PV103.bin F5960BE0 rom/rob/mothead_PV104.bin 8F210090 rom/rob/mothead_PV201.bin 68FCEAD8 rom/rob/mothead_PV202.bin 63E1B617 rom/rob/mothead_PV204.bin 80617968 rom/rob/mothead_PV205.bin 8E3424EE rom/rob/mothead_PV206.bin 5F22B61A rom/rob/mothead_PV207.bin 72C3D410 rom/rob/mothead_PV210.bin DC6E5B36 rom/rob/mothead_PV211.bin 29694311 rom/rob/mothead_PV212.bin 885DA744 rom/rob/mothead_PV213.bin F7D83A68 rom/rob/mothead_PV214.bin FEC451C1 rom/rob/mothead_PV218.bin D3CAD61D rom/rob/mothead_PV219.bin 907C93C0 rom/rob/mothead_PV220.bin AFEA5750 rom/rob/mothead_PV221.bin 9E0A442C rom/rob/mothead_PV222.bin 6A2F6512 rom/rob/mothead_PV223.bin 901CA512 rom/rob/mothead_PV224.bin EF252B7F rom/rob/mothead_PV225.bin F2ABEB4B rom/rob/mothead_PV226.bin 94110BF0 rom/rob/mothead_PV227.bin 13D43BF0 rom/rob/mothead_PV228.bin 785CBFEC rom/rob/mothead_PV232.bin F70D696D rom/rob/mothead_PV233.bin FFB18436 rom/rob/mothead_PV234.bin 2B091843 rom/rob/mothead_PV235.bin 94517E67 rom/rob/mothead_PV236.bin C1F65832 rom/rob/mothead_PV238.bin 10F84BDF rom/rob/mothead_PV239.bin E7599A8E rom/rob/mothead_PV240.bin 8D5FAE26 rom/rob/mothead_PV241.bin EDECF060 rom/rob/mothead_PV242.bin 785B33A6 rom/rob/mothead_PV243.bin 1F7777F7 rom/rob/mothead_PV244.bin 501EFC69 rom/rob/mothead_PV246.bin 8281FDBA rom/rob/mothead_PV247.bin 7FCC32CF rom/rob/mothead_PV248.bin A4E3F518 rom/rob/mothead_PV249.bin 447C81E6 rom/rob/mothead_PV251.bin 044A01B1 rom/rob/mothead_PV253.bin 088B3988 rom/rob/mothead_PV255.bin EDF65EE7 rom/rob/mothead_PV257.bin 60ABBEBA rom/rob/mothead_PV259.bin 86C88A3D rom/rob/mothead_PV260.bin F4E28C06 rom/rob/mothead_PV261.bin F054B4EB rom/rob/mothead_PV262.bin B3DE54B9 rom/rob/mothead_PV432.bin 5901BA12 rom/rob/mothead_PV433.bin D01E4A05 rom/rob/mothead_PV434.bin 534FC8B4 rom/rob/mothead_PV435.bin 39688F9C rom/rob/mothead_PV600.bin 2CA3E84B rom/rob/mothead_PV601.bin 33655BBB rom/rob/mothead_PV602.bin E8B5BE33 rom/rob/mothead_PV603.bin 2B5609CC rom/rob/mothead_PV605.bin 71138329 rom/rob/mothead_PV607.bin EE15744B rom/rob/mothead_PV608.bin 9AE2A665 rom/rob/mothead_PV609.bin 76AF802E rom/rob/mothead_PV610.bin 1FDBE08F rom/rob/mothead_PV611.bin F6CC9D4B rom/rob/mothead_PV612.bin 17F0CF94 rom/rob/mothead_PV613.bin A2B38CF3 rom/rob/mothead_PV614.bin 17C24EA0 rom/rob/mothead_PV615.bin 8873275B rom/rob/mothead_PV616.bin 76BD7837 rom/rob/mothead_PV617.bin 2D377174 rom/rob/mothead_PV618.bin 9C78366C rom/rob/mothead_PV619.bin 5032AE35 rom/rob/mothead_PV620.bin 2EEE7D43 rom/rob/mothead_PV621.bin 2420EFDD rom/rob/mothead_PV623.bin 57B6EA67 rom/rob/mothead_PV624.bin 0D0466DC rom/rob/mothead_PV625.bin A5BFA40F rom/rob/mothead_PV626.bin 7BBFBF8B rom/rob/mothead_PV627.bin B9A20532 rom/rob/mothead_PV628.bin 76285120 rom/rob/mothead_PV629.bin 86441FD6 rom/rob/mothead_PV630.bin 4DB269C0 rom/rob/mothead_PV631.bin 0FB2BF34 rom/rob/mothead_PV637.bin B2B99A41 rom/rob/mothead_PV638.bin 1373CCEE rom/rob/mothead_PV639.bin 7A988415 rom/rob/mothead_PV640.bin 68A7C26B rom/rob/mothead_PV641.bin BDAB3D2C rom/rob/mothead_PV642.bin 4DAC25B6 rom/rob/mothead_PV710.bin 01238C7E rom/rob/mothead_PV723.bin F738290D rom/rob/mothead_PV724.bin 988EC738 rom/rob/mothead_PV725.bin 79EC1284 rom/rob/mothead_PV726.bin 7DBED8D1 rom/rob/mothead_PV727.bin 708CF6EA rom/rob/mothead_PV728.bin 1EAFEF66 rom/rob/mothead_PV729.bin FB1A2F30 rom/rob/mothead_PV730.bin 399FD761 rom/rob/mothead_PV731.bin 20C30D75 rom/rob/mothead_PV732.bin AC300D2A rom/rob/mothead_PV733.bin BC232212 rom/rob/mothead_PV734.bin 3F75063A rom/rob/mothead_PV736.bin CA4A42CA rom/rob/mothead_PV737.bin 30C81D0D rom/rob/mothead_PV738.bin AE74F2D7 rom/rob/mothead_PV739.bin C7EB4022 rom/rob/mothead_PV832.bin 850AD2A8 rom/rob/mothead_TEST_DESIGN.bin 2645DD0D rom/rob/mot_ALL_SELECTOR_POSE.farc DD1FB415 rom/rob/mot_AUTH_HAK.farc D06E913A rom/rob/mot_AUTH_KAI.farc C4E11950 rom/rob/mot_AUTH_LEN.farc 54832199 rom/rob/mot_AUTH_LUK.farc FCDE3F60 rom/rob/mot_AUTH_MEI.farc 5022A71D rom/rob/mot_AUTH_MIK.farc 39EDE6D9 rom/rob/mot_AUTH_NER.farc 0C4E858B rom/rob/mot_AUTH_RIN.farc 9C644FE4 rom/rob/mot_AUTH_SAK.farc 28932520 rom/rob/mot_CMN.farc 28AE6059 rom/rob/mot_db.farc 6E06941F rom/rob/mot_EDT.farc 476B72D7 rom/rob/mot_EDT2.farc 9A45D7CF rom/rob/mot_EDTF1.farc C98DA9BF rom/rob/mot_KAI.farc A686B386 rom/rob/mot_LEN.farc 97AD9349 rom/rob/mot_LUK.farc 2839D708 rom/rob/mot_MEI.farc 6F2AFE71 rom/rob/mot_MIK.farc D361F11D rom/rob/mot_NER.farc 83214E6B rom/rob/mot_PV001.farc 80B55785 rom/rob/mot_PV002.farc 2430AA45 rom/rob/mot_PV003.farc D82364CE rom/rob/mot_PV004.farc 71F656A1 rom/rob/mot_PV005.farc C7DB4FCB rom/rob/mot_PV006.farc 59E61319 rom/rob/mot_PV007.farc 416B5E54 rom/rob/mot_PV008.farc DD98009F rom/rob/mot_PV009.farc C6E483CA rom/rob/mot_PV010.farc CE632342 rom/rob/mot_PV011.farc 507EDAAE rom/rob/mot_PV013.farc 59E31C33 rom/rob/mot_PV014.farc 42A1F736 rom/rob/mot_PV015.farc AD3B1B5E rom/rob/mot_PV016.farc 9B7CF300 rom/rob/mot_PV017.farc 779B5F95 rom/rob/mot_PV018.farc 039870FE rom/rob/mot_PV019.farc F685F4FF rom/rob/mot_PV020.farc 9092CB1C rom/rob/mot_PV021.farc 23255833 rom/rob/mot_PV022.farc AFB89EF1 rom/rob/mot_PV023.farc 555F0452 rom/rob/mot_PV024.farc A951E754 rom/rob/mot_PV025.farc 0FAF6575 rom/rob/mot_PV027.farc D7872F90 rom/rob/mot_PV027_FACE_HAK.farc DA971F43 rom/rob/mot_PV027_FACE_KAI.farc 7D4CB428 rom/rob/mot_PV027_FACE_LUK.farc 8582CA8F rom/rob/mot_PV027_FACE_MEI.farc 6C3E5992 rom/rob/mot_PV027_FACE_MIK.farc 4B668F81 rom/rob/mot_PV027_FACE_NER.farc 29EDBAA9 rom/rob/mot_PV027_FACE_RIN.farc 086A4A96 rom/rob/mot_PV027_FACE_SAK.farc F12E4D27 rom/rob/mot_PV027_FACE_TET.farc 3DDAD540 rom/rob/mot_PV028.farc 5F3C4913 rom/rob/mot_PV029.farc A09E6E6F rom/rob/mot_PV029_FACE_HAK.farc A587BAC9 rom/rob/mot_PV029_FACE_KAI.farc 7B05E08D rom/rob/mot_PV029_FACE_LEN.farc 83C45CEE rom/rob/mot_PV029_FACE_LUK.farc 5EE78E7C rom/rob/mot_PV029_FACE_MEI.farc 2BC1FD5C rom/rob/mot_PV029_FACE_MIK.farc 3C70F039 rom/rob/mot_PV029_FACE_RIN.farc 2E9C26CA rom/rob/mot_PV029_FACE_SAK.farc 0119EBAB rom/rob/mot_PV029_FACE_TET.farc BEF6FDB6 rom/rob/mot_PV030.farc 9065CECD rom/rob/mot_PV030_FACE_HAK.farc 583E7D47 rom/rob/mot_PV030_FACE_KAI.farc 7D2088D1 rom/rob/mot_PV030_FACE_LEN.farc C513CFE4 rom/rob/mot_PV030_FACE_LUK.farc 0B3CFE9F rom/rob/mot_PV030_FACE_MEI.farc 8EAC371B rom/rob/mot_PV030_FACE_MIK.farc 106D954F rom/rob/mot_PV030_FACE_NER.farc 9D3C0936 rom/rob/mot_PV030_FACE_RIN.farc 988D14BB rom/rob/mot_PV030_FACE_SAK.farc 62E19641 rom/rob/mot_PV030_FACE_TET.farc FDFDF2C8 rom/rob/mot_PV031.farc 1B3A22BD rom/rob/mot_PV031_FACE_KAI.farc 8178813B rom/rob/mot_PV031_FACE_LEN.farc BBD8FF75 rom/rob/mot_PV031_FACE_LUK.farc 8F336BC6 rom/rob/mot_PV031_FACE_MEI.farc 4AAA30E7 rom/rob/mot_PV031_FACE_MIK.farc B9231D06 rom/rob/mot_PV031_FACE_NER.farc C882B93B rom/rob/mot_PV031_FACE_RIN.farc 5A118BF2 rom/rob/mot_PV031_FACE_SAK.farc 4127FD9E rom/rob/mot_PV031_FACE_TET.farc 438764E8 rom/rob/mot_PV032.farc 73DB10DC rom/rob/mot_PV032_FACE_HAK.farc 2C1C5509 rom/rob/mot_PV032_FACE_KAI.farc C6FD97CE rom/rob/mot_PV032_FACE_LEN.farc 071BDD88 rom/rob/mot_PV032_FACE_LUK.farc B6EB3BE5 rom/rob/mot_PV032_FACE_MEI.farc 7E04431C rom/rob/mot_PV032_FACE_MIK.farc E5B7558C rom/rob/mot_PV032_FACE_RIN.farc 1D8B4315 rom/rob/mot_PV032_FACE_SAK.farc E23477FC rom/rob/mot_PV032_FACE_TET.farc 693E634C rom/rob/mot_PV037.farc A8910973 rom/rob/mot_PV038.farc 00E45EB8 rom/rob/mot_PV039.farc 6AE62BF3 rom/rob/mot_PV040.farc 0AEB8C5A rom/rob/mot_PV041.farc B0A35172 rom/rob/mot_PV042.farc B2F170A1 rom/rob/mot_PV043.farc 0158079E rom/rob/mot_PV044.farc 5F735677 rom/rob/mot_PV045.farc AB1B3818 rom/rob/mot_PV046.farc F72C3906 rom/rob/mot_PV047.farc 6495CBDD rom/rob/mot_PV048.farc 16E120B7 rom/rob/mot_PV049.farc DCA86EC5 rom/rob/mot_PV050.farc BDC4C6C9 rom/rob/mot_PV052.farc B7B60AB3 rom/rob/mot_PV053.farc 899C150C rom/rob/mot_PV054.farc 9CC8409E rom/rob/mot_PV055.farc 1E74CBB7 rom/rob/mot_PV056.farc EA13A898 rom/rob/mot_PV057.farc 47E84F6F rom/rob/mot_PV058.farc AAB7FE03 rom/rob/mot_PV059.farc 4B1FEDD7 rom/rob/mot_PV060.farc C2A418C9 rom/rob/mot_PV061.farc 8D28C33D rom/rob/mot_PV062.farc A9E35B74 rom/rob/mot_PV063.farc 32DB766A rom/rob/mot_PV064.farc 01D763D1 rom/rob/mot_PV065.farc E5F6AAC4 rom/rob/mot_PV066.farc 0A5DA6D2 rom/rob/mot_PV079.farc 4A1A8AA0 rom/rob/mot_PV081.farc 9702C7F1 rom/rob/mot_PV083.farc D8B7EFE7 rom/rob/mot_PV084.farc 42AB59A8 rom/rob/mot_PV085.farc E18F2171 rom/rob/mot_PV086.farc 292AAA03 rom/rob/mot_PV087.farc 463CA0C6 rom/rob/mot_PV088.farc AA2C3AFE rom/rob/mot_PV089.farc 153E3C23 rom/rob/mot_PV090.farc E24F08AC rom/rob/mot_PV091.farc CB5759AE rom/rob/mot_PV092.farc 732E2696 rom/rob/mot_PV093.farc 98E41F08 rom/rob/mot_PV094.farc C327FA78 rom/rob/mot_PV095.farc AE673996 rom/rob/mot_PV096.farc C2D694E7 rom/rob/mot_PV097.farc E676ED74 rom/rob/mot_PV102.farc 3C9A124A rom/rob/mot_PV102_FACE_KAI.farc FCCCC86F rom/rob/mot_PV102_FACE_LEN.farc 9796B616 rom/rob/mot_PV102_FACE_LUK.farc 3B2C937F rom/rob/mot_PV102_FACE_MEI.farc CA0F893F rom/rob/mot_PV102_FACE_MIK.farc 0E90FF3D rom/rob/mot_PV102_FACE_NER.farc 5FF2D2E8 rom/rob/mot_PV102_FACE_RIN.farc 6500A6CA rom/rob/mot_PV102_FACE_SAK.farc 9F7313AA rom/rob/mot_PV102_FACE_TET.farc 0F79667B rom/rob/mot_PV103.farc D6D877CF rom/rob/mot_PV103_FACE_HAK.farc DB3E0D49 rom/rob/mot_PV103_FACE_KAI.farc 89E85660 rom/rob/mot_PV103_FACE_LEN.farc 1BA17F81 rom/rob/mot_PV103_FACE_LUK.farc 32231FC2 rom/rob/mot_PV103_FACE_MEI.farc CF1E5D20 rom/rob/mot_PV103_FACE_NER.farc 9E7C371E rom/rob/mot_PV103_FACE_RIN.farc FE715049 rom/rob/mot_PV103_FACE_SAK.farc 36EC3596 rom/rob/mot_PV103_FACE_TET.farc 6FF65A81 rom/rob/mot_PV104.farc 05DDCE82 rom/rob/mot_PV104_FACE_HAK.farc 6079A137 rom/rob/mot_PV104_FACE_KAI.farc 700047FF rom/rob/mot_PV104_FACE_LEN.farc 0A933EDC rom/rob/mot_PV104_FACE_LUK.farc 35FCB1FB rom/rob/mot_PV104_FACE_MEI.farc 0907703E rom/rob/mot_PV104_FACE_MIK.farc 407F154D rom/rob/mot_PV104_FACE_NER.farc BAEA0F52 rom/rob/mot_PV104_FACE_RIN.farc 0687A07B rom/rob/mot_PV104_FACE_SAK.farc 9FBA005B rom/rob/mot_PV104_FACE_TET.farc 294384E0 rom/rob/mot_PV201_FACE_HAK.farc BF802324 rom/rob/mot_PV201_FACE_KAI.farc FF7124EB rom/rob/mot_PV201_FACE_LEN.farc 5FF94D0E rom/rob/mot_PV201_FACE_LUK.farc B1EB5966 rom/rob/mot_PV201_FACE_MEI.farc D46D936F rom/rob/mot_PV201_FACE_MIK.farc 9C4EBA4D rom/rob/mot_PV201_FACE_NER.farc B3732EEE rom/rob/mot_PV201_FACE_RIN.farc 494E673D rom/rob/mot_PV201_FACE_SAK.farc DE79533F rom/rob/mot_PV201_FACE_TET.farc C36BBA55 rom/rob/mot_PV202.farc 0ADC19DC rom/rob/mot_PV202_FACE_HAK.farc FA3FA8E8 rom/rob/mot_PV202_FACE_KAI.farc 805719A3 rom/rob/mot_PV202_FACE_LEN.farc A7597636 rom/rob/mot_PV202_FACE_LUK.farc 0D8DFF60 rom/rob/mot_PV202_FACE_MIK.farc DD50EC7A rom/rob/mot_PV202_FACE_NER.farc 328C6663 rom/rob/mot_PV202_FACE_RIN.farc 585228F2 rom/rob/mot_PV202_FACE_SAK.farc DE23EB72 rom/rob/mot_PV202_FACE_TET.farc 6F3E2D37 rom/rob/mot_PV204.farc 39A1E77D rom/rob/mot_PV204_FACE_HAK.farc FBED96A8 rom/rob/mot_PV204_FACE_KAI.farc 542C5FC1 rom/rob/mot_PV204_FACE_LEN.farc 98EEC3B5 rom/rob/mot_PV204_FACE_LUK.farc 79315D9A rom/rob/mot_PV204_FACE_MEI.farc D7F851AB rom/rob/mot_PV204_FACE_MIK.farc B51F768E rom/rob/mot_PV204_FACE_NER.farc 2B79E1A6 rom/rob/mot_PV204_FACE_RIN.farc 778DA720 rom/rob/mot_PV204_FACE_SAK.farc 87C8EF9A rom/rob/mot_PV205.farc A2E21EEA rom/rob/mot_PV205_FACE_HAK.farc A508B6A6 rom/rob/mot_PV205_FACE_KAI.farc B9844EE9 rom/rob/mot_PV205_FACE_LEN.farc 892F0BBD rom/rob/mot_PV205_FACE_LUK.farc D4ECBC43 rom/rob/mot_PV205_FACE_MEI.farc 9A8B0E18 rom/rob/mot_PV205_FACE_MIK.farc 3260903A rom/rob/mot_PV205_FACE_NER.farc 3B081816 rom/rob/mot_PV205_FACE_RIN.farc 850C0FF8 rom/rob/mot_PV205_FACE_SAK.farc 3CBC3B6A rom/rob/mot_PV205_FACE_TET.farc 6B1CF400 rom/rob/mot_PV206.farc 72660B2D rom/rob/mot_PV206_FACE_HAK.farc D279636B rom/rob/mot_PV206_FACE_KAI.farc 552976CD rom/rob/mot_PV206_FACE_LEN.farc EA2C49C5 rom/rob/mot_PV206_FACE_MEI.farc 8A250A93 rom/rob/mot_PV206_FACE_MIK.farc 7D70536C rom/rob/mot_PV206_FACE_NER.farc B94704DC rom/rob/mot_PV206_FACE_RIN.farc 468FB881 rom/rob/mot_PV206_FACE_SAK.farc F5BF820C rom/rob/mot_PV206_FACE_TET.farc 98D8C417 rom/rob/mot_PV207.farc 0391AD72 rom/rob/mot_PV207_FACE_HAK.farc 9D369AA1 rom/rob/mot_PV207_FACE_KAI.farc 88762C11 rom/rob/mot_PV207_FACE_LEN.farc F244E846 rom/rob/mot_PV207_FACE_LUK.farc 13AC524F rom/rob/mot_PV207_FACE_MEI.farc C747B780 rom/rob/mot_PV207_FACE_MIK.farc 0CCCFF55 rom/rob/mot_PV207_FACE_NER.farc 15391257 rom/rob/mot_PV207_FACE_RIN.farc D4DDC517 rom/rob/mot_PV207_FACE_TET.farc CAF6DF29 rom/rob/mot_PV208.farc C66506EF rom/rob/mot_PV208_FACE_HAK.farc 1B8C64B2 rom/rob/mot_PV208_FACE_KAI.farc 76CD4111 rom/rob/mot_PV208_FACE_LEN.farc 67ECE393 rom/rob/mot_PV208_FACE_LUK.farc 6EF1CD38 rom/rob/mot_PV208_FACE_MEI.farc 2EF514F6 rom/rob/mot_PV208_FACE_MIK.farc CD1A3737 rom/rob/mot_PV208_FACE_NER.farc FDE8FF73 rom/rob/mot_PV208_FACE_RIN.farc 4DE67660 rom/rob/mot_PV208_FACE_SAK.farc 9550ABEC rom/rob/mot_PV208_FACE_TET.farc B45021B5 rom/rob/mot_PV210.farc 3E5944B2 rom/rob/mot_PV210_FACE_HAK.farc 653E7C8D rom/rob/mot_PV210_FACE_KAI.farc 2D7C422C rom/rob/mot_PV210_FACE_LUK.farc 7C73C056 rom/rob/mot_PV210_FACE_MEI.farc 36225B4C rom/rob/mot_PV210_FACE_MIK.farc 28BED80A rom/rob/mot_PV210_FACE_NER.farc 08C608A0 rom/rob/mot_PV210_FACE_RIN.farc 23B04CF5 rom/rob/mot_PV210_FACE_SAK.farc BAFE7F36 rom/rob/mot_PV210_FACE_TET.farc 9BA70E89 rom/rob/mot_PV211.farc 8667699A rom/rob/mot_PV211_FACE_HAK.farc 3D78A274 rom/rob/mot_PV211_FACE_KAI.farc 7255ECC9 rom/rob/mot_PV211_FACE_LEN.farc 95FCA063 rom/rob/mot_PV211_FACE_LUK.farc 6ED62ACC rom/rob/mot_PV211_FACE_MEI.farc 3B495316 rom/rob/mot_PV211_FACE_MIK.farc 8BECAA7F rom/rob/mot_PV211_FACE_NER.farc 3DF1EEC0 rom/rob/mot_PV211_FACE_SAK.farc 650E5B6F rom/rob/mot_PV211_FACE_TET.farc 3D483E40 rom/rob/mot_PV212.farc 4778AD14 rom/rob/mot_PV212_FACE_HAK.farc D883FF80 rom/rob/mot_PV212_FACE_KAI.farc E64F0134 rom/rob/mot_PV212_FACE_LEN.farc C733095F rom/rob/mot_PV212_FACE_LUK.farc D97789EF rom/rob/mot_PV212_FACE_MEI.farc 14B4273B rom/rob/mot_PV212_FACE_MIK.farc 0CD2A368 rom/rob/mot_PV212_FACE_NER.farc AB5A1824 rom/rob/mot_PV212_FACE_RIN.farc C8CC39AD rom/rob/mot_PV212_FACE_SAK.farc 7E116F84 rom/rob/mot_PV212_FACE_TET.farc 2AFD2C6A rom/rob/mot_PV213.farc 53EA615E rom/rob/mot_PV214.farc 31D1BEA2 rom/rob/mot_PV214_FACE_KAI.farc 2ACA5B15 rom/rob/mot_PV214_FACE_LEN.farc 7C51A621 rom/rob/mot_PV214_FACE_LUK.farc 475E67AB rom/rob/mot_PV214_FACE_MEI.farc 65F93BD7 rom/rob/mot_PV214_FACE_MIK.farc 4E20AE2F rom/rob/mot_PV214_FACE_NER.farc 234BE388 rom/rob/mot_PV214_FACE_RIN.farc 5DD6B7E4 rom/rob/mot_PV214_FACE_SAK.farc 70B6E986 rom/rob/mot_PV214_FACE_TET.farc DC284597 rom/rob/mot_PV218.farc D7762DE0 rom/rob/mot_PV218_FACE_HAK.farc 633DF6F4 rom/rob/mot_PV218_FACE_KAI.farc 9060B501 rom/rob/mot_PV218_FACE_LEN.farc E52CCED0 rom/rob/mot_PV218_FACE_LUK.farc 9BF365E7 rom/rob/mot_PV218_FACE_MEI.farc 00CF569D rom/rob/mot_PV218_FACE_NER.farc 972DB190 rom/rob/mot_PV218_FACE_RIN.farc DCFB92CF rom/rob/mot_PV218_FACE_SAK.farc A11370B0 rom/rob/mot_PV218_FACE_TET.farc FEE5BC5D rom/rob/mot_PV219.farc F76177BC rom/rob/mot_PV219_FACE_HAK.farc D071FED8 rom/rob/mot_PV219_FACE_KAI.farc 4EAF1680 rom/rob/mot_PV219_FACE_LEN.farc 67AA80A7 rom/rob/mot_PV219_FACE_LUK.farc 696B43FB rom/rob/mot_PV219_FACE_MEI.farc 4346488D rom/rob/mot_PV219_FACE_MIK.farc C977CEDA rom/rob/mot_PV219_FACE_NER.farc D50115B4 rom/rob/mot_PV219_FACE_RIN.farc C0E2B71C rom/rob/mot_PV219_FACE_SAK.farc 70894DFE rom/rob/mot_PV219_FACE_TET.farc 4E84BD33 rom/rob/mot_PV031_FACE_HAK.farc AE8BF51E rom/rob/mot_PV032_FACE_NER.farc 79071BAE rom/rob/mot_PV051.farc 51844B97 rom/rob/mot_PV082.farc C9E8996D rom/rob/mot_PV102_FACE_HAK.farc 103D6223 rom/rob/mot_PV103_FACE_MIK.farc 1D7F7643 rom/rob/mot_PV201.farc C51658B3 rom/rob/mot_PV202_FACE_MEI.farc 19E7C001 rom/rob/mot_PV204_FACE_TET.farc 62C0D325 rom/rob/mot_PV206_FACE_LUK.farc 423538F2 rom/rob/mot_PV207_FACE_SAK.farc 0E39D543 rom/rob/mot_PV210_FACE_LEN.farc A32BFEEE rom/rob/mot_PV211_FACE_RIN.farc 117564CE rom/rob/mot_PV214_FACE_HAK.farc 6D9EADF8 rom/rob/mot_PV218_FACE_MIK.farc 8AF41808 rom/rob/mot_PV220.farc EB54A43D rom/rob/mot_PV221_FACE_MEI.farc EE8FE42B rom/rob/mot_PV222_FACE_TET.farc 04EA5894 rom/rob/mot_PV224_FACE_LUK.farc 91412A64 rom/rob/mot_PV225_FACE_TET.farc 60F39DF4 rom/rob/mot_PV232_FACE_KAI.farc B85EA1D1 rom/rob/mot_PV233_FACE_NER.farc FCDE2606 rom/rob/mot_PV235_FACE_HAK.farc 5680B92C rom/rob/mot_PV236_FACE_NER.farc 64DFDCE5 rom/rob/mot_PV255.farc DAA6EA49 rom/rob/mot_PV609.farc F5EB1947 rom/rob/mot_PV627.farc D9F2BD91 rom/rob/mot_PV220_FACE_HAK.farc 87D80FE7 rom/rob/mot_PV220_FACE_KAI.farc A2C42711 rom/rob/mot_PV220_FACE_LEN.farc 577C71C9 rom/rob/mot_PV220_FACE_LUK.farc D5422989 rom/rob/mot_PV220_FACE_MEI.farc 883C3427 rom/rob/mot_PV220_FACE_MIK.farc EB91F559 rom/rob/mot_PV220_FACE_NER.farc 3DB98431 rom/rob/mot_PV220_FACE_RIN.farc 3E29BFDB rom/rob/mot_PV220_FACE_SAK.farc 3034C4D3 rom/rob/mot_PV220_FACE_TET.farc F6BB7AA5 rom/rob/mot_PV221.farc 97462CC6 rom/rob/mot_PV221_FACE_HAK.farc E790AB0F rom/rob/mot_PV221_FACE_KAI.farc 78DF8957 rom/rob/mot_PV221_FACE_LEN.farc 973C9A0F rom/rob/mot_PV221_FACE_LUK.farc 21F6129A rom/rob/mot_PV221_FACE_MIK.farc D9F257C6 rom/rob/mot_PV221_FACE_NER.farc A4C6428F rom/rob/mot_PV221_FACE_RIN.farc AEC45047 rom/rob/mot_PV221_FACE_SAK.farc 53247744 rom/rob/mot_PV221_FACE_TET.farc 5ED2914E rom/rob/mot_PV222.farc DA5C0E6B rom/rob/mot_PV222_FACE_HAK.farc 1241EBE5 rom/rob/mot_PV222_FACE_KAI.farc 4228A2F4 rom/rob/mot_PV222_FACE_LEN.farc 74C3D243 rom/rob/mot_PV222_FACE_LUK.farc 40B46699 rom/rob/mot_PV222_FACE_MEI.farc 68043BF4 rom/rob/mot_PV222_FACE_MIK.farc 46B708C6 rom/rob/mot_PV222_FACE_NER.farc 83B9FA27 rom/rob/mot_PV222_FACE_RIN.farc 5F8E61BD rom/rob/mot_PV222_FACE_SAK.farc 00341A4C rom/rob/mot_PV223.farc F5946932 rom/rob/mot_PV223_FACE_HAK.farc B31AD813 rom/rob/mot_PV223_FACE_KAI.farc CAABE24E rom/rob/mot_PV223_FACE_LEN.farc 05344A04 rom/rob/mot_PV223_FACE_LUK.farc E8DA3541 rom/rob/mot_PV223_FACE_MEI.farc 490FCA9E rom/rob/mot_PV223_FACE_MIK.farc 4FD87274 rom/rob/mot_PV223_FACE_NER.farc DD52DBE4 rom/rob/mot_PV223_FACE_RIN.farc 360BA728 rom/rob/mot_PV223_FACE_SAK.farc A5446E91 rom/rob/mot_PV223_FACE_TET.farc F10462EB rom/rob/mot_PV224.farc FD2C9EFB rom/rob/mot_PV224_FACE_HAK.farc 56490A1D rom/rob/mot_PV224_FACE_KAI.farc 01CB9011 rom/rob/mot_PV224_FACE_LEN.farc CB259AFD rom/rob/mot_PV224_FACE_MEI.farc F52FF561 rom/rob/mot_PV224_FACE_MIK.farc 8004BE7C rom/rob/mot_PV224_FACE_NER.farc 34C39A6A rom/rob/mot_PV224_FACE_RIN.farc 95DF5D3D rom/rob/mot_PV224_FACE_SAK.farc A08C7A6F rom/rob/mot_PV224_FACE_TET.farc DCFB2609 rom/rob/mot_PV225.farc C6AE05A9 rom/rob/mot_PV225_FACE_HAK.farc 67BA1221 rom/rob/mot_PV225_FACE_KAI.farc A978E579 rom/rob/mot_PV225_FACE_LEN.farc C0E5752C rom/rob/mot_PV225_FACE_LUK.farc 3F0D37ED rom/rob/mot_PV225_FACE_MEI.farc FD9AE0AD rom/rob/mot_PV225_FACE_MIK.farc DF47B8CF rom/rob/mot_PV225_FACE_NER.farc 4EEF103D rom/rob/mot_PV225_FACE_RIN.farc 173B259A rom/rob/mot_PV225_FACE_SAK.farc B0AD16CA rom/rob/mot_PV226.farc 3AEBDE0E rom/rob/mot_PV227.farc 7C450317 rom/rob/mot_PV228.farc FAB9F40A rom/rob/mot_PV231.farc 83B2DC5A rom/rob/mot_PV231_FACE_HAK.farc F1371573 rom/rob/mot_PV231_FACE_KAI.farc 6E0A8AEB rom/rob/mot_PV231_FACE_LEN.farc C91D2AD1 rom/rob/mot_PV231_FACE_LUK.farc 7B661085 rom/rob/mot_PV231_FACE_MEI.farc 3CB0FA1C rom/rob/mot_PV231_FACE_MIK.farc C7A85094 rom/rob/mot_PV231_FACE_NER.farc 427B3341 rom/rob/mot_PV231_FACE_RIN.farc EAD5DFF8 rom/rob/mot_PV231_FACE_SAK.farc F121ED7F rom/rob/mot_PV231_FACE_TET.farc E687DA39 rom/rob/mot_PV232.farc C36AD8F1 rom/rob/mot_PV232_FACE_HAK.farc 0232BDF6 rom/rob/mot_PV232_FACE_LEN.farc DE0D2983 rom/rob/mot_PV232_FACE_LUK.farc 3DE218D1 rom/rob/mot_PV232_FACE_MEI.farc 87569015 rom/rob/mot_PV232_FACE_MIK.farc 41E10073 rom/rob/mot_PV232_FACE_NER.farc 8143C600 rom/rob/mot_PV232_FACE_RIN.farc 0C3E36E8 rom/rob/mot_PV232_FACE_SAK.farc 2F9A6402 rom/rob/mot_PV232_FACE_TET.farc 5758E900 rom/rob/mot_PV233.farc F25944F3 rom/rob/mot_PV233_FACE_HAK.farc 47263259 rom/rob/mot_PV233_FACE_KAI.farc 5C018E52 rom/rob/mot_PV233_FACE_LEN.farc F269FCD5 rom/rob/mot_PV233_FACE_LUK.farc 9A572038 rom/rob/mot_PV233_FACE_MEI.farc 0786BB32 rom/rob/mot_PV233_FACE_MIK.farc 60588C47 rom/rob/mot_PV233_FACE_RIN.farc 0B82CECF rom/rob/mot_PV233_FACE_SAK.farc 4D3346F6 rom/rob/mot_PV233_FACE_TET.farc 3FC81FB1 rom/rob/mot_PV234.farc 89EE9496 rom/rob/mot_PV234_FACE_HAK.farc 771AC878 rom/rob/mot_PV234_FACE_KAI.farc 36594FC8 rom/rob/mot_PV234_FACE_LEN.farc C733A674 rom/rob/mot_PV234_FACE_LUK.farc 83455B41 rom/rob/mot_PV234_FACE_MEI.farc C2085FD5 rom/rob/mot_PV234_FACE_MIK.farc DD3A7517 rom/rob/mot_PV234_FACE_NER.farc 5247C07E rom/rob/mot_PV234_FACE_RIN.farc 4F653629 rom/rob/mot_PV234_FACE_SAK.farc E3150089 rom/rob/mot_PV234_FACE_TET.farc E2B9DFDE rom/rob/mot_PV235.farc 132D1EA1 rom/rob/mot_PV235_FACE_KAI.farc A0509F39 rom/rob/mot_PV235_FACE_LEN.farc DF8CED8B rom/rob/mot_PV235_FACE_LUK.farc AE14119D rom/rob/mot_PV235_FACE_MEI.farc 851A1DE8 rom/rob/mot_PV235_FACE_MIK.farc 90214A28 rom/rob/mot_PV235_FACE_NER.farc B04A1309 rom/rob/mot_PV235_FACE_RIN.farc EE262478 rom/rob/mot_PV235_FACE_SAK.farc C2557026 rom/rob/mot_PV235_FACE_TET.farc 3B0A3410 rom/rob/mot_PV236.farc 672FF2FB rom/rob/mot_PV236_FACE_HAK.farc 5F01C601 rom/rob/mot_PV236_FACE_KAI.farc 9936AA2F rom/rob/mot_PV236_FACE_LEN.farc DD8586F1 rom/rob/mot_PV236_FACE_LUK.farc D762E696 rom/rob/mot_PV236_FACE_MEI.farc 80187D21 rom/rob/mot_PV236_FACE_MIK.farc 47BCDA3B rom/rob/mot_PV236_FACE_RIN.farc 7D033E0B rom/rob/mot_PV236_FACE_SAK.farc 59B01F3A rom/rob/mot_PV236_FACE_TET.farc E03846B0 rom/rob/mot_PV238.farc 0C7C660B rom/rob/mot_PV239.farc AEC4C3B1 rom/rob/mot_PV240.farc E17CB211 rom/rob/mot_PV241.farc 812063E8 rom/rob/mot_PV242.farc C33E5400 rom/rob/mot_PV243.farc 29A576EA rom/rob/mot_PV244.farc 92BFFC5A rom/rob/mot_PV246.farc B37B7828 rom/rob/mot_PV247.farc D6639AEB rom/rob/mot_PV248.farc B515BF16 rom/rob/mot_PV249.farc 76D882CD rom/rob/mot_PV250.farc 9182120E rom/rob/mot_PV251.farc 0C4AD4F8 rom/rob/mot_PV253.farc 22CAFBAA rom/rob/mot_PV257.farc 959382CB rom/rob/mot_PV259.farc 9F273E32 rom/rob/mot_PV260.farc 03CF56A3 rom/rob/mot_PV261.farc 307674B1 rom/rob/mot_PV262.farc A765F88C rom/rob/mot_PV432.farc 942718B2 rom/rob/mot_PV433.farc 1E5AF14A rom/rob/mot_PV434.farc A2CB59DB rom/rob/mot_PV435.farc 8F810415 rom/rob/mot_PV600.farc 09AE3483 rom/rob/mot_PV601.farc 86E8CBDD rom/rob/mot_PV602.farc 677F2EF2 rom/rob/mot_PV603.farc 7AC5F916 rom/rob/mot_PV604.farc 161C33B9 rom/rob/mot_PV605.farc F1B2636A rom/rob/mot_PV607.farc BA07C4A2 rom/rob/mot_PV608.farc D8B8919A rom/rob/mot_PV610.farc 9DA0BB84 rom/rob/mot_PV611.farc D2E3D5AF rom/rob/mot_PV612.farc 64EA0AFF rom/rob/mot_PV613.farc FC28AA41 rom/rob/mot_PV614.farc 2D532502 rom/rob/mot_PV615.farc 25AF554C rom/rob/mot_PV616.farc 2B0AF01F rom/rob/mot_PV617.farc 803C6D72 rom/rob/mot_PV618.farc A99D6727 rom/rob/mot_PV619.farc 18980224 rom/rob/mot_PV620.farc 1C9D01CD rom/rob/mot_PV621.farc 615ED08D rom/rob/mot_PV622.farc AF97BF8C rom/rob/mot_PV623.farc 5069FE6A rom/rob/mot_PV624.farc 30D1ED50 rom/rob/mot_PV625.farc 43AFCE74 rom/rob/mot_PV626.farc 488C9958 rom/rob/mot_PV628.farc DFC1AD31 rom/rob/mot_PV629.farc 90494243 rom/rob/mot_PV630.farc AA3EF9C1 rom/rob/mot_PV631.farc A1E99585 rom/rob/mot_PV637.farc 08B44675 rom/rob/mot_PV638.farc B27583FC rom/rob/mot_PV639.farc 4142C057 rom/rob/mot_PV640.farc A1084B03 rom/rob/mot_PV641.farc 7FD9035B rom/rob/mot_PV642.farc FC401099 rom/rob/mot_PV710.farc 13FBDF9A rom/rob/mot_PV722.farc 5DB02443 rom/rob/mot_PV723.farc 0D699E56 rom/rob/mot_PV724.farc CAC590BA rom/rob/mot_PV725.farc 6F1515FA rom/rob/mot_PV726.farc 0FB7EA65 rom/rob/mot_PV727.farc A55652ED rom/rob/mot_PV728.farc EEB7EB0F rom/rob/mot_PV729.farc DB0D7BF3 rom/rob/mot_PV730.farc 89145BED rom/rob/mot_PV731.farc FC88B6FF rom/rob/mot_PV732.farc DAD97F51 rom/rob/mot_PV733.farc A1C3DF77 rom/rob/mot_PV734.farc F356C916 rom/rob/mot_PV736.farc C34CEECE rom/rob/mot_PV737.farc 970B05EF rom/rob/mot_PV738.farc D3AF873D rom/rob/mot_PV739.farc C7C25486 rom/rob/mot_PV740.farc B1C031E2 rom/rob/mot_PV832.farc AFA1D91D rom/rob/mot_RIN.farc 3D2AEA9F rom/rob/mot_SAK.farc 81A606F2 rom/rob/mot_TEST_DESIGN.farc F3A9B25F rom/rob/mot_TET.farc 9A295A3E rom/rob/rob_mot_tbl.bin 38345C72 rom/script/pv_079_hard.dsc 681A936E rom/script/pv_260_normal.dsc A56A3EDA rom/script/pv_001_easy.dsc 4AA93F87 rom/script/pv_001_extreme.dsc 3659CD8B rom/script/pv_001_extreme_1.dsc 11D58E5E rom/script/pv_001_hard.dsc 030F8B7C rom/script/pv_001_normal.dsc B9E766FA rom/script/pv_002_easy.dsc 192A921A rom/script/pv_002_extreme.dsc E4717931 rom/script/pv_002_extreme_1.dsc 8F8EB4F4 rom/script/pv_002_hard.dsc F5A62426 rom/script/pv_002_normal.dsc F4E87501 rom/script/pv_003_easy.dsc 3984554F rom/script/pv_003_extreme.dsc B8895B83 rom/script/pv_003_extreme_1.dsc 176CDB0D rom/script/pv_003_hard.dsc 806B1D4D rom/script/pv_003_normal.dsc 7A257548 rom/script/pv_004_easy.dsc AEAFFC85 rom/script/pv_004_extreme.dsc B3DD560A rom/script/pv_005_easy.dsc 94EDF711 rom/script/pv_005_extreme.dsc A1C43375 rom/script/pv_005_extreme_1.dsc FC5ADC71 rom/script/pv_005_hard.dsc 79034B96 rom/script/pv_005_normal.dsc 3A7B5A08 rom/script/pv_006_easy.dsc 1F4273DF rom/script/pv_006_extreme.dsc AD6C78EF rom/script/pv_006_extreme_1.dsc 8D0F9A0E rom/script/pv_006_hard.dsc 6C2EA854 rom/script/pv_007_easy.dsc 04ADEF2C rom/script/pv_007_extreme.dsc 0B1575DD rom/script/pv_007_extreme_1.dsc B96F08FE rom/script/pv_007_hard.dsc DCB50586 rom/script/pv_008_easy.dsc F7BBD6A6 rom/script/pv_008_extreme.dsc 395D5770 rom/script/pv_008_extreme_1.dsc 4A4EB891 rom/script/pv_008_hard.dsc 955DFD0B rom/script/pv_009_easy.dsc C5637101 rom/script/pv_009_extreme.dsc 6D0FC43A rom/script/pv_009_hard.dsc 81781750 rom/script/pv_010_easy.dsc 6DABE47A rom/script/pv_010_extreme.dsc 23493D67 rom/script/pv_010_extreme_1.dsc 9A08BD81 rom/script/pv_010_hard.dsc 70E0BD34 rom/script/pv_011_easy.dsc 1A02F34D rom/script/pv_011_extreme.dsc 42B24F56 rom/script/pv_011_extreme_1.dsc 8E63EC56 rom/script/pv_011_hard.dsc 1B11B469 rom/script/pv_011_normal.dsc FBAB2850 rom/script/pv_012_extreme.dsc 965F6CBB rom/script/pv_012_hard.dsc CEB44624 rom/script/pv_012_normal.dsc CB078FE5 rom/script/pv_013_extreme.dsc C417B6F2 rom/script/pv_013_hard.dsc 9E7B3FEA rom/script/pv_013_normal.dsc 594797AD rom/script/pv_014_extreme.dsc EDBE8158 rom/script/pv_014_extreme_1.dsc 5B8584EA rom/script/pv_014_hard.dsc 2AAF243B rom/script/pv_014_normal.dsc 4D7458B3 rom/script/pv_015_extreme.dsc 3955CBFC rom/script/pv_015_extreme_1.dsc 3DEEF12D rom/script/pv_015_hard.dsc AA84A7CB rom/script/pv_015_normal.dsc E0DCAB36 rom/script/pv_016_easy.dsc 4F84C2D1 rom/script/pv_016_extreme.dsc 2ADB794D rom/script/pv_016_hard.dsc 48130194 rom/script/pv_017_extreme.dsc 695AEE5B rom/script/pv_017_extreme_1.dsc D55AD167 rom/script/pv_017_hard.dsc 41586D5E rom/script/pv_017_normal.dsc 30742F01 rom/script/pv_004_hard.dsc A21EA07D rom/script/pv_008_normal.dsc FA436B22 rom/script/pv_013_extreme_1.dsc 9AEA2ABA rom/script/pv_018_easy.dsc C074DDC9 rom/script/pv_023_easy.dsc A4BB7233 rom/script/pv_027_hard.dsc B7E97FC3 rom/script/pv_031_extreme_1.dsc 3D7BBBEC rom/script/pv_039_easy.dsc B496615B rom/script/pv_043_easy.dsc 2E9C8979 rom/script/pv_046_normal.dsc A09F937B rom/script/pv_050_normal.dsc 648E5D0A rom/script/pv_054_extreme_1.dsc 805980C3 rom/script/pv_058_extreme.dsc 201A8E75 rom/script/pv_061_hard.dsc 5B3B89B2 rom/script/pv_065_extreme.dsc 39CC3B17 rom/script/pv_018_extreme.dsc 05285931 rom/script/pv_018_hard.dsc 1E2EE838 rom/script/pv_019_easy.dsc C6D4609E rom/script/pv_019_extreme.dsc 18AF4CDA rom/script/pv_019_extreme_1.dsc 9C2C9C65 rom/script/pv_019_hard.dsc E4AD3FC0 rom/script/pv_020_easy.dsc 94C95124 rom/script/pv_020_extreme.dsc 9EB1469F rom/script/pv_020_hard.dsc C949E281 rom/script/pv_020_normal.dsc 4F675190 rom/script/pv_021_extreme.dsc 7F2268EB rom/script/pv_021_hard.dsc 7575AAE5 rom/script/pv_021_normal.dsc 100FC3DB rom/script/pv_022_easy.dsc 0BE60E90 rom/script/pv_022_extreme.dsc 7775F044 rom/script/pv_022_hard.dsc 69EAF0D1 rom/script/pv_022_normal.dsc 8E6CE0D6 rom/script/pv_023_extreme.dsc 64C4AB7D rom/script/pv_023_extreme_1.dsc E8D7300C rom/script/pv_023_hard.dsc 90DB043D rom/script/pv_023_normal.dsc B2DA4968 rom/script/pv_024_easy.dsc C7C01079 rom/script/pv_024_extreme.dsc 9772A2B0 rom/script/pv_024_extreme_1.dsc B78B7393 rom/script/pv_024_hard.dsc 3198A1EE rom/script/pv_024_normal.dsc BA88B704 rom/script/pv_025_easy.dsc C5B9D0D9 rom/script/pv_025_extreme.dsc 42348859 rom/script/pv_025_hard.dsc 6776008D rom/script/pv_025_normal.dsc 22FE9795 rom/script/pv_027_easy.dsc 43BF7C99 rom/script/pv_027_extreme.dsc 74EE049F rom/script/pv_027_extreme_1.dsc EAB3CFC4 rom/script/pv_027_normal.dsc 4C2F59B6 rom/script/pv_028_easy.dsc 9BA03267 rom/script/pv_028_extreme.dsc E7804992 rom/script/pv_028_extreme_1.dsc F0C82363 rom/script/pv_028_hard.dsc A2B32D58 rom/script/pv_028_normal.dsc 60DFAE56 rom/script/pv_029_extreme.dsc C9170839 rom/script/pv_029_extreme_1.dsc 68422DEE rom/script/pv_029_hard.dsc 49A23A49 rom/script/pv_029_normal.dsc 0A169847 rom/script/pv_030_easy.dsc B88B1E7E rom/script/pv_030_extreme.dsc 8EF0D9F7 rom/script/pv_030_extreme_1.dsc 80E49DF8 rom/script/pv_030_hard.dsc 0C92809B rom/script/pv_030_normal.dsc 83372986 rom/script/pv_031_extreme.dsc 87D37084 rom/script/pv_031_hard.dsc 928C550B rom/script/pv_031_normal.dsc 96AFCFE9 rom/script/pv_032_encore.dsc 1B202EB6 rom/script/pv_032_extreme.dsc 9E647E40 rom/script/pv_032_extreme_1.dsc B8077A58 rom/script/pv_032_hard.dsc 49DC4B33 rom/script/pv_032_normal.dsc 39DC49FC rom/script/pv_037_easy.dsc 25F3E856 rom/script/pv_037_extreme.dsc D9708E06 rom/script/pv_037_extreme_1.dsc 33F9112C rom/script/pv_037_hard.dsc 87254D09 rom/script/pv_037_normal.dsc 159081CE rom/script/pv_038_easy.dsc A55229FA rom/script/pv_038_extreme.dsc 6D78ADF5 rom/script/pv_038_extreme_1.dsc C1201CBF rom/script/pv_038_hard.dsc 20E51D24 rom/script/pv_038_normal.dsc 2E858CAE rom/script/pv_039_extreme.dsc 718D55C4 rom/script/pv_039_extreme_1.dsc 53CFED69 rom/script/pv_039_hard.dsc C7CDBA86 rom/script/pv_039_normal.dsc 9D51A818 rom/script/pv_040_easy.dsc 33F51114 rom/script/pv_040_extreme.dsc DD418039 rom/script/pv_040_extreme_1.dsc 7FDB7A60 rom/script/pv_040_hard.dsc 6CC56926 rom/script/pv_040_normal.dsc 4D7F3165 rom/script/pv_041_easy.dsc D0E3DA17 rom/script/pv_041_extreme.dsc 482EDB59 rom/script/pv_041_hard.dsc 61BE158A rom/script/pv_041_normal.dsc 00825D36 rom/script/pv_042_easy.dsc CC66C623 rom/script/pv_042_extreme.dsc EB781533 rom/script/pv_042_hard.dsc A12999B4 rom/script/pv_042_normal.dsc C0F4FC11 rom/script/pv_043_extreme.dsc BEF4306A rom/script/pv_043_extreme_1.dsc E3B180BC rom/script/pv_043_hard.dsc 04A9A095 rom/script/pv_043_normal.dsc DB4ABB7F rom/script/pv_044_easy.dsc 73C9B09D rom/script/pv_044_extreme.dsc 044E6314 rom/script/pv_044_hard.dsc F804D381 rom/script/pv_044_normal.dsc A7442870 rom/script/pv_045_easy.dsc BBF603B2 rom/script/pv_045_extreme.dsc 1368A26E rom/script/pv_045_extreme_1.dsc CC594C4D rom/script/pv_045_hard.dsc 04A6967B rom/script/pv_045_normal.dsc 5592B67C rom/script/pv_046_easy.dsc F9F832E6 rom/script/pv_046_extreme.dsc 8A87F0AC rom/script/pv_046_extreme_1.dsc 06941506 rom/script/pv_046_hard.dsc 223621E6 rom/script/pv_047_easy.dsc 32BE1383 rom/script/pv_047_extreme.dsc 7E66F064 rom/script/pv_047_hard.dsc 6383B972 rom/script/pv_047_normal.dsc 747815B8 rom/script/pv_048_easy.dsc 73358EF9 rom/script/pv_048_extreme.dsc A7A7AE24 rom/script/pv_048_hard.dsc 0E899E9E rom/script/pv_048_normal.dsc 06429EA4 rom/script/pv_049_easy.dsc C982AA9E rom/script/pv_049_extreme.dsc 08E99BDD rom/script/pv_049_extreme_1.dsc FE127A97 rom/script/pv_049_hard.dsc FC889DF5 rom/script/pv_049_normal.dsc 3C5BA256 rom/script/pv_050_easy.dsc 37F5A8B1 rom/script/pv_050_extreme.dsc 8A53A830 rom/script/pv_050_extreme_1.dsc 64DECD75 rom/script/pv_050_hard.dsc 307AA6FA rom/script/pv_051_easy.dsc 4A190253 rom/script/pv_051_extreme.dsc 7871D82E rom/script/pv_051_extreme_1.dsc F172724B rom/script/pv_051_hard.dsc F1AF8C62 rom/script/pv_051_normal.dsc A097135C rom/script/pv_052_easy.dsc 83BE21BB rom/script/pv_052_extreme.dsc 047479F8 rom/script/pv_052_extreme_1.dsc 9E7AEAC2 rom/script/pv_052_hard.dsc D3BC6861 rom/script/pv_052_normal.dsc F710AA94 rom/script/pv_053_easy.dsc 62E7FEF3 rom/script/pv_053_extreme.dsc FCF717F3 rom/script/pv_053_extreme_1.dsc 566A2C4E rom/script/pv_053_hard.dsc 1444FF1D rom/script/pv_053_normal.dsc 3CA75D71 rom/script/pv_054_easy.dsc 50412C39 rom/script/pv_054_extreme.dsc 2293C5A0 rom/script/pv_054_hard.dsc D3871C21 rom/script/pv_054_normal.dsc 9C047B71 rom/script/pv_055_easy.dsc 68DAD40E rom/script/pv_055_extreme.dsc F58FB800 rom/script/pv_055_extreme_1.dsc 54EA9822 rom/script/pv_055_hard.dsc B6DF9BE7 rom/script/pv_055_normal.dsc 77612415 rom/script/pv_056_easy.dsc DA04C81D rom/script/pv_056_extreme.dsc 6231D2EE rom/script/pv_056_hard.dsc 0E4B8403 rom/script/pv_056_normal.dsc 6DB482CB rom/script/pv_057_easy.dsc 5E1F9D2C rom/script/pv_057_extreme.dsc 51A53C43 rom/script/pv_057_extreme_1.dsc 22A04731 rom/script/pv_057_hard.dsc 0CB8C8E9 rom/script/pv_057_normal.dsc 1C30218E rom/script/pv_058_easy.dsc E8358344 rom/script/pv_058_extreme_1.dsc 93E97B29 rom/script/pv_058_hard.dsc 569CD85D rom/script/pv_058_normal.dsc 50C70F31 rom/script/pv_059_easy.dsc 14DDFDF7 rom/script/pv_059_extreme.dsc A0F96CE9 rom/script/pv_059_extreme_1.dsc 077A945F rom/script/pv_059_hard.dsc 3E6C1E5C rom/script/pv_059_normal.dsc 2E7CD82E rom/script/pv_060_easy.dsc B8DB73CE rom/script/pv_060_extreme.dsc DD6601CB rom/script/pv_060_extreme_1.dsc F1E81D74 rom/script/pv_060_hard.dsc A4B60197 rom/script/pv_060_normal.dsc 68C1D181 rom/script/pv_061_easy.dsc 23610D0C rom/script/pv_061_extreme.dsc 39847D46 rom/script/pv_061_extreme_1.dsc 81B93800 rom/script/pv_061_normal.dsc 4C0BB70E rom/script/pv_062_easy.dsc BCFC5DA1 rom/script/pv_062_extreme.dsc DC04262D rom/script/pv_062_extreme_1.dsc 2DC79F31 rom/script/pv_062_hard.dsc 88A9DFA7 rom/script/pv_062_normal.dsc DD62712D rom/script/pv_063_easy.dsc EC27245A rom/script/pv_063_extreme.dsc D2976563 rom/script/pv_063_extreme_1.dsc DC107CA4 rom/script/pv_063_hard.dsc C62A8EBC rom/script/pv_063_normal.dsc FD2E7D76 rom/script/pv_064_easy.dsc 3475A249 rom/script/pv_064_extreme.dsc D619925A rom/script/pv_064_extreme_1.dsc 9EA670C7 rom/script/pv_064_hard.dsc 8A1FA2B7 rom/script/pv_064_normal.dsc 3D0AC3AD rom/script/pv_065_easy.dsc 1E54862F rom/script/pv_065_extreme_1.dsc 40FCD723 rom/script/pv_065_hard.dsc B9C74989 rom/script/pv_065_normal.dsc FB5B75B1 rom/script/pv_066_easy.dsc D4D4485A rom/script/pv_066_extreme.dsc A0C39E00 rom/script/pv_066_extreme_1.dsc F75CFBED rom/script/pv_066_hard.dsc 1C90D1A5 rom/script/pv_066_normal.dsc 242A229C rom/script/pv_067_extreme.dsc 45A7E6CF rom/script/pv_067_hard.dsc 72CEE8DE rom/script/pv_067_normal.dsc 4C507D2C rom/script/pv_068_easy.dsc CF7EBBB1 rom/script/pv_068_extreme.dsc 31DDA0E6 rom/script/pv_068_hard.dsc 04A388A1 rom/script/pv_068_normal.dsc 065C1EB9 rom/script/pv_079_easy.dsc A8E05918 rom/script/pv_079_extreme.dsc C82CCFEE rom/script/pv_079_normal.dsc 803C2FC6 rom/script/pv_081_easy.dsc DC981053 rom/script/pv_081_extreme.dsc B4BCE7FA rom/script/pv_081_extreme_1.dsc 7DD2C169 rom/script/pv_081_hard.dsc AA94FA51 rom/script/pv_081_normal.dsc CD5E136B rom/script/pv_082_easy.dsc B284FC47 rom/script/pv_082_extreme.dsc 69FC7368 rom/script/pv_082_extreme_1.dsc 9DBCE0CD rom/script/pv_082_hard.dsc 7CB1475C rom/script/pv_082_normal.dsc 53A026EB rom/script/pv_083_easy.dsc B96B2106 rom/script/pv_083_extreme.dsc 0F91A6FB rom/script/pv_083_hard.dsc 096FA701 rom/script/pv_083_normal.dsc 43AB0EA3 rom/script/pv_084_easy.dsc 359E6ABA rom/script/pv_084_extreme.dsc A192F3D1 rom/script/pv_084_hard.dsc 5D0879D6 rom/script/pv_084_normal.dsc DEEDB5FA rom/script/pv_085_extreme.dsc 1EB4096F rom/script/pv_085_extreme_1.dsc EF1D4639 rom/script/pv_085_hard.dsc 42E781FF rom/script/pv_085_normal.dsc 7DCB8214 rom/script/pv_086_easy.dsc B6BFADFB rom/script/pv_086_extreme.dsc 24A21B0A rom/script/pv_086_hard.dsc 77BC6502 rom/script/pv_086_normal.dsc 86E70969 rom/script/pv_087_easy.dsc 6DF0A7C8 rom/script/pv_087_extreme.dsc 464B2245 rom/script/pv_087_extreme_1.dsc C2943C32 rom/script/pv_087_hard.dsc 97D4EE94 rom/script/pv_087_normal.dsc 4A6D06E9 rom/script/pv_088_easy.dsc FF264BBE rom/script/pv_088_extreme.dsc 48AE6A2B rom/script/pv_088_hard.dsc 6B0DDA47 rom/script/pv_088_normal.dsc 725BFA01 rom/script/pv_089_easy.dsc 99D4AD49 rom/script/pv_089_extreme.dsc 138A7451 rom/script/pv_089_extreme_1.dsc 7D6BC4E2 rom/script/pv_089_hard.dsc 372D2AEC rom/script/pv_089_normal.dsc DE363D93 rom/script/pv_090_easy.dsc D4E6F756 rom/script/pv_090_extreme.dsc 304094CD rom/script/pv_090_extreme_1.dsc 36B53828 rom/script/pv_090_hard.dsc 1592E9FB rom/script/pv_090_normal.dsc 7874592B rom/script/pv_091_easy.dsc C77B1382 rom/script/pv_091_extreme.dsc 517A8A57 rom/script/pv_091_hard.dsc 506676A9 rom/script/pv_091_normal.dsc 4E821D27 rom/script/pv_092_easy.dsc 9C9C1004 rom/script/pv_092_hard.dsc EEBE2682 rom/script/pv_092_normal.dsc F64EE3C5 rom/script/pv_093_easy.dsc B942CDCD rom/script/pv_093_extreme.dsc C0A9CAF8 rom/script/pv_093_hard.dsc 3F8DB0C8 rom/script/pv_093_normal.dsc 51FE68AC rom/script/pv_094_easy.dsc 591F8A37 rom/script/pv_094_extreme.dsc 1AB6F5EF rom/script/pv_094_extreme_1.dsc 705E6D1B rom/script/pv_094_hard.dsc E7B17A5F rom/script/pv_094_normal.dsc 84D5C1AB rom/script/pv_095_easy.dsc E7E181F8 rom/script/pv_095_extreme.dsc E9ED321B rom/script/pv_095_hard.dsc 4092471C rom/script/pv_095_normal.dsc 986E2382 rom/script/pv_096_easy.dsc 400B92D5 rom/script/pv_096_extreme.dsc 0E90F73B rom/script/pv_096_hard.dsc 5C26CEC8 rom/script/pv_096_normal.dsc DCBE43C1 rom/script/pv_097_easy.dsc 8B88AA82 rom/script/pv_097_extreme.dsc 0D8C94BA rom/script/pv_097_hard.dsc 40E83BC0 rom/script/pv_097_normal.dsc 7E689B9C rom/script/pv_101_extreme.dsc 62284407 rom/script/pv_101_extreme_1.dsc F456999B rom/script/pv_101_hard.dsc 64DD71E6 rom/script/pv_101_normal.dsc 9F1E2CE1 rom/script/pv_102_easy.dsc DCDC615F rom/script/pv_102_extreme.dsc 4AE85A52 rom/script/pv_102_hard.dsc 175548B8 rom/script/pv_102_normal.dsc 3062AC3A rom/script/pv_103_extreme.dsc C4ADC4AF rom/script/pv_103_hard.dsc 1C526D39 rom/script/pv_103_normal.dsc C2C17CB3 rom/script/pv_104_hard.dsc 7A8A78A1 rom/script/pv_104_normal.dsc DF053B6D rom/script/pv_201_extreme.dsc 767AF450 rom/script/pv_201_extreme_1.dsc 096BBDB3 rom/script/pv_201_hard.dsc 4EE06AC9 rom/script/pv_201_normal.dsc B6B0FA87 rom/script/pv_202_extreme.dsc 70CEF20E rom/script/pv_202_extreme_1.dsc 83F1B89C rom/script/pv_202_hard.dsc 3E6628E2 rom/script/pv_202_normal.dsc 7113DD5C rom/script/pv_203_extreme.dsc 647BF6EE rom/script/pv_203_hard.dsc EACD792D rom/script/pv_203_normal.dsc C47FF165 rom/script/pv_204_easy.dsc 6FC576BA rom/script/pv_204_extreme.dsc FB3001E7 rom/script/pv_204_hard.dsc 52341D43 rom/script/pv_204_normal.dsc 7256BFC8 rom/script/pv_205_hard.dsc 6F1DC918 rom/script/pv_205_normal.dsc C3C16B49 rom/script/pv_206_easy.dsc 7864A9D8 rom/script/pv_206_extreme.dsc 0E11271D rom/script/pv_206_hard.dsc 37C39A45 rom/script/pv_206_normal.dsc A946642B rom/script/pv_207_extreme.dsc 0E8DA035 rom/script/pv_207_hard.dsc 001789AE rom/script/pv_207_normal.dsc 0CBAE29F rom/script/pv_208_easy.dsc C784D9E5 rom/script/pv_208_extreme.dsc 11D7B4DE rom/script/pv_208_extreme_1.dsc 4CB9EFFA rom/script/pv_208_hard.dsc 21703410 rom/script/pv_208_normal.dsc 0880B676 rom/script/pv_209_extreme.dsc 717786BE rom/script/pv_209_extreme_1.dsc 69029A87 rom/script/pv_209_normal.dsc C7A948FE rom/script/pv_210_extreme.dsc 7EADBE59 rom/script/pv_210_extreme_1.dsc DFCB4582 rom/script/pv_210_hard.dsc FF9F2D36 rom/script/pv_210_normal.dsc F0201855 rom/script/pv_211_extreme.dsc C7E22AA6 rom/script/pv_211_extreme_1.dsc 4B1B604F rom/script/pv_211_hard.dsc 0AE10552 rom/script/pv_211_normal.dsc 6023F154 rom/script/pv_212_extreme.dsc ABF7CFF4 rom/script/pv_212_extreme_1.dsc EF9CEC98 rom/script/pv_212_hard.dsc 123A99B2 rom/script/pv_212_normal.dsc 87D7A775 rom/script/pv_213_easy.dsc 6F3379B2 rom/script/pv_213_extreme.dsc A6B7709C rom/script/pv_213_hard.dsc 8113BB8E rom/script/pv_213_normal.dsc F77D9D79 rom/script/pv_214_extreme.dsc 7AB2AD55 rom/script/pv_214_hard.dsc BB48B877 rom/script/pv_214_normal.dsc 45B09FA0 rom/script/pv_215_extreme.dsc CC253D2D rom/script/pv_215_hard.dsc 3BC5FBA4 rom/script/pv_215_normal.dsc C615D693 rom/script/pv_216_easy.dsc F7CBCB4E rom/script/pv_216_extreme.dsc 395138C6 rom/script/pv_216_hard.dsc 0264AA43 rom/script/pv_216_normal.dsc DFC37253 rom/script/pv_218_extreme.dsc DE2CF56E rom/script/pv_218_hard.dsc 6209011C rom/script/pv_218_normal.dsc 0D17F2AB rom/script/pv_219_easy.dsc 38A0EA6A rom/script/pv_219_extreme.dsc 22E747A7 rom/script/pv_219_extreme_1.dsc 67CB97A2 rom/script/pv_219_hard.dsc FB78A0A7 rom/script/pv_220_easy.dsc FB309FEE rom/script/pv_220_extreme.dsc 36193F0E rom/script/pv_220_hard.dsc D3265FAB rom/script/pv_220_normal.dsc D40FD647 rom/script/pv_221_easy.dsc C9629C60 rom/script/pv_221_extreme.dsc 4E4C39F6 rom/script/pv_221_extreme_1.dsc 587A1ABF rom/script/pv_221_hard.dsc 0F1DA7C9 rom/script/pv_221_normal.dsc 0C9ECC0C rom/script/pv_222_extreme.dsc A9F84EAB rom/script/pv_222_hard.dsc 199C1D52 rom/script/pv_222_normal.dsc 942DF67F rom/script/pv_223_extreme.dsc 71B996E8 rom/script/pv_223_hard.dsc A214E1B6 rom/script/pv_223_normal.dsc 96405E3E rom/script/pv_224_extreme.dsc 86B00E0F rom/script/pv_224_extreme_1.dsc E70744B0 rom/script/pv_224_normal.dsc AFA67C8D rom/script/pv_225_easy.dsc 75769DF1 rom/script/pv_225_extreme.dsc 9CA9BF4B rom/script/pv_225_hard.dsc 4B95DF66 rom/script/pv_225_normal.dsc BEA6A63E rom/script/pv_226_extreme.dsc 1465AC31 rom/script/pv_226_extreme_1.dsc FAE19809 rom/script/pv_226_hard.dsc 7556BF39 rom/script/pv_226_normal.dsc BAA50488 rom/script/pv_227_extreme.dsc E9BFC217 rom/script/pv_227_hard.dsc 84ABEB36 rom/script/pv_227_normal.dsc C418829F rom/script/pv_228_extreme.dsc D105177A rom/script/pv_228_hard.dsc D1EB5240 rom/script/pv_228_normal.dsc 46EFDA4F rom/script/pv_231_extreme.dsc CB5C1ACE rom/script/pv_231_extreme_1.dsc 68C2A46B rom/script/pv_231_normal.dsc 009F13F6 rom/script/pv_232_easy.dsc 51E9CDB2 rom/script/pv_232_extreme.dsc 38D6A9AA rom/script/pv_232_extreme_1.dsc FF824E09 rom/script/pv_232_hard.dsc F908B877 rom/script/pv_232_normal.dsc D5369637 rom/script/pv_233_extreme.dsc D3E14CCD rom/script/pv_233_hard.dsc D3A563D5 rom/script/pv_233_normal.dsc 5AC3C8FD rom/script/pv_234_easy.dsc 07648C25 rom/script/pv_234_extreme.dsc C1679949 rom/script/pv_234_extreme_1.dsc 0CADEF49 rom/script/pv_234_hard.dsc 395242BA rom/script/pv_234_normal.dsc D87C0199 rom/script/pv_235_easy.dsc CEE6B2E8 rom/script/pv_235_extreme.dsc 913AC8DD rom/script/pv_235_hard.dsc 31A863BA rom/script/pv_236_extreme.dsc 8C87D3FD rom/script/pv_236_hard.dsc 484541B5 rom/script/pv_236_normal.dsc 331FA8E3 rom/script/pv_238_easy.dsc AF49CF30 rom/script/pv_238_extreme.dsc 71856D88 rom/script/pv_238_hard.dsc D22D6C12 rom/script/pv_238_normal.dsc 465BA128 rom/script/pv_239_extreme.dsc 2B891D9C rom/script/pv_239_hard.dsc 188162F1 rom/script/pv_239_normal.dsc 043BCFD2 rom/script/pv_240_extreme.dsc 3CD3A651 rom/script/pv_240_hard.dsc 38B752BD rom/script/pv_240_normal.dsc 048A3AB4 rom/script/pv_241_easy.dsc 0EB4D411 rom/script/pv_241_extreme.dsc 46757DE4 rom/script/pv_241_hard.dsc 358D8661 rom/script/pv_241_normal.dsc 15F1CF9B rom/script/pv_242_extreme.dsc DCD09A22 rom/script/pv_242_hard.dsc 5949BA89 rom/script/pv_242_normal.dsc A41BD831 rom/script/pv_243_easy.dsc 996AC463 rom/script/pv_243_extreme.dsc 92A604C7 rom/script/pv_243_hard.dsc B44CCBD6 rom/script/pv_243_normal.dsc 1D911F0B rom/script/pv_244_easy.dsc 8C2F4D3F rom/script/pv_244_extreme.dsc 7CA33096 rom/script/pv_244_hard.dsc C20CA2A4 rom/script/pv_244_normal.dsc A9EF68D0 rom/script/pv_246_extreme.dsc 30FA7F65 rom/script/pv_246_hard.dsc 6CD31DED rom/script/pv_246_normal.dsc 86C9CA6D rom/script/pv_247_easy.dsc FD1A426D rom/script/pv_247_extreme.dsc 8DEF4E45 rom/script/pv_247_hard.dsc BB37F221 rom/script/pv_248_easy.dsc 4DE91D61 rom/script/pv_248_extreme.dsc 61BF4D1F rom/script/pv_248_hard.dsc 2C2CA66E rom/script/pv_248_normal.dsc A9B7CE64 rom/script/pv_249_easy.dsc 6DB573AF rom/script/pv_249_extreme.dsc ABC66CB4 rom/script/pv_249_hard.dsc ECE9C0B8 rom/script/pv_249_normal.dsc 3AFFA79F rom/script/pv_250_easy.dsc 671113BD rom/script/pv_250_extreme.dsc D1004FB1 rom/script/pv_250_hard.dsc 23245ACB rom/script/pv_250_normal.dsc F9E2E432 rom/script/pv_251_easy.dsc E3BEA9E4 rom/script/pv_251_extreme.dsc 2DCC3BD9 rom/script/pv_251_hard.dsc 51CDE90A rom/script/pv_251_normal.dsc F06D9FBB rom/script/pv_253_easy.dsc 9D4BFC8D rom/script/pv_253_hard.dsc 4BFF047E rom/script/pv_253_normal.dsc EACA696C rom/script/pv_255_easy.dsc DDB077B7 rom/script/pv_255_extreme.dsc 0399BDA8 rom/script/pv_255_hard.dsc DD72FBFB rom/script/pv_255_normal.dsc 2218A94B rom/script/pv_257_easy.dsc 385B42C4 rom/script/pv_257_extreme.dsc B5F83610 rom/script/pv_257_hard.dsc 403162B0 rom/script/pv_257_normal.dsc 1D0290F6 rom/script/pv_259_easy.dsc D5703D5F rom/script/pv_259_extreme.dsc 871D9A49 rom/script/pv_259_hard.dsc 5BDC1A31 rom/script/pv_259_normal.dsc 227AFB5E rom/script/pv_260_easy.dsc 51FE857A rom/script/pv_260_extreme.dsc 24ACC4D7 rom/script/pv_260_hard.dsc A44D9636 rom/script/pv_261_easy.dsc 62072997 rom/script/pv_261_extreme.dsc E0BE1F87 rom/script/pv_261_hard.dsc 8389CDB1 rom/script/pv_261_normal.dsc 97C4175D rom/script/pv_262_easy.dsc 15B7A27A rom/script/pv_262_extreme.dsc 2B3A41E4 rom/script/pv_262_hard.dsc 15D36C60 rom/script/pv_262_normal.dsc 4095010E rom/script/pv_265_easy.dsc 4B09CAE3 rom/script/pv_265_extreme.dsc 8A8145E9 rom/script/pv_265_hard.dsc 3150B964 rom/script/pv_265_normal.dsc D58B3694 rom/script/pv_401_extreme.dsc C1DF3A40 rom/script/pv_401_extreme_1.dsc EDF8DF74 rom/script/pv_401_hard.dsc 574E88D2 rom/script/pv_401_normal.dsc 4A74AA58 rom/script/pv_402_easy.dsc 22C84A6F rom/script/pv_084_extreme_1.dsc DA371828 rom/script/pv_088_extreme_1.dsc 28043FBD rom/script/pv_092_extreme.dsc 9E786B13 rom/script/pv_096_extreme_1.dsc 167132D5 rom/script/pv_104_extreme.dsc E6FEEECB rom/script/pv_205_extreme.dsc E3FDFB81 rom/script/pv_209_hard.dsc EEF6DB0B rom/script/pv_214_easy.dsc 99BD332A rom/script/pv_219_normal.dsc 8897E664 rom/script/pv_224_hard.dsc C620E915 rom/script/pv_231_hard.dsc D22D9B3C rom/script/pv_235_normal.dsc 84DCF1A6 rom/script/pv_242_easy.dsc B7A3F2B9 rom/script/pv_247_normal.dsc 78C7A43F rom/script/pv_253_extreme.dsc 4F327170 rom/script/pv_402_extreme_1.dsc 8DB20296 rom/script/pv_402_hard.dsc 183D9E28 rom/script/pv_402_normal.dsc 4ED847F1 rom/script/pv_403_extreme.dsc 5B24C156 rom/script/pv_403_extreme_1.dsc 46A4E51B rom/script/pv_403_hard.dsc 347CEA8E rom/script/pv_403_normal.dsc 3C28B1E6 rom/script/pv_404_extreme.dsc 0D937913 rom/script/pv_404_extreme_1.dsc 5E6CCAD1 rom/script/pv_404_hard.dsc E918927C rom/script/pv_404_normal.dsc B26EA62E rom/script/pv_405_easy.dsc 973527B7 rom/script/pv_405_extreme.dsc 8560C75E rom/script/pv_405_extreme_1.dsc 9047D724 rom/script/pv_405_hard.dsc 94BD5750 rom/script/pv_405_normal.dsc 8BA04E57 rom/script/pv_407_extreme_1.dsc 531E3764 rom/script/pv_407_hard.dsc 64F920B6 rom/script/pv_407_normal.dsc 27301F2F rom/script/pv_408_extreme.dsc A0D5765B rom/script/pv_408_hard.dsc BDDE8EA4 rom/script/pv_408_normal.dsc DA6406E7 rom/script/pv_409_easy.dsc 7185FA51 rom/script/pv_409_extreme.dsc B25865A6 rom/script/pv_409_hard.dsc E9F6E893 rom/script/pv_409_normal.dsc 846B885C rom/script/pv_410_easy.dsc F3E37D2E rom/script/pv_410_extreme.dsc E7D618EA rom/script/pv_410_hard.dsc F03CC052 rom/script/pv_410_normal.dsc 5F1F32E5 rom/script/pv_411_extreme.dsc 55B83B23 rom/script/pv_411_hard.dsc FB0FE840 rom/script/pv_411_normal.dsc 8030E7F6 rom/script/pv_412_hard.dsc 04F2768A rom/script/pv_412_normal.dsc 3627673D rom/script/pv_413_extreme.dsc 2CE58F9A rom/script/pv_413_extreme_1.dsc AC7DA763 rom/script/pv_413_hard.dsc 4E675151 rom/script/pv_413_normal.dsc 757A3601 rom/script/pv_414_extreme.dsc DC21F1D8 rom/script/pv_414_extreme_1.dsc 54C6264B rom/script/pv_414_hard.dsc AD745F48 rom/script/pv_414_normal.dsc DA076028 rom/script/pv_415_easy.dsc A9245ABD rom/script/pv_415_extreme.dsc 4B32630D rom/script/pv_415_extreme_1.dsc DD2766A0 rom/script/pv_415_hard.dsc 6ED8E424 rom/script/pv_415_normal.dsc AC78FEAC rom/script/pv_416_easy.dsc 00ECEB5E rom/script/pv_416_extreme.dsc C05F23B6 rom/script/pv_416_normal.dsc 1096FE0B rom/script/pv_417_extreme.dsc 42564497 rom/script/pv_417_hard.dsc 93D757FE rom/script/pv_417_normal.dsc 9BC39807 rom/script/pv_418_easy.dsc F6970E94 rom/script/pv_418_extreme.dsc CD23749F rom/script/pv_418_hard.dsc 110D2BF5 rom/script/pv_418_normal.dsc 3AB8CEB9 rom/script/pv_419_easy.dsc F00274BB rom/script/pv_419_extreme.dsc B3438178 rom/script/pv_419_hard.dsc A384C367 rom/script/pv_419_normal.dsc 6FC45FF7 rom/script/pv_420_extreme.dsc B12E3101 rom/script/pv_420_hard.dsc 3872277E rom/script/pv_420_normal.dsc 30132D8E rom/script/pv_421_extreme.dsc 14D3D908 rom/script/pv_421_extreme_1.dsc A970BE34 rom/script/pv_421_normal.dsc B6A39E1F rom/script/pv_422_extreme.dsc 9F385D0F rom/script/pv_422_extreme_1.dsc EB2BFB36 rom/script/pv_422_hard.dsc E33F8A11 rom/script/pv_422_normal.dsc 1E699628 rom/script/pv_423_extreme.dsc 8FCC56B4 rom/script/pv_423_extreme_1.dsc A3482C51 rom/script/pv_423_hard.dsc A9827105 rom/script/pv_423_normal.dsc 8DC89527 rom/script/pv_424_easy.dsc 584819AB rom/script/pv_424_extreme.dsc 9F92F3ED rom/script/pv_424_extreme_1.dsc E28136B7 rom/script/pv_424_hard.dsc FC9B8326 rom/script/pv_424_normal.dsc 5729764A rom/script/pv_425_extreme.dsc 88D1EB75 rom/script/pv_425_hard.dsc DD77B5DB rom/script/pv_426_extreme.dsc 6C06E8DD rom/script/pv_426_hard.dsc C376DF45 rom/script/pv_426_normal.dsc A00ABE1D rom/script/pv_427_easy.dsc 398A793C rom/script/pv_427_extreme.dsc 02875766 rom/script/pv_427_hard.dsc 2081783A rom/script/pv_427_normal.dsc 759AF989 rom/script/pv_428_extreme.dsc C0532D08 rom/script/pv_428_extreme_1.dsc A5AE7753 rom/script/pv_428_hard.dsc 823FAB63 rom/script/pv_428_normal.dsc 0B38AAB2 rom/script/pv_429_easy.dsc 7A22E7CD rom/script/pv_429_extreme.dsc 2FD844CC rom/script/pv_429_extreme_1.dsc 36E23DFF rom/script/pv_429_hard.dsc 2726EDB5 rom/script/pv_429_normal.dsc 11DF6BA1 rom/script/pv_430_easy.dsc 7D4D67B0 rom/script/pv_430_hard.dsc 9DC00083 rom/script/pv_430_normal.dsc AD9F08A1 rom/script/pv_431_extreme.dsc 53F93FCF rom/script/pv_431_hard.dsc BEDE855A rom/script/pv_431_normal.dsc 17B90E26 rom/script/pv_432_easy.dsc C7206F4E rom/script/pv_432_extreme.dsc 0571FF01 rom/script/pv_432_hard.dsc EE975FE2 rom/script/pv_432_normal.dsc 34704A06 rom/script/pv_433_easy.dsc B4489645 rom/script/pv_433_extreme.dsc CF569FCC rom/script/pv_433_hard.dsc 4340D551 rom/script/pv_433_normal.dsc CECC287C rom/script/pv_434_easy.dsc A32DBF80 rom/script/pv_434_extreme.dsc BF1984AA rom/script/pv_434_hard.dsc 26C5E857 rom/script/pv_434_normal.dsc 2039CDE9 rom/script/pv_435_hard.dsc 94865B92 rom/script/pv_435_normal.dsc 957ED391 rom/script/pv_436_easy.dsc 2889D99E rom/script/pv_436_extreme.dsc F2F5E1B5 rom/script/pv_436_hard.dsc DD1D92CB rom/script/pv_436_normal.dsc AF678CE7 rom/script/pv_437_extreme.dsc 6C80423C rom/script/pv_437_hard.dsc 125A427F rom/script/pv_437_normal.dsc 69A665E4 rom/script/pv_438_extreme.dsc 04DC81E4 rom/script/pv_438_hard.dsc B6AF3774 rom/script/pv_438_normal.dsc 9E6C89AB rom/script/pv_439_easy.dsc 639CA9F9 rom/script/pv_439_extreme.dsc 09EF8ECB rom/script/pv_439_hard.dsc 766E19A4 rom/script/pv_439_normal.dsc 727C11E7 rom/script/pv_440_easy.dsc 10D95923 rom/script/pv_440_hard.dsc 3C9FC6F1 rom/script/pv_440_normal.dsc AA49F01C rom/script/pv_441_extreme.dsc 97106866 rom/script/pv_441_hard.dsc DA321D60 rom/script/pv_441_normal.dsc B1E7450A rom/script/pv_442_easy.dsc B550B4FA rom/script/pv_442_extreme.dsc E81926C4 rom/script/pv_442_hard.dsc 27204A58 rom/script/pv_442_normal.dsc D3EE3EEC rom/script/pv_443_easy.dsc B44DA82F rom/script/pv_443_extreme.dsc EDCECC9F rom/script/pv_443_hard.dsc 5C3FFA7D rom/script/pv_443_normal.dsc EACC718B rom/script/pv_600_easy.dsc 55EF125E rom/script/pv_600_extreme.dsc EF5975D8 rom/script/pv_600_hard.dsc E5313131 rom/script/pv_600_normal.dsc C0B6096D rom/script/pv_601_extreme.dsc B1952826 rom/script/pv_601_hard.dsc F65966A7 rom/script/pv_601_normal.dsc 583070DF rom/script/pv_602_easy.dsc E5CD6440 rom/script/pv_602_extreme.dsc 68ABD27F rom/script/pv_602_hard.dsc BB751311 rom/script/pv_602_normal.dsc 931D4E0C rom/script/pv_603_easy.dsc D996A55F rom/script/pv_603_extreme.dsc 4280D540 rom/script/pv_603_hard.dsc D9371EAF rom/script/pv_603_normal.dsc 28BBFC14 rom/script/pv_604_easy.dsc 8AC73691 rom/script/pv_604_extreme.dsc A39BE2DD rom/script/pv_604_hard.dsc C802C4F8 rom/script/pv_604_normal.dsc 4D8FE5EA rom/script/pv_605_easy.dsc 8A26BAE6 rom/script/pv_605_extreme.dsc DE358191 rom/script/pv_605_normal.dsc 16A7B1B2 rom/script/pv_607_easy.dsc 7433BF0D rom/script/pv_607_extreme.dsc 45E2D7DC rom/script/pv_607_hard.dsc 6E99F89F rom/script/pv_607_normal.dsc FA917C48 rom/script/pv_608_easy.dsc 2BC6643B rom/script/pv_608_extreme.dsc 56E00753 rom/script/pv_608_hard.dsc 28B1DA82 rom/script/pv_608_normal.dsc 4CC11AC9 rom/script/pv_609_easy.dsc B502744C rom/script/pv_609_extreme.dsc 794CD45C rom/script/pv_609_hard.dsc DC85D47B rom/script/pv_609_normal.dsc 3DAC6822 rom/script/pv_610_easy.dsc 287F44E6 rom/script/pv_610_extreme.dsc 11AC1223 rom/script/pv_610_hard.dsc 3EA821C9 rom/script/pv_610_normal.dsc DBADEE53 rom/script/pv_611_extreme.dsc EB533EAC rom/script/pv_611_hard.dsc 3C917C75 rom/script/pv_611_normal.dsc DDD65A6B rom/script/pv_612_easy.dsc 235DF7B3 rom/script/pv_612_extreme.dsc 5B5724D6 rom/script/pv_612_hard.dsc AC0DE6D6 rom/script/pv_612_normal.dsc A7724998 rom/script/pv_613_easy.dsc D94A6422 rom/script/pv_613_extreme.dsc CE628CA6 rom/script/pv_613_hard.dsc 1DD06CE7 rom/script/pv_613_normal.dsc A2C75A7B rom/script/pv_614_extreme.dsc 1288E6FE rom/script/pv_614_hard.dsc B0A572EA rom/script/pv_614_normal.dsc 3115F728 rom/script/pv_615_easy.dsc 8FA88B74 rom/script/pv_615_extreme.dsc B4B79D38 rom/script/pv_615_hard.dsc 29D33EC8 rom/script/pv_616_easy.dsc C1D5A84E rom/script/pv_616_extreme.dsc 6BDF13F1 rom/script/pv_616_hard.dsc DC8D7BFF rom/script/pv_616_normal.dsc 5CE69DF9 rom/script/pv_617_extreme.dsc 3CE78EDB rom/script/pv_617_hard.dsc E780ADD6 rom/script/pv_617_normal.dsc DE865F01 rom/script/pv_618_easy.dsc 9F234803 rom/script/pv_618_extreme.dsc A3CA77F4 rom/script/pv_618_hard.dsc A4FC6048 rom/script/pv_618_normal.dsc 4DA427B9 rom/script/pv_619_easy.dsc 70FFCECF rom/script/pv_619_extreme.dsc ACEED224 rom/script/pv_619_hard.dsc B70AC164 rom/script/pv_619_normal.dsc DC18AB4A rom/script/pv_620_easy.dsc 3C662266 rom/script/pv_620_extreme.dsc E44336FA rom/script/pv_620_normal.dsc 2D3508E4 rom/script/pv_621_easy.dsc 37336FB6 rom/script/pv_621_extreme.dsc 961BE775 rom/script/pv_621_hard.dsc EFCA2214 rom/script/pv_621_normal.dsc 9989211C rom/script/pv_622_easy.dsc C90A6926 rom/script/pv_622_extreme.dsc A41E85B2 rom/script/pv_622_hard.dsc 9E05AEBE rom/script/pv_622_normal.dsc 99F09CFE rom/script/pv_623_easy.dsc DE457A08 rom/script/pv_623_extreme.dsc CD7DF773 rom/script/pv_623_hard.dsc FF4D4D28 rom/script/pv_623_normal.dsc B0061EA1 rom/script/pv_624_easy.dsc 317F6537 rom/script/pv_624_extreme.dsc 9972F01A rom/script/pv_624_hard.dsc 2B81D650 rom/script/pv_624_normal.dsc F54BD407 rom/script/pv_625_hard.dsc 5711A769 rom/script/pv_625_normal.dsc 968276FF rom/script/pv_626_easy.dsc DC1C0E44 rom/script/pv_626_extreme.dsc 20C35461 rom/script/pv_626_hard.dsc 269329D7 rom/script/pv_626_normal.dsc 77B1A1B9 rom/script/pv_627_easy.dsc 6806FAC1 rom/script/pv_627_extreme.dsc EF0AD937 rom/script/pv_627_hard.dsc 6FD4FAF7 rom/script/pv_627_normal.dsc 9AFBC354 rom/script/pv_628_easy.dsc AC39E385 rom/script/pv_628_extreme.dsc 355C488D rom/script/pv_628_hard.dsc D590A9E3 rom/script/pv_628_normal.dsc 5D9B5CDB rom/script/pv_629_easy.dsc C909FE10 rom/script/pv_629_extreme.dsc 44E2E6B5 rom/script/pv_629_hard.dsc AB0A5102 rom/script/pv_630_easy.dsc 6AF7B496 rom/script/pv_630_extreme.dsc 984941D1 rom/script/pv_630_hard.dsc 704E6602 rom/script/pv_630_normal.dsc 2D4526F9 rom/script/pv_631_easy.dsc A84DCAFA rom/script/pv_631_extreme.dsc 99DB8C90 rom/script/pv_631_hard.dsc 34508993 rom/script/pv_631_normal.dsc E46AE0D2 rom/script/pv_637_easy.dsc 3D89CDFC rom/script/pv_637_extreme.dsc BCDA2E13 rom/script/pv_637_hard.dsc 263F183F rom/script/pv_637_normal.dsc 075166C2 rom/script/pv_638_easy.dsc A0437A88 rom/script/pv_638_extreme.dsc 03C4E956 rom/script/pv_638_hard.dsc D9921311 rom/script/pv_638_normal.dsc C71BF509 rom/script/pv_639_extreme.dsc 990961FE rom/script/pv_402_extreme.dsc FB9E6181 rom/script/pv_407_extreme.dsc 2061842F rom/script/pv_412_extreme.dsc 5FF778DD rom/script/pv_416_hard.dsc 1082AEFA rom/script/pv_421_hard.dsc DE8DE37A rom/script/pv_425_normal.dsc B5F81A4B rom/script/pv_430_extreme.dsc EC9BA228 rom/script/pv_435_extreme.dsc 3DCA160D rom/script/pv_440_extreme.dsc 3FE74792 rom/script/pv_601_easy.dsc 00E4B62D rom/script/pv_605_hard.dsc A45DA3B0 rom/script/pv_611_easy.dsc DAAF2E76 rom/script/pv_615_normal.dsc 1C2D1E5E rom/script/pv_620_hard.dsc DE497FF8 rom/script/pv_625_extreme.dsc 72A20C06 rom/script/pv_629_normal.dsc 99FECCD7 rom/script/pv_639_hard.dsc A68BF106 rom/script/pv_722_easy.dsc 97C37BCD rom/script/pv_726_hard.dsc 43AC2370 rom/script/pv_731_easy.dsc A7C95048 rom/script/pv_736_hard.dsc 875E6EEF rom/script/pv_639_normal.dsc 94D5E9E0 rom/script/pv_640_easy.dsc C75D9D8A rom/script/pv_640_extreme.dsc 975279A3 rom/script/pv_640_hard.dsc E45BD044 rom/script/pv_640_normal.dsc 96A5B6BB rom/script/pv_641_easy.dsc 294B061F rom/script/pv_641_extreme.dsc 0F7032B6 rom/script/pv_641_hard.dsc 40AE5C4C rom/script/pv_641_normal.dsc BECDD6C8 rom/script/pv_642_easy.dsc 1DA5F826 rom/script/pv_642_extreme.dsc C2624516 rom/script/pv_642_hard.dsc FD782288 rom/script/pv_642_normal.dsc 4F036C01 rom/script/pv_710_easy.dsc 83CBB982 rom/script/pv_710_extreme.dsc 7E76539B rom/script/pv_710_hard.dsc 8DCA80E9 rom/script/pv_710_normal.dsc 057D63EC rom/script/pv_722_extreme.dsc 83CA3801 rom/script/pv_722_hard.dsc CCC45AD4 rom/script/pv_722_normal.dsc 7E877EEC rom/script/pv_723_easy.dsc 0AF66A8F rom/script/pv_723_extreme.dsc A82341C1 rom/script/pv_723_hard.dsc 85D30986 rom/script/pv_723_normal.dsc DBD40CF2 rom/script/pv_724_easy.dsc 0B711633 rom/script/pv_724_extreme.dsc 9BDECA3B rom/script/pv_724_hard.dsc 30C21361 rom/script/pv_724_normal.dsc 6D97A45F rom/script/pv_725_easy.dsc 653502FC rom/script/pv_725_extreme.dsc 06C7CBDF rom/script/pv_725_hard.dsc 5804170C rom/script/pv_725_normal.dsc CF00CEB0 rom/script/pv_726_easy.dsc AB604F24 rom/script/pv_726_extreme.dsc 7D9FF60B rom/script/pv_726_normal.dsc 9E428F9C rom/script/pv_727_easy.dsc 0D920142 rom/script/pv_727_extreme.dsc FC5E02DE rom/script/pv_727_hard.dsc 9D1F211D rom/script/pv_727_normal.dsc 2219193E rom/script/pv_728_easy.dsc A821666E rom/script/pv_728_extreme.dsc E3E0AD64 rom/script/pv_728_hard.dsc 4295048D rom/script/pv_728_normal.dsc C2BEB540 rom/script/pv_729_easy.dsc AC005FF1 rom/script/pv_729_extreme.dsc 9C922E28 rom/script/pv_729_hard.dsc F85D8482 rom/script/pv_729_normal.dsc D96769D2 rom/script/pv_730_easy.dsc 3ABE0731 rom/script/pv_730_extreme.dsc 0A773EED rom/script/pv_730_hard.dsc E2628663 rom/script/pv_730_normal.dsc 44A75C5A rom/script/pv_731_extreme.dsc 9B5ACA6B rom/script/pv_731_hard.dsc 58CFB01F rom/script/pv_731_normal.dsc B94A1ADF rom/script/pv_732_easy.dsc A7D9FB75 rom/script/pv_732_extreme.dsc 4ED63BD7 rom/script/pv_732_hard.dsc 2A1AB39C rom/script/pv_732_normal.dsc 86C08125 rom/script/pv_733_easy.dsc 635C6926 rom/script/pv_733_extreme.dsc F03B1889 rom/script/pv_733_hard.dsc 4DBAE275 rom/script/pv_733_normal.dsc ACF528E5 rom/script/pv_734_easy.dsc 06CDE987 rom/script/pv_734_extreme.dsc D96CB68A rom/script/pv_734_hard.dsc 78D24578 rom/script/pv_734_normal.dsc B20AFB9A rom/script/pv_736_easy.dsc 5DCF7A31 rom/script/pv_736_extreme.dsc EE902872 rom/script/pv_736_normal.dsc 6B82ECA7 rom/script/pv_737_easy.dsc 694931D3 rom/script/pv_737_extreme.dsc 6486CE59 rom/script/pv_737_hard.dsc F7D0D55C rom/script/pv_737_normal.dsc 459C5EEA rom/script/pv_738_extreme.dsc BC99BCD1 rom/script/pv_738_hard.dsc 34E71E37 rom/script/pv_738_normal.dsc 0D547301 rom/script/pv_739_easy.dsc C69080EF rom/script/pv_739_extreme.dsc 68E1ECE3 rom/script/pv_739_hard.dsc EE35E342 rom/script/pv_739_normal.dsc 221D8776 rom/script/pv_740_easy.dsc DA0B7A6B rom/script/pv_740_extreme.dsc D4E7C7C5 rom/script/pv_740_hard.dsc B23C953B rom/script/pv_740_normal.dsc F05FF0A4 rom/script/pv_832_easy.dsc 03E0DBD3 rom/script/pv_832_extreme.dsc 762F5177 rom/script/pv_832_hard.dsc 1326952C rom/script/pv_832_normal.dsc EA731D11 rom/script/pv_999_normal.dsc FD8D1E42 rom/skin_param/ext_skp_hakitm001_joha_outer_01__divskn.txt 4D24DA8E rom/skin_param/ext_skp_hakitm002_joha_outer_02__divskn.txt 84BAACF1 rom/skin_param/ext_skp_hakitm003_joha_outer_03__divskn.txt 7F86191A rom/skin_param/ext_skp_hakitm004_joha_outer_04__divskn.txt 79ACFF1E rom/skin_param/ext_skp_hakitm500_atam_atama_00__divskn.txt 04BDCDAC rom/skin_param/ext_skp_hakitm501_atam_atama_01__divskn.txt 6E716419 rom/skin_param/ext_skp_hakitm502_atam_atama_02__divskn.txt 284CA3EC rom/skin_param/ext_skp_hakitm700_atam_zujo_00__divskn.txt 74629E5C rom/skin_param/ext_skp_hnditm057_schoolbag_b_close_bone_l__divskn.txt 323082A7 rom/skin_param/ext_skp_hnditm057_schoolbag_b_close_bone_r__divskn.txt B579B24D rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_l_kai__divskn.txt 2EE3AAE2 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_l__divskn.txt 2EE3AAE2 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_r_kai__divskn.txt 246D6842 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_r_len__divskn.txt 246D6842 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_r__divskn.txt 246D6842 rom/skin_param/ext_skp_kaiitm001_joha_outer_01__divskn.txt 8C1BE0FB rom/skin_param/ext_skp_kaiitm002_joha_outer_02__divskn.txt 9F36E712 rom/skin_param/ext_skp_kaiitm003_joha_outer_03__divskn.txt 3F8FE4E8 rom/skin_param/ext_skp_kaiitm004_joha_outer_04__divskn.txt 3E616EB3 rom/skin_param/ext_skp_kaiitm006_joha_outer_06__divskn.txt 2E548BD1 rom/skin_param/ext_skp_kaiitm008_joha_outer_08__divskn.txt D5F07089 rom/skin_param/ext_skp_kaiitm009_joha_outer_09__divskn.txt E2588062 rom/skin_param/ext_skp_kaiitm011_joha_outer_11__divskn.txt 946809E5 rom/skin_param/ext_skp_kaiitm012_joha_outer_12__divskn.txt 4941911F rom/skin_param/ext_skp_kaiitm015_joha_outer_15__divskn.txt 3EA50175 rom/skin_param/ext_skp_kaiitm016_joha_outer_16__divskn.txt E3EC46A4 rom/skin_param/ext_skp_kaiitm018_joha_outer_18__divskn.txt 847FFEA3 rom/skin_param/ext_skp_kaiitm019_joha_outer_19__divskn.txt F370F7A5 rom/skin_param/ext_skp_kaiitm020_joha_outer_20__divskn.txt DE1EBE3F rom/skin_param/ext_skp_kaiitm022_joha_outer_22__divskn.txt 8633A383 rom/skin_param/ext_skp_kaiitm024_joha_outer_24__divskn.txt 37C513E8 rom/skin_param/ext_skp_kaiitm025_joha_outer_25__divskn.txt E735CA83 rom/skin_param/ext_skp_kaiitm027_joha_outer_27__divskn.txt 215E9852 rom/skin_param/ext_skp_hnditm601_pv_bonbon_sing_l_len__divskn.txt 2EE3AAE2 rom/skin_param/ext_skp_kaiitm010_joha_outer_10__divskn.txt 497365B1 rom/skin_param/ext_skp_kaiitm028_joha_outer_28__divskn.txt 78D2D4EF rom/skin_param/ext_skp_kaiitm502_atam_atama_02__divskn.txt 9CB70A08 rom/skin_param/ext_skp_kaiitm524_atam_atama_24__divskn.txt E93C73E7 rom/skin_param/ext_skp_kaiitm705_atam_zujo_05__divskn.txt 686FC4D4 rom/skin_param/ext_skp_lenitm009_joha_outer_09__divskn.txt 382B6653 rom/skin_param/ext_skp_lenitm022_joha_outer_22__divskn.txt 9747EDC4 rom/skin_param/ext_skp_lenitm034_joha_outer_34__divskn.txt E1027AB5 rom/skin_param/ext_skp_lenitm507_atam_atama_07__divskn.txt 685B5D10 rom/skin_param/ext_skp_lenitm528_atam_atama_28__divskn.txt C48FB670 rom/skin_param/ext_skp_kaiitm029_joha_outer_29__divskn.txt FA3EA7B9 rom/skin_param/ext_skp_kaiitm030_joha_outer_30__divskn.txt 5C18A136 rom/skin_param/ext_skp_kaiitm031_joha_outer_31__divskn.txt B2C76F64 rom/skin_param/ext_skp_kaiitm032_joha_outer_32__divskn.txt 7DBD2466 rom/skin_param/ext_skp_kaiitm033_joha_outer_33__divskn.txt 5D7B06EE rom/skin_param/ext_skp_kaiitm034_joha_outer_34__divskn.txt 07F5CE85 rom/skin_param/ext_skp_kaiitm036_joha_outer_36__divskn.txt F303BEAB rom/skin_param/ext_skp_kaiitm041_joha_outer_41__divskn.txt 1BF2404D rom/skin_param/ext_skp_kaiitm042_joha_outer_42__divskn.txt 9C52BBDE rom/skin_param/ext_skp_kaiitm500_atam_atama_00__divskn.txt 19EC854D rom/skin_param/ext_skp_kaiitm501_atam_atama_01__divskn.txt 8E03B4E2 rom/skin_param/ext_skp_kaiitm503_atam_atama_03__divskn.txt 4BAE4D26 rom/skin_param/ext_skp_kaiitm504_atam_atama_04__divskn.txt 1E2FFD8B rom/skin_param/ext_skp_kaiitm505_atam_atama_05__divskn.txt AA42F404 rom/skin_param/ext_skp_kaiitm506_atam_atama_06__divskn.txt 840EC0D4 rom/skin_param/ext_skp_kaiitm507_atam_atama_07__divskn.txt F35392FF rom/skin_param/ext_skp_kaiitm508_atam_atama_08__divskn.txt 13B49259 rom/skin_param/ext_skp_kaiitm509_atam_atama_09__divskn.txt A9B6B152 rom/skin_param/ext_skp_kaiitm510_atam_atama_10__divskn.txt 2ACC939E rom/skin_param/ext_skp_kaiitm520_atam_atama_20__divskn.txt 01F8B471 rom/skin_param/ext_skp_kaiitm522_atam_atama_22__divskn.txt 8F3918A7 rom/skin_param/ext_skp_kaiitm523_atam_atama_23__divskn.txt 667D75E2 rom/skin_param/ext_skp_kaiitm527_atam_atama_27__divskn.txt 2E0C888E rom/skin_param/ext_skp_kaiitm528_atam_atama_28__divskn.txt 73491F88 rom/skin_param/ext_skp_kaiitm529_atam_atama_29__divskn.txt 272D1656 rom/skin_param/ext_skp_kaiitm531_atam_atama_31__divskn.txt 419552EE rom/skin_param/ext_skp_kaiitm532_atam_atama_32__divskn.txt 5A5353AB rom/skin_param/ext_skp_kaiitm533_atam_atama_33__divskn.txt 13B49259 rom/skin_param/ext_skp_kaiitm534_atam_atama_34__divskn.txt 1CDB2E67 rom/skin_param/ext_skp_kaiitm536_atam_atama_36__divskn.txt 78E123DE rom/skin_param/ext_skp_kaiitm541_atam_atama_41__divskn.txt D2F4972E rom/skin_param/ext_skp_kaiitm542_atam_atama_42__divskn.txt AEE53D61 rom/skin_param/ext_skp_kaiitm701_atam_zujo_01__divskn.txt 1FA0E0F0 rom/skin_param/ext_skp_kaiitm706_atam_zujo_06__divskn.txt A570CFCC rom/skin_param/ext_skp_kaiitm750_joha_neck_50__divskn.txt F0AF8544 rom/skin_param/ext_skp_kaiitm751_joha_neck_51__divskn.txt 65631614 rom/skin_param/ext_skp_kaiitm775_joha_ushiro_75__divskn.txt 8AA2DBC3 rom/skin_param/ext_skp_lenitm001_joha_outer_01__divskn.txt 55A8C416 rom/skin_param/ext_skp_lenitm002_joha_outer_02__divskn.txt 21274F4A rom/skin_param/ext_skp_lenitm003_joha_outer_03__divskn.txt 9705B54B rom/skin_param/ext_skp_lenitm004_joha_outer_04__divskn.txt B36FD6EE rom/skin_param/ext_skp_lenitm005_joha_outer_05__divskn.txt D72CBA3A rom/skin_param/ext_skp_lenitm007_joha_outer_07__divskn.txt 7FE0EA6C rom/skin_param/ext_skp_lenitm008_joha_outer_08__divskn.txt 9772EBEA rom/skin_param/ext_skp_lenitm010_joha_outer_10__divskn.txt 93EE30EE rom/skin_param/ext_skp_lenitm011_joha_outer_11__divskn.txt C871752A rom/skin_param/ext_skp_lenitm012_joha_outer_12__divskn.txt 20FDB291 rom/skin_param/ext_skp_lenitm013_joha_outer_13__divskn.txt A2F40B68 rom/skin_param/ext_skp_lenitm014_joha_outer_14__divskn.txt CA074C71 rom/skin_param/ext_skp_lenitm015_joha_outer_15__divskn.txt C80B1B33 rom/skin_param/ext_skp_lenitm016_joha_outer_16__divskn.txt 9121F172 rom/skin_param/ext_skp_lenitm017_joha_outer_17__divskn.txt F1075733 rom/skin_param/ext_skp_lenitm018_joha_outer_18__divskn.txt C28E33B0 rom/skin_param/ext_skp_lenitm019_joha_outer_19__divskn.txt EE076B01 rom/skin_param/ext_skp_lenitm021_joha_outer_21__divskn.txt 92F4F9FE rom/skin_param/ext_skp_lenitm023_joha_outer_23__divskn.txt 3CBC9280 rom/skin_param/ext_skp_lenitm024_joha_outer_24__divskn.txt 925824D3 rom/skin_param/ext_skp_lenitm025_joha_outer_25__divskn.txt 89E8F269 rom/skin_param/ext_skp_lenitm026_joha_outer_26__divskn.txt 705B679A rom/skin_param/ext_skp_lenitm027_joha_outer_27__divskn.txt EFF34072 rom/skin_param/ext_skp_lenitm028_joha_outer_28__divskn.txt 00C9F784 rom/skin_param/ext_skp_lenitm029_joha_outer_29__divskn.txt E3DE802F rom/skin_param/ext_skp_lenitm030_joha_outer_30__divskn.txt A8E54719 rom/skin_param/ext_skp_lenitm031_joha_outer_31__divskn.txt 8CA5C00D rom/skin_param/ext_skp_lenitm032_joha_outer_32__divskn.txt 0DEB4749 rom/skin_param/ext_skp_lenitm033_joha_outer_33__divskn.txt BBC1212D rom/skin_param/ext_skp_lenitm035_joha_outer_35__divskn.txt A9E9FC90 rom/skin_param/ext_skp_lenitm036_joha_outer_36__divskn.txt 9B6123B7 rom/skin_param/ext_skp_lenitm038_joha_outer_38__divskn.txt 179D24CD rom/skin_param/ext_skp_lenitm040_joha_outer_40__divskn.txt C6801D18 rom/skin_param/ext_skp_lenitm500_atam_atama_00__divskn.txt D910C084 rom/skin_param/ext_skp_lenitm501_atam_atama_01__divskn.txt 3E519A80 rom/skin_param/ext_skp_lenitm502_atam_atama_02__divskn.txt 2C4F0FEA rom/skin_param/ext_skp_lenitm503_atam_atama_03__divskn.txt FD3D9A32 rom/skin_param/ext_skp_lenitm504_atam_atama_04__divskn.txt 2E592957 rom/skin_param/ext_skp_lenitm505_atam_atama_05__divskn.txt 98E59E3E rom/skin_param/ext_skp_lenitm506_atam_atama_06__divskn.txt B98FCC44 rom/skin_param/ext_skp_lenitm508_atam_atama_08__divskn.txt 5C7DA3B0 rom/skin_param/ext_skp_lenitm509_atam_atama_09__divskn.txt 62721319 rom/skin_param/ext_skp_lenitm510_atam_atama_10__divskn.txt E42BD014 rom/skin_param/ext_skp_lenitm511_atam_atama_11__divskn.txt 96BC8337 rom/skin_param/ext_skp_lenitm519_atam_atama_19__divskn.txt 29757C9E rom/skin_param/ext_skp_lenitm521_atam_atama_21__divskn.txt 38F0F907 rom/skin_param/ext_skp_lenitm522_atam_atama_22__divskn.txt F530E67C rom/skin_param/ext_skp_lenitm523_atam_atama_23__divskn.txt FBFC8406 rom/skin_param/ext_skp_lenitm524_atam_atama_24__divskn.txt E292B771 rom/skin_param/ext_skp_lenitm525_atam_atama_25__divskn.txt D2956189 rom/skin_param/ext_skp_lenitm526_atam_atama_26__divskn.txt 9FD32D2F rom/skin_param/ext_skp_lenitm529_atam_atama_29__divskn.txt F54C8A9A rom/skin_param/ext_skp_lenitm530_atam_atama_30__divskn.txt 9632D537 rom/skin_param/ext_skp_lenitm531_atam_atama_31__divskn.txt 61DAC8D3 rom/skin_param/ext_skp_lenitm532_atam_atama_32__divskn.txt B5D58E3C rom/skin_param/ext_skp_lenitm533_atam_atama_33__divskn.txt 9F0BB8EF rom/skin_param/ext_skp_lenitm534_atam_atama_34__divskn.txt 718D4801 rom/skin_param/ext_skp_lenitm535_atam_atama_35__divskn.txt C2F62745 rom/skin_param/ext_skp_lenitm536_atam_atama_36__divskn.txt 5DCD74FC rom/skin_param/ext_skp_lenitm537_atam_atama_37__divskn.txt 02BDAE3B rom/skin_param/ext_skp_lenitm538_atam_atama_38__divskn.txt 4F56EAB9 rom/skin_param/ext_skp_lenitm540_atam_atama_40__divskn.txt C441EDC1 rom/skin_param/ext_skp_lenitm775_joha_ushiro_75__divskn.txt D216DEAD rom/skin_param/ext_skp_lukitm001_joha_outer_01_zzc__divskn.txt 654805C5 rom/skin_param/ext_skp_lukitm002_joha_outer_02__divskn.txt E17F62F1 rom/skin_param/ext_skp_lukitm003_joha_outer_03__divskn.txt 25195EA0 rom/skin_param/ext_skp_lukitm004_joha_outer_04__divskn.txt 214BCD31 rom/skin_param/ext_skp_lukitm005_joha_outer_05__divskn.txt E4D482F7 rom/skin_param/ext_skp_lukitm006_joha_outer_06__divskn.txt 220D8A17 rom/skin_param/ext_skp_lukitm007_joha_outer_07__divskn.txt ADA69068 rom/skin_param/ext_skp_lukitm008_joha_outer_08__divskn.txt B5B57701 rom/skin_param/ext_skp_lukitm009_joha_outer_09__divskn.txt 280C99FE rom/skin_param/ext_skp_lukitm010_joha_outer_10__divskn.txt 16DA411B rom/skin_param/ext_skp_lukitm012_joha_outer_12__divskn.txt B890CD58 rom/skin_param/ext_skp_lukitm013_joha_outer_13__divskn.txt 8276AF21 rom/skin_param/ext_skp_lukitm014_joha_outer_14__divskn.txt 7A2DCF8C rom/skin_param/ext_skp_lukitm015_joha_outer_15__divskn.txt 9FF9A753 rom/skin_param/ext_skp_lukitm017_joha_outer_17_zzc__divskn.txt 8AEF2838 rom/skin_param/ext_skp_lukitm018_joha_outer_18__divskn.txt 41A3DEC2 rom/skin_param/ext_skp_lukitm019_joha_outer_19__divskn.txt F41EA21C rom/skin_param/ext_skp_lukitm020_joha_outer_20__divskn.txt F5759B2F rom/skin_param/ext_skp_lukitm021_joha_outer_21__divskn.txt 03807B90 rom/skin_param/ext_skp_lukitm022_joha_outer_22__divskn.txt 2D127092 rom/skin_param/ext_skp_lukitm023_joha_outer_23__divskn.txt 02E7BA68 rom/skin_param/ext_skp_lukitm025_joha_outer_25__divskn.txt C0950F86 rom/skin_param/ext_skp_lukitm026_joha_outer_26__divskn.txt 2BAE2E86 rom/skin_param/ext_skp_lukitm027_joha_outer_27__divskn.txt 9FE08A57 rom/skin_param/ext_skp_lukitm028_joha_outer_28__divskn.txt 5961D7D3 rom/skin_param/ext_skp_lukitm029_joha_outer_29__divskn.txt F8742093 rom/skin_param/ext_skp_lukitm030_joha_outer_30__divskn.txt E62E3AD6 rom/skin_param/ext_skp_lukitm031_joha_outer_31__divskn.txt F3C25D81 rom/skin_param/ext_skp_lukitm032_joha_outer_32__divskn.txt 76ED4243 rom/skin_param/ext_skp_lukitm033_joha_outer_33__divskn.txt 8F2BC033 rom/skin_param/ext_skp_lukitm034_joha_outer_34__divskn.txt 214BCD31 rom/skin_param/ext_skp_lukitm035_joha_outer_35__divskn.txt 62E22A35 rom/skin_param/ext_skp_lukitm037_joha_outer_37__divskn.txt 10E57D9A rom/skin_param/ext_skp_lukitm038_joha_outer_38__divskn.txt CE8AFFED rom/skin_param/ext_skp_lukitm039_joha_outer_39__divskn.txt 3156C805 rom/skin_param/ext_skp_lukitm040_joha_outer_40__divskn.txt 98F0E7C2 rom/skin_param/ext_skp_lukitm042_joha_outer_42__divskn.txt 149B3BCF rom/skin_param/ext_skp_lukitm311_ude_hand_11__divskn.txt A62E4BCF rom/skin_param/ext_skp_lukitm500_atam_atama_00__divskn.txt 1E93DA16 rom/skin_param/ext_skp_lukitm501_atam_atama_01__divskn.txt E540B91D rom/skin_param/ext_skp_lukitm502_atam_atama_02__divskn.txt 60D49880 rom/skin_param/ext_skp_lukitm503_atam_atama_03__divskn.txt 73E7D894 rom/skin_param/ext_skp_lukitm504_atam_atama_04__divskn.txt 2AD8D280 rom/skin_param/ext_skp_lukitm506_atam_atama_06__divskn.txt D8424EDF rom/skin_param/ext_skp_lukitm507_atam_atama_07__divskn.txt 55B50F1E rom/skin_param/ext_skp_lukitm508_atam_atama_08__divskn.txt 1E93DA16 rom/skin_param/ext_skp_lukitm509_atam_atama_09__divskn.txt 73E7D894 rom/skin_param/ext_skp_lukitm510_atam_atama_10__divskn.txt 1E93DA16 rom/skin_param/ext_skp_lukitm511_atam_atama_11__divskn.txt E4F6544F rom/skin_param/ext_skp_lukitm512_atam_atama_12__divskn.txt 5C4FF82F rom/skin_param/ext_skp_lukitm513_atam_atama_13__divskn.txt 34637A9E rom/skin_param/ext_skp_lukitm514_atam_atama_14__divskn.txt 9A20B7AD rom/skin_param/ext_skp_lukitm515_atam_atama_15__divskn.txt 7054E187 rom/skin_param/ext_skp_lukitm516_atam_atama_16__divskn.txt 30B9489A rom/skin_param/ext_skp_lukitm525_atam_atama_25__divskn.txt 7C08E2E9 rom/skin_param/ext_skp_lukitm526_atam_atama_26__divskn.txt B2685485 rom/skin_param/ext_skp_lukitm527_atam_atama_27__divskn.txt 08415D9B rom/skin_param/ext_skp_lukitm528_atam_atama_28__divskn.txt 9BF39C9D rom/skin_param/ext_skp_lukitm529_atam_atama_29__divskn.txt E57BE10E rom/skin_param/ext_skp_lukitm530_atam_atama_30__divskn.txt 3A35570E rom/skin_param/ext_skp_lukitm531_atam_atama_31__divskn.txt 03571AC4 rom/skin_param/ext_skp_lukitm532_atam_atama_32__divskn.txt 755E0D97 rom/skin_param/ext_skp_lukitm533_atam_atama_33__divskn.txt 0E59E330 rom/skin_param/ext_skp_lukitm534_atam_atama_34__divskn.txt 85FC9650 rom/skin_param/ext_skp_lukitm535_atam_atama_35__divskn.txt 0AEF6013 rom/skin_param/ext_skp_lukitm537_atam_atama_37__divskn.txt B25AA34F rom/skin_param/ext_skp_lukitm538_atam_atama_38__divskn.txt 9F6E06A5 rom/skin_param/ext_skp_lukitm539_atam_atama_39__divskn.txt 422048E7 rom/skin_param/ext_skp_lukitm540_atam_atama_40__divskn.txt E739752A rom/skin_param/ext_skp_lukitm542_atam_atama_42__divskn.txt 12DEB872 rom/skin_param/ext_skp_lukitm700_atam_zujo_00__divskn.txt 9FEF0013 rom/skin_param/ext_skp_lukitm702_atam_zujo_02__divskn.txt B841A829 rom/skin_param/ext_skp_lukitm703_atam_zujo_03__divskn.txt 0F0D1518 rom/skin_param/ext_skp_lukitm705_atam_zujo_05__divskn.txt B83E4D47 rom/skin_param/ext_skp_meiitm001_joha_outer_01__divskn.txt DA57FC3C rom/skin_param/ext_skp_meiitm002_joha_outer_02__divskn.txt 41569244 rom/skin_param/ext_skp_meiitm004_joha_outer_04__divskn.txt 2DCCF95F rom/skin_param/ext_skp_meiitm005_joha_outer_05__divskn.txt 23C85D3A rom/skin_param/ext_skp_meiitm006_joha_outer_06__divskn.txt 2CB0A9B8 rom/skin_param/ext_skp_meiitm008_joha_outer_08__divskn.txt 88D864E1 rom/skin_param/ext_skp_meiitm009_joha_outer_09__divskn.txt 3A9CEBCD rom/skin_param/ext_skp_meiitm010_joha_outer_10__divskn.txt D7067EDF rom/skin_param/ext_skp_meiitm011_joha_outer_11__divskn.txt 129AA502 rom/skin_param/ext_skp_meiitm012_joha_outer_12__divskn.txt E9F58A3B rom/skin_param/ext_skp_meiitm013_joha_outer_13__divskn.txt 15C853A7 rom/skin_param/ext_skp_meiitm014_joha_outer_14__divskn.txt B2CEA443 rom/skin_param/ext_skp_meiitm015_joha_outer_15__divskn.txt E8572C6C rom/skin_param/ext_skp_meiitm017_joha_outer_17_zzc__divskn.txt 7E2556A7 rom/skin_param/ext_skp_meiitm018_joha_outer_18__divskn.txt A4E3B72D rom/skin_param/ext_skp_meiitm019_joha_outer_19__divskn.txt 5AA3F97F rom/skin_param/ext_skp_meiitm020_joha_outer_20__divskn.txt 2F81C041 rom/skin_param/ext_skp_meiitm021_joha_outer_21__divskn.txt AB5D216A rom/skin_param/ext_skp_meiitm022_joha_outer_22__divskn.txt AE7781F9 rom/skin_param/ext_skp_meiitm023_joha_outer_23__divskn.txt 0A00487A rom/skin_param/ext_skp_meiitm024_joha_outer_24__divskn.txt 9CF9E170 rom/skin_param/ext_skp_meiitm025_joha_outer_25__divskn.txt 6D8D4950 rom/skin_param/ext_skp_meiitm026_joha_outer_26__divskn.txt FA002260 rom/skin_param/ext_skp_meiitm027_joha_outer_27__divskn.txt 5A8626FD rom/skin_param/ext_skp_meiitm029_joha_outer_29__divskn.txt 955BA10A rom/skin_param/ext_skp_meiitm030_joha_outer_30__divskn.txt E5328983 rom/skin_param/ext_skp_meiitm032_joha_outer_32__divskn.txt AC3A0FC9 rom/skin_param/ext_skp_meiitm033_joha_outer_33__divskn.txt 0CA9311C rom/skin_param/ext_skp_meiitm500_atam_atama_00__divskn.txt C77F53B1 rom/skin_param/ext_skp_meiitm501_atam_atama_01__divskn.txt DD359CDB rom/skin_param/ext_skp_meiitm502_atam_atama_02__divskn.txt 87B06D33 rom/skin_param/ext_skp_meiitm503_atam_atama_03__divskn.txt 7CA5CEE3 rom/skin_param/ext_skp_meiitm504_atam_atama_04__divskn.txt 3D15FFE6 rom/skin_param/ext_skp_meiitm505_atam_atama_05__divskn.txt C1254D7D rom/skin_param/ext_skp_meiitm506_atam_atama_06__divskn.txt 371F01B9 rom/skin_param/ext_skp_meiitm508_atam_atama_08__divskn.txt 667ABD2E rom/skin_param/ext_skp_meiitm509_atam_atama_09__divskn.txt 8A104EA8 rom/skin_param/ext_skp_meiitm510_atam_atama_10__divskn.txt B1CFB791 rom/skin_param/ext_skp_meiitm511_atam_atama_11__divskn.txt F2B75879 rom/skin_param/ext_skp_meiitm512_atam_atama_12__divskn.txt 00D8137C rom/skin_param/ext_skp_meiitm513_atam_atama_13__divskn.txt E1F74858 rom/skin_param/ext_skp_meiitm514_atam_atama_14__divskn.txt 727A8466 rom/skin_param/ext_skp_meiitm515_atam_atama_15__divskn.txt 349DCD6F rom/skin_param/ext_skp_meiitm521_atam_atama_21__divskn.txt B14D9896 rom/skin_param/ext_skp_meiitm522_atam_atama_22__divskn.txt A99F80CA rom/skin_param/ext_skp_meiitm523_atam_atama_23__divskn.txt 9536DA3F rom/skin_param/ext_skp_meiitm525_atam_atama_25__divskn.txt 5E7F0941 rom/skin_param/ext_skp_meiitm526_atam_atama_26__divskn.txt 7A04E25C rom/skin_param/ext_skp_meiitm527_atam_atama_27__divskn.txt FFDB626C rom/skin_param/ext_skp_meiitm528_atam_atama_28__divskn.txt 6F46A143 rom/skin_param/ext_skp_meiitm529_atam_atama_29__divskn.txt F3F39871 rom/skin_param/ext_skp_meiitm530_atam_atama_30__divskn.txt 1729312E rom/skin_param/ext_skp_meiitm532_atam_atama_32__divskn.txt 3855628D rom/skin_param/ext_skp_meiitm533_atam_atama_33__divskn.txt 0CB7B09A rom/skin_param/ext_skp_meiitm700_atam_zujo_00__divskn.txt 6CE45455 rom/skin_param/ext_skp_meiitm701_atam_zujo_01__divskn.txt D7FAE2BD rom/skin_param/ext_skp_meiitm702_atam_zujo_02__divskn.txt 8E1948E0 rom/skin_param/ext_skp_lukitm011_joha_outer_11__divskn.txt 50240D20 rom/skin_param/ext_skp_lukitm024_joha_outer_24__divskn.txt 7715ABE7 rom/skin_param/ext_skp_lukitm036_joha_outer_36__divskn.txt E0A4B742 rom/skin_param/ext_skp_lukitm505_atam_atama_05__divskn.txt 428394B7 rom/skin_param/ext_skp_lukitm517_atam_atama_17__divskn.txt 2A9A98A2 rom/skin_param/ext_skp_lukitm536_atam_atama_36__divskn.txt 3B9D4131 rom/skin_param/ext_skp_meiitm003_joha_outer_03__divskn.txt FF3BA966 rom/skin_param/ext_skp_meiitm016_joha_outer_16__divskn.txt 728A8122 rom/skin_param/ext_skp_meiitm028_joha_outer_28__divskn.txt B9121E5E rom/skin_param/ext_skp_meiitm507_atam_atama_07__divskn.txt 1C6898BA rom/skin_param/ext_skp_meiitm524_atam_atama_24__divskn.txt 5EF04A2A rom/skin_param/ext_skp_meiitm705_atam_zujo_05__divskn.txt D36B6569 rom/skin_param/ext_skp_meiitm709_atam_zujo_09__divskn.txt 2B69955A rom/skin_param/ext_skp_meiitm775_joha_ushiro_75__divskn.txt 9B576E3B rom/skin_param/ext_skp_mikitm001_joha_outer_01__divskn.txt 5BF7D343 rom/skin_param/ext_skp_mikitm002_joha_outer_02__divskn.txt FC16024B rom/skin_param/ext_skp_mikitm003_joha_outer_03__divskn.txt CEA69D40 rom/skin_param/ext_skp_mikitm004_joha_outer_04__divskn.txt 60742290 rom/skin_param/ext_skp_mikitm005_joha_outer_05__divskn.txt 05C447F3 rom/skin_param/ext_skp_mikitm006_joha_outer_06__divskn.txt AA966DF0 rom/skin_param/ext_skp_mikitm007_joha_outer_07__divskn.txt 8450E7B3 rom/skin_param/ext_skp_mikitm008_joha_outer_08__divskn.txt 34E8037D rom/skin_param/ext_skp_mikitm010_joha_outer_10__divskn.txt F81B0047 rom/skin_param/ext_skp_mikitm011_joha_outer_11__divskn.txt AEE44D44 rom/skin_param/ext_skp_mikitm012_joha_outer_12__divskn.txt 45FA3DA4 rom/skin_param/ext_skp_mikitm013_joha_outer_13__divskn.txt 8A2B3217 rom/skin_param/ext_skp_mikitm014_joha_outer_14__divskn.txt 6322964D rom/skin_param/ext_skp_mikitm015_joha_outer_15__divskn.txt CBA071FF rom/skin_param/ext_skp_mikitm016_joha_outer_16__divskn.txt 862218E1 rom/skin_param/ext_skp_mikitm017_joha_outer_17__divskn.txt 05C447F3 rom/skin_param/ext_skp_mikitm018_joha_outer_18__divskn.txt 7547744B rom/skin_param/ext_skp_mikitm019_joha_outer_19__divskn.txt 847E5718 rom/skin_param/ext_skp_mikitm020_joha_outer_20__divskn.txt D418840D rom/skin_param/ext_skp_mikitm022_joha_outer_22_zzc__divskn.txt B5ED7130 rom/skin_param/ext_skp_mikitm023_joha_outer_23__divskn.txt 91C30F14 rom/skin_param/ext_skp_mikitm024_joha_outer_24__divskn.txt 8946A95D rom/skin_param/ext_skp_mikitm025_joha_outer_25__divskn.txt EE4DFBCE rom/skin_param/ext_skp_mikitm026_joha_outer_26__divskn.txt 89B73FB8 rom/skin_param/ext_skp_mikitm027_joha_outer_27__divskn.txt 8B67EE31 rom/skin_param/ext_skp_mikitm029_joha_outer_29__divskn.txt E8B018B1 rom/skin_param/ext_skp_mikitm030_joha_outer_30__divskn.txt 862218E1 rom/skin_param/ext_skp_mikitm031_joha_outer_31__divskn.txt 79C95511 rom/skin_param/ext_skp_mikitm032_joha_outer_32__divskn.txt 9C0EEE6B rom/skin_param/ext_skp_mikitm038_joha_outer_38__divskn.txt 5822232A rom/skin_param/ext_skp_mikitm041_joha_outer_41__divskn.txt 9E09C52E rom/skin_param/ext_skp_mikitm042_joha_outer_42__divskn.txt 9EBF87E0 rom/skin_param/ext_skp_mikitm043_joha_outer_43__divskn.txt 7674C6AF rom/skin_param/ext_skp_mikitm044_joha_outer_44__divskn.txt 3379CB65 rom/skin_param/ext_skp_mikitm045_joha_outer_45__divskn.txt E1DF73A0 rom/skin_param/ext_skp_mikitm046_joha_outer_46__divskn.txt E5F4A646 rom/skin_param/ext_skp_mikitm047_joha_outer_47__divskn.txt BC2EEC9D rom/skin_param/ext_skp_mikitm048_joha_outer_48__divskn.txt 7FC7D9C6 rom/skin_param/ext_skp_mikitm049_joha_outer_49__divskn.txt BAE140AE rom/skin_param/ext_skp_mikitm050_joha_outer_50__divskn.txt A366912B rom/skin_param/ext_skp_mikitm051_joha_outer_51__divskn.txt DE6B1241 rom/skin_param/ext_skp_mikitm053_joha_outer_53__divskn.txt F0021584 rom/skin_param/ext_skp_mikitm054_joha_outer_54__divskn.txt 74392B6C rom/skin_param/ext_skp_mikitm055_joha_outer_55__divskn.txt B71FC8C5 rom/skin_param/ext_skp_mikitm056_joha_outer_56__divskn.txt 52D68518 rom/skin_param/ext_skp_mikitm057_joha_outer_57__divskn.txt 9CC9CF6A rom/skin_param/ext_skp_mikitm058_joha_outer_58__divskn.txt 006E8F44 rom/skin_param/ext_skp_mikitm059_joha_outer_59__divskn.txt 7B33B910 rom/skin_param/ext_skp_mikitm060_joha_outer_60__divskn.txt EBDEA426 rom/skin_param/ext_skp_mikitm061_joha_outer_61__divskn.txt 05C447F3 rom/skin_param/ext_skp_mikitm063_joha_outer_63__divskn.txt 423ECA6B rom/skin_param/ext_skp_mikitm064_joha_outer_64__divskn.txt 47994D0C rom/skin_param/ext_skp_mikitm066_joha_outer_66__divskn.txt 7AEAE985 rom/skin_param/ext_skp_mikitm067_joha_outer_67__divskn.txt 3F360360 rom/skin_param/ext_skp_mikitm068_joha_outer_68__divskn.txt 9051C0B4 rom/skin_param/ext_skp_mikitm069_joha_outer_69__divskn.txt 9C4ADA52 rom/skin_param/ext_skp_mikitm070_joha_outer_70__divskn.txt 6B324288 rom/skin_param/ext_skp_mikitm071_joha_outer_71__divskn.txt 6ABE10D4 rom/skin_param/ext_skp_mikitm072_joha_outer_72__divskn.txt 71642F89 rom/skin_param/ext_skp_mikitm073_joha_outer_73__divskn.txt F912649B rom/skin_param/ext_skp_mikitm074_joha_outer_74__divskn.txt 3B076776 rom/skin_param/ext_skp_mikitm075_joha_outer_75__divskn.txt 7226B61C rom/skin_param/ext_skp_mikitm076_joha_outer_76__divskn.txt 31E4706D rom/skin_param/ext_skp_mikitm078_joha_outer_78__divskn.txt FA69172D rom/skin_param/ext_skp_mikitm079_joha_outer_79__divskn.txt 7B05F40F rom/skin_param/ext_skp_mikitm080_joha_outer_80__divskn.txt 6C4CCD10 rom/skin_param/ext_skp_mikitm081_joha_outer_81__divskn.txt DBE5F45D rom/skin_param/ext_skp_mikitm082_joha_outer_82__divskn.txt 034D07E0 rom/skin_param/ext_skp_mikitm083_joha_outer_83__divskn.txt 34BBF4EF rom/skin_param/ext_skp_mikitm084_joha_outer_84__divskn.txt 8205C4E5 rom/skin_param/ext_skp_mikitm085_joha_outer_85__divskn.txt B5B53C8B rom/skin_param/ext_skp_mikitm087_joha_outer_87__divskn.txt 56417917 rom/skin_param/ext_skp_mikitm088_joha_outer_88__divskn.txt FFA7C9D5 rom/skin_param/ext_skp_mikitm089_joha_outer_89__divskn.txt C0A95582 rom/skin_param/ext_skp_mikitm091_joha_outer_91__divskn.txt 58431A97 rom/skin_param/ext_skp_mikitm092_joha_outer_92__divskn.txt A28A7CA1 rom/skin_param/ext_skp_mikitm093_joha_outer_93__divskn.txt 5F4F85D3 rom/skin_param/ext_skp_mikitm094_joha_outer_94__divskn.txt 862218E1 rom/skin_param/ext_skp_mikitm095_joha_outer_95__divskn.txt 34302067 rom/skin_param/ext_skp_mikitm096_joha_outer_96__divskn.txt D126D43C rom/skin_param/ext_skp_mikitm097_joha_outer_97__divskn.txt 8D6A931D rom/skin_param/ext_skp_mikitm098_joha_outer_98__divskn.txt FC35D2E7 rom/skin_param/ext_skp_mikitm099_joha_outer_99__divskn.txt 5BAA1705 rom/skin_param/ext_skp_mikitm100_joha_outer_100__divskn.txt EB87BE6A rom/skin_param/ext_skp_mikitm101_joha_outer_101__divskn.txt A2C905E1 rom/skin_param/ext_skp_mikitm103_joha_outer_103__divskn.txt 2FCCA9D0 rom/skin_param/ext_skp_mikitm104_joha_outer_104__divskn.txt 17B75285 rom/skin_param/ext_skp_mikitm105_joha_outer_105__divskn.txt 5ED2C5E6 rom/skin_param/ext_skp_mikitm106_joha_outer_106__divskn.txt ECE1D208 rom/skin_param/ext_skp_mikitm107_joha_outer_107__divskn.txt 02B3DC05 rom/skin_param/ext_skp_mikitm108_joha_outer_108__divskn.txt B0FF8C59 rom/skin_param/ext_skp_mikitm109_joha_outer_109__divskn.txt A6D394EF rom/skin_param/ext_skp_mikitm110_joha_outer_110__divskn.txt 2FF360CE rom/skin_param/ext_skp_mikitm111_joha_outer_111__divskn.txt DE47A971 rom/skin_param/ext_skp_mikitm112_joha_outer_112__divskn.txt 9BD4A7B8 rom/skin_param/ext_skp_mikitm113_joha_outer_113__divskn.txt DE17C9C5 rom/skin_param/ext_skp_mikitm115_joha_outer_115__divskn.txt 54C9B5CA rom/skin_param/ext_skp_mikitm116_joha_outer_116__divskn.txt 3758B88F rom/skin_param/ext_skp_mikitm118_joha_outer_118__divskn.txt D9DCFE67 rom/skin_param/ext_skp_mikitm119_joha_outer_119__divskn.txt 6F9C059F rom/skin_param/ext_skp_mikitm120_joha_outer_120__divskn.txt DA66AED9 rom/skin_param/ext_skp_mikitm123_joha_outer_123__divskn.txt 858B6DD0 rom/skin_param/ext_skp_mikitm124_joha_outer_124__divskn.txt 31D91254 rom/skin_param/ext_skp_mikitm125_joha_outer_125__divskn.txt 0FA7BE78 rom/skin_param/ext_skp_mikitm126_joha_outer_126__divskn.txt 20585E87 rom/skin_param/ext_skp_mikitm127_joha_outer_127__divskn.txt 7EB12E71 rom/skin_param/ext_skp_mikitm128_joha_outer_128__divskn.txt BE624A63 rom/skin_param/ext_skp_mikitm130_joha_outer_130__divskn.txt F3341B0F rom/skin_param/ext_skp_mikitm131_joha_outer_131__divskn.txt AE77BAEC rom/skin_param/ext_skp_mikitm132_joha_outer_132__divskn.txt AEC0E7EC rom/skin_param/ext_skp_mikitm133_joha_outer_133__divskn.txt 5AC35C25 rom/skin_param/ext_skp_mikitm134_joha_outer_134__divskn.txt 618269E3 rom/skin_param/ext_skp_mikitm135_joha_outer_135__divskn.txt 681E9874 rom/skin_param/ext_skp_mikitm136_joha_outer_136__divskn.txt A3E7E5A5 rom/skin_param/ext_skp_mikitm137_joha_outer_137__divskn.txt 05C447F3 rom/skin_param/ext_skp_mikitm138_joha_outer_138__divskn.txt EE4F7DB8 rom/skin_param/ext_skp_mikitm139_joha_outer_139__divskn.txt 601B2221 rom/skin_param/ext_skp_mikitm140_joha_outer_140__divskn.txt B51D0AB1 rom/skin_param/ext_skp_mikitm142_joha_outer_142__divskn.txt 50DB8293 rom/skin_param/ext_skp_mikitm143_joha_outer_143__divskn.txt A410E502 rom/skin_param/ext_skp_mikitm144_joha_outer_144__divskn.txt DC798F7C rom/skin_param/ext_skp_mikitm145_joha_outer_145__divskn.txt 16593EC0 rom/skin_param/ext_skp_mikitm146_joha_outer_146__divskn.txt 13095E7E rom/skin_param/ext_skp_mikitm147_joha_outer_147__divskn.txt 8D19D53A rom/skin_param/ext_skp_mikitm148_joha_outer_148__divskn.txt 26B6438D rom/skin_param/ext_skp_mikitm149_joha_outer_149__divskn.txt E562ACB0 rom/skin_param/ext_skp_mikitm151_joha_outer_151__divskn.txt 013CF39B rom/skin_param/ext_skp_mikitm152_joha_outer_152__divskn.txt BF7D6BC4 rom/skin_param/ext_skp_mikitm153_joha_outer_153__divskn.txt 63B13007 rom/skin_param/ext_skp_mikitm009_joha_outer_09__divskn.txt 1A44438B rom/skin_param/ext_skp_mikitm021_joha_outer_21__divskn.txt 64A9306A rom/skin_param/ext_skp_mikitm040_joha_outer_40__divskn.txt 5822232A rom/skin_param/ext_skp_mikitm052_joha_outer_52__divskn.txt 69592F1D rom/skin_param/ext_skp_mikitm065_joha_outer_65__divskn.txt 973AAA32 rom/skin_param/ext_skp_mikitm077_joha_outer_77__divskn.txt A79D2AB9 rom/skin_param/ext_skp_mikitm090_joha_outer_90__divskn.txt 05C447F3 rom/skin_param/ext_skp_mikitm102_joha_outer_102__divskn.txt 4DD3584B rom/skin_param/ext_skp_mikitm114_joha_outer_114__divskn.txt 798BEBFE rom/skin_param/ext_skp_mikitm129_joha_outer_129__divskn.txt F23767D7 rom/skin_param/ext_skp_mikitm141_joha_outer_141__divskn.txt A94451A4 rom/skin_param/ext_skp_lenitm700_atam_zujo_00__divskn.txt F22FAB4C rom/skin_param/ext_skp_meiitm704_atam_zujo_04__divskn.txt 8FE7B9BB rom/skin_param/ext_skp_mikitm155_joha_outer_155__divskn.txt 379F8814 rom/skin_param/ext_skp_mikitm156_joha_outer_156__divskn.txt BD8C869A rom/skin_param/ext_skp_mikitm158_joha_outer_158__divskn.txt 25C4ECDD rom/skin_param/ext_skp_mikitm160_joha_outer_160__divskn.txt B3A112C0 rom/skin_param/ext_skp_mikitm162_joha_outer_162__divskn.txt E78B23CA rom/skin_param/ext_skp_mikitm163_joha_outer_163__divskn.txt 8FA33D89 rom/skin_param/ext_skp_mikitm164_joha_outer_164__divskn.txt 860582A0 rom/skin_param/ext_skp_mikitm165_joha_outer_165__divskn.txt 042C4E88 rom/skin_param/ext_skp_mikitm167_joha_outer_167__divskn.txt 2DD00E12 rom/skin_param/ext_skp_mikitm169_joha_outer_169__divskn.txt 37FBF027 rom/skin_param/ext_skp_mikitm170_joha_outer_170__divskn.txt FEDA77CC rom/skin_param/ext_skp_mikitm173_joha_outer_173__divskn.txt 8851741A rom/skin_param/ext_skp_mikitm467_ude_hand_167__divskn.txt 2532F654 rom/skin_param/ext_skp_mikitm500_atam_atama_00__divskn.txt 023A24E1 rom/skin_param/ext_skp_mikitm501_atam_atama_01__divskn.txt 46C1D123 rom/skin_param/ext_skp_mikitm502_atam_atama_02__divskn.txt 327BFA33 rom/skin_param/ext_skp_mikitm504_atam_atama_04__divskn.txt 85935CEC rom/skin_param/ext_skp_mikitm505_atam_atama_05__divskn.txt 33E89077 rom/skin_param/ext_skp_mikitm506_atam_atama_06__divskn.txt 2712B460 rom/skin_param/ext_skp_mikitm507_atam_atama_07__divskn.txt 6B7CB6FC rom/skin_param/ext_skp_mikitm508_atam_atama_08__divskn.txt 0A845D3C rom/skin_param/ext_skp_mikitm509_atam_atama_09__divskn.txt 94EABF1A rom/skin_param/ext_skp_mikitm520_atam_atama_20__divskn.txt E91A73D5 rom/skin_param/ext_skp_mikitm524_atam_atama_24__divskn.txt DBF3E169 rom/skin_param/ext_skp_mikitm525_atam_atama_25__divskn.txt 6CAFF96E rom/skin_param/ext_skp_mikitm526_atam_atama_26__divskn.txt 2BC13821 rom/skin_param/ext_skp_mikitm527_atam_atama_27__divskn.txt 8C626EA5 rom/skin_param/ext_skp_mikitm528_atam_atama_28__divskn.txt 9FBF330C rom/skin_param/ext_skp_mikitm530_atam_atama_30__divskn.txt 66FB7BCC rom/skin_param/ext_skp_mikitm531_atam_atama_31__divskn.txt DE2B21D9 rom/skin_param/ext_skp_mikitm532_atam_atama_32__divskn.txt 3990F531 rom/skin_param/ext_skp_mikitm533_atam_atama_33__divskn.txt E74DCC49 rom/skin_param/ext_skp_mikitm534_atam_atama_34__divskn.txt A9DB9978 rom/skin_param/ext_skp_mikitm535_atam_atama_35__divskn.txt 6FA3E009 rom/skin_param/ext_skp_mikitm537_atam_atama_37__divskn.txt A9DB9978 rom/skin_param/ext_skp_mikitm538_atam_atama_38__divskn.txt E188A7F4 rom/skin_param/ext_skp_mikitm539_atam_atama_39__divskn.txt 503D85EF rom/skin_param/ext_skp_mikitm540_atam_atama_40__divskn.txt A9DB9978 rom/skin_param/ext_skp_mikitm541_atam_atama_41__divskn.txt B22D4C52 rom/skin_param/ext_skp_mikitm542_atam_atama_42__divskn.txt C6BBED2B rom/skin_param/ext_skp_mikitm543_atam_atama_43__divskn.txt C597AD61 rom/skin_param/ext_skp_mikitm544_atam_atama_44__divskn.txt 3F1C9DE2 rom/skin_param/ext_skp_mikitm545_atam_atama_45__divskn.txt 87C11CD6 rom/skin_param/ext_skp_mikitm546_atam_atama_46__divskn.txt 7669FDF7 rom/skin_param/ext_skp_mikitm547_atam_atama_47__divskn.txt B5D1D099 rom/skin_param/ext_skp_mikitm549_atam_atama_49__divskn.txt 29AF20C6 rom/skin_param/ext_skp_mikitm550_atam_atama_50__divskn.txt 3990F531 rom/skin_param/ext_skp_mikitm551_atam_atama_51__divskn.txt 7D661C89 rom/skin_param/ext_skp_mikitm552_atam_atama_52__divskn.txt 0CE74CFF rom/skin_param/ext_skp_mikitm553_atam_atama_53__divskn.txt 610B3F4C rom/skin_param/ext_skp_mikitm554_atam_atama_54__divskn.txt 61D5D40A rom/skin_param/ext_skp_mikitm555_atam_atama_55__divskn.txt 89D67510 rom/skin_param/ext_skp_mikitm556_atam_atama_56__divskn.txt D34669A8 rom/skin_param/ext_skp_mikitm557_atam_atama_57__divskn.txt C81BD2A8 rom/skin_param/ext_skp_mikitm558_atam_atama_58__divskn.txt 770FBDCC rom/skin_param/ext_skp_mikitm559_atam_atama_59__divskn.txt B5D1D099 rom/skin_param/ext_skp_mikitm593_atam_atama_93__divskn.txt 78AB177C rom/skin_param/ext_skp_mikitm594_atam_atama_94__divskn.txt 408477EB rom/skin_param/ext_skp_mikitm595_atam_atama_95__divskn.txt C16CE759 rom/skin_param/ext_skp_mikitm596_atam_atama_96__divskn.txt 6B99AC48 rom/skin_param/ext_skp_mikitm597_atam_atama_97__divskn.txt 4520ABDC rom/skin_param/ext_skp_mikitm598_atam_atama_98__divskn.txt D9259F16 rom/skin_param/ext_skp_mikitm599_atam_atama_99__divskn.txt B9971A42 rom/skin_param/ext_skp_mikitm600_atam_atama_100__divskn.txt 9721AEBC rom/skin_param/ext_skp_mikitm601_atam_atama_101__divskn.txt 23FE17A8 rom/skin_param/ext_skp_mikitm602_atam_atama_102__divskn.txt A4C475E6 rom/skin_param/ext_skp_mikitm603_atam_atama_103__divskn.txt 2EA73AD2 rom/skin_param/ext_skp_mikitm605_atam_atama_105__divskn.txt F298B535 rom/skin_param/ext_skp_mikitm606_atam_atama_106__divskn.txt 089887AD rom/skin_param/ext_skp_mikitm607_atam_atama_107__divskn.txt 2E51EEDA rom/skin_param/ext_skp_mikitm608_atam_atama_108__divskn.txt A72F4FC5 rom/skin_param/ext_skp_mikitm609_atam_atama_109__divskn.txt 5E688A5C rom/skin_param/ext_skp_mikitm610_atam_atama_110__divskn.txt DEC35D28 rom/skin_param/ext_skp_mikitm611_atam_atama_111__divskn.txt A9DB9978 rom/skin_param/ext_skp_mikitm612_atam_atama_112__divskn.txt A9DB9978 rom/skin_param/ext_skp_mikitm613_atam_atama_113__divskn.txt FD657ECD rom/skin_param/ext_skp_mikitm614_atam_atama_114__divskn.txt 39A956EE rom/skin_param/ext_skp_mikitm615_atam_atama_115__divskn.txt 6300DDC7 rom/skin_param/ext_skp_mikitm618_atam_atama_118__divskn.txt 27B6372B rom/skin_param/ext_skp_mikitm619_atam_atama_119__divskn.txt 6005F61D rom/skin_param/ext_skp_mikitm620_atam_atama_120__divskn.txt 8D52A8DA rom/skin_param/ext_skp_mikitm621_atam_atama_121__divskn.txt CD90D0FA rom/skin_param/ext_skp_mikitm623_atam_atama_123__divskn.txt 6B8E9556 rom/skin_param/ext_skp_mikitm624_atam_atama_124__divskn.txt 5766FE02 rom/skin_param/ext_skp_mikitm625_atam_atama_125__divskn.txt 023A24E1 rom/skin_param/ext_skp_mikitm626_atam_atama_126__divskn.txt 24E06709 rom/skin_param/ext_skp_mikitm627_atam_atama_127__divskn.txt 97EBF71A rom/skin_param/ext_skp_mikitm628_atam_atama_128__divskn.txt 6697392C rom/skin_param/ext_skp_mikitm630_atam_atama_130__divskn.txt 72D320C0 rom/skin_param/ext_skp_mikitm632_atam_atama_132__divskn.txt EC2B7BCE rom/skin_param/ext_skp_mikitm633_atam_atama_133__divskn.txt 46AD0A2D rom/skin_param/ext_skp_mikitm634_atam_atama_134__divskn.txt E59B7CBF rom/skin_param/ext_skp_mikitm635_atam_atama_135__divskn.txt AB465E69 rom/skin_param/ext_skp_mikitm636_atam_atama_136__divskn.txt BA9636A5 rom/skin_param/ext_skp_mikitm637_atam_atama_137__divskn.txt AB3F040E rom/skin_param/ext_skp_mikitm638_atam_atama_138__divskn.txt A34AE7C4 rom/skin_param/ext_skp_mikitm639_atam_atama_139__divskn.txt 1212A262 rom/skin_param/ext_skp_mikitm640_atam_atama_140__divskn.txt 8155128F rom/skin_param/ext_skp_mikitm641_atam_atama_141__divskn.txt 52CA686C rom/skin_param/ext_skp_mikitm642_atam_atama_142__divskn.txt B4EBAE0C rom/skin_param/ext_skp_mikitm644_atam_atama_144__divskn.txt 38FFCB48 rom/skin_param/ext_skp_mikitm645_atam_atama_145__divskn.txt 78BAD7A8 rom/skin_param/ext_skp_mikitm646_atam_atama_146__divskn.txt 8A13D8D7 rom/skin_param/ext_skp_mikitm647_atam_atama_147__divskn.txt D3DCF94B rom/skin_param/ext_skp_mikitm648_atam_atama_148__divskn.txt 9B95854A rom/skin_param/ext_skp_mikitm649_atam_atama_149__divskn.txt 01A3ABC4 rom/skin_param/ext_skp_mikitm651_atam_atama_151__divskn.txt 1496B2FD rom/skin_param/ext_skp_mikitm652_atam_atama_152__divskn.txt 83853C94 rom/skin_param/ext_skp_mikitm653_atam_atama_153__divskn.txt F31EAEC9 rom/skin_param/ext_skp_mikitm655_atam_atama_155__divskn.txt F765C923 rom/skin_param/ext_skp_mikitm656_atam_atama_156__divskn.txt 59FB3DE7 rom/skin_param/ext_skp_mikitm660_atam_atama_160__divskn.txt 4D1D337F rom/skin_param/ext_skp_mikitm662_atam_atama_162__divskn.txt 24BCEA2F rom/skin_param/ext_skp_mikitm663_atam_atama_163__divskn.txt A244EDCA rom/skin_param/ext_skp_mikitm664_atam_atama_164__divskn.txt 455E0131 rom/skin_param/ext_skp_mikitm665_atam_atama_165__divskn.txt 7A706C5D rom/skin_param/ext_skp_mikitm667_atam_atama_167__divskn.txt 089887AD rom/skin_param/ext_skp_mikitm669_atam_atama_169__divskn.txt 0DA3E3BC rom/skin_param/ext_skp_mikitm670_atam_atama_170__divskn.txt 8E9C3C34 rom/skin_param/ext_skp_mikitm673_atam_atama_173__divskn.txt 39826281 rom/skin_param/ext_skp_mikitm700_atam_zujo_00__divskn.txt FFF4385B rom/skin_param/ext_skp_mikitm701_face_hitai_01__divskn.txt 5A7D4362 rom/skin_param/ext_skp_mikitm709_atam_zujo_09__divskn.txt 715B58C9 rom/skin_param/ext_skp_mikitm711_atam_zujo_11__divskn.txt 922179B4 rom/skin_param/ext_skp_mikitm715_atam_zujo_15__divskn.txt FD1C57DC rom/skin_param/ext_skp_mikitm718_atam_zujo_18__divskn.txt 6C33BE57 rom/skin_param/ext_skp_mikitm721_atam_zujo_21__divskn.txt 891330EA rom/skin_param/ext_skp_mikitm722_atam_zujo_22__divskn.txt CE988E0B rom/skin_param/ext_skp_mikitm745_atam_zujo_45__divskn.txt 06B46774 rom/skin_param/ext_skp_mikitm746_atam_zujo_46__divskn.txt E774C913 rom/skin_param/ext_skp_mikitm748_atam_zujo_48__divskn.txt A61065AA rom/skin_param/ext_skp_mikitm749_atam_zujo_49__divskn.txt 53BCFB17 rom/skin_param/ext_skp_mikitm751_joha_neck_51__divskn.txt C8834A12 rom/skin_param/ext_skp_mikitm438_ude_hand_138__divskn.txt 3FDAE812 rom/skin_param/ext_skp_mikitm522_atam_atama_22__divskn.txt 750B04C5 rom/skin_param/ext_skp_mikitm536_atam_atama_36__divskn.txt A9DB9978 rom/skin_param/ext_skp_mikitm548_atam_atama_48__divskn.txt DC921685 rom/skin_param/ext_skp_mikitm560_atam_atama_60__divskn.txt B76EF533 rom/skin_param/ext_skp_mikitm604_atam_atama_104__divskn.txt 75655482 rom/skin_param/ext_skp_mikitm616_atam_atama_116__divskn.txt 6E071CC2 rom/skin_param/ext_skp_mikitm631_atam_atama_131__divskn.txt BDD4DC2C rom/skin_param/ext_skp_mikitm643_atam_atama_143__divskn.txt 52307DF6 rom/skin_param/ext_skp_mikitm658_atam_atama_158__divskn.txt 9B5BEEDE rom/skin_param/ext_skp_mikitm702_atam_zujo_02__divskn.txt 187620AC rom/skin_param/ext_skp_mikitm752_joha_neck_52__divskn.txt 38DABA50 rom/skin_param/ext_skp_neritm003_joha_outer_03__divskn.txt 4F6944E2 rom/skin_param/ext_skp_rinitm010_joha_outer_10__divskn.txt 511EB230 rom/skin_param/ext_skp_rinitm023_joha_outer_23__divskn.txt 01118353 rom/skin_param/ext_skp_rinitm035_joha_outer_35__divskn.txt 0EA5111E rom/skin_param/ext_skp_rinitm500_atam_atama_00__divskn.txt B35E76FD rom/skin_param/ext_skp_rinitm512_atam_atama_12__divskn.txt F63C9AFE rom/skin_param/ext_skp_rinitm529_atam_atama_29__divskn.txt 01BFA23A rom/skin_param/ext_skp_rinitm541_atam_atama_41__divskn.txt C0205C6C rom/skin_param/ext_skp_rinitm706_atam_zujo_06__divskn.txt F7DB2AF2 rom/skin_param/ext_skp_rinitm719_atam_zujo_19__divskn.txt FEC26DAC rom/skin_param/ext_skp_mikitm775_joha_ushiro_75__divskn.txt 930463CA rom/skin_param/ext_skp_mikitm776_joha_ushiro_76__divskn.txt 930463CA rom/skin_param/ext_skp_mikitm777_joha_ushiro_77__divskn.txt 850DC7F1 rom/skin_param/ext_skp_mikitm780_joha_ushiro_80__divskn.txt E794BD23 rom/skin_param/ext_skp_mikitm781_joha_ushiro_81__divskn.txt 021D1808 rom/skin_param/ext_skp_mikitm782_joha_ushiro_82__divskn.txt 781FC504 rom/skin_param/ext_skp_mikitm783_joha_ushiro_83__divskn.txt 8488D5F9 rom/skin_param/ext_skp_mikitm784_joha_ushiro_84__divskn.txt FD7A5090 rom/skin_param/ext_skp_mikitm790_atam_zujo_90__divskn.txt EA293B0E rom/skin_param/ext_skp_neritm001_joha_outer_01__divskn.txt FCA51C45 rom/skin_param/ext_skp_neritm002_joha_outer_02__divskn.txt 84EB0D79 rom/skin_param/ext_skp_neritm004_joha_outer_04__divskn.txt 07111C81 rom/skin_param/ext_skp_neritm500_atam_atama_00__divskn.txt 9883A4BF rom/skin_param/ext_skp_neritm501_atam_atama_01__divskn.txt 8FB444DB rom/skin_param/ext_skp_rinitm001_joha_outer_01__divskn.txt A39FD710 rom/skin_param/ext_skp_rinitm002_joha_outer_02__divskn.txt F8E6E228 rom/skin_param/ext_skp_rinitm003_joha_outer_03__divskn.txt 0133F70C rom/skin_param/ext_skp_rinitm004_joha_outer_04__divskn.txt 0CABFE9F rom/skin_param/ext_skp_rinitm005_joha_outer_05__divskn.txt 6228AEB1 rom/skin_param/ext_skp_rinitm006_joha_outer_06__divskn.txt AFCBC71A rom/skin_param/ext_skp_rinitm007_joha_outer_07__divskn.txt 0B2FD66E rom/skin_param/ext_skp_rinitm009_joha_outer_09__divskn.txt FA69D76E rom/skin_param/ext_skp_rinitm011_joha_outer_11__divskn.txt 27D9EFAA rom/skin_param/ext_skp_rinitm012_joha_outer_12__divskn.txt 34B0C381 rom/skin_param/ext_skp_rinitm013_joha_outer_13__divskn.txt 3FD953BC rom/skin_param/ext_skp_rinitm014_joha_outer_14__divskn.txt 33212428 rom/skin_param/ext_skp_rinitm015_joha_outer_15__divskn.txt A17CB969 rom/skin_param/ext_skp_rinitm016_joha_outer_16__divskn.txt 031C9CD4 rom/skin_param/ext_skp_rinitm017_joha_outer_17__divskn.txt 29075ABC rom/skin_param/ext_skp_rinitm018_joha_outer_18__divskn.txt 36D46DC1 rom/skin_param/ext_skp_rinitm019_joha_outer_19__divskn.txt A1251601 rom/skin_param/ext_skp_rinitm020_joha_outer_20__divskn.txt 821104DD rom/skin_param/ext_skp_rinitm021_joha_outer_21__divskn.txt F520829F rom/skin_param/ext_skp_rinitm024_joha_outer_24__divskn.txt D37A60F8 rom/skin_param/ext_skp_rinitm025_joha_outer_25__divskn.txt 013D4D61 rom/skin_param/ext_skp_rinitm026_joha_outer_26_zzc__divskn.txt 7A40F3E8 rom/skin_param/ext_skp_rinitm027_joha_outer_27__divskn.txt 1A443A27 rom/skin_param/ext_skp_rinitm028_joha_outer_28__divskn.txt 5390B7FD rom/skin_param/ext_skp_rinitm029_joha_outer_29__divskn.txt 1C1EF3E9 rom/skin_param/ext_skp_rinitm030_joha_outer_30__divskn.txt 9DDE250B rom/skin_param/ext_skp_rinitm031_joha_outer_31__divskn.txt 1B85D852 rom/skin_param/ext_skp_rinitm032_joha_outer_32__divskn.txt E1A9DDF5 rom/skin_param/ext_skp_rinitm033_joha_outer_33__divskn.txt D74AC82B rom/skin_param/ext_skp_rinitm034_joha_outer_34__divskn.txt 8880981A rom/skin_param/ext_skp_rinitm036_joha_outer_36__divskn.txt DE5E3ACE rom/skin_param/ext_skp_rinitm037_joha_outer_37__divskn.txt 27CD999D rom/skin_param/ext_skp_rinitm038_joha_outer_38__divskn.txt 4A63B0B1 rom/skin_param/ext_skp_rinitm039_joha_outer_39__divskn.txt E919B6EA rom/skin_param/ext_skp_rinitm040_joha_outer_40__divskn.txt 25803125 rom/skin_param/ext_skp_rinitm041_joha_outer_41__divskn.txt D49BF6A9 rom/skin_param/ext_skp_rinitm043_joha_outer_43__divskn.txt 09F13CC8 rom/skin_param/ext_skp_rinitm044_joha_outer_44__divskn.txt 03329C70 rom/skin_param/ext_skp_rinitm045_joha_outer_45__divskn.txt 179D24CD rom/skin_param/ext_skp_rinitm047_joha_outer_47__divskn.txt C44496FD rom/skin_param/ext_skp_rinitm048_joha_outer_48__divskn.txt 152702C4 rom/skin_param/ext_skp_rinitm501_atam_atama_01__divskn.txt 25B0ABB9 rom/skin_param/ext_skp_rinitm502_atam_atama_02__divskn.txt 5F7BC57F rom/skin_param/ext_skp_rinitm503_atam_atama_03__divskn.txt DAFA77EF rom/skin_param/ext_skp_rinitm504_atam_atama_04__divskn.txt 219EAD84 rom/skin_param/ext_skp_rinitm505_atam_atama_05__divskn.txt A33A5A8D rom/skin_param/ext_skp_rinitm506_atam_atama_06__divskn.txt 31DD9D62 rom/skin_param/ext_skp_rinitm507_atam_atama_07__divskn.txt A33A5A8D rom/skin_param/ext_skp_rinitm508_atam_atama_08__divskn.txt 4EFD05CA rom/skin_param/ext_skp_rinitm509_atam_atama_09__divskn.txt 85AFBD4E rom/skin_param/ext_skp_rinitm510_atam_atama_10__divskn.txt 1E466AD7 rom/skin_param/ext_skp_rinitm511_atam_atama_11__divskn.txt 4EFD05CA rom/skin_param/ext_skp_rinitm513_atam_atama_13__divskn.txt 219EAD84 rom/skin_param/ext_skp_rinitm514_atam_atama_14__divskn.txt 6B54760D rom/skin_param/ext_skp_rinitm515_atam_atama_15__divskn.txt 45354EC4 rom/skin_param/ext_skp_rinitm516_atam_atama_16__divskn.txt 4DABA121 rom/skin_param/ext_skp_rinitm517_atam_atama_17__divskn.txt 7C61E7F7 rom/skin_param/ext_skp_rinitm518_atam_atama_18__divskn.txt E3EB0236 rom/skin_param/ext_skp_rinitm519_atam_atama_19__divskn.txt D6B09073 rom/skin_param/ext_skp_rinitm520_atam_atama_20__divskn.txt 5BDF15F8 rom/skin_param/ext_skp_rinitm526_atam_atama_26__divskn.txt 9E1D0233 rom/skin_param/ext_skp_rinitm527_atam_atama_27__divskn.txt 16153C35 rom/skin_param/ext_skp_rinitm528_atam_atama_28__divskn.txt 554C7EAC rom/skin_param/ext_skp_rinitm530_atam_atama_30__divskn.txt 6AB338C1 rom/skin_param/ext_skp_rinitm531_atam_atama_31__divskn.txt E2501EE0 rom/skin_param/ext_skp_rinitm532_atam_atama_32__divskn.txt 6E3160B4 rom/skin_param/ext_skp_rinitm533_atam_atama_33__divskn.txt B35E76FD rom/skin_param/ext_skp_rinitm534_atam_atama_34__divskn.txt 09E54640 rom/skin_param/ext_skp_rinitm535_atam_atama_35__divskn.txt 904A29FB rom/skin_param/ext_skp_rinitm536_atam_atama_36__divskn.txt D1A5C023 rom/skin_param/ext_skp_rinitm537_atam_atama_37__divskn.txt 051566B0 rom/skin_param/ext_skp_rinitm538_atam_atama_38__divskn.txt 66D793B1 rom/skin_param/ext_skp_rinitm539_atam_atama_39__divskn.txt 19BFD3E2 rom/skin_param/ext_skp_rinitm540_atam_atama_40__divskn.txt E31888E3 rom/skin_param/ext_skp_rinitm543_atam_atama_43__divskn.txt E14ACBC0 rom/skin_param/ext_skp_rinitm544_atam_atama_44__divskn.txt 308ADC0C rom/skin_param/ext_skp_rinitm545_atam_atama_45__divskn.txt 6E7EFCBE rom/skin_param/ext_skp_rinitm547_atam_atama_47__divskn.txt D3F558ED rom/skin_param/ext_skp_rinitm548_atam_atama_48__divskn.txt 48E6CB56 rom/skin_param/ext_skp_rinitm600_atama_cat_00__divskn.txt 8ED6582E rom/skin_param/ext_skp_rinitm701_atam_zujo_01__divskn.txt 272C9797 rom/skin_param/ext_skp_rinitm702_atam_zujo_02__divskn.txt 187620AC rom/skin_param/ext_skp_rinitm703_atam_zujo_03__divskn.txt 8C06D20F rom/skin_param/ext_skp_rinitm704_atam_zujo_04__divskn.txt 187620AC rom/skin_param/ext_skp_rinitm705_atam_zujo_05__divskn.txt 1E08F32F rom/skin_param/ext_skp_rinitm707_atam_zujo_07__divskn.txt 57BA5035 rom/skin_param/ext_skp_rinitm708_atam_zujo_08__divskn.txt 8768EBAB rom/skin_param/ext_skp_rinitm709_atam_zujo_09__divskn.txt 272C9797 rom/skin_param/ext_skp_rinitm710_atam_zujo_10__divskn.txt 0CBB9E5A rom/skin_param/ext_skp_rinitm711_atam_zujo_11__divskn.txt B07EF5CA rom/skin_param/ext_skp_rinitm712_atam_zujo_12__divskn.txt E27DEA48 rom/skin_param/ext_skp_rinitm714_atam_zujo_14__divskn.txt 49A799C8 rom/skin_param/ext_skp_rinitm715_atam_zujo_15__divskn.txt FB6C0405 rom/skin_param/ext_skp_rinitm716_atam_zujo_16__divskn.txt AA26FB95 rom/skin_param/ext_skp_rinitm717_atam_zujo_17__divskn.txt 9FCFE7F0 rom/skin_param/ext_skp_rinitm718_atam_zujo_18__divskn.txt AA451C84 rom/skin_param/ext_skp_rinitm720_atam_zujo_20__divskn.txt 66A42663 rom/skin_param/ext_skp_rinitm721_atam_zujo_21__divskn.txt 89E3A891 rom/skin_param/ext_skp_rinitm775_joha_ushiro_75__divskn.txt F51F42DD rom/skin_param/ext_skp_rinitm776_joha_ushiro_76__divskn.txt F5DAAD39 rom/skin_param/ext_skp_rinitm777_joha_ushiro_77__divskn.txt C1C339B2 rom/skin_param/ext_skp_rinitm997_atam_zujo_97__divskn.txt AA451C84 rom/skin_param/ext_skp_rinitm999_atam_zujo_99__divskn.txt 272C9797 rom/skin_param/ext_skp_sakitm001_joha_outer_01__divskn.txt 6759ECD8 rom/skin_param/ext_skp_sakitm002_joha_outer_02__divskn.txt A4876D4D rom/skin_param/ext_skp_sakitm003_joha_outer_03__divskn.txt F585A0CE rom/skin_param/ext_skp_sakitm005_joha_outer_05__divskn.txt BDA58F1A rom/skin_param/ext_skp_sakitm500_atam_atama_00__divskn.txt 32FC9CD9 rom/skin_param/ext_skp_sakitm501_atam_atama_01__divskn.txt 9A371BE2 rom/skin_param/ext_skp_sakitm600_atama_cat_01__divskn.txt 395B3F57 rom/skin_param/ext_skp_sakitm775_joha_ushiro_75__divskn.txt 2921F138 rom/skin_param/ext_skp_tetitm001_joha_outer_01__divskn.txt 5333E0E9 rom/skin_param/ext_skp_tetitm002_joha_outer_02__divskn.txt 27FD8FEF rom/skin_param/ext_skp_tetitm003_joha_outer_03__divskn.txt 23DF162B rom/skin_param/ext_skp_tetitm500_atam_atama_00__divskn.txt 9F60FE5A rom/skin_param/ext_skp_tetitm502_atam_atama_02__divskn.txt 9F60FE5A rom/skin_param/ext_skp_tetitm503_atam_atama_03__divskn.txt 68DA14FD rom/skin_param/osage_setting.txt 10D9C7FE rom/skin_param/sp_skp.farc D7C4A2C8 rom/skin_param/sp_skp_db.txt 09EBB9A1 rom/sound/button.farc D4314C72 rom/sound/pv600_effect.farc 7DC9A152 rom/sound/pv601_effect.farc 1C9517FC rom/sound/pv602_effect.farc 4B04891D rom/sound/pv603_effect.farc F2FBE7AE rom/sound/pv604_effect.farc D181548E rom/sound/pv605_effect.farc D3437F6E rom/sound/pv607_effect.farc 05BD6C43 rom/sound/pv608_effect.farc 52D0A0BA rom/sound/pv609_effect.farc B0F0ED60 rom/sound/pv610_effect.farc 858EA4EA rom/sound/pv611_effect.farc 305989D8 rom/sound/pv612_effect.farc D11D6928 rom/sound/pv613_effect.farc F0627441 rom/sound/pv614_effect.farc 06FF8DCE rom/sound/pv615_effect.farc 96373245 rom/sound/pv617_effect.farc 027BB6CD rom/sound/pv618_effect.farc D22AC7A5 rom/sound/pv619_effect.farc 72BF56A4 rom/sound/pv620_effect.farc B00F8146 rom/sound/pv621_effect.farc 8BD1AFF2 rom/sound/pv622_effect.farc 3CA9B0D6 rom/sound/pv623_effect.farc A1C4D442 rom/sound/pv624_effect.farc 8F71E931 rom/sound/pv625_effect.farc B57EA346 rom/sound/pv626_effect.farc 1E923F71 rom/sound/pv627_effect.farc EB6EF226 rom/sound/pv628_effect.farc B8FF3EDF rom/sound/pv629_effect.farc 117FAF2F rom/sound/pv630_effect.farc 066EDD45 rom/sound/pv631_effect.farc 36AE3F6D rom/sound/pv637_effect.farc FB23B20C rom/sound/pv639_effect.farc C9734FB1 rom/sound/pv640_effect.farc F4DCF27B rom/sound/pv641_effect.farc 1287C462 rom/sound/pv642_effect.farc CFF26B0A rom/sound/pv710_effect.farc AEBDF761 rom/sound/pv722_effect.farc 1C351A95 rom/sound/pv723_effect.farc 1A6CB53D rom/sound/pv724_effect.farc A6470E93 rom/sound/pv725_effect.farc 22CCC68C rom/sound/pv726_effect.farc 8B9968B6 rom/sound/pv727_effect.farc 852DCF77 rom/sound/pv728_effect.farc 5A81B18D rom/sound/pv729_effect.farc F8E34938 rom/sound/pv730_effect.farc 62DD79D0 rom/sound/pv731_effect.farc 995B327C rom/sound/pv732_effect.farc 0EF1320D rom/sound/pv733_effect.farc CE7B424A rom/sound/pv736_effect.farc 82054E35 rom/sound/pv737_effect.farc 596D1BC5 rom/sound/pv738_effect.farc 85BD1F12 rom/sound/pv739_effect.farc 9FA1BBBD rom/sound/pv740_effect.farc 2A5F82E9 rom/sound/pvchange.farc 0BCD83AB rom/sound/result_len.farc D3786616 rom/sound/result_miku.farc 926B306C rom/sound/result_rin.farc 6078F06B rom/sound/se.farc 62216ECE rom/sound/se_adv.farc 0590DA6E rom/sound/se_aime.farc E8F2F34B rom/sound/se_cmn.farc 1B61F363 rom/sound/se_over.farc 02095243 rom/sound/se_result.farc D919C8BD rom/sound/se_sel.farc 7F243885 rom/sound/slide_bell.farc 8151DDCF rom/sound/slide_bell2.farc C54D1E9C rom/sound/slide_harp.farc 5DC013C1 rom/sound/slide_laser.farc E5CE6B76 rom/sound/slide_long.farc 574FFD70 rom/sound/slide_piano.farc 74D32839 rom/sound/slide_se.farc C7AAAE53 rom/sound/slide_windchime.farc 4840E25B rom/sound/pv616_effect.farc 758809CE rom/sound/pv638_effect.farc 827FB0AD rom/sound/pv734_effect.farc 5C17A58C rom/stage_param/coli_no_ring.txt C7369958 rom/stage_param/coli_pv083_stgns098.txt 4322EE7D rom/stage_param/coli_pv434_mhd3070.txt 90B45C59 rom/stage_param/coli_pv434_mhd6677.txt 87509EC5 rom/stage_param/coli_pv614_mhd0000.txt A9A0D16B rom/stage_param/coli_pv614_mhd7334.txt AC40F66C rom/stage_param/coli_pv620_p1_00000.txt 6C44C7D4 rom/stage_param/coli_pv620_p1_03848.txt DCFC3EA8 rom/stage_param/coli_pv620_p1_06720.txt A32AEBA4 rom/stage_param/coli_pv620_p1_07038.txt A32AEBA4 rom/stage_param/coli_pv620_p1_11992.txt 3E01760A rom/stage_param/coli_pv620_p2_00000.txt 4E48EDD7 rom/stage_param/coli_pv620_p2_01568.txt B4BD325B rom/stage_param/coli_pv620_p2_07518.txt 0FFCB3A4 rom/stage_param/coli_pv620_p2_11992.txt 1767399C rom/stage_param/coli_stgd2pv037s01_snow.txt 5E74069B rom/stage_param/coli_stgd2pv038s01.txt E53CB8F8 rom/stage_param/coli_stgd2pv044s03.txt 3DA04D3D rom/stage_param/coli_stgd2pv046s04.txt 1B095B78 rom/stage_param/coli_stgd2pv047s03.txt B04A3BB7 rom/stage_param/coli_stgd2pv047s04.txt 77E764E9 rom/stage_param/coli_stgd2pv051s05.txt 144F4F2F rom/stage_param/coli_stgd2pv058s01.txt 7EBE038A rom/stage_param/coli_stgd2pv065s01.txt 76B0F15C rom/stage_param/coli_stgpv081s01.txt B8DC74C1 rom/stage_param/coli_stgpv081s06.txt 3E9CE864 rom/stage_param/coli_stgpv082s62.txt 3A7797D6 rom/stage_param/coli_stgpv082s63.txt A61E7622 rom/stage_param/coli_stgpv083s05.txt 04E38931 rom/stage_param/coli_stgpv083s18.txt B325EE5C rom/stage_param/coli_stgpv091s09.txt EFECA48C rom/stage_param/coli_stgpv091s15.txt 61BE60C3 rom/stage_param/coli_stgpv104s02.txt 059FD8E9 rom/stage_param/coli_stgpv219s09.txt 8271223D rom/stage_param/coli_stgpv219s10.txt C7369958 rom/stage_param/coli_stgpv221s07.txt CBEB5BE3 rom/stage_param/coli_stgpv221s11.txt E4262A5F rom/stage_param/coli_stgpv222s02.txt 6CA5D865 rom/stage_param/coli_stgpv226s01.txt 2F2E0E8F rom/stage_param/coli_stgpv233s02.txt EF408E5A rom/stage_param/coli_stgpv235s04.txt 46FE95EE rom/stage_param/coli_stgpv236s07.txt 758FC167 rom/stage_param/coli_stgpv240s01.txt C219CCDC rom/stage_param/coli_stgpv241s01.txt BBE33D94 rom/stage_param/coli_stgpv241_mhd481.txt 6974CDD3 rom/stage_param/coli_stgpv601s04.txt 5021E013 rom/stage_param/coli_stgpv602s01.txt 13374B55 rom/stage_param/coli_stgpv602s03.txt 564E121B rom/stage_param/coli_stgpv605s01.txt 40FADD6E rom/stage_param/coli_stgpv622s01.txt AA29C76D rom/stage_param/coli_stgpv625s01.txt 5937333A rom/stage_param/coli_stgpv625s04.txt F5257559 rom/stage_param/coli_stgpv740s01.txt BB3388D2 rom/stage_param/fog_ring_d2ns058.txt EF17102D rom/stage_param/fog_ring_d2ns082.txt 6825C7BF rom/stage_param/fog_ring_d2pv050s01.txt EF17102D rom/stage_param/fog_ring_ns004.txt 6FCC594C rom/stage_param/fog_ring_ns021.txt 8273ADF5 rom/stage_param/fog_ring_ns022.txt 83FAD4A3 rom/stage_param/fog_ring_ns023.txt 35AD01AE rom/stage_param/coli_pv625_mhd3860.txt F8E390B1 rom/stage_param/coli_stgpv083s18_clone1.txt 0E232977 rom/stage_param/coli_stgpv600s04.txt C0A381EA rom/stage_param/fog_ring_ns032.txt 72805160 rom/stage_param/leaf_ns094.txt 1920B7AC rom/stage_param/rain_pv233s02.txt 9E194743 rom/stage_param/ripple_pv233s03.txt 6047BCF8 rom/stage_param/snow_pv007s10.txt 41E435F7 rom/stage_param/splash_d2ns064.txt 912A1E6A rom/stage_param/fog_ring_ns084.txt 1F144BC2 rom/stage_param/fog_ring_ns084_snow.txt 1F144BC2 rom/stage_param/fog_ring_ns086.txt C448FE31 rom/stage_param/fog_ring_ns249.txt B9162C2B rom/stage_param/fog_ring_pv001s01.txt 8273ADF5 rom/stage_param/fog_ring_pv001s02.txt 8273ADF5 rom/stage_param/fog_ring_pv001s03.txt 8273ADF5 rom/stage_param/fog_ring_pv001s04.txt 8273ADF5 rom/stage_param/fog_ring_pv001s05.txt 8273ADF5 rom/stage_param/fog_ring_pv001s06.txt 8273ADF5 rom/stage_param/fog_ring_pv001s07.txt 8273ADF5 rom/stage_param/fog_ring_pv008s01.txt B4665FDD rom/stage_param/fog_ring_pv008s07.txt B4665FDD rom/stage_param/fog_ring_pv223s02.txt EF9B3C68 rom/stage_param/fog_ring_pv223s03.txt EF9B3C68 rom/stage_param/fog_ring_pv241s01.txt 0EAF9745 rom/stage_param/leaf_pv081s03.txt 5670C40F rom/stage_param/leaf_pv087s02.txt 663FE483 rom/stage_param/leaf_pv087s17.txt 663FE483 rom/stage_param/leaf_pv221s01.txt 43C20938 rom/stage_param/leaf_pv441s01_clone1.txt 23ECC832 rom/stage_param/leaf_tst.txt 205F942A rom/stage_param/litproj_d2pv208s01.txt BAA46088 rom/stage_param/litproj_pv255s01.txt 835F0189 rom/stage_param/litproj_pv257s01.txt ADA9290F rom/stage_param/litproj_pv627s02.txt 32256156 rom/stage_param/rain_ns005_clone1.txt 0A25FE49 rom/stage_param/rain_pv011s01.txt 3BCB3105 rom/stage_param/rain_pv011s06.txt 3BCB3105 rom/stage_param/rain_pv083s08.txt 6218F42E rom/stage_param/rain_pv083s24.txt 484DD473 rom/stage_param/rain_pv089s03_clone1.txt 05C9D401 rom/stage_param/rain_pv233s03.txt A7B7D5AD rom/stage_param/rain_pv233s06.txt F4BB4EB5 rom/stage_param/rain_pv233s07.txt A7B7D5AD rom/stage_param/rain_pv432s01.txt EB6E2F7E rom/stage_param/rain_pv432s02_clone1.txt B449C12D rom/stage_param/rain_pv609s01_rain.txt 782DDB5D rom/stage_param/rain_pv619s02_rain.txt E0DE6F83 rom/stage_param/rain_pv625s01_clone.txt 54D7936D rom/stage_param/ripple_d2ns064.txt 1FC980C5 rom/stage_param/ripple_ns123.txt 7F5988D6 rom/stage_param/ripple_pv083s24.txt F15ECED8 rom/stage_param/ripple_pv089s03_clone1.txt F15ECED8 rom/stage_param/ripple_pv219s02.txt 98785ADB rom/stage_param/ripple_pv219s05.txt 2C932C06 rom/stage_param/ripple_pv220s03.txt 1FC980C5 rom/stage_param/ripple_pv233s01.txt 42E2E78D rom/stage_param/ripple_pv233s06.txt 6047BCF8 rom/stage_param/ripple_pv233s07.txt 6047BCF8 rom/stage_param/ripple_pv236s02.txt 78D2F9B0 rom/stage_param/ripple_pv432s01.txt 3A0E8724 rom/stage_param/ripple_pv432s02_clone1.txt 985108AC rom/stage_param/snow_d2pv037s01_snow.txt B5C347A2 rom/stage_param/snow_d2pv051s03.txt D98E0C3B rom/stage_param/snow_ns005_snow.txt 2FB25F4B rom/stage_param/snow_ns014_snow.txt BCC4FA75 rom/stage_param/snow_ns015_snow.txt 752B73C8 rom/stage_param/snow_ns033.txt 62BE1941 rom/stage_param/snow_ns084_snow.txt 6C9EFC8C rom/stage_param/snow_pv007s01.txt 7D6215B2 rom/stage_param/snow_pv007s06.txt 637B51F3 rom/stage_param/snow_pv007s07_snow.txt B746DB63 rom/stage_param/snow_pv007s09.txt 43F6C549 rom/stage_param/snow_pv007s11_snow.txt D0458C46 rom/stage_param/snow_pv020s01.txt F3490395 rom/stage_param/snow_pv020s02.txt 9D77296D rom/stage_param/snow_pv020s03.txt 2F20AAEA rom/stage_param/snow_pv086s02.txt A28D550F rom/stage_param/snow_pv218s01.txt FF3CA6D9 rom/stage_param/snow_pv218s02.txt FF3CA6D9 rom/stage_param/snow_pv224s01.txt A6F89750 rom/stage_param/snow_pv224s02.txt 74A98783 rom/stage_param/snow_pv224s03.txt 77562BA4 rom/stage_param/snow_pv244s01.txt 978071BD rom/stage_param/snow_pv247s02.txt A40FCD70 rom/stage_param/snow_pv609s01_snow.txt D13AACC9 rom/stage_param/snow_pv622s01_snow.txt 51378EC3 rom/stage_param/snow_pv737s01.txt 995D9895 rom/stage_param/snow_pv737s02.txt 5508691F rom/stage_param/splash_ns123.txt F6595122 rom/stage_param/splash_pv220s03.txt 912A1E6A rom/stage_param/splash_pv233s01.txt DE422615 rom/stage_param/splash_pv233s03.txt DE422615 rom/stage_param/splash_pv233s06.txt DE422615 rom/stage_param/splash_pv233s07.txt DE422615 rom/stage_param/splash_pv236s02.txt F582BB0C rom/stage_param/star_ns266.txt 54809301 rom/stage_param/star_pv242s01.txt FC265C7B rom/stage_param/star_pv253s01.txt F2991F16 rom/stage_param/star_pv253s02.txt F2991F16 rom/stage_param/star_pv253s03.txt F2991F16 rom/stage_param/star_pv253s04.txt F2991F16 rom/stage_param/star_pv253s05.txt F2991F16 rom/stage_param/star_pv253s06.txt F2991F16 rom/stage_param/star_pv253s07.txt F2991F16 rom/stage_param/star_pv253s08.txt F2991F16 rom/stage_param/star_pv253s09.txt F2991F16 rom/stage_param/star_pv621s01.txt D3FC4B18 rom/stage_param/star_pv622s01.txt 37A8C1E3 rom/stage_param/star_pv622s01_snow.txt 37A8C1E3 rom/stage_param/star_pv626s01.txt 21321B56 rom/stage_param/star_pv638s01.txt 0D315CCB rom/stage_param/star_pv642s04.txt 818BEC6E rom/photo_print/card/CLT_CRD0271_01.jpg A4F27F93 rom/photo_print/card/CLT_CRD0000_01.jpg 5330040B rom/photo_print/card/CLT_CRD0001_01.jpg 648A4E18 rom/photo_print/card/CLT_CRD0002_01.jpg 6EEE7995 rom/photo_print/card/CLT_CRD0003_01.jpg BF939B8C rom/photo_print/card/CLT_CRD0004_01.jpg AEC407E2 rom/photo_print/card/CLT_CRD0005_01.jpg 6FC75B6C rom/photo_print/card/CLT_CRD0006_01.jpg 6531F36B rom/photo_print/card/CLT_CRD0007_01.jpg 90ED6E1A rom/photo_print/card/CLT_CRD0008_01.jpg 7293B5E6 rom/photo_print/card/CLT_CRD0009_01.jpg 7E010E4C rom/photo_print/card/CLT_CRD0010_01.jpg 232FE088 rom/photo_print/card/CLT_CRD0011_01.jpg A7B39322 rom/photo_print/card/CLT_CRD0012_01.jpg 9E998994 rom/photo_print/card/CLT_CRD0013_01.jpg E68318B2 rom/photo_print/card/CLT_CRD0014_01.jpg 98E7209B rom/photo_print/card/CLT_CRD0015_01.jpg 7ADF4A67 rom/photo_print/card/CLT_CRD0017_01.jpg 08001113 rom/photo_print/card/CLT_CRD0018_01.jpg AF749343 rom/photo_print/card/CLT_CRD0019_01.jpg A5D0A7FE rom/photo_print/card/CLT_CRD0020_01.jpg 26E511EF rom/photo_print/card/CLT_CRD0021_01.jpg E7990363 rom/photo_print/card/CLT_CRD0022_01.jpg E77FCAD1 rom/photo_print/card/CLT_CRD0023_01.jpg 3B7824F8 rom/photo_print/card/CLT_CRD0024_01.jpg FBFD7966 rom/photo_print/card/CLT_CRD0025_01.jpg 96E01D9D rom/photo_print/card/CLT_CRD0026_01.jpg E5D0E6B7 rom/photo_print/card/CLT_CRD0027_01.jpg A11AAFB2 rom/photo_print/card/CLT_CRD0028_01.jpg 8D069CCF rom/photo_print/card/CLT_CRD0029_01.jpg 5FDE5DFF rom/photo_print/card/CLT_CRD0030_01.jpg 464F90DA rom/photo_print/card/CLT_CRD0031_01.jpg BBE4E772 rom/photo_print/card/CLT_CRD0032_01.jpg 13440440 rom/photo_print/card/CLT_CRD0034_01.jpg 81527166 rom/photo_print/card/CLT_CRD0035_01.jpg B9DB0B04 rom/photo_print/card/CLT_CRD0036_01.jpg FCAF1E36 rom/photo_print/card/CLT_CRD0037_01.jpg 61B56997 rom/photo_print/card/CLT_CRD0038_01.jpg 3108962A rom/photo_print/card/CLT_CRD0039_01.jpg 00DDE11D rom/photo_print/card/CLT_CRD0040_01.jpg A5F1E308 rom/photo_print/card/CLT_CRD0041_01.jpg 0F9112DD rom/photo_print/card/CLT_CRD0042_01.jpg CE5E52E6 rom/photo_print/card/CLT_CRD0043_01.jpg 1D452D52 rom/photo_print/card/CLT_CRD0044_01.jpg FF438207 rom/photo_print/card/CLT_CRD0045_01.jpg 7CDA52FE rom/photo_print/card/CLT_CRD0046_01.jpg E2C72135 rom/photo_print/card/CLT_CRD0047_01.jpg A8B0F4C2 rom/photo_print/card/CLT_CRD0048_01.jpg E0EF5C6C rom/photo_print/card/CLT_CRD0049_01.jpg 30CE3997 rom/photo_print/card/CLT_CRD0051_01.jpg D66D8F20 rom/photo_print/card/CLT_CRD0052_01.jpg 2B809C7B rom/photo_print/card/CLT_CRD0053_01.jpg 6B65BBD2 rom/photo_print/card/CLT_CRD0054_01.jpg 871EC938 rom/photo_print/card/CLT_CRD0055_01.jpg 4C0EC1CF rom/photo_print/card/CLT_CRD0056_01.jpg 793A2FF5 rom/photo_print/card/CLT_CRD0057_01.jpg 03ACE248 rom/photo_print/card/CLT_CRD0058_01.jpg E5BB956B rom/photo_print/card/CLT_CRD0059_01.jpg 9B76C2C1 rom/photo_print/card/CLT_CRD0060_01.jpg D668B881 rom/photo_print/card/CLT_CRD0061_01.jpg 9DEC1796 rom/photo_print/card/CLT_CRD0062_01.jpg 982175C3 rom/photo_print/card/CLT_CRD0063_01.jpg 17A924E9 rom/photo_print/card/CLT_CRD0064_01.jpg 4593DD54 rom/photo_print/card/CLT_CRD0065_01.jpg 6F9617D3 rom/photo_print/card/CLT_CRD0066_01.jpg C9F4C520 rom/photo_print/card/CLT_CRD0016_01.jpg 137F2601 rom/photo_print/card/CLT_CRD0033_01.jpg 829F410C rom/photo_print/card/CLT_CRD0050_01.jpg 90696D53 rom/photo_print/card/CLT_CRD0067_01.jpg F1DD7F0E rom/photo_print/card/CLT_CRD0084_01.jpg 9F18D156 rom/photo_print/card/CLT_CRD0101_01.jpg 0420DD0A rom/photo_print/card/CLT_CRD0118_01.jpg 73D79A2C rom/photo_print/card/CLT_CRD0135_01.jpg B9320480 rom/photo_print/card/CLT_CRD0152_01.jpg 7BCA8351 rom/photo_print/card/CLT_CRD0169_01.jpg DEFE8CE7 rom/photo_print/card/CLT_CRD0186_01.jpg DB0D365A rom/photo_print/card/CLT_CRD0203_01.jpg C9B24F55 rom/photo_print/card/CLT_CRD0220_01.jpg F2233C6B rom/photo_print/card/CLT_CRD0237_01.jpg 985B1C20 rom/photo_print/card/CLT_CRD0254_01.jpg A94E071C rom/photo_print/card/CLT_CRD0068_01.jpg F80E831E rom/photo_print/card/CLT_CRD0069_01.jpg 48D64F4D rom/photo_print/card/CLT_CRD0070_01.jpg 9E4884F8 rom/photo_print/card/CLT_CRD0071_01.jpg 59CFE49A rom/photo_print/card/CLT_CRD0072_01.jpg F6E095C7 rom/photo_print/card/CLT_CRD0073_01.jpg E757086C rom/photo_print/card/CLT_CRD0074_01.jpg 7DE01F54 rom/photo_print/card/CLT_CRD0075_01.jpg A8C4D4E7 rom/photo_print/card/CLT_CRD0076_01.jpg 270FEA8F rom/photo_print/card/CLT_CRD0077_01.jpg 1F135785 rom/photo_print/card/CLT_CRD0078_01.jpg 35470773 rom/photo_print/card/CLT_CRD0079_01.jpg 6B13DC3A rom/photo_print/card/CLT_CRD0080_01.jpg 2EC70D94 rom/photo_print/card/CLT_CRD0081_01.jpg 1B432A12 rom/photo_print/card/CLT_CRD0082_01.jpg 677F26E8 rom/photo_print/card/CLT_CRD0083_01.jpg E93C4C56 rom/photo_print/card/CLT_CRD0085_01.jpg 7A10CEC5 rom/photo_print/card/CLT_CRD0086_01.jpg 4625F421 rom/photo_print/card/CLT_CRD0087_01.jpg EF52748F rom/photo_print/card/CLT_CRD0088_01.jpg FB974487 rom/photo_print/card/CLT_CRD0089_01.jpg 47B28626 rom/photo_print/card/CLT_CRD0090_01.jpg D70704FD rom/photo_print/card/CLT_CRD0091_01.jpg BA8D4BC2 rom/photo_print/card/CLT_CRD0092_01.jpg 1021B700 rom/photo_print/card/CLT_CRD0093_01.jpg 65D1C147 rom/photo_print/card/CLT_CRD0094_01.jpg 05F609EE rom/photo_print/card/CLT_CRD0095_01.jpg 913B6DD4 rom/photo_print/card/CLT_CRD0096_01.jpg 88F2C517 rom/photo_print/card/CLT_CRD0097_01.jpg 934E6F44 rom/photo_print/card/CLT_CRD0098_01.jpg 835822AD rom/photo_print/card/CLT_CRD0099_01.jpg 346B4498 rom/photo_print/card/CLT_CRD0100_01.jpg 2D4A0C47 rom/photo_print/card/CLT_CRD0102_01.jpg 99EF6A4D rom/photo_print/card/CLT_CRD0103_01.jpg 6199EF1A rom/photo_print/card/CLT_CRD0104_01.jpg CDCD4AA7 rom/photo_print/card/CLT_CRD0105_01.jpg 536DA05C rom/photo_print/card/CLT_CRD0106_01.jpg DF4646BF rom/photo_print/card/CLT_CRD0107_01.jpg F08D5EF3 rom/photo_print/card/CLT_CRD0108_01.jpg 6BFC687F rom/photo_print/card/CLT_CRD0109_01.jpg 492338D3 rom/photo_print/card/CLT_CRD0110_01.jpg 372131CE rom/photo_print/card/CLT_CRD0111_01.jpg 4B7F3535 rom/photo_print/card/CLT_CRD0112_01.jpg FD165620 rom/photo_print/card/CLT_CRD0113_01.jpg 19F4E10E rom/photo_print/card/CLT_CRD0114_01.jpg A50DE06D rom/photo_print/card/CLT_CRD0115_01.jpg DC2E8896 rom/photo_print/card/CLT_CRD0116_01.jpg 543B3FEC rom/photo_print/card/CLT_CRD0117_01.jpg 196CA994 rom/photo_print/card/CLT_CRD0119_01.jpg 13EB570C rom/photo_print/card/CLT_CRD0120_01.jpg 5136E6F7 rom/photo_print/card/CLT_CRD0121_01.jpg 10CB188D rom/photo_print/card/CLT_CRD0122_01.jpg D83C6970 rom/photo_print/card/CLT_CRD0123_01.jpg F65B6903 rom/photo_print/card/CLT_CRD0124_01.jpg E10A4D92 rom/photo_print/card/CLT_CRD0125_01.jpg 5D2F855B rom/photo_print/card/CLT_CRD0126_01.jpg C719D6CE rom/photo_print/card/CLT_CRD0127_01.jpg 5C24341E rom/photo_print/card/CLT_CRD0128_01.jpg 0DD315DD rom/photo_print/card/CLT_CRD0129_01.jpg 7E100B0B rom/photo_print/card/CLT_CRD0130_01.jpg AECD0619 rom/photo_print/card/CLT_CRD0131_01.jpg 56319EC9 rom/photo_print/card/CLT_CRD0132_01.jpg 087A50BA rom/photo_print/card/CLT_CRD0133_01.jpg 05252024 rom/photo_print/card/CLT_CRD0134_01.jpg F07CBBE0 rom/photo_print/card/CLT_CRD0136_01.jpg FEE9824B rom/photo_print/card/CLT_CRD0137_01.jpg BA94E490 rom/photo_print/card/CLT_CRD0138_01.jpg 76E95DC8 rom/photo_print/card/CLT_CRD0139_01.jpg ED5B139F rom/photo_print/card/CLT_CRD0140_01.jpg 20CE1B20 rom/photo_print/card/CLT_CRD0141_01.jpg 0DA3EC0E rom/photo_print/card/CLT_CRD0142_01.jpg F34BBF24 rom/photo_print/card/CLT_CRD0143_01.jpg B5B92966 rom/photo_print/card/CLT_CRD0144_01.jpg 6B2BC6EB rom/photo_print/card/CLT_CRD0145_01.jpg 8FA117DF rom/photo_print/card/CLT_CRD0146_01.jpg B5F1B0C4 rom/photo_print/card/CLT_CRD0147_01.jpg 84152926 rom/photo_print/card/CLT_CRD0148_01.jpg A6F03019 rom/photo_print/card/CLT_CRD0149_01.jpg 2F40C186 rom/photo_print/card/CLT_CRD0150_01.jpg 0755BE8C rom/photo_print/card/CLT_CRD0151_01.jpg 7BC71110 rom/photo_print/card/CLT_CRD0153_01.jpg 05432790 rom/photo_print/card/CLT_CRD0154_01.jpg D725D4D3 rom/photo_print/card/CLT_CRD0155_01.jpg 53741E1C rom/photo_print/card/CLT_CRD0156_01.jpg C8FE7149 rom/photo_print/card/CLT_CRD0157_01.jpg 76CA0E00 rom/photo_print/card/CLT_CRD0158_01.jpg 1C376326 rom/photo_print/card/CLT_CRD0159_01.jpg 741EAA11 rom/photo_print/card/CLT_CRD0160_01.jpg E2864066 rom/photo_print/card/CLT_CRD0161_01.jpg C40FA2C2 rom/photo_print/card/CLT_CRD0162_01.jpg C481B147 rom/photo_print/card/CLT_CRD0163_01.jpg A073EB11 rom/photo_print/card/CLT_CRD0164_01.jpg FA9BEBE5 rom/photo_print/card/CLT_CRD0165_01.jpg 579401A3 rom/photo_print/card/CLT_CRD0166_01.jpg EF24881D rom/photo_print/card/CLT_CRD0167_01.jpg 263E34C0 rom/photo_print/card/CLT_CRD0168_01.jpg 0DF19897 rom/photo_print/card/CLT_CRD0170_01.jpg D5D04242 rom/photo_print/card/CLT_CRD0171_01.jpg FFC2568C rom/photo_print/card/CLT_CRD0172_01.jpg 5BAC9D12 rom/photo_print/card/CLT_CRD0173_01.jpg FE81C735 rom/photo_print/card/CLT_CRD0174_01.jpg 078B3884 rom/photo_print/card/CLT_CRD0175_01.jpg B78D4E67 rom/photo_print/card/CLT_CRD0176_01.jpg 74B61B9F rom/photo_print/card/CLT_CRD0177_01.jpg 9262A330 rom/photo_print/card/CLT_CRD0178_01.jpg 2134B75E rom/photo_print/card/CLT_CRD0179_01.jpg 967B58E4 rom/photo_print/card/CLT_CRD0180_01.jpg BD0FACC9 rom/photo_print/card/CLT_CRD0181_01.jpg 5F1BE524 rom/photo_print/card/CLT_CRD0182_01.jpg E693F4D4 rom/photo_print/card/CLT_CRD0183_01.jpg EDB5D21B rom/photo_print/card/CLT_CRD0184_01.jpg A013DB8B rom/photo_print/card/CLT_CRD0185_01.jpg 229D8A24 rom/photo_print/card/CLT_CRD0187_01.jpg 420E1484 rom/photo_print/card/CLT_CRD0188_01.jpg 754677CF rom/photo_print/card/CLT_CRD0189_01.jpg 7DC7F1F3 rom/photo_print/card/CLT_CRD0190_01.jpg 8445B1CD rom/photo_print/card/CLT_CRD0191_01.jpg 6F3CB710 rom/photo_print/card/CLT_CRD0192_01.jpg 585E0C77 rom/photo_print/card/CLT_CRD0193_01.jpg DF5899B6 rom/photo_print/card/CLT_CRD0194_01.jpg 45186FBB rom/photo_print/card/CLT_CRD0195_01.jpg A20EC50E rom/photo_print/card/CLT_CRD0196_01.jpg ED26D146 rom/photo_print/card/CLT_CRD0197_01.jpg D3DF55DA rom/photo_print/card/CLT_CRD0198_01.jpg 605D051B rom/photo_print/card/CLT_CRD0199_01.jpg DA63C182 rom/photo_print/card/CLT_CRD0200_01.jpg 7D943A11 rom/photo_print/card/CLT_CRD0201_01.jpg D60E7037 rom/photo_print/card/CLT_CRD0202_01.jpg EAD16C3E rom/photo_print/card/CLT_CRD0204_01.jpg 3EE3CB2C rom/photo_print/card/CLT_CRD0205_01.jpg 773931AD rom/photo_print/card/CLT_CRD0206_01.jpg 05573353 rom/photo_print/card/CLT_CRD0207_01.jpg 7AD5E2B4 rom/photo_print/card/CLT_CRD0208_01.jpg E85612EA rom/photo_print/card/CLT_CRD0209_01.jpg 2172E63E rom/photo_print/card/CLT_CRD0210_01.jpg 114FF36E rom/photo_print/card/CLT_CRD0211_01.jpg F401B645 rom/photo_print/card/CLT_CRD0212_01.jpg 4BC429BF rom/photo_print/card/CLT_CRD0213_01.jpg 0350F207 rom/photo_print/card/CLT_CRD0214_01.jpg 0D547389 rom/photo_print/card/CLT_CRD0215_01.jpg DBA60843 rom/photo_print/card/CLT_CRD0216_01.jpg 0F5C5705 rom/photo_print/card/CLT_CRD0217_01.jpg 1D9C0ADD rom/photo_print/card/CLT_CRD0218_01.jpg FE560EA3 rom/photo_print/card/CLT_CRD0219_01.jpg DE12E32F rom/photo_print/card/CLT_CRD0221_01.jpg 1032C05A rom/photo_print/card/CLT_CRD0222_01.jpg C5E8959E rom/photo_print/card/CLT_CRD0223_01.jpg 58F0B93B rom/photo_print/card/CLT_CRD0224_01.jpg 7D66090B rom/photo_print/card/CLT_CRD0225_01.jpg 596F6FFA rom/photo_print/card/CLT_CRD0226_01.jpg F0438FA7 rom/photo_print/card/CLT_CRD0227_01.jpg 6DA274C9 rom/photo_print/card/CLT_CRD0228_01.jpg B702C046 rom/photo_print/card/CLT_CRD0229_01.jpg CAAE135D rom/photo_print/card/CLT_CRD0230_01.jpg 5CC135A7 rom/photo_print/card/CLT_CRD0231_01.jpg E85954DF rom/photo_print/card/CLT_CRD0232_01.jpg C948EC14 rom/photo_print/card/CLT_CRD0233_01.jpg DD2ACA03 rom/photo_print/card/CLT_CRD0234_01.jpg 1258D02A rom/photo_print/card/CLT_CRD0235_01.jpg 2D09EAAA rom/photo_print/card/CLT_CRD0236_01.jpg 4DCEC9BD rom/photo_print/card/CLT_CRD0238_01.jpg 727C7454 rom/photo_print/card/CLT_CRD0239_01.jpg 09A0E692 rom/photo_print/card/CLT_CRD0240_01.jpg C76638A3 rom/photo_print/card/CLT_CRD0241_01.jpg DB8B6574 rom/photo_print/card/CLT_CRD0242_01.jpg 5A3CAA53 rom/photo_print/card/CLT_CRD0243_01.jpg 58300360 rom/photo_print/card/CLT_CRD0244_01.jpg F77A2C64 rom/photo_print/card/CLT_CRD0245_01.jpg 4B2B8696 rom/photo_print/card/CLT_CRD0246_01.jpg 03C6E28F rom/photo_print/card/CLT_CRD0247_01.jpg B3CC76F4 rom/photo_print/card/CLT_CRD0248_01.jpg 9BA83CBA rom/photo_print/card/CLT_CRD0249_01.jpg 044D34C1 rom/photo_print/card/CLT_CRD0250_01.jpg 94AB3CD4 rom/photo_print/card/CLT_CRD0251_01.jpg 32E957A6 rom/photo_print/card/CLT_CRD0252_01.jpg 3F6F09DD rom/photo_print/card/CLT_CRD0253_01.jpg 7C391B47 rom/photo_print/card/CLT_CRD0255_01.jpg A0CC2D47 rom/photo_print/card/CLT_CRD0256_01.jpg 97573DDA rom/photo_print/card/CLT_CRD0257_01.jpg 20A4A139 rom/photo_print/card/CLT_CRD0258_01.jpg C2DCDD89 rom/photo_print/card/CLT_CRD0259_01.jpg CBCAD4E4 rom/photo_print/card/CLT_CRD0260_01.jpg 82DBCD07 rom/photo_print/card/CLT_CRD0261_01.jpg 27275778 rom/photo_print/card/CLT_CRD0262_01.jpg BCB82201 rom/photo_print/card/CLT_CRD0263_01.jpg CBDD70DE rom/photo_print/card/CLT_CRD0264_01.jpg 9C589F8F rom/photo_print/card/CLT_CRD0265_01.jpg 250315F8 rom/photo_print/card/CLT_CRD0266_01.jpg DA740E40 rom/photo_print/card/CLT_CRD0267_01.jpg FDB4BE9E rom/photo_print/card/CLT_CRD0268_01.jpg F0BF3C59 rom/photo_print/card/CLT_CRD0269_01.jpg C9F90F46 rom/photo_print/card/CLT_CRD0270_01.jpg C2ADD35E rom/photo_print/card/CLT_CRD0272_01.jpg CC29228F rom/photo_print/card/CLT_CRD0273_01.jpg B1C357B2 rom/photo_print/card/CLT_CRD0274_01.jpg 27BDDE89 rom/photo_print/card/CLT_CRD0275_01.jpg 803F4956 rom/photo_print/card/CLT_CRD0276_01.jpg 87EA9910 rom/photo_print/card/CLT_CRD0277_01.jpg 29F522B3 rom/photo_print/card/CLT_CRD0278_01.jpg 6F938CE6 rom/photo_print/card/CLT_CRD0279_01.jpg 0872EEC3 rom/photo_print/card/CLT_CRD0280_01.jpg D85EA9B3 rom/photo_print/card/CLT_CRD0281_01.jpg 858FD6A3 rom/photo_print/card/CLT_CRD0282_01.jpg 9D721BD7 rom/photo_print/card/CLT_CRD0283_01.jpg 8846C6EC rom/photo_print/card/CLT_CRD0284_01.jpg 0335115E rom/photo_print/card/CLT_CRD0285_01.jpg B4C87802 rom/photo_print/card/CLT_CRD0286_01.jpg 0B6156D4 rom/photo_print/card/CLT_CRD0287_01.jpg DE68DCA2 rom/photo_print/card/CLT_CRD0289_01.jpg 2E7C7BBE rom/photo_print/card/CLT_CRD0290_01.jpg 5578FF4B rom/photo_print/card/CLT_CRD0291_01.jpg 419CCD6E rom/photo_print/card/CLT_CRD0292_01.jpg C1C0FF04 rom/photo_print/card/CLT_CRD0293_01.jpg 580E4DE6 rom/photo_print/card/CLT_CRD0294_01.jpg 2FF04F36 rom/photo_print/card/CLT_CRD0295_01.jpg 5FDD876C rom/photo_print/card/CLT_CRD0296_01.jpg 461CE8DB rom/photo_print/card/CLT_CRD0297_01.jpg F0C57A8F rom/photo_print/card/CLT_CRD0298_01.jpg 19B99DEC rom/photo_print/card/CLT_CRD0299_01.jpg B58F3EA9 rom/photo_print/card/CLT_CRD0300_01.jpg 7AF85207 rom/photo_print/card/CLT_CRD0301_01.jpg 4BD81D46 rom/photo_print/card/CLT_CRD0302_01.jpg D5A3E57A rom/photo_print/card/CLT_CRD0303_01.jpg 6E099825 rom/photo_print/card/CLT_CRD0304_01.jpg DD7C7EC4 rom/photo_print/card/CLT_CRD0306_01.jpg 8AFA6BBB rom/photo_print/card/CLT_CRD0307_01.jpg D5E1820F rom/photo_print/card/CLT_CRD0308_01.jpg DC8567AE rom/photo_print/card/CLT_CRD0309_01.jpg 6B592CC3 rom/photo_print/card/CLT_CRD0310_01.jpg 3C2B7EC6 rom/photo_print/card/CLT_CRD0311_01.jpg C820C4A5 rom/photo_print/card/CLT_CRD0312_01.jpg 57F56AF9 rom/photo_print/card/CLT_CRD0313_01.jpg B52FD69A rom/photo_print/card/CLT_CRD0314_01.jpg 07B26F9E rom/photo_print/card/CLT_CRD0315_01.jpg D78F2F41 rom/photo_print/card/CLT_CRD0316_01.jpg C88E5271 rom/photo_print/card/CLT_CRD0317_01.jpg 71C66005 rom/photo_print/card/CLT_CRD0318_01.jpg 421A43F6 rom/photo_print/card/CLT_CRD0319_01.jpg 0ED5C93B rom/photo_print/card/CLT_CRD0320_01.jpg 37D32A22 rom/photo_print/card/CLT_CRD0321_01.jpg A9F5EF17 rom/photo_print/card/CLT_CRD0323_01.jpg 4ADC3D45 rom/photo_print/card/CLT_CRD0324_01.jpg 1519C8D2 rom/photo_print/card/CLT_CRD0325_01.jpg 6E354CC4 rom/photo_print/card/CLT_CRD0326_01.jpg C007C083 rom/photo_print/card/CLT_CRD0327_01.jpg EF0E46A1 rom/photo_print/card/CLT_CRD0328_01.jpg 7CC7C488 rom/photo_print/card/CLT_CRD0329_01.jpg F88F6C5E rom/photo_print/card/CLT_CRD0330_01.jpg 36251574 rom/photo_print/card/CLT_CRD0331_01.jpg 0A303C10 rom/photo_print/card/CLT_CRD0332_01.jpg 22543654 rom/photo_print/card/CLT_CRD0333_01.jpg 6B99EF10 rom/photo_print/card/CLT_CRD0334_01.jpg 42C67BF8 rom/photo_print/card/CLT_CRD0335_01.jpg 18FAC083 rom/photo_print/card/CLT_CRD0336_01.jpg 4EE786D8 rom/photo_print/card/CLT_CRD0337_01.jpg DA41C478 rom/photo_print/card/CLT_CRD0338_01.jpg 0814201F rom/photo_print/card/CLT_CRD0340_01.jpg AA800EA8 rom/photo_print/card/CLT_CRD0341_01.jpg 40F769C8 rom/photo_print/card/CLT_CRD0342_01.jpg 23E72F7F rom/photo_print/card/CLT_CRD0343_01.jpg 96527BE8 rom/photo_print/card/CLT_CRD0344_01.jpg AB984ADC rom/photo_print/card/CLT_CRD0345_01.jpg 529B7630 rom/photo_print/card/CLT_CRD0346_01.jpg D1F037D3 rom/photo_print/card/CLT_CRD0347_01.jpg 167A0BA7 rom/photo_print/card/CLT_CRD0348_01.jpg 5C39BE36 rom/photo_print/card/CLT_CRD0349_01.jpg 9299B16A rom/photo_print/card/CLT_CRD0350_01.jpg D2A81376 rom/photo_print/card/CLT_CRD0351_01.jpg C4AB0AFB rom/photo_print/card/CLT_CRD0352_01.jpg F5B35F56 rom/photo_print/card/CLT_CRD0353_01.jpg 39963568 rom/photo_print/card/CLT_CRD0354_01.jpg 203B9EDB rom/photo_print/card/CLT_CRD0355_01.jpg 3C14C48B rom/photo_print/card/CLT_CRD0357_01.jpg FBB303CD rom/photo_print/card/CLT_CRD0358_01.jpg 2EC26D2A rom/photo_print/card/CLT_CRD0359_01.jpg A19D05BA rom/photo_print/card/CLT_CRD0360_01.jpg D5E210B2 rom/photo_print/card/CLT_CRD0361_01.jpg EC792089 rom/photo_print/card/CLT_CRD0362_01.jpg A48D0A28 rom/photo_print/card/CLT_CRD0363_01.jpg 9033F71C rom/photo_print/card/CLT_CRD0364_01.jpg D684E1E1 rom/photo_print/card/CLT_CRD0365_01.jpg 24D2726A rom/photo_print/card/CLT_CRD0366_01.jpg 9AF977CB rom/photo_print/card/CLT_CRD0367_01.jpg 5EED1BE0 rom/photo_print/card/CLT_CRD0368_01.jpg 23A7621C rom/photo_print/card/CLT_CRD0369_01.jpg E3B914E5 rom/photo_print/card/CLT_CRD0370_01.jpg 22EFDAFF rom/photo_print/card/CLT_CRD0371_01.jpg 189FF09E rom/photo_print/card/CLT_CRD0372_01.jpg A808AB97 rom/photo_print/card/CLT_CRD0374_01.jpg FAABB4E0 rom/photo_print/card/CLT_CRD0375_01.jpg 81EFEB78 rom/photo_print/card/CLT_CRD0376_01.jpg D376B1C6 rom/photo_print/card/CLT_CRD0377_01.jpg DDC612F9 rom/photo_print/card/CLT_CRD0378_01.jpg 7F0C49CB rom/photo_print/card/CLT_CRD0379_01.jpg CA00D62C rom/photo_print/card/CLT_CRD0380_01.jpg C36AF38A rom/photo_print/card/CLT_CRD0381_01.jpg 2D661637 rom/photo_print/card/CLT_CRD0382_01.jpg 5988B49B rom/photo_print/card/CLT_CRD0383_01.jpg CF7E19ED rom/photo_print/card/CLT_CRD0384_01.jpg 8BD0B808 rom/photo_print/card/CLT_CRD0385_01.jpg 9A96D3A6 rom/photo_print/card/CLT_CRD0386_01.jpg 01DF5D06 rom/photo_print/card/CLT_CRD0387_01.jpg EA465312 rom/photo_print/card/CLT_CRD0388_01.jpg 80A8C815 rom/photo_print/card/CLT_CRD0389_01.jpg 42924415 rom/photo_print/card/CLT_CRD0391_01.jpg D7FD7B49 rom/photo_print/card/CLT_CRD0392_01.jpg 0B6C6C4B rom/photo_print/card/CLT_CRD0393_01.jpg 12C08F39 rom/photo_print/card/CLT_CRD0394_01.jpg DA4691F5 rom/photo_print/card/CLT_CRD0395_01.jpg C44F4481 rom/photo_print/card/CLT_CRD0396_01.jpg BA382D07 rom/photo_print/card/CLT_CRD0397_01.jpg 76659EE4 rom/photo_print/card/CLT_CRD0398_01.jpg CCF7A97A rom/photo_print/card/CLT_CRD0399_01.jpg 3AEF67F9 rom/photo_print/card/CLT_CRD0400_01.jpg BCBBF5D6 rom/photo_print/card/CLT_CRD0401_01.jpg C36FBEA9 rom/photo_print/card/CLT_CRD0402_01.jpg 93178B03 rom/photo_print/card/CLT_CRD0403_01.jpg 2077848E rom/photo_print/card/CLT_CRD0404_01.jpg 6F0DCB9E rom/photo_print/card/CLT_CRD0405_01.jpg 392BB70F rom/photo_print/card/CLT_CRD0406_01.jpg D2E0FEF6 rom/photo_print/card/CLT_CRD0408_01.jpg 328CC11B rom/photo_print/card/CLT_CRD0409_01.jpg B47378C1 rom/photo_print/card/CLT_CRD0410_01.jpg 6AA3CFCE rom/photo_print/card/CLT_CRD0411_01.jpg C4E800D8 rom/photo_print/card/CLT_CRD0412_01.jpg 671CEC1B rom/photo_print/card/CLT_CRD0413_01.jpg C173C7E6 rom/photo_print/card/CLT_CRD0414_01.jpg 2169991B rom/photo_print/card/CLT_CRD0415_01.jpg 88828C03 rom/photo_print/card/CLT_CRD0416_01.jpg 9C423B69 rom/photo_print/card/CLT_CRD0417_01.jpg AA8E2CF9 rom/photo_print/card/CLT_CRD0418_01.jpg CA38F7B4 rom/photo_print/card/CLT_CRD0419_01.jpg B4729CAC rom/photo_print/card/CLT_CRD0420_01.jpg 8E6248C6 rom/photo_print/card/CLT_CRD0421_01.jpg C67AB47D rom/photo_print/card/CLT_CRD0422_01.jpg BE0B5105 rom/photo_print/card/CLT_CRD0423_01.jpg AE5309EF rom/photo_print/card/CLT_CRD0425_01.jpg 3F93386C rom/photo_print/card/CLT_CRD0426_01.jpg 9F5CF2F3 rom/photo_print/card/CLT_CRD0427_01.jpg 6114FF6B rom/photo_print/card/CLT_CRD0428_01.jpg 48470912 rom/photo_print/card/CLT_CRD0429_01.jpg 5AD5E6B0 rom/photo_print/card/CLT_CRD0430_01.jpg E34B1C8D rom/photo_print/card/CLT_CRD0431_01.jpg 3EBCCE7F rom/photo_print/card/CLT_CRD0432_01.jpg F8286732 rom/photo_print/card/CLT_CRD0433_01.jpg EDA17ADE rom/photo_print/card/CLT_CRD0434_01.jpg 284E2435 rom/photo_print/card/CLT_CRD0435_01.jpg 32766A6A rom/photo_print/card/CLT_CRD0436_01.jpg 9893829D rom/photo_print/card/CLT_CRD0437_01.jpg ABB30A52 rom/photo_print/card/CLT_CRD0438_01.jpg CC3E4126 rom/photo_print/card/CLT_CRD0439_01.jpg 473306EF rom/photo_print/card/CLT_CRD0440_01.jpg 0D3B0D8C rom/photo_print/card/CLT_CRD0442_01.jpg A6A91A04 rom/photo_print/card/CLT_CRD0443_01.jpg 96FD9311 rom/photo_print/card/CLT_CRD0444_01.jpg 0309A003 rom/photo_print/card/CLT_CRD0445_01.jpg 4A2881D6 rom/photo_print/card/CLT_CRD0446_01.jpg 1222B6BD rom/photo_print/card/CLT_CRD0447_01.jpg 00CE3CC1 rom/photo_print/card/CLT_CRD0448_01.jpg E8C8EB63 rom/photo_print/card/CLT_CRD0449_01.jpg D76C5016 rom/photo_print/card/CLT_CRD0450_01.jpg 6B211877 rom/photo_print/card/CLT_CRD0451_01.jpg A645E5B9 rom/photo_print/card/CLT_CRD0452_01.jpg 220D243B rom/photo_print/card/CLT_CRD0453_01.jpg 0419A702 rom/photo_print/card/CLT_CRD0454_01.jpg B938A48A rom/photo_print/card/CLT_CRD0455_01.jpg E97244BB rom/photo_print/card/CLT_CRD0456_01.jpg 34404E73 rom/photo_print/card/CLT_CRD0457_01.jpg 0E454FC0 rom/photo_print/card/CLT_CRD0459_01.jpg DA50F6D6 rom/photo_print/card/CLT_CRD0460_01.jpg 396ADC4B rom/photo_print/card/CLT_CRD0461_01.jpg 008674CA rom/photo_print/card/CLT_CRD0462_01.jpg 0919EC53 rom/photo_print/card/CLT_CRD0463_01.jpg 53CD10ED rom/photo_print/card/CLT_CRD0464_01.jpg 7318C972 rom/photo_print/card/CLT_CRD0465_01.jpg 2D768D13 rom/photo_print/card/CLT_CRD0466_01.jpg E2BBB2FD rom/photo_print/card/CLT_CRD0467_01.jpg BCD702BB rom/photo_print/card/CLT_CRD0468_01.jpg A81A14ED rom/photo_print/card/CLT_CRD0469_01.jpg 25CC55D4 rom/photo_print/card/CLT_CRD0470_01.jpg 479B073D rom/photo_print/card/CLT_CRD0471_01.jpg 1F12495B rom/photo_print/card/CLT_CRD0472_01.jpg BF09ADB9 rom/photo_print/card/CLT_CRD0473_01.jpg EEEEB7F1 rom/photo_print/card/CLT_CRD0474_01.jpg FE01309D rom/photo_print/card/CLT_CRD0476_01.jpg A8E63F7C rom/photo_print/card/CLT_CRD0477_01.jpg 68D6F6FF rom/photo_print/card/CLT_CRD0478_01.jpg F0E1393A rom/photo_print/card/CLT_CRD0479_01.jpg D3E308F8 rom/photo_print/card/CLT_CRD0480_01.jpg DB9FDB47 rom/photo_print/card/CLT_CRD0481_01.jpg 80D78BA7 rom/photo_print/card/CLT_CRD0482_01.jpg 119B5D52 rom/photo_print/card/CLT_CRD0483_01.jpg 5DCB59D8 rom/photo_print/card/CLT_CRD0484_01.jpg E2A70AF9 rom/photo_print/card/CLT_CRD0485_01.jpg 5C5BECBB rom/photo_print/card/CLT_CRD0486_01.jpg 97FDBD31 rom/photo_print/card/CLT_CRD0487_01.jpg BBAE0264 rom/photo_print/card/CLT_CRD0488_01.jpg 58E28AD0 rom/photo_print/card/CLT_CRD0489_01.jpg 96ACA27A rom/photo_print/card/CLT_CRD0490_01.jpg 6B47253E rom/photo_print/card/CLT_CRD0491_01.jpg 6586CADD rom/photo_print/card/CLT_CRD0493_01.jpg 4DD00F35 rom/photo_print/card/CLT_CRD0494_01.jpg D0B9C359 rom/photo_print/card/CLT_CRD0495_01.jpg FFB495ED rom/photo_print/card/CLT_CRD0496_01.jpg 2DDF20F2 rom/photo_print/card/CLT_CRD0497_01.jpg F64F2D74 rom/photo_print/card/CLT_CRD0498_01.jpg AE615FE2 rom/photo_print/card/CLT_CRD0499_01.jpg F63B3EF1 rom/photo_print/card/CLT_CRD0500_01.jpg 6C906D7A rom/photo_print/card/CLT_CRD0501_01.jpg 470F86DF rom/photo_print/card/CLT_CRD0502_01.jpg 7E40D5BC rom/photo_print/card/CLT_CRD0503_01.jpg E0F2C33B rom/photo_print/card/CLT_CRD0504_01.jpg F097DDB0 rom/photo_print/card/CLT_CRD0505_01.jpg 3A73E4FE rom/photo_print/card/CLT_CRD0506_01.jpg 260814DE rom/photo_print/card/CLT_CRD0507_01.jpg A49C5A4D rom/photo_print/card/CLT_CRD0508_01.jpg 457738BE rom/photo_print/card/CLT_CRD0510_01.jpg D025588A rom/photo_print/card/CLT_CRD0511_01.jpg 82001303 rom/photo_print/card/CLT_CRD0512_01.jpg 211654CC rom/photo_print/card/CLT_CRD0513_01.jpg 973A1D58 rom/photo_print/card/CLT_CRD0514_01.jpg BE7DCD13 rom/photo_print/card/CLT_CRD0515_01.jpg F468A9DC rom/photo_print/card/CLT_CRD0516_01.jpg 66CAF3CD rom/photo_print/card/CLT_CRD0517_01.jpg 66B7363C rom/photo_print/card/CLT_CRD0518_01.jpg 498C7C41 rom/photo_print/card/CLT_CRD0519_01.jpg 083B5C08 rom/photo_print/card/CLT_CRD0520_01.jpg CFD34F96 rom/photo_print/card/CLT_CRD0521_01.jpg 5C1030ED rom/photo_print/card/CLT_CRD0522_01.jpg F9E002D9 rom/photo_print/card/CLT_CRD0523_01.jpg 3402C281 rom/photo_print/card/CLT_CRD0524_01.jpg 1D1728FA rom/photo_print/card/CLT_CRD0525_01.jpg 06D60DBE rom/photo_print/card/CLT_CRD0527_01.jpg 318F6766 rom/photo_print/card/CLT_CRD0528_01.jpg 97E72864 rom/photo_print/card/CLT_CRD0529_01.jpg 6F724DB6 rom/photo_print/card/CLT_CRD0530_01.jpg 346CDB29 rom/photo_print/card/CLT_CRD0531_01.jpg 244CA7DB rom/photo_print/card/CLT_CRD0532_01.jpg 94153BB3 rom/photo_print/card/CLT_CRD0533_01.jpg 8C5BAF19 rom/photo_print/card/CLT_CRD0534_01.jpg 603BD1DE rom/photo_print/card/CLT_CRD0535_01.jpg D8A64101 rom/photo_print/card/CLT_CRD0536_01.jpg EA8DDF37 rom/photo_print/card/CLT_CRD0537_01.jpg 55C15843 rom/photo_print/card/CLT_CRD0538_01.jpg 5E9092D6 rom/photo_print/card/CLT_CRD0539_01.jpg BE96A6AB rom/photo_print/card/CLT_CRD0540_01.jpg 72F250E3 rom/photo_print/card/CLT_CRD0541_01.jpg 0564C944 rom/photo_print/card/CLT_CRD0542_01.jpg 25154490 rom/photo_print/card/CLT_CRD0544_01.jpg 05542817 rom/photo_print/card/CLT_CRD0545_01.jpg F2DF9C28 rom/photo_print/card/CLT_CRD0546_01.jpg C867B781 rom/photo_print/card/CLT_CRD0547_01.jpg CBED371C rom/photo_print/card/CLT_CRD0554_01.jpg 00F59612 rom/photo_print/card/CLT_CRD0555_01.jpg 2F4B070A rom/photo_print/card/CLT_CRD0556_01.jpg 15703F35 rom/photo_print/card/CLT_CRD0557_01.jpg 93F043B3 rom/photo_print/card/CLT_CRD0558_01.jpg B0DCC8C2 rom/photo_print/card/CLT_CRD0559_01.jpg 8ED8F131 rom/photo_print/card/CLT_CRD0560_01.jpg E03CBDB4 rom/photo_print/card/CLT_CRD0561_01.jpg 744356EE rom/photo_print/card/CLT_CRD0562_01.jpg 37FB54E3 rom/photo_print/card/CLT_CRD0563_01.jpg 5D08819F rom/photo_print/card/CLT_CRD0564_01.jpg 6C038C9A rom/photo_print/card/CLT_CRD0565_01.jpg 7B915931 rom/photo_print/card/CLT_CRD0288_01.jpg A80A3BA6 rom/photo_print/card/CLT_CRD0305_01.jpg ACA6AFCA rom/photo_print/card/CLT_CRD0322_01.jpg 32C216CD rom/photo_print/card/CLT_CRD0339_01.jpg 0FEB4D74 rom/photo_print/card/CLT_CRD0356_01.jpg EF28219F rom/photo_print/card/CLT_CRD0373_01.jpg D722EBBF rom/photo_print/card/CLT_CRD0390_01.jpg 7B8C7EA1 rom/photo_print/card/CLT_CRD0407_01.jpg 647A8131 rom/photo_print/card/CLT_CRD0424_01.jpg BAB92118 rom/photo_print/card/CLT_CRD0441_01.jpg 8746A93E rom/photo_print/card/CLT_CRD0458_01.jpg 28CC0E11 rom/photo_print/card/CLT_CRD0475_01.jpg BE7E5014 rom/photo_print/card/CLT_CRD0492_01.jpg 6DF5A128 rom/photo_print/card/CLT_CRD0509_01.jpg B5A24614 rom/photo_print/card/CLT_CRD0526_01.jpg 8CF6C301 rom/photo_print/card/CLT_CRD0543_01.jpg 0DF14B54 rom/photo_print/card/CLT_CRD0566_01.jpg 13D58669 rom/photo_print/card/CLT_CRD0583_01.jpg D5FC2F6F rom/photo_print/card/CLT_CRD0600_01.jpg 382B2DAE rom/photo_print/card/CLT_CRD0567_01.jpg 301CC1E8 rom/photo_print/card/CLT_CRD0568_01.jpg DB52D9D9 rom/photo_print/card/CLT_CRD0569_01.jpg B5FBA4F2 rom/photo_print/card/CLT_CRD0570_01.jpg A7A71634 rom/photo_print/card/CLT_CRD0571_01.jpg ADF6241A rom/photo_print/card/CLT_CRD0572_01.jpg 3A7B06E2 rom/photo_print/card/CLT_CRD0573_01.jpg E898BCB6 rom/photo_print/card/CLT_CRD0574_01.jpg 8D202514 rom/photo_print/card/CLT_CRD0575_01.jpg 71D7437F rom/photo_print/card/CLT_CRD0576_01.jpg 79CCB45E rom/photo_print/card/CLT_CRD0577_01.jpg D9BF428C rom/photo_print/card/CLT_CRD0578_01.jpg F450BAD4 rom/photo_print/card/CLT_CRD0579_01.jpg 09598539 rom/photo_print/card/CLT_CRD0580_01.jpg E4B0A870 rom/photo_print/card/CLT_CRD0581_01.jpg 752CBA15 rom/photo_print/card/CLT_CRD0582_01.jpg 53DBCAEA rom/photo_print/card/CLT_CRD0584_01.jpg 314C944E rom/photo_print/card/CLT_CRD0585_01.jpg B04B35F6 rom/photo_print/card/CLT_CRD0586_01.jpg 2B9DD68E rom/photo_print/card/CLT_CRD0587_01.jpg 1FA71178 rom/photo_print/card/CLT_CRD0588_01.jpg F4277A59 rom/photo_print/card/CLT_CRD0589_01.jpg 8365FD2E rom/photo_print/card/CLT_CRD0590_01.jpg 99DECB1A rom/photo_print/card/CLT_CRD0591_01.jpg 45D95556 rom/photo_print/card/CLT_CRD0592_01.jpg 78497070 rom/photo_print/card/CLT_CRD0593_01.jpg 056A5951 rom/photo_print/card/CLT_CRD0594_01.jpg 97404066 rom/photo_print/card/CLT_CRD0595_01.jpg 60D06937 rom/photo_print/card/CLT_CRD0596_01.jpg 7919C33C rom/photo_print/card/CLT_CRD0597_01.jpg AEA8566C rom/photo_print/card/CLT_CRD0598_01.jpg 031716D4 rom/photo_print/card/CLT_CRD0599_01.jpg 186A376B rom/photo_print/card/CLT_CRD0601_01.jpg 2877ACE8 rom/photo_print/card/CLT_CRD0602_01.jpg B4602DA9 rom/photo_print/card/CLT_CRD0603_01.jpg E1ABB893 rom/photo_print/card/CLT_CRD0604_01.jpg 0D373EF8 rom/photo_print/card/CLT_CRD0605_01.jpg 3B0A7CA6 rom/photo_print/card/CLT_CRD0606_01.jpg 9A8EF5FE rom/photo_print/card/CLT_CRD0607_01.jpg A31FCA92 rom/photo_print/card/CLT_CRD0608_01.jpg 1DD373E0 rom/photo_print/card/CLT_CRD0609_01.jpg AC133F53 rom/photo_print/card/CLT_CRD0610_01.jpg 0A2326A5 rom/photo_print/card/CLT_CRD0611_01.jpg A851E860 rom/photo_print/card/CLT_CRD0612_01.jpg 35D85701 rom/photo_print/card/CLT_CRD0613_01.jpg D5C4FC9D rom/photo_print/card/CLT_CRD0614_01.jpg 97D19327 rom/photo_print/card/CLT_CRD0615_01.jpg 27755328 rom/photo_print/card/CLT_CRD0616_01.jpg EC6C1BE8 rom/photo_print/card/CLT_CRD0617_01.jpg 4347D666 rom/photo_print/card/CLT_CRD0618_01.jpg 6B8D513D rom/photo_print/card/CLT_CRD0619_01.jpg 5AB8FE9E rom/photo_print/card/CLT_CRD0620_01.jpg 0A486E9B rom/photo_print/card/CLT_CRD0621_01.jpg F7DC7052 rom/photo_print/card/CLT_CRD0622_01.jpg 8E1A677F rom/photo_print/card/CLT_CRD0623_01.jpg 349E6E0E rom/photo_print/card/CLT_CRD0624_01.jpg 5D914A7F rom/photo_print/card/CLT_CRD0625_01.jpg C86A4E5A rom/photo_print/card/CLT_CRD0626_01.jpg 5A2BE598 rom/photo_print/card/CLT_CRD0627_01.jpg 332FB2DB rom/photo_print/card/CLT_CRD0628_01.jpg 945D8B04 rom/photo_print/card/CLT_CRD0629_01.jpg 50C964A9 rom/photo_print/card/CLT_CRD0630_01.jpg BFD62A4D rom/photo_print/card/CLT_CRD0631_01.jpg C9109522 rom/photo_print/card/CLT_CRD0632_01.jpg 1C1C7320 rom/photo_print/card/CLT_CRD0633_01.jpg 96AA0185 rom/photo_print/ext/ext_ic_img01_00.jpg 9184F8C3 rom/photo_print/ext/ext_ic_img02_00.jpg D861438E rom/photo_print/ext/ext_ic_img03_00.jpg D08D8442 rom/photo_print/ext/ext_img01_00.jpg 0329B80C rom/photo_print/ext/ext_img02_00.jpg 63FC9F70 rom/photo_print/ext/ext_img03_00.jpg 370BDC94 rom/photo_print/ext/ext_ss_rights01.tga 8FAB82F1 rom/photo_print/ext/ext_ss_rights01_ic.tga E2D69CA9 rom/photo_print/ext/ext_ss_rights02.tga 650A7E12 rom/photo_print/ext/ext_ss_rights02_ic.tga 175E9AFE rom/photo_print/ext/ext_ss_rights03.tga 74FD8F7B rom/photo_print/ext/ext_ss_rights03_ic.tga 92253B16 rom/photo_print/stamp/stamp000_01.tga C005A330 rom/photo_print/stamp/stamp001_01.tga 18D6BC3C rom/photo_print/stamp/stamp002_00.tga 8C32C9F6 rom/photo_print/stamp/stamp003_00.tga 35302BFA rom/photo_print/stamp/stamp004_00.tga 470A7BBF rom/photo_print/stamp/stamp005_00.tga A33BB186 rom/photo_print/stamp/stamp006_00.tga 30FC5917 rom/photo_print/stamp/stamp007_00.tga E401FBBE rom/photo_print/stamp/stamp008_00.tga 59E0A727 rom/photo_print/stamp/stamp009_00.tga FAD87BF1 rom/photo_print/stamp/stamp010_00.tga 50B6607D rom/photo_print/stamp/stamp011_00.tga 93798E84 rom/photo_print/stamp/stamp012_00.tga 323472D0 rom/photo_print/stamp/stamp013_00.tga A2EB194A rom/photo_print/stamp/stamp014_00.tga A2E24AFA rom/photo_print/stamp/stamp016_00.tga 3A21B4C7 rom/photo_print/stamp/stamp017_00.tga 56AEA0AA rom/photo_print/stamp/stamp018_00.tga 0FA0F6A7 rom/photo_print/stamp/stamp019_00.tga 7CEAF63C rom/photo_print/stamp/stamp020_00.tga C6955087 rom/photo_print/stamp/stamp021_00.tga 56CD3D2F rom/photo_print/stamp/stamp022_00.tga CB449193 rom/photo_print/stamp/stamp023_00.tga 37619944 rom/photo_print/stamp/stamp024_00.tga 7A96A20C rom/photo_print/stamp/stamp030_02.tga 955E0F9C rom/photo_print/stamp/stamp031_02.tga 6B538EE6 rom/photo_print/stamp/stamp032_02.tga AC39D739 rom/photo_print/stamp/stamp033_02.tga 5D598812 rom/photo_print/stamp/stamp034_02.tga 23C90DF6 rom/photo_print/stamp/stamp035_02.tga F2A3E944 rom/photo_print/stamp/stamp040_00.tga 854DED5F rom/photo_print/stamp/stamp041_00.tga 4F718416 rom/photo_print/stamp/stamp043_00.tga FAEDB916 rom/photo_print/stamp/stamp044_00.tga 27D802D5 rom/photo_print/stamp/stamp045_00.tga F11C9813 rom/photo_print/stamp/stamp046_00.tga 30E1C357 rom/photo_print/stamp/stamp047_00.tga 3F83BE6B rom/photo_print/stamp/stamp048_00.tga 3E54562A rom/photo_print/stamp/stamp049_00.tga FE99F560 rom/photo_print/stamp/stamp050_00.tga 9ED6DE02 rom/photo_print/stamp/stamp051_00.tga 4BC559FF rom/photo_print/stamp/stamp052_00.tga 4E1CE0BC rom/photo_print/stamp/stamp053_00.tga 24005799 rom/photo_print/stamp/stamp054_00.tga F9B3651B rom/photo_print/stamp/stamp055_00.tga FD625B17 rom/photo_print/stamp/stamp056_00.tga DF97892D rom/photo_print/stamp/stamp057_00.tga 00FA25B8 rom/photo_print/stamp/stamp058_00.tga 1FC5777E rom/photo_print/stamp/stamp059_00.tga A9690988 rom/photo_print/stamp/stamp061_00.tga 2D9A9249 rom/photo_print/stamp/stamp062_00.tga 9B010377 rom/photo_print/stamp/stamp063_00.tga 161B3E43 rom/photo_print/stamp/stamp064_00.tga 8D7FFF5D rom/photo_print/stamp/stamp065_00.tga 08D33828 rom/photo_print/stamp/stamp066_00.tga E002BA85 rom/photo_print/stamp/stamp067_00.tga 0C29099F rom/photo_print/stamp/stamp068_00.tga 4147FB08 rom/photo_print/stamp/stamp069_00.tga E9A6364C rom/photo_print/stamp/stamp070_00.tga 3A772612 rom/photo_print/stamp/stamp071_00.tga 29CF17D6 rom/photo_print/stamp/stamp072_00.tga 6B0B616C rom/photo_print/stamp/stamp073_00.tga 6722EDC9 rom/photo_print/stamp/stamp074_00.tga 38861CFD rom/photo_print/stamp/stamp075_00.tga 8E5DC50D rom/photo_print/stamp/stamp076_00.tga E19E8272 rom/photo_print/stamp/stamp077_00.tga 10D53246 rom/photo_print/stamp/stamp078_00.tga 0265378F rom/photo_print/stamp/stamp079_00.tga C52EC04E rom/photo_print/stamp/stamp080_00.tga 36C27F75 rom/photo_print/stamp/stamp081_00.tga 071CB73C rom/photo_print/stamp/stamp082_00.tga FC6B55FC rom/photo_print/stamp/stamp083_00.tga B4A37DF8 rom/photo_print/stamp/stamp084_00.tga CD768F70 rom/photo_print/stamp/stamp085_00.tga A2F72952 rom/photo_print/stamp/stamp086_00.tga 92DD6F12 rom/photo_print/stamp/stamp087_00.tga 1F5D0AED rom/photo_print/stamp/stamp015_00.tga 8ED43EFC rom/photo_print/stamp/stamp042_00.tga E6A84DE3 rom/photo_print/stamp/stamp060_00.tga A0B8D906 rom/pv_param/pv710/bloom.txt B21B8636 rom/pv_param/pv710/cc.txt 9F325BC8 rom/pv_param/pv710/chara_light.txt 732314C5 rom/pv_param/pv710/dof.txt 2A2B98EC rom/pv_param/pv710/stage_light.txt A30C0CCE rom/pv_param/pv740/dof.txt 6309A2D1 rom/sound/bgm/encore_jng_adx.ogg B879C4CB rom/sound/bgm/random_select.ogg 11025647 rom/sound/bgm/result_ft_clear.ogg 310FFC3B rom/sound/bgm/result_lp.ogg F5DD51FD rom/sound/bgm/result_verB_clear.ogg A5F605DF rom/sound/bgm/screenshot.ogg D175AAA7 rom/sound/bgm/selector_ft_lp.ogg 73392E98 rom/sound/bgm/selector_verB_a_lp.ogg 3246A78E rom/sound/song/pv_001.ogg 1C98A85C rom/sound/song/pv_002.ogg 77AC5730 rom/sound/song/pv_003.ogg 816A75FE rom/sound/song/pv_004.ogg 336C18F8 rom/sound/song/pv_005.ogg 138839BF rom/sound/song/pv_006.ogg 282E7515 rom/sound/song/pv_007.ogg F76F9F56 rom/sound/song/pv_008.ogg 8F563212 rom/sound/song/pv_009.ogg 4BC17D9C rom/sound/song/pv_010.ogg 8374D37B rom/sound/song/pv_011.ogg 3788CCD2 rom/sound/song/pv_012.ogg CC6ED135 rom/sound/song/pv_013.ogg E9D9EF25 rom/sound/song/pv_014.ogg 708382D4 rom/sound/song/pv_015.ogg CFC3378D rom/sound/song/pv_016.ogg 1BCC9472 rom/sound/song/pv_017.ogg C06304A9 rom/sound/song/pv_018.ogg 55494B3A rom/sound/song/pv_019.ogg E99876E6 rom/sound/song/pv_021.ogg 7018C955 rom/sound/song/pv_022.ogg B6510BC9 rom/sound/song/pv_023.ogg 56957253 rom/sound/song/pv_024.ogg 388F1DB7 rom/sound/song/pv_025.ogg 2848D4B8 rom/sound/song/pv_026.ogg 118D4D10 rom/sound/song/pv_027.ogg B40BA9FF rom/sound/song/pv_028.ogg 96294A6D rom/sound/song/pv_029.ogg 3B3FFAA3 rom/sound/song/pv_030.ogg 51968963 rom/sound/song/pv_031.ogg 8E00148B rom/sound/song/pv_032.ogg DE0A32E2 rom/sound/song/pv_033.ogg F7F8470B rom/sound/song/pv_034.ogg CD70D1A0 rom/sound/song/pv_035.ogg DCB8436C rom/sound/song/pv_036.ogg BA78A63F rom/sound/song/pv_037.ogg 2CA97AC5 rom/sound/song/pv_038.ogg ED0293E5 rom/sound/song/pv_039.ogg 7F5543C2 rom/sound/song/pv_041.ogg 652151AD rom/sound/song/pv_042.ogg 46E95728 rom/sound/song/pv_043.ogg 6478E129 rom/sound/song/pv_044.ogg 97D97174 rom/sound/song/pv_045.ogg 06FB40D5 rom/sound/song/pv_046.ogg D1B85F8E rom/sound/song/pv_047.ogg 0DEC9749 rom/sound/song/pv_048.ogg 49C1A0F0 rom/sound/song/pv_049.ogg 2DBA41B6 rom/sound/song/pv_050.ogg 2422987F rom/sound/song/pv_051.ogg 50E063B2 rom/sound/song/pv_052.ogg 342DA983 rom/sound/song/pv_053.ogg 725A327D rom/sound/song/pv_054.ogg C2953768 rom/sound/song/pv_055.ogg BE3D80A8 rom/sound/song/pv_056.ogg D2314E6B rom/sound/song/pv_057.ogg 6FA11AB3 rom/sound/song/pv_058.ogg 839EC91E rom/sound/song/pv_059.ogg C7ACF496 rom/sound/song/pv_061.ogg 2ABD3DBF rom/sound/song/pv_062.ogg F4242D55 rom/sound/song/pv_063.ogg 084CF89D rom/sound/song/pv_064.ogg 79DD1186 rom/sound/song/pv_065.ogg FF71BCD5 rom/sound/song/pv_066.ogg 99C42876 rom/sound/song/pv_079.ogg 9FEE09E4 rom/sound/song/pv_081.ogg 92B723DD rom/sound/song/pv_082.ogg 02477B43 rom/sound/song/pv_083.ogg 56B3C97C rom/sound/song/pv_084.ogg 605DF0B2 rom/sound/song/pv_085.ogg 9D1D0267 rom/sound/song/pv_086.ogg 783004A6 rom/sound/song/pv_087.ogg B6C55BA1 rom/sound/song/pv_088.ogg B4AA4FDC rom/sound/song/pv_089.ogg AA67CD1C rom/sound/song/pv_090.ogg 1EF44CE5 rom/sound/song/pv_091.ogg D603C3C8 rom/sound/song/pv_092.ogg 8840750E rom/sound/song/pv_094.ogg C9E98E66 rom/sound/song/pv_095.ogg 9AFB027A rom/sound/song/pv_096.ogg A00EFA8C rom/sound/song/pv_097.ogg 0B92D454 rom/sound/song/pv_101.ogg A2EAC506 rom/sound/song/pv_102.ogg 11138999 rom/sound/song/pv_103.ogg EDEAB6AB rom/sound/song/pv_104.ogg 8FA20F81 rom/sound/song/pv_201.ogg 02501EDF rom/sound/song/pv_202.ogg 2147FC5C rom/sound/song/pv_203.ogg 6C234527 rom/sound/song/pv_204.ogg 2098E9BC rom/sound/song/pv_205.ogg F1B9DF28 rom/sound/song/pv_206.ogg B23C8878 rom/sound/song/pv_207.ogg 4E82E264 rom/sound/song/pv_208.ogg 8E98EDE7 rom/sound/song/pv_209.ogg FC532E93 rom/sound/song/pv_210.ogg 9662A664 rom/sound/song/pv_211.ogg F011C647 rom/sound/song/pv_020.ogg 001E6929 rom/sound/song/pv_040.ogg 3238023B rom/sound/song/pv_060.ogg 8DECF3BC rom/sound/song/pv_093.ogg ECBFDA9A rom/sound/song/pv_212.ogg 6712B106 rom/sound/song/pv_233.ogg AE8AE48D rom/sound/song/pv_244.ogg EC3A2799 rom/sound/song/pv_265.ogg FBEE6A44 rom/sound/song/pv_421.ogg 97D6CAAE rom/sound/song/pv_441.ogg D4063DD1 rom/sound/song/pv_618.ogg 55B839CD rom/sound/song/pv_641.ogg 727F0DF2 rom/sound/song/pv_213.ogg 9C826B63 rom/sound/song/pv_214.ogg 21E54143 rom/sound/song/pv_215.ogg 1DC9A831 rom/sound/song/pv_216.ogg 87C9A4E0 rom/sound/song/pv_218.ogg 4DA0B37B rom/sound/song/pv_219.ogg A257A6F4 rom/sound/song/pv_220.ogg 5D8B2EDD rom/sound/song/pv_221.ogg DF0E5E52 rom/sound/song/pv_222.ogg BCAA5288 rom/sound/song/pv_223.ogg 8A82C337 rom/sound/song/pv_224.ogg 367010BC rom/sound/song/pv_225.ogg B8C848B6 rom/sound/song/pv_226.ogg 2FBE680F rom/sound/song/pv_227.ogg 048FD581 rom/sound/song/pv_227_rin.ogg 5476D324 rom/sound/song/pv_228.ogg D3985FCB rom/sound/song/pv_231.ogg B92B66FF rom/sound/song/pv_232.ogg C19CBDD0 rom/sound/song/pv_234.ogg EBD5D108 rom/sound/song/pv_235.ogg 9321BDB5 rom/sound/song/pv_236.ogg ED3C868A rom/sound/song/pv_238.ogg CD3A6B39 rom/sound/song/pv_238_kaito.ogg B665967E rom/sound/song/pv_238_len.ogg 1A609C4A rom/sound/song/pv_238_luka.ogg E6E9EA8D rom/sound/song/pv_238_meiko.ogg 3542DEA9 rom/sound/song/pv_238_rin.ogg A8DE978D rom/sound/song/pv_239.ogg 584474E9 rom/sound/song/pv_239_luka.ogg 6BDD754C rom/sound/song/pv_239_meiko.ogg 3514F515 rom/sound/song/pv_239_rin.ogg DA7EC86A rom/sound/song/pv_240.ogg 67D353A3 rom/sound/song/pv_241.ogg 0B312FEF rom/sound/song/pv_242.ogg A795CEB7 rom/sound/song/pv_243.ogg 2360622C rom/sound/song/pv_243_miku.ogg 0205919B rom/sound/song/pv_244_len.ogg DC7EE1FD rom/sound/song/pv_246.ogg 8777555D rom/sound/song/pv_246_kaito.ogg F2D67CCC rom/sound/song/pv_247.ogg 9192D48F rom/sound/song/pv_248.ogg E8107583 rom/sound/song/pv_249.ogg EF5AA99E rom/sound/song/pv_250.ogg BEF223B1 rom/sound/song/pv_251.ogg AC1D3B10 rom/sound/song/pv_253.ogg 2AB583EF rom/sound/song/pv_254.ogg 3B7E29E7 rom/sound/song/pv_255.ogg 412DD378 rom/sound/song/pv_257.ogg 98C667DA rom/sound/song/pv_259.ogg BB95499E rom/sound/song/pv_260.ogg 9519E4D7 rom/sound/song/pv_261.ogg F35896E9 rom/sound/song/pv_262.ogg BD2C3685 rom/sound/song/pv_262_kai.ogg C135CC2C rom/sound/song/pv_262_mik.ogg BE6062D1 rom/sound/song/pv_262_rin.ogg 6C314DC1 rom/sound/song/pv_401.ogg 742B02CD rom/sound/song/pv_402.ogg 24764EDF rom/sound/song/pv_403.ogg 2248DA3C rom/sound/song/pv_404.ogg C2B1F8A5 rom/sound/song/pv_405.ogg 7991B112 rom/sound/song/pv_407.ogg D532D55F rom/sound/song/pv_408.ogg BE217F8D rom/sound/song/pv_409.ogg B5EA9AD9 rom/sound/song/pv_410.ogg 1FD18E91 rom/sound/song/pv_411.ogg 30901286 rom/sound/song/pv_412.ogg 7FB5EDCE rom/sound/song/pv_413.ogg 0B27AA04 rom/sound/song/pv_414.ogg 6D58DB1D rom/sound/song/pv_415.ogg 19F6A1FB rom/sound/song/pv_416.ogg C374EA2F rom/sound/song/pv_417.ogg E1110DE0 rom/sound/song/pv_418.ogg A9BAC713 rom/sound/song/pv_419.ogg 841CF31F rom/sound/song/pv_420.ogg B870F2CD rom/sound/song/pv_422.ogg 486FDC84 rom/sound/song/pv_423.ogg 7A9A21EF rom/sound/song/pv_424.ogg 16621A99 rom/sound/song/pv_425.ogg 34DC711A rom/sound/song/pv_426.ogg F51A64BB rom/sound/song/pv_427.ogg 2BB171BF rom/sound/song/pv_428.ogg 6CCD19E9 rom/sound/song/pv_429.ogg 8F175080 rom/sound/song/pv_430.ogg 9882F545 rom/sound/song/pv_431.ogg 831E1806 rom/sound/song/pv_432.ogg EC1659E6 rom/sound/song/pv_433.ogg C5876364 rom/sound/song/pv_434.ogg 269E4976 rom/sound/song/pv_435.ogg C302B877 rom/sound/song/pv_436.ogg 6DD0811D rom/sound/song/pv_437.ogg ACB0AAA7 rom/sound/song/pv_438.ogg 399C9BC0 rom/sound/song/pv_439.ogg 79C68956 rom/sound/song/pv_440.ogg DC56928C rom/sound/song/pv_442.ogg 6AB91EBB rom/sound/song/pv_443.ogg 08567A63 rom/sound/song/pv_600.ogg 2B3375B8 rom/sound/song/pv_601.ogg F3A95BFD rom/sound/song/pv_602.ogg FF41452E rom/sound/song/pv_603.ogg 6294F99D rom/sound/song/pv_604.ogg C694FB89 rom/sound/song/pv_605.ogg 681C7B84 rom/sound/song/pv_607.ogg 83A100D1 rom/sound/song/pv_608.ogg 327A6FB4 rom/sound/song/pv_609.ogg 056E03AA rom/sound/song/pv_610.ogg 4282AE3C rom/sound/song/pv_611.ogg 51E4F1F9 rom/sound/song/pv_612.ogg 579D8B81 rom/sound/song/pv_613.ogg E27B1C7E rom/sound/song/pv_614.ogg 8DDFE1AD rom/sound/song/pv_615.ogg 868E7225 rom/sound/song/pv_616.ogg BBDCCC29 rom/sound/song/pv_617.ogg F73DF1F5 rom/sound/song/pv_619.ogg F709BD19 rom/sound/song/pv_620.ogg EFBC8F24 rom/sound/song/pv_621.ogg 7DCF0337 rom/sound/song/pv_621_meiko.ogg E7951E35 rom/sound/song/pv_622.ogg 0FE48733 rom/sound/song/pv_623.ogg 9F61050F rom/sound/song/pv_624.ogg DD4AECAE rom/sound/song/pv_625.ogg 2DE45738 rom/sound/song/pv_626.ogg 5C8816E0 rom/sound/song/pv_627.ogg 6D5D7B7E rom/sound/song/pv_628.ogg E822E614 rom/sound/song/pv_629.ogg 17B4F7E2 rom/sound/song/pv_630.ogg 8699084D rom/sound/song/pv_631.ogg 97314709 rom/sound/song/pv_637.ogg 9FF5B111 rom/sound/song/pv_637_all.ogg 5B72BC67 rom/sound/song/pv_638.ogg 0D07CA70 rom/sound/song/pv_639.ogg 13720829 rom/sound/song/pv_640.ogg 43B40DE9 rom/sound/song/pv_642.ogg 078D32F7 rom/sound/song/pv_710.ogg 98395B7D rom/sound/song/pv_722.ogg E10ECC0C rom/sound/song/pv_723.ogg 3E12B568 rom/sound/song/pv_724.ogg 1242E2BD rom/sound/song/pv_725.ogg 16D24AD5 rom/sound/song/pv_726.ogg 524F5760 rom/sound/song/pv_727.ogg 7E50E78B rom/sound/song/pv_728.ogg 930E044D rom/sound/song/pv_729.ogg 83D2A528 rom/sound/song/pv_730.ogg 272466BB rom/sound/song/pv_731.ogg CEE9C519 rom/sound/song/pv_732.ogg F8FD2F58 rom/sound/song/pv_733.ogg 950DBEB5 rom/sound/song/pv_734.ogg 99272300 rom/sound/song/pv_736.ogg E07927EB rom/sound/song/pv_737.ogg 88393B85 rom/sound/song/pv_738.ogg 26C1FE7C rom/sound/song/pv_739.ogg 522D8C00 rom/sound/song/pv_740.ogg B70A7C3C rom/sound/song/pv_832.ogg C8AE0DF4 rom/photo_print/stamp/ext/ext_stamp001_00.tga CC536E68 rom/photo_print/stamp/ext/ext_stamp002_00.tga 9C638554 rom/photo_print/stamp/ext/ext_stamp003_00.tga 5F4B78CE rom/photo_print/stamp/ext/ext_stamp004_00.tga 7EB148B0 rom/photo_print/stamp/module/stamp_md_sub_000_00.tga 92C5233C rom/photo_print/stamp/module/stamp_md_sub_001_00.tga 98AD84E9 rom/photo_print/stamp/module/stamp_md_sub_002_00.tga 197C964C rom/photo_print/stamp/module/stamp_md_sub_003_00.tga 61060BCD rom/photo_print/stamp/module/stamp_md_sub_004_00.tga 7A60C691 rom/photo_print/stamp/module/stamp_md_sub_005_00.tga 90971714 rom/photo_print/stamp/module/stamp_md_sub_006_00.tga 5126EC1A rom/photo_print/stamp/module/stamp_md_sub_007_00.tga B254D05F rom/photo_print/stamp/module/stamp_md_sub_008_00.tga 3FE45DBB rom/photo_print/stamp/module/stamp_md_sub_009_00.tga A3D46BFF rom/photo_print/stamp/module/stamp_md_sub_010_00.tga 0CA56F0F rom/photo_print/stamp/module/stamp_md_sub_011_00.tga 0A70E4C8 rom/photo_print/stamp/module/stamp_md_sub_012_00.tga 343F9355 rom/photo_print/stamp/module/stamp_md_sub_013_00.tga EAABBBEA rom/photo_print/stamp/module/stamp_md_sub_014_00.tga D94E1D99 rom/photo_print/stamp/module/stamp_md_sub_016_00.tga 1A9D8F98 rom/photo_print/stamp/module/stamp_md_sub_017_00.tga 98CE179B rom/photo_print/stamp/module/stamp_md_sub_018_00.tga 5457035A rom/photo_print/stamp/module/stamp_md_sub_019_00.tga 22706406 rom/photo_print/stamp/module/stamp_md_sub_020_00.tga 1FDEB98C rom/photo_print/stamp/module/stamp_md_sub_021_00.tga 0586813D rom/photo_print/stamp/module/stamp_md_sub_022_00.tga 3F5208FA rom/photo_print/stamp/module/stamp_md_sub_023_00.tga D11BBC30 rom/photo_print/stamp/module/stamp_md_sub_024_00.tga 16D0FFD4 rom/photo_print/stamp/module/stamp_md_sub_025_00.tga A5A19D38 rom/photo_print/stamp/module/stamp_md_sub_026_00.tga 84F32C0A rom/photo_print/stamp/module/stamp_md_sub_027_00.tga 1ED795AF rom/photo_print/stamp/module/stamp_md_sub_028_00.tga 4BF2576D rom/photo_print/stamp/module/stamp_md_sub_029_00.tga 1ED53B7F rom/photo_print/stamp/module/stamp_md_sub_030_00.tga A613DD97 rom/photo_print/stamp/module/stamp_md_sub_032_00.tga C62931EB rom/photo_print/stamp/module/stamp_md_sub_033_00.tga B6846FC7 rom/photo_print/stamp/module/stamp_md_sub_034_00.tga 85F15E13 rom/photo_print/stamp/module/stamp_md_sub_035_00.tga 8765860A rom/photo_print/stamp/module/stamp_md_sub_036_00.tga 196BD4F7 rom/photo_print/stamp/module/stamp_md_sub_037_00.tga D3A8B096 rom/photo_print/stamp/module/stamp_md_sub_038_00.tga ACEB0CB3 rom/photo_print/stamp/module/stamp_md_sub_039_00.tga EEFAC576 rom/photo_print/stamp/module/stamp_md_sub_040_00.tga C45831BE rom/photo_print/stamp/module/stamp_md_sub_041_00.tga A6383072 rom/photo_print/stamp/module/stamp_md_sub_042_00.tga FF0AB25C rom/photo_print/stamp/module/stamp_md_sub_043_00.tga EDC49985 rom/photo_print/stamp/module/stamp_md_sub_044_00.tga 447354B1 rom/photo_print/stamp/module/stamp_md_sub_045_00.tga 662E270E rom/photo_print/stamp/module/stamp_md_sub_046_00.tga AA00A76F rom/photo_print/stamp/module/stamp_md_sub_048_00.tga 8C5D16DC rom/photo_print/stamp/module/stamp_md_sub_049_00.tga 29176AAE rom/photo_print/stamp/module/stamp_md_sub_050_00.tga 04EFF093 rom/photo_print/stamp/module/stamp_md_sub_051_00.tga 9263F05F rom/photo_print/stamp/module/stamp_md_sub_052_00.tga 2EBFDC8E rom/photo_print/stamp/module/stamp_md_sub_053_00.tga 643E016A rom/photo_print/stamp/module/stamp_md_sub_054_00.tga 2368996B rom/photo_print/stamp/module/stamp_md_sub_055_00.tga F5DF5C88 rom/photo_print/stamp/module/stamp_md_sub_056_00.tga BCFFA7B0 rom/photo_print/stamp/module/stamp_md_sub_057_00.tga A01365BB rom/photo_print/stamp/module/stamp_md_sub_058_00.tga 3D120102 rom/photo_print/stamp/module/stamp_md_sub_059_00.tga E0C6247A rom/photo_print/stamp/module/stamp_md_sub_060_00.tga 4382C309 rom/photo_print/stamp/module/stamp_md_sub_061_00.tga 4AFF5792 rom/photo_print/stamp/module/stamp_md_sub_062_00.tga C61BCFAF rom/photo_print/stamp/module/stamp_md_sub_015_00.tga 50EF5981 rom/photo_print/stamp/module/stamp_md_sub_031_00.tga 7F1EABBB rom/photo_print/stamp/module/stamp_md_sub_047_00.tga F740D309 rom/photo_print/stamp/module/stamp_md_sub_063_00.tga 346056BA rom/photo_print/stamp/module/stamp_md_sub_079_00.tga 7992D7F8 rom/photo_print/stamp/module/stamp_md_sub_095_00.tga 1308CC7F rom/photo_print/stamp/module/stamp_md_sub_111_00.tga C9E7CF2E rom/photo_print/stamp/module/stamp_md_sub_128_00.tga 05AA5F32 rom/photo_print/stamp/module/stamp_md_sub_145_00.tga 1B4925EF rom/photo_print/stamp/module/stamp_md_sub_162_00.tga C055091F rom/photo_print/stamp/module/stamp_md_sub_193_00.tga 34E3B644 rom/photo_print/stamp/module/stamp_md_sub_209_00.tga 04128ED3 rom/photo_print/stamp/module/stamp_md_sub_225_00.tga 3DD0A0F9 rom/photo_print/stamp/module/stamp_md_sub_241_00.tga EB315BA0 rom/photo_print/stamp/module/stamp_md_sub_257_00.tga 4DDCC125 rom/photo_print/stamp/module/stamp_md_sub_273_00.tga 26073395 rom/photo_print/stamp/module/stamp_md_sub_289_00.tga 2E769C60 rom/photo_print/stamp/module/stamp_md_sub_305_00.tga F4133F0E rom/photo_print/stamp/module/stamp_md_sub_323_00.tga EFDC7C03 rom/photo_print/stamp/module/stamp_md_sub_341_00.tga 4ED80719 rom/photo_print/stamp/module/stamp_md_sub_359_00.tga 391EDA23 rom/photo_print/stamp/module/stamp_md_sub_375_00.tga C08D7CA5 rom/photo_print/stamp/module/stamp_md_sub_393_00.tga F9BF5004 rom/photo_print/stamp/module/stamp_md_sub_064_00.tga 8C069260 rom/photo_print/stamp/module/stamp_md_sub_065_00.tga E52B999C rom/photo_print/stamp/module/stamp_md_sub_066_00.tga FC081E76 rom/photo_print/stamp/module/stamp_md_sub_067_00.tga 78750116 rom/photo_print/stamp/module/stamp_md_sub_068_00.tga 08751694 rom/photo_print/stamp/module/stamp_md_sub_069_00.tga C16A9C9B rom/photo_print/stamp/module/stamp_md_sub_070_00.tga 8A84B711 rom/photo_print/stamp/module/stamp_md_sub_071_00.tga ADE4AD08 rom/photo_print/stamp/module/stamp_md_sub_072_00.tga 35D75971 rom/photo_print/stamp/module/stamp_md_sub_073_00.tga 468BDD06 rom/photo_print/stamp/module/stamp_md_sub_074_00.tga D15E0A15 rom/photo_print/stamp/module/stamp_md_sub_075_00.tga C31CAE1D rom/photo_print/stamp/module/stamp_md_sub_076_00.tga 17A79635 rom/photo_print/stamp/module/stamp_md_sub_077_00.tga 3F0827F0 rom/photo_print/stamp/module/stamp_md_sub_078_00.tga CDD160C5 rom/photo_print/stamp/module/stamp_md_sub_080_00.tga 0ACC8DE0 rom/photo_print/stamp/module/stamp_md_sub_081_00.tga F6F35689 rom/photo_print/stamp/module/stamp_md_sub_082_00.tga 9D92A0E0 rom/photo_print/stamp/module/stamp_md_sub_083_00.tga FB7280EA rom/photo_print/stamp/module/stamp_md_sub_084_00.tga BD3B359C rom/photo_print/stamp/module/stamp_md_sub_085_00.tga 8215C98B rom/photo_print/stamp/module/stamp_md_sub_086_00.tga F8E50A74 rom/photo_print/stamp/module/stamp_md_sub_087_00.tga 5BCBAB43 rom/photo_print/stamp/module/stamp_md_sub_088_00.tga 01A6D6D8 rom/photo_print/stamp/module/stamp_md_sub_089_00.tga 0BFF6847 rom/photo_print/stamp/module/stamp_md_sub_090_00.tga 909A76F8 rom/photo_print/stamp/module/stamp_md_sub_091_00.tga 4D681B2C rom/photo_print/stamp/module/stamp_md_sub_092_00.tga 5EAD1206 rom/photo_print/stamp/module/stamp_md_sub_093_00.tga 4317AE90 rom/photo_print/stamp/module/stamp_md_sub_094_00.tga 1AEC1323 rom/photo_print/stamp/module/stamp_md_sub_096_00.tga 0BF4DF26 rom/photo_print/stamp/module/stamp_md_sub_097_00.tga F09C30A8 rom/photo_print/stamp/module/stamp_md_sub_098_00.tga 5825946E rom/photo_print/stamp/module/stamp_md_sub_099_00.tga BE4B53AB rom/photo_print/stamp/module/stamp_md_sub_100_00.tga DC8A61A3 rom/photo_print/stamp/module/stamp_md_sub_101_00.tga 1075CC12 rom/photo_print/stamp/module/stamp_md_sub_102_00.tga 7FB60BD7 rom/photo_print/stamp/module/stamp_md_sub_103_00.tga CCC2512A rom/photo_print/stamp/module/stamp_md_sub_104_00.tga F6D443D1 rom/photo_print/stamp/module/stamp_md_sub_105_00.tga 12271B3B rom/photo_print/stamp/module/stamp_md_sub_106_00.tga 8B97755A rom/photo_print/stamp/module/stamp_md_sub_107_00.tga 348AF030 rom/photo_print/stamp/module/stamp_md_sub_108_00.tga 342D0F3D rom/photo_print/stamp/module/stamp_md_sub_109_00.tga 9E100433 rom/photo_print/stamp/module/stamp_md_sub_110_00.tga 7F0569DD rom/photo_print/stamp/module/stamp_md_sub_112_00.tga 1AEEC6A9 rom/photo_print/stamp/module/stamp_md_sub_113_00.tga 971BC1FC rom/photo_print/stamp/module/stamp_md_sub_114_00.tga 38AC152F rom/photo_print/stamp/module/stamp_md_sub_115_00.tga 036AA244 rom/photo_print/stamp/module/stamp_md_sub_116_00.tga C955EFF0 rom/photo_print/stamp/module/stamp_md_sub_117_00.tga 09989567 rom/photo_print/stamp/module/stamp_md_sub_118_00.tga F1CD1A22 rom/photo_print/stamp/module/stamp_md_sub_119_00.tga F083B9DC rom/photo_print/stamp/module/stamp_md_sub_120_00.tga 605D3456 rom/photo_print/stamp/module/stamp_md_sub_121_00.tga 4A62F772 rom/photo_print/stamp/module/stamp_md_sub_122_00.tga 157A91DD rom/photo_print/stamp/module/stamp_md_sub_124_00.tga 46CE2B56 rom/photo_print/stamp/module/stamp_md_sub_125_00.tga 9D36F17D rom/photo_print/stamp/module/stamp_md_sub_126_00.tga 31E044FE rom/photo_print/stamp/module/stamp_md_sub_127_00.tga 55F53C2E rom/photo_print/stamp/module/stamp_md_sub_129_00.tga BFC2834B rom/photo_print/stamp/module/stamp_md_sub_130_00.tga 4C1DFB32 rom/photo_print/stamp/module/stamp_md_sub_131_00.tga 363B2590 rom/photo_print/stamp/module/stamp_md_sub_132_00.tga DA6A6654 rom/photo_print/stamp/module/stamp_md_sub_133_00.tga 96E30CD3 rom/photo_print/stamp/module/stamp_md_sub_134_00.tga D8C2365A rom/photo_print/stamp/module/stamp_md_sub_135_00.tga DD533B9D rom/photo_print/stamp/module/stamp_md_sub_136_00.tga 77F1C171 rom/photo_print/stamp/module/stamp_md_sub_137_00.tga 03ECD96C rom/photo_print/stamp/module/stamp_md_sub_138_00.tga 590F4E63 rom/photo_print/stamp/module/stamp_md_sub_139_00.tga 4087492A rom/photo_print/stamp/module/stamp_md_sub_141_00.tga A6A2F200 rom/photo_print/stamp/module/stamp_md_sub_142_00.tga F8090C1F rom/photo_print/stamp/module/stamp_md_sub_143_00.tga 8F38D8C3 rom/photo_print/stamp/module/stamp_md_sub_144_00.tga C5908520 rom/photo_print/stamp/module/stamp_md_sub_146_00.tga B304CB39 rom/photo_print/stamp/module/stamp_md_sub_147_00.tga C5C04D2D rom/photo_print/stamp/module/stamp_md_sub_148_00.tga 93697B9C rom/photo_print/stamp/module/stamp_md_sub_149_00.tga 616623B1 rom/photo_print/stamp/module/stamp_md_sub_150_00.tga 23804836 rom/photo_print/stamp/module/stamp_md_sub_151_00.tga 1FD70DB7 rom/photo_print/stamp/module/stamp_md_sub_153_00.tga CD4EEE1B rom/photo_print/stamp/module/stamp_md_sub_154_00.tga 1B81FF8D rom/photo_print/stamp/module/stamp_md_sub_155_00.tga 8E61B407 rom/photo_print/stamp/module/stamp_md_sub_156_00.tga 28149094 rom/photo_print/stamp/module/stamp_md_sub_157_00.tga 09E147BC rom/photo_print/stamp/module/stamp_md_sub_158_00.tga 0FEA08B0 rom/photo_print/stamp/module/stamp_md_sub_159_00.tga 122F9412 rom/photo_print/stamp/module/stamp_md_sub_160_00.tga 7140D9D8 rom/photo_print/stamp/module/stamp_md_sub_161_00.tga 592B0136 rom/photo_print/stamp/module/stamp_md_sub_163_00.tga FBB4FF2A rom/photo_print/stamp/module/stamp_md_sub_164_00.tga 27353EFD rom/photo_print/stamp/module/stamp_md_sub_165_00.tga 3FAD19A1 rom/photo_print/stamp/module/stamp_md_sub_166_00.tga C8FB9F96 rom/photo_print/stamp/module/stamp_md_sub_167_00.tga B36F0719 rom/photo_print/stamp/module/stamp_md_sub_168_00.tga DA7BBFC9 rom/photo_print/stamp/module/stamp_md_sub_169_00.tga E61E7EE7 rom/photo_print/stamp/module/stamp_md_sub_170_00.tga 87808B22 rom/photo_print/stamp/module/stamp_md_sub_171_00.tga 438FFEC5 rom/photo_print/stamp/module/stamp_md_sub_172_00.tga 034574F3 rom/photo_print/stamp/module/stamp_md_sub_188_00.tga 57DCFBF9 rom/photo_print/stamp/module/stamp_md_sub_189_00.tga 39C1259E rom/photo_print/stamp/module/stamp_md_sub_190_00.tga A42D5D46 rom/photo_print/stamp/module/stamp_md_sub_191_00.tga AE92216C rom/photo_print/stamp/module/stamp_md_sub_192_00.tga 701274F6 rom/photo_print/stamp/module/stamp_md_sub_194_00.tga F56A150B rom/photo_print/stamp/module/stamp_md_sub_195_00.tga D54C2A06 rom/photo_print/stamp/module/stamp_md_sub_196_00.tga 72130520 rom/photo_print/stamp/module/stamp_md_sub_197_00.tga D8FD3525 rom/photo_print/stamp/module/stamp_md_sub_198_00.tga 8A52A1F8 rom/photo_print/stamp/module/stamp_md_sub_199_00.tga 37275D07 rom/photo_print/stamp/module/stamp_md_sub_200_00.tga 0F9EA6C2 rom/photo_print/stamp/module/stamp_md_sub_201_00.tga 58325A35 rom/photo_print/stamp/module/stamp_md_sub_202_00.tga B277B6F2 rom/photo_print/stamp/module/stamp_md_sub_203_00.tga 4C855364 rom/photo_print/stamp/module/stamp_md_sub_204_00.tga 1389C7CB rom/photo_print/stamp/module/stamp_md_sub_205_00.tga 36F472C2 rom/photo_print/stamp/module/stamp_md_sub_206_00.tga 0ADBAB32 rom/photo_print/stamp/module/stamp_md_sub_207_00.tga 54F3C981 rom/photo_print/stamp/module/stamp_md_sub_208_00.tga CC528BE3 rom/photo_print/stamp/module/stamp_md_sub_210_00.tga 0CCDB21B rom/photo_print/stamp/module/stamp_md_sub_211_00.tga 699A4B56 rom/photo_print/stamp/module/stamp_md_sub_212_00.tga 59461149 rom/photo_print/stamp/module/stamp_md_sub_213_00.tga DE9BD34F rom/photo_print/stamp/module/stamp_md_sub_214_00.tga B4D33AB5 rom/photo_print/stamp/module/stamp_md_sub_215_00.tga A9FDF241 rom/photo_print/stamp/module/stamp_md_sub_216_00.tga 2BCC7161 rom/photo_print/stamp/module/stamp_md_sub_217_00.tga F2059B6C rom/photo_print/stamp/module/stamp_md_sub_218_00.tga 417DE2D3 rom/photo_print/stamp/module/stamp_md_sub_219_00.tga 09F80902 rom/photo_print/stamp/module/stamp_md_sub_220_00.tga 61382902 rom/photo_print/stamp/module/stamp_md_sub_221_00.tga 74B35AAD rom/photo_print/stamp/module/stamp_md_sub_222_00.tga DB069995 rom/photo_print/stamp/module/stamp_md_sub_223_00.tga C009E20E rom/photo_print/stamp/module/stamp_md_sub_224_00.tga A77576BF rom/photo_print/stamp/module/stamp_md_sub_226_00.tga F650FA1B rom/photo_print/stamp/module/stamp_md_sub_227_00.tga BFC87B97 rom/photo_print/stamp/module/stamp_md_sub_228_00.tga E47FF0DD rom/photo_print/stamp/module/stamp_md_sub_229_00.tga 0C40D703 rom/photo_print/stamp/module/stamp_md_sub_230_00.tga 76504299 rom/photo_print/stamp/module/stamp_md_sub_231_00.tga 6E5A9A53 rom/photo_print/stamp/module/stamp_md_sub_232_00.tga F00745E9 rom/photo_print/stamp/module/stamp_md_sub_233_00.tga F24B2837 rom/photo_print/stamp/module/stamp_md_sub_234_00.tga 78259285 rom/photo_print/stamp/module/stamp_md_sub_235_00.tga 340E1355 rom/photo_print/stamp/module/stamp_md_sub_236_00.tga 8D97A80C rom/photo_print/stamp/module/stamp_md_sub_237_00.tga 73D282D7 rom/photo_print/stamp/module/stamp_md_sub_238_00.tga 46AAE428 rom/photo_print/stamp/module/stamp_md_sub_239_00.tga 35D606D4 rom/photo_print/stamp/module/stamp_md_sub_240_00.tga C495C03A rom/photo_print/stamp/module/stamp_md_sub_242_00.tga 77FE45BF rom/photo_print/stamp/module/stamp_md_sub_243_00.tga 89F7AFB4 rom/photo_print/stamp/module/stamp_md_sub_244_00.tga C7D64D0E rom/photo_print/stamp/module/stamp_md_sub_245_00.tga 4D603A33 rom/photo_print/stamp/module/stamp_md_sub_246_00.tga 6EB17DAC rom/photo_print/stamp/module/stamp_md_sub_247_00.tga A494D9A0 rom/photo_print/stamp/module/stamp_md_sub_248_00.tga 4B6160F3 rom/photo_print/stamp/module/stamp_md_sub_249_00.tga 15BFE149 rom/photo_print/stamp/module/stamp_md_sub_250_00.tga F921B225 rom/photo_print/stamp/module/stamp_md_sub_251_00.tga 785025B6 rom/photo_print/stamp/module/stamp_md_sub_252_00.tga CCF3B72B rom/photo_print/stamp/module/stamp_md_sub_253_00.tga 65D56624 rom/photo_print/stamp/module/stamp_md_sub_254_00.tga A56B65D3 rom/photo_print/stamp/module/stamp_md_sub_255_00.tga 07A07B7B rom/photo_print/stamp/module/stamp_md_sub_256_00.tga AEC9BCEA rom/photo_print/stamp/module/stamp_md_sub_258_00.tga 6FF73E22 rom/photo_print/stamp/module/stamp_md_sub_259_00.tga C2007C07 rom/photo_print/stamp/module/stamp_md_sub_260_00.tga FCE6A6DA rom/photo_print/stamp/module/stamp_md_sub_261_00.tga 7FA806EA rom/photo_print/stamp/module/stamp_md_sub_262_00.tga 8FFC3601 rom/photo_print/stamp/module/stamp_md_sub_263_00.tga BDD39D4E rom/photo_print/stamp/module/stamp_md_sub_264_00.tga FCB48755 rom/photo_print/stamp/module/stamp_md_sub_265_00.tga 06882B23 rom/photo_print/stamp/module/stamp_md_sub_266_00.tga 538ABD25 rom/photo_print/stamp/module/stamp_md_sub_267_00.tga B8640609 rom/photo_print/stamp/module/stamp_md_sub_268_00.tga 0376B82E rom/photo_print/stamp/module/stamp_md_sub_269_00.tga E84A6235 rom/photo_print/stamp/module/stamp_md_sub_270_00.tga 1F672B24 rom/photo_print/stamp/module/stamp_md_sub_271_00.tga 73E86741 rom/photo_print/stamp/module/stamp_md_sub_272_00.tga C94CEF7D rom/photo_print/stamp/module/stamp_md_sub_274_00.tga 22616850 rom/photo_print/stamp/module/stamp_md_sub_275_00.tga 998E299E rom/photo_print/stamp/module/stamp_md_sub_276_00.tga 3F158FF7 rom/photo_print/stamp/module/stamp_md_sub_277_00.tga 662631E9 rom/photo_print/stamp/module/stamp_md_sub_278_00.tga AB59E275 rom/photo_print/stamp/module/stamp_md_sub_279_00.tga 379C9615 rom/photo_print/stamp/module/stamp_md_sub_280_00.tga C2897664 rom/photo_print/stamp/module/stamp_md_sub_281_00.tga 1665A09B rom/photo_print/stamp/module/stamp_md_sub_282_00.tga CDA17A9D rom/photo_print/stamp/module/stamp_md_sub_283_00.tga 19C6D60B rom/photo_print/stamp/module/stamp_md_sub_284_00.tga 31AA1797 rom/photo_print/stamp/module/stamp_md_sub_285_00.tga 183D20EA rom/photo_print/stamp/module/stamp_md_sub_286_00.tga 3E9EEB34 rom/photo_print/stamp/module/stamp_md_sub_287_00.tga D1E1D26E rom/photo_print/stamp/module/stamp_md_sub_288_00.tga 39748CC9 rom/photo_print/stamp/module/stamp_md_sub_290_00.tga 4DE7A503 rom/photo_print/stamp/module/stamp_md_sub_291_00.tga 06730EFB rom/photo_print/stamp/module/stamp_md_sub_292_00.tga 8234A798 rom/photo_print/stamp/module/stamp_md_sub_293_00.tga 664757C0 rom/photo_print/stamp/module/stamp_md_sub_294_00.tga 4DEB24E6 rom/photo_print/stamp/module/stamp_md_sub_295_00.tga 1C93B8B8 rom/photo_print/stamp/module/stamp_md_sub_296_00.tga F37356B2 rom/photo_print/stamp/module/stamp_md_sub_297_00.tga 2E3232EF rom/photo_print/stamp/module/stamp_md_sub_298_00.tga 1716F63D rom/photo_print/stamp/module/stamp_md_sub_299_00.tga D7F38D60 rom/photo_print/stamp/module/stamp_md_sub_300_00.tga 34AA1594 rom/photo_print/stamp/module/stamp_md_sub_301_00.tga A6F79FE1 rom/photo_print/stamp/module/stamp_md_sub_302_00.tga 0096B281 rom/photo_print/stamp/module/stamp_md_sub_303_00.tga D8CD4BC5 rom/photo_print/stamp/module/stamp_md_sub_304_00.tga B9BB34A5 rom/photo_print/stamp/module/stamp_md_sub_306_00.tga 9214CDA2 rom/photo_print/stamp/module/stamp_md_sub_308_00.tga 2B273497 rom/photo_print/stamp/module/stamp_md_sub_309_00.tga 49BF5DE0 rom/photo_print/stamp/module/stamp_md_sub_310_00.tga 657DCBEC rom/photo_print/stamp/module/stamp_md_sub_311_00.tga 0A466B9B rom/photo_print/stamp/module/stamp_md_sub_313_00.tga 528E6C91 rom/photo_print/stamp/module/stamp_md_sub_314_00.tga C9288CB7 rom/photo_print/stamp/module/stamp_md_sub_315_00.tga 60D4B599 rom/photo_print/stamp/module/stamp_md_sub_316_00.tga CD9C303A rom/photo_print/stamp/module/stamp_md_sub_317_00.tga CF0DD183 rom/photo_print/stamp/module/stamp_md_sub_318_00.tga 5DB13E89 rom/photo_print/stamp/module/stamp_md_sub_319_00.tga EF748687 rom/photo_print/stamp/module/stamp_md_sub_320_00.tga A879784D rom/photo_print/stamp/module/stamp_md_sub_321_00.tga 53D1C08E rom/photo_print/stamp/module/stamp_md_sub_322_00.tga 7B800749 rom/photo_print/stamp/module/stamp_md_sub_324_00.tga 74A99273 rom/photo_print/stamp/module/stamp_md_sub_325_00.tga 90EC4194 rom/photo_print/stamp/module/stamp_md_sub_326_00.tga FFF5F1BE rom/photo_print/stamp/module/stamp_md_sub_327_00.tga BD335A15 rom/photo_print/stamp/module/stamp_md_sub_328_00.tga 912F9AE2 rom/photo_print/stamp/module/stamp_md_sub_329_00.tga A878E44E rom/photo_print/stamp/module/stamp_md_sub_330_00.tga E0EAA392 rom/photo_print/stamp/module/stamp_md_sub_331_00.tga EF817E00 rom/photo_print/stamp/module/stamp_md_sub_332_00.tga 6E19A033 rom/photo_print/stamp/module/stamp_md_sub_334_00.tga 8522882A rom/photo_print/stamp/module/stamp_md_sub_335_00.tga 76179688 rom/photo_print/stamp/module/stamp_md_sub_336_00.tga 1D759835 rom/photo_print/stamp/module/stamp_md_sub_338_00.tga C35FA6FE rom/photo_print/stamp/module/stamp_md_sub_339_00.tga 42B1652C rom/photo_print/stamp/module/stamp_md_sub_340_00.tga 664437F4 rom/photo_print/stamp/module/stamp_md_sub_343_00.tga 68C536A8 rom/photo_print/stamp/module/stamp_md_sub_344_00.tga A568881A rom/photo_print/stamp/module/stamp_md_sub_345_00.tga 1227A47D rom/photo_print/stamp/module/stamp_md_sub_346_00.tga 4B4A78ED rom/photo_print/stamp/module/stamp_md_sub_347_00.tga 887F0FF3 rom/photo_print/stamp/module/stamp_md_sub_348_00.tga D06D0FC3 rom/photo_print/stamp/module/stamp_md_sub_349_00.tga 2940C873 rom/photo_print/stamp/module/stamp_md_sub_350_00.tga 60DFB7B0 rom/photo_print/stamp/module/stamp_md_sub_351_00.tga BA17B361 rom/photo_print/stamp/module/stamp_md_sub_352_00.tga 47688A9D rom/photo_print/stamp/module/stamp_md_sub_353_00.tga 295FF785 rom/photo_print/stamp/module/stamp_md_sub_354_00.tga 45230B2A rom/photo_print/stamp/module/stamp_md_sub_355_00.tga CA4D9C87 rom/photo_print/stamp/module/stamp_md_sub_356_00.tga 31AF00FD rom/photo_print/stamp/module/stamp_md_sub_358_00.tga B2F2BA13 rom/photo_print/stamp/module/stamp_md_sub_360_00.tga 1B79843F rom/photo_print/stamp/module/stamp_md_sub_361_00.tga 35BB024D rom/photo_print/stamp/module/stamp_md_sub_362_00.tga C5290653 rom/photo_print/stamp/module/stamp_md_sub_363_00.tga B3B2BC38 rom/photo_print/stamp/module/stamp_md_sub_364_00.tga D80CA25D rom/photo_print/stamp/module/stamp_md_sub_365_00.tga 0FBD262D rom/photo_print/stamp/module/stamp_md_sub_366_00.tga 4B6BFB27 rom/photo_print/stamp/module/stamp_md_sub_367_00.tga 9FA4E224 rom/photo_print/stamp/module/stamp_md_sub_368_00.tga 1F77DF86 rom/photo_print/stamp/module/stamp_md_sub_369_00.tga 4D7FEB22 rom/photo_print/stamp/module/stamp_md_sub_370_00.tga 7BF534F3 rom/photo_print/stamp/module/stamp_md_sub_371_00.tga 04D47A2D rom/photo_print/stamp/module/stamp_md_sub_372_00.tga E54B997D rom/photo_print/stamp/module/stamp_md_sub_373_00.tga 17DAD79C rom/photo_print/stamp/module/stamp_md_sub_374_00.tga 84AFCC63 rom/photo_print/stamp/module/stamp_md_sub_376_00.tga DF854163 rom/photo_print/stamp/module/stamp_md_sub_377_00.tga B2262233 rom/photo_print/stamp/module/stamp_md_sub_378_00.tga 4A5E0D9D rom/photo_print/stamp/module/stamp_md_sub_379_00.tga 0A5121CE rom/photo_print/stamp/module/stamp_md_sub_380_00.tga 02D7D69B rom/photo_print/stamp/module/stamp_md_sub_381_00.tga 77FD68B0 rom/photo_print/stamp/module/stamp_md_sub_382_00.tga 1E60DFA3 rom/photo_print/stamp/module/stamp_md_sub_383_00.tga C2955FCA rom/photo_print/stamp/module/stamp_md_sub_385_00.tga DB3DEC1E rom/photo_print/stamp/module/stamp_md_sub_386_00.tga C93EB20B rom/photo_print/stamp/module/stamp_md_sub_387_00.tga 86A76000 rom/photo_print/stamp/module/stamp_md_sub_389_00.tga A5025226 rom/photo_print/stamp/module/stamp_md_sub_390_00.tga 6E3D7E7B rom/photo_print/stamp/module/stamp_md_sub_391_00.tga 056A6306 rom/photo_print/stamp/module/stamp_md_sub_392_00.tga 4467DC61 rom/photo_print/stamp/module/stamp_md_sub_394_00.tga 68F8B0CD rom/photo_print/stamp/module/stamp_md_sub_395_00.tga 7D7D645B rom/photo_print/stamp/module/stamp_md_sub_398_00.tga 826CD5FB rom/photo_print/stamp/module/stamp_md_sub_402_00.tga 507B4D05 rom/photo_print/stamp/module/stamp_md_sub_403_00.tga EDE1A7CC rom/photo_print/stamp/module/stamp_md_sub_404_00.tga 96C7932A rom/photo_print/stamp/module/stamp_md_sub_405_00.tga 1A9FDC21 rom/photo_print/stamp/module/stamp_md_sub_406_00.tga 42C3E5A6 rom/photo_print/stamp/module/stamp_md_sub_407_00.tga F638D00F rom/photo_print/stamp/module/stamp_md_sub_408_00.tga CA0C14A5 rom/photo_print/stamp/module/stamp_md_sub_409_00.tga D37CC553 rom/photo_print/stamp/module/stamp_md_sub_410_00.tga D0744C6F rom/photo_print/stamp/module/stamp_md_sub_411_00.tga 34CEB465 rom/photo_print/stamp/module/stamp_md_sub_412_00.tga 1B4D9BB7 rom/photo_print/stamp/module/stamp_md_sub_420_00.tga CA8C911B rom/photo_print/stamp/module/stamp_md_sub_421_00.tga 3A71CD10 rom/photo_print/stamp/module/stamp_md_sub_422_00.tga 9B935077 rom/photo_print/stamp/module/stamp_md_sub_423_00.tga 588370F9 rom/photo_print/stamp/module/stamp_md_sub_ext001_00.tga 68FE128B rom/photo_print/stamp/module/stamp_md_sub_ext002_00.tga 5332CC25 rom/photo_print/stamp/module/stamp_md_sub_ext003_00.tga B02FB1EC rom/photo_print/stamp/module/stamp_md_sub_ext004_00.tga 836BB4A6 rom/photo_print/stamp/module/stamp_md_sub_ext005_00.tga 01DE9AFC rom/photo_print/stamp/module/stamp_md_sub_ext006_00.tga 77E959E2 rom/photo_print/stamp/module/stamp_md_sub_ext007_00.tga 8E5F09A8 rom/photo_print/stamp/module/stamp_md_sub_ext008_00.tga BDDFBBC1 rom/photo_print/stamp/module/stamp_md_sub_ext009_00.tga 190A378D rom/photo_print/stamp/module/stamp_md_sub_ext010_00.tga A393842A rom/photo_print/stamp/module/stamp_md_sub_ext011_00.tga CAE8F81E rom/photo_print/stamp/module/stamp_md_sub_ext012_00.tga 9282B0D9 rom/photo_print/stamp/pv/stamp_pv001_logo001_00.tga C33FC925 rom/photo_print/stamp/pv/stamp_pv002_logo002_00.tga 74FD52F1 rom/photo_print/stamp/pv/stamp_pv003_logo003_00.tga 2463F9E6 rom/photo_print/stamp/pv/stamp_pv004_logo004_00.tga EEF10A55 rom/photo_print/stamp/pv/stamp_pv005_logo005_00.tga 3523AC5D rom/photo_print/stamp/pv/stamp_pv006_logo006_00.tga 6A774A3E rom/photo_print/stamp/pv/stamp_pv007_logo007_00.tga 4DCF2921 rom/photo_print/stamp/pv/stamp_pv008_logo008_00.tga CF410419 rom/photo_print/stamp/pv/stamp_pv009_logo009_00.tga 41E06B00 rom/photo_print/stamp/pv/stamp_pv010_logo010_00.tga 324ED023 rom/photo_print/stamp/pv/stamp_pv011_logo011_00.tga 7F91D99D rom/photo_print/stamp/pv/stamp_pv012_logo012_00.tga 956F7BD5 rom/photo_print/stamp/pv/stamp_pv013_logo013_00.tga E9F6B134 rom/photo_print/stamp/pv/stamp_pv014_logo014_00.tga AE29CDFF rom/photo_print/stamp/pv/stamp_pv016_logo016_00.tga 08BE9118 rom/photo_print/stamp/pv/stamp_pv017_logo017_00.tga F82E92AF rom/photo_print/stamp/pv/stamp_pv018_logo018_00.tga EA613F69 rom/photo_print/stamp/pv/stamp_pv019_logo019_00.tga A53F9C25 rom/photo_print/stamp/pv/stamp_pv020_logo020_00.tga 6A432B7C rom/photo_print/stamp/pv/stamp_pv021_logo021_00.tga 81A0CA9C rom/photo_print/stamp/pv/stamp_pv022_logo022_00.tga E8D3E8CA rom/photo_print/stamp/pv/stamp_pv023_logo023_00.tga 21D6E715 rom/photo_print/stamp/pv/stamp_pv024_logo024_00.tga 466D880A rom/photo_print/stamp/pv/stamp_pv025_logo025_00.tga E79A5549 rom/photo_print/stamp/pv/stamp_pv027_logo027_00.tga A93B85F5 rom/photo_print/stamp/pv/stamp_pv028_logo028_00.tga 2AC6CDDE rom/photo_print/stamp/pv/stamp_pv029_logo029_00.tga B6E2AE71 rom/photo_print/stamp/pv/stamp_pv030_logo030_00.tga B9546294 rom/photo_print/stamp/pv/stamp_pv032_logo032_00.tga 207E95C1 rom/photo_print/stamp/pv/stamp_pv037_logo037_00.tga CFCD366A rom/photo_print/stamp/pv/stamp_pv038_logo038_00.tga A8E97487 rom/photo_print/stamp/pv/stamp_pv039_logo039_00.tga EA152DD3 rom/photo_print/stamp/pv/stamp_pv040_logo040_00.tga 9A8640A8 rom/photo_print/stamp/pv/stamp_pv041_logo041_00.tga 6A81ADB5 rom/photo_print/stamp/pv/stamp_pv042_logo042_00.tga 855E645B rom/photo_print/stamp/pv/stamp_pv043_logo043_00.tga 3912D06F rom/photo_print/stamp/pv/stamp_pv044_logo044_00.tga A61B57E7 rom/photo_print/stamp/pv/stamp_pv045_logo045_00.tga FD71FB85 rom/photo_print/stamp/pv/stamp_pv046_logo046_00.tga 32587512 rom/photo_print/stamp/pv/stamp_pv047_logo047_00.tga 05FD7435 rom/photo_print/stamp/pv/stamp_pv048_logo048_00.tga C67BE822 rom/photo_print/stamp/pv/stamp_pv049_logo049_00.tga D7E60A70 rom/photo_print/stamp/pv/stamp_pv051_logo051_00.tga 5B8455E4 rom/photo_print/stamp/pv/stamp_pv052_logo052_00.tga C82C607F rom/photo_print/stamp/pv/stamp_pv053_logo053_00.tga F6CAE985 rom/photo_print/stamp/pv/stamp_pv054_logo054_00.tga 5D5E72F2 rom/photo_print/stamp/pv/stamp_pv055_logo055_00.tga D133406C rom/photo_print/stamp/pv/stamp_pv056_logo056_00.tga 950E8833 rom/photo_print/stamp/pv/stamp_pv057_logo057_00.tga 908F4C8C rom/photo_print/stamp/pv/stamp_pv058_logo058_00.tga 45959F5B rom/photo_print/stamp/pv/stamp_pv059_logo059_00.tga 5513FF8B rom/photo_print/stamp/pv/stamp_pv060_logo060_00.tga EDBDB5F3 rom/photo_print/stamp/pv/stamp_pv061_logo061_00.tga 58061228 rom/photo_print/stamp/pv/stamp_pv062_logo062_00.tga 4B9FBF7C rom/photo_print/stamp/pv/stamp_pv063_logo063_00.tga C6102945 rom/photo_print/stamp/pv/stamp_pv064_logo064_00.tga 7B7671EE rom/photo_print/stamp/pv/stamp_pv015_logo015_00.tga 00300724 rom/photo_print/stamp/pv/stamp_pv031_logo031_00.tga 8D710EF3 rom/photo_print/stamp/pv/stamp_pv050_logo050_00.tga 227D9752 rom/photo_print/stamp/pv/stamp_pv065_logo065_00.tga 03F575A2 rom/photo_print/stamp/pv/stamp_pv093_logo093_00.tga 6B4EC239 rom/photo_print/stamp/pv/stamp_pv207_logo207_00.tga 8AB43CED rom/photo_print/stamp/pv/stamp_pv223_logo223_00.tga 2A0DBF7D rom/photo_print/stamp/pv/stamp_pv241_logo241_00.tga B6436C92 rom/photo_print/stamp/pv/stamp_pv261_logo261_00.tga D2BE4B23 rom/photo_print/stamp/pv/stamp_pv413_logo413_00.tga 36C003EE rom/photo_print/stamp/pv/stamp_pv428_logo428_00.tga 37D5F4BD rom/photo_print/stamp/pv/stamp_pv443_logo443_00.tga CF872F97 rom/photo_print/stamp/pv/stamp_pv615_logo615_00.tga 76BEF6ED rom/photo_print/stamp/pv/stamp_pv630_logo630_00.tga C9D33010 rom/photo_print/stamp/pv/stamp_pv066_logo066_00.tga 1DB95254 rom/photo_print/stamp/pv/stamp_pv079_logo079_00.tga F75EED39 rom/photo_print/stamp/pv/stamp_pv081_logo081_00.tga 7D600E19 rom/photo_print/stamp/pv/stamp_pv082_logo082_00.tga 24FA5766 rom/photo_print/stamp/pv/stamp_pv083_logo083_00.tga AD680AB4 rom/photo_print/stamp/pv/stamp_pv084_logo084_00.tga 4B0EF51E rom/photo_print/stamp/pv/stamp_pv085_logo085_00.tga E32DEA05 rom/photo_print/stamp/pv/stamp_pv086_logo086_00.tga C8F78640 rom/photo_print/stamp/pv/stamp_pv087_logo087_00.tga CC4A83CE rom/photo_print/stamp/pv/stamp_pv088_logo088_00.tga FC442C12 rom/photo_print/stamp/pv/stamp_pv089_logo089_00.tga CC455320 rom/photo_print/stamp/pv/stamp_pv090_logo090_00.tga 8AF17E19 rom/photo_print/stamp/pv/stamp_pv091_logo091_00.tga 9BBA53C4 rom/photo_print/stamp/pv/stamp_pv092_logo092_00.tga 822E4BF8 rom/photo_print/stamp/pv/stamp_pv094_logo094_00.tga BB8844DF rom/photo_print/stamp/pv/stamp_pv095_logo095_00.tga 6BA0CA19 rom/photo_print/stamp/pv/stamp_pv096_logo096_00.tga E75D3FDE rom/photo_print/stamp/pv/stamp_pv097_logo097_00.tga 7D9772D3 rom/photo_print/stamp/pv/stamp_pv101_logo101_00.tga 88CEC92B rom/photo_print/stamp/pv/stamp_pv102_logo102_00.tga CEA2194D rom/photo_print/stamp/pv/stamp_pv103_logo103_00.tga 6B5BE979 rom/photo_print/stamp/pv/stamp_pv104_logo104_00.tga 4CFAC38D rom/photo_print/stamp/pv/stamp_pv201_logo201_00.tga 43C5C261 rom/photo_print/stamp/pv/stamp_pv202_logo202_00.tga E83FAAB5 rom/photo_print/stamp/pv/stamp_pv203_logo203_00.tga D80F4DAC rom/photo_print/stamp/pv/stamp_pv204_logo204_00.tga 6C9BD279 rom/photo_print/stamp/pv/stamp_pv205_logo205_00.tga F6731B8C rom/photo_print/stamp/pv/stamp_pv206_logo206_00.tga E6446A18 rom/photo_print/stamp/pv/stamp_pv208_logo208_00.tga BDF07C60 rom/photo_print/stamp/pv/stamp_pv209_logo209_00.tga EB58C05F rom/photo_print/stamp/pv/stamp_pv210_logo210_00.tga AA55A120 rom/photo_print/stamp/pv/stamp_pv211_logo211_00.tga D1ABB1A7 rom/photo_print/stamp/pv/stamp_pv212_logo212_00.tga CA09DF41 rom/photo_print/stamp/pv/stamp_pv213_logo213_00.tga 7617893C rom/photo_print/stamp/pv/stamp_pv214_logo214_00.tga 38409483 rom/photo_print/stamp/pv/stamp_pv215_logo215_00.tga 391DD13A rom/photo_print/stamp/pv/stamp_pv216_logo216_00.tga 05DD3BA3 rom/photo_print/stamp/pv/stamp_pv218_logo218_00.tga FCF6A399 rom/photo_print/stamp/pv/stamp_pv219_logo219_00.tga EB285E20 rom/photo_print/stamp/pv/stamp_pv220_logo220_00.tga 028D041B rom/photo_print/stamp/pv/stamp_pv221_logo221_00.tga 4D421847 rom/photo_print/stamp/pv/stamp_pv222_logo222_00.tga F71E90D3 rom/photo_print/stamp/pv/stamp_pv224_logo224_00.tga D040702F rom/photo_print/stamp/pv/stamp_pv225_logo225_00.tga 6B623160 rom/photo_print/stamp/pv/stamp_pv226_logo226_00.tga 7FDB4C84 rom/photo_print/stamp/pv/stamp_pv227_logo227_00.tga EE83EAFA rom/photo_print/stamp/pv/stamp_pv228_logo228_00.tga 838C303A rom/photo_print/stamp/pv/stamp_pv231_logo231_00.tga EF7A6DA4 rom/photo_print/stamp/pv/stamp_pv232_logo232_00.tga F9A572D8 rom/photo_print/stamp/pv/stamp_pv233_logo233_00.tga 0E664131 rom/photo_print/stamp/pv/stamp_pv234_logo234_00.tga 56EB23A4 rom/photo_print/stamp/pv/stamp_pv235_logo235_00.tga DD5570F7 rom/photo_print/stamp/pv/stamp_pv236_logo236_00.tga 790BC882 rom/photo_print/stamp/pv/stamp_pv238_logo238_00.tga 51177349 rom/photo_print/stamp/pv/stamp_pv239_logo239_00.tga E3B90762 rom/photo_print/stamp/pv/stamp_pv240_logo240_00.tga 0465F910 rom/photo_print/stamp/pv/stamp_pv242_logo242_00.tga B4C91785 rom/photo_print/stamp/pv/stamp_pv243_logo243_00.tga 2CE26985 rom/photo_print/stamp/pv/stamp_pv244_logo244_00.tga 8ACB92E3 rom/photo_print/stamp/pv/stamp_pv246_logo246_00.tga 58285ED7 rom/photo_print/stamp/pv/stamp_pv247_logo247_00.tga 84B408DA rom/photo_print/stamp/pv/stamp_pv248_logo248_00.tga EDECAD7F rom/photo_print/stamp/pv/stamp_pv249_logo249_00.tga E0325433 rom/photo_print/stamp/pv/stamp_pv250_logo250_00.tga 711B6EE9 rom/photo_print/stamp/pv/stamp_pv251_logo251_00.tga F608B3E2 rom/photo_print/stamp/pv/stamp_pv253_logo253_00.tga 67289D6D rom/photo_print/stamp/pv/stamp_pv255_logo255_00.tga 0F0516C9 rom/photo_print/stamp/pv/stamp_pv257_logo257_00.tga 30E49D9D rom/photo_print/stamp/pv/stamp_pv259_logo259_00.tga DD64190A rom/photo_print/stamp/pv/stamp_pv260_logo260_00.tga 6A54B7AE rom/photo_print/stamp/pv/stamp_pv262_logo262_00.tga 2E54B026 rom/photo_print/stamp/pv/stamp_pv265_logo265_00.tga 804B5B5C rom/photo_print/stamp/pv/stamp_pv401_logo401_00.tga 8A7DAC53 rom/photo_print/stamp/pv/stamp_pv402_logo402_00.tga 8DE9E34A rom/photo_print/stamp/pv/stamp_pv403_logo403_00.tga 940363FB rom/photo_print/stamp/pv/stamp_pv403_logo403_ex_00.tga 09737333 rom/photo_print/stamp/pv/stamp_pv404_logo404_00.tga 0FA159CD rom/photo_print/stamp/pv/stamp_pv405_logo405_00.tga 1A24905C rom/photo_print/stamp/pv/stamp_pv407_logo407_00.tga 9B9B4A5E rom/photo_print/stamp/pv/stamp_pv408_logo408_00.tga 6A3C33FA rom/photo_print/stamp/pv/stamp_pv409_logo409_00.tga 065E41EB rom/photo_print/stamp/pv/stamp_pv410_logo410_00.tga 6819687F rom/photo_print/stamp/pv/stamp_pv411_logo411_00.tga 4022ED51 rom/photo_print/stamp/pv/stamp_pv412_logo412_00.tga 2B2976E5 rom/photo_print/stamp/pv/stamp_pv414_logo414_00.tga 693517FE rom/photo_print/stamp/pv/stamp_pv415_logo415_00.tga 7D810A96 rom/photo_print/stamp/pv/stamp_pv416_logo416_00.tga 38258FE9 rom/photo_print/stamp/pv/stamp_pv417_logo417_00.tga 193EDFF6 rom/photo_print/stamp/pv/stamp_pv418_logo418_00.tga 20E52D38 rom/photo_print/stamp/pv/stamp_pv419_logo419_00.tga 8C33A6FE rom/photo_print/stamp/pv/stamp_pv420_logo420_00.tga B7B67F6F rom/photo_print/stamp/pv/stamp_pv421_logo421_00.tga 334002B8 rom/photo_print/stamp/pv/stamp_pv422_logo422_00.tga F0D9FBBF rom/photo_print/stamp/pv/stamp_pv423_logo423_00.tga 22EF7E5D rom/photo_print/stamp/pv/stamp_pv424_logo424_00.tga A92F8D20 rom/photo_print/stamp/pv/stamp_pv425_logo425_00.tga 3CEE8B84 rom/photo_print/stamp/pv/stamp_pv426_logo426_00.tga 808EFBF4 rom/photo_print/stamp/pv/stamp_pv427_logo427_00.tga 5D200B9F rom/photo_print/stamp/pv/stamp_pv429_logo429_00.tga 3E9A081E rom/photo_print/stamp/pv/stamp_pv430_logo430_00.tga A114CCD7 rom/photo_print/stamp/pv/stamp_pv431_logo431_00.tga E77924B9 rom/photo_print/stamp/pv/stamp_pv432_logo432_00.tga 5FF8A8B0 rom/photo_print/stamp/pv/stamp_pv433_logo433_00.tga 3101C130 rom/photo_print/stamp/pv/stamp_pv434_logo434_00.tga 8D80F850 rom/photo_print/stamp/pv/stamp_pv435_logo435_00.tga 547DE5B6 rom/photo_print/stamp/pv/stamp_pv436_logo436_00.tga 8806C867 rom/photo_print/stamp/pv/stamp_pv437_logo437_00.tga 8073965B rom/photo_print/stamp/pv/stamp_pv438_logo438_00.tga 2DEB99BA rom/photo_print/stamp/pv/stamp_pv439_logo439_00.tga 06643A3B rom/photo_print/stamp/pv/stamp_pv440_logo440_00.tga 90E2AE84 rom/photo_print/stamp/pv/stamp_pv441_logo441_00.tga 7DCB1872 rom/photo_print/stamp/pv/stamp_pv442_logo442_00.tga 19C087C9 rom/photo_print/stamp/pv/stamp_pv600_logo600_00.tga 6269F945 rom/photo_print/stamp/pv/stamp_pv601_logo601_00.tga EEEDD74F rom/photo_print/stamp/pv/stamp_pv602_logo602_00.tga 4AA52D98 rom/photo_print/stamp/pv/stamp_pv603_logo603_00.tga 664773C6 rom/photo_print/stamp/pv/stamp_pv604_logo604_00.tga 911B518C rom/photo_print/stamp/pv/stamp_pv605_logo605_00.tga 54C77486 rom/photo_print/stamp/pv/stamp_pv607_logo607_00.tga 3E840491 rom/photo_print/stamp/pv/stamp_pv608_logo608_00.tga 030016AF rom/photo_print/stamp/pv/stamp_pv609_logo609_00.tga 6FA56A28 rom/photo_print/stamp/pv/stamp_pv610_logo610_00.tga 4BFACCA3 rom/photo_print/stamp/pv/stamp_pv611_logo611_00.tga 9E191314 rom/photo_print/stamp/pv/stamp_pv612_logo612_00.tga F511B9CF rom/photo_print/stamp/pv/stamp_pv613_logo613_00.tga 81425F8D rom/photo_print/stamp/pv/stamp_pv614_logo614_00.tga D5A1D20C rom/photo_print/stamp/pv/stamp_pv616_logo616_00.tga DB405E1D rom/photo_print/stamp/pv/stamp_pv617_logo617_00.tga 2D12C742 rom/photo_print/stamp/pv/stamp_pv618_logo618_00.tga 10B65472 rom/photo_print/stamp/pv/stamp_pv619_logo619_00.tga A6A42B39 rom/photo_print/stamp/pv/stamp_pv620_logo620_00.tga 5AD1A210 rom/photo_print/stamp/pv/stamp_pv621_logo621_00.tga 1DB2FEB0 rom/photo_print/stamp/pv/stamp_pv622_logo622_00.tga 353FECF6 rom/photo_print/stamp/pv/stamp_pv623_logo623_00.tga 3AF24D8F rom/photo_print/stamp/pv/stamp_pv624_logo624_00.tga C86BC55E rom/photo_print/stamp/pv/stamp_pv625_logo625_00.tga A147986C rom/photo_print/stamp/pv/stamp_pv626_logo626_00.tga 059BBD4F rom/photo_print/stamp/pv/stamp_pv627_logo627_00.tga 1A997F23 rom/photo_print/stamp/pv/stamp_pv628_logo628_00.tga 055C7D1D rom/photo_print/stamp/pv/stamp_pv629_logo629_00.tga 63316CA2 rom/photo_print/stamp/pv/stamp_pv631_logo631_00.tga 0B97EB07 rom/photo_print/stamp/pv/stamp_pv637_logo637_00.tga 5E9B1887 rom/photo_print/stamp/pv/stamp_pv638_logo638_00.tga 049E1838 rom/photo_print/stamp/pv/stamp_pv639_logo639_00.tga FD512A4D rom/photo_print/stamp/pv/stamp_pv640_logo640_00.tga F8D44B3D rom/photo_print/stamp/pv/stamp_pv641_logo641_00.tga 6C3C6612 rom/photo_print/stamp/pv/stamp_pv642_logo642_00.tga 1DAF669C rom/photo_print/stamp/pv/stamp_pv710_logo710_00.tga 4C9DBCFB rom/photo_print/stamp/pv/stamp_pv722_logo722_00.tga 0C0C9CBA rom/photo_print/stamp/pv/stamp_pv723_logo723_00.tga E5E7375B rom/photo_print/stamp/pv/stamp_pv724_logo724_00.tga D45DBBF8 rom/photo_print/stamp/pv/stamp_pv725_logo725_00.tga 8699573B rom/photo_print/stamp/pv/stamp_pv726_logo726_00.tga B3F8B8A7 rom/photo_print/stamp/pv/stamp_pv727_logo727_00.tga BA0B967A rom/photo_print/stamp/pv/stamp_pv728_logo728_00.tga 0DA3E2CB rom/photo_print/stamp/pv/stamp_pv729_logo729_00.tga 96E049A9 rom/photo_print/stamp/pv/stamp_pv730_logo730_00.tga 1B9E5BDC rom/photo_print/stamp/pv/stamp_pv731_logo731_00.tga FF72A6E1 rom/photo_print/stamp/pv/stamp_pv732_logo732_00.tga 8CEA3A49 rom/photo_print/stamp/pv/stamp_pv733_logo733_00.tga 7CCD1813 rom/photo_print/stamp/pv/stamp_pv734_logo734_00.tga 18D10A5D rom/photo_print/stamp/pv/stamp_pv736_logo736_00.tga 7C1F7CC5 rom/photo_print/stamp/pv/stamp_pv737_logo737_00.tga 722C1436 rom/photo_print/stamp/pv/stamp_pv738_logo738_00.tga 5DD8A756 rom/photo_print/stamp/pv/stamp_pv739_logo739_00.tga 8772D31E rom/photo_print/stamp/pv/stamp_pv740_logo740_00.tga 77C9AEF2 rom/photo_print/stamp/pv/stamp_pv832_logo832_00.tga 7317EB58 ================================================ FILE: source-code/data/verify_mount_data.sfv ================================================ ; Generated by QuickSFV v2.36 on 2021-10-27 at 17:56:21 ; http://www.QuickSFV.org ; ; 45 15:58.08 2016-10-30 mdata/M215/info.txt ; 1056 14:19.40 2016-12-07 mdata/M215/rom/objset/mdata_obj_db.bin ; 864 14:19.40 2016-12-07 mdata/M215/rom/objset/mdata_tex_db.bin ; 1464001 14:19.40 2016-12-07 mdata/M215/rom/objset/meiitm809.farc ; 1801679 14:19.40 2016-12-07 mdata/M215/rom/objset/meiitm823.farc ; 59 11:20.49 2016-12-07 mdata/M220/info.txt ; 262629 06:41.41 2016-11-09 mdata/M220/rom/mdata_chritm_prop.farc ; 54328 11:10.31 2016-12-06 mdata/M220/rom/mdata_gm_collection_card_tbl.farc ; 21937 07:27.43 2016-11-09 mdata/M220/rom/mdata_gm_module_tbl.farc ; 130435 09:47.13 2016-12-09 mdata/M220/rom/mdata_pv_db.txt ; 927440 08:53.45 2016-12-09 mdata/M220/rom/mdata_pv_field.txt ; 54714 04:29.37 2016-11-16 mdata/M220/rom/mdata_rob_sleeve_data.txt ; 266140 11:47.36 2016-11-29 mdata/M220/rom/mdata_stage_data.bin ; 17244430 10:18.12 2016-12-02 mdata/M220/rom/osage_play_data/kaiitm043_joha_outer_43__divskn.farc ; 28461396 17:39.54 2016-10-30 mdata/M220/rom/osage_play_data/kaiitm044_joha_outer_44__divskn.farc ; 1437441 15:25.12 2016-11-25 mdata/M220/rom/osage_play_data/kaiitm543_atam_atama_43__divskn.farc ; 1712836 17:39.54 2016-10-30 mdata/M220/rom/osage_play_data/kaiitm544_atam_atama_44__divskn.farc ; 2090009 17:39.54 2016-10-30 mdata/M220/rom/osage_play_data/kaiitm708_atam_zujo_08__divskn.farc ; 2224061 12:06.03 2016-11-29 mdata/M220/rom/osage_play_data/lenitm041_joha_outer_41__divskn.farc ; 1009700 15:25.12 2016-11-25 mdata/M220/rom/osage_play_data/lenitm541_atam_atama_41__divskn.farc ; 6851122 14:12.54 2016-11-15 mdata/M220/rom/osage_play_data/lukitm043_joha_outer_43__divskn.farc ; 8108727 13:05.09 2016-11-14 mdata/M220/rom/osage_play_data/lukitm543_atam_atama_43__divskn.farc ; 1564 10:18.12 2016-12-02 mdata/M220/rom/osage_play_data/mdata_opd_db.txt ; 2408987 12:06.03 2016-11-29 mdata/M220/rom/osage_play_data/meiitm034_joha_outer_34__divskn.farc ; 2161544 15:25.12 2016-11-25 mdata/M220/rom/osage_play_data/meiitm534_atam_atama_34__divskn.farc ; 5262898 12:06.03 2016-11-29 mdata/M220/rom/osage_play_data/mikitm171_joha_outer_171__divskn.farc ; 28751224 11:28.36 2016-11-16 mdata/M220/rom/osage_play_data/mikitm172_joha_outer_172__divskn.farc ; 54885615 17:39.54 2016-10-30 mdata/M220/rom/osage_play_data/mikitm174_joha_outer_174__divskn.farc ; 11034331 08:48.04 2016-12-02 mdata/M220/rom/osage_play_data/mikitm671_atam_atama_171__divskn.farc ; 8734657 13:05.09 2016-11-14 mdata/M220/rom/osage_play_data/mikitm672_atam_atama_172__divskn.farc ; 9661531 17:39.54 2016-10-30 mdata/M220/rom/osage_play_data/mikitm674_atam_atama_174__divskn.farc ; 30446901 07:23.14 2016-11-17 mdata/M220/rom/osage_play_data/rinitm042_joha_outer_42__divskn.farc ; 6325840 15:25.12 2016-11-25 mdata/M220/rom/osage_play_data/rinitm049_joha_outer_49__divskn.farc ; 1682711 14:12.54 2016-11-15 mdata/M220/rom/osage_play_data/rinitm542_atam_atama_42__divskn.farc ; 1075061 15:25.12 2016-11-25 mdata/M220/rom/osage_play_data/rinitm549_atam_atama_49__divskn.farc ; 203150 14:12.55 2016-11-15 mdata/M220/rom/osage_play_data/rinitm722_atam_zujo_22__divskn.farc ; 1320903 14:12.55 2016-11-15 mdata/M220/rom/osage_play_data/rinitm778_joha_ushiro_78__divskn.farc ; 249994 02:39.04 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0634_01.jpg ; 195708 02:39.06 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0635_01.jpg ; 251487 02:39.07 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0636_01.jpg ; 257190 02:39.09 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0637_01.jpg ; 252768 02:39.11 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0638_01.jpg ; 257483 02:39.13 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0639_01.jpg ; 246946 02:39.15 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0640_01.jpg ; 236538 02:39.17 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0641_01.jpg ; 239023 02:39.18 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0642_01.jpg ; 275560 02:39.20 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0643_01.jpg ; 250910 02:39.22 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0644_01.jpg ; 234450 02:39.23 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0645_01.jpg ; 246921 02:38.53 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0646_01.jpg ; 247684 02:38.55 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0647_01.jpg ; 258917 02:38.57 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0648_01.jpg ; 229720 02:38.59 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0649_01.jpg ; 243356 02:39.00 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0650_01.jpg ; 226333 02:39.02 2016-12-05 mdata/M220/rom/photo_print/card/CLT_CRD0651_01.jpg ; 333652 02:42.56 2016-12-05 mdata/M220/rom/photo_print/stamp/pv/stamp_pv254_logo254_00.tga ; 365612 02:43.00 2016-12-05 mdata/M220/rom/photo_print/stamp/pv/stamp_pv263_logo263_00.tga ; 921644 02:44.25 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_399_00.tga ; 921644 02:44.28 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_413_00.tga ; 921644 02:44.30 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_414_00.tga ; 921644 02:44.33 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_415_00.tga ; 921644 02:44.35 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_416_00.tga ; 921644 02:44.38 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_417_00.tga ; 921644 02:44.40 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_418_00.tga ; 921644 02:44.17 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_419_00.tga ; 921644 02:44.21 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_424_00.tga ; 921644 02:44.23 2016-12-05 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_425_00.tga ; 6590881 09:25.50 2016-11-11 mdata/M220/rom/objset/kaiitm003.farc ; 16775763 08:52.53 2016-11-11 mdata/M220/rom/objset/kaiitm032.farc ; 14718893 16:23.34 2016-12-01 mdata/M220/rom/objset/kaiitm043.farc ; 15003404 08:52.52 2016-11-11 mdata/M220/rom/objset/kaiitm044.farc ; 1957406 03:37.18 2016-11-09 mdata/M220/rom/objset/kaiitm332.farc ; 172423 13:33.50 2016-11-07 mdata/M220/rom/objset/kaiitm343.farc ; 1891914 13:53.06 2016-11-07 mdata/M220/rom/objset/kaiitm344.farc ; 975576 08:49.05 2016-12-01 mdata/M220/rom/objset/kaiitm543.farc ; 980189 13:55.25 2016-11-07 mdata/M220/rom/objset/kaiitm544.farc ; 4553588 03:37.18 2016-11-09 mdata/M220/rom/objset/kaiitm705.farc ; 4260594 13:55.25 2016-11-07 mdata/M220/rom/objset/kaiitm708.farc ; 485333 13:33.50 2016-11-07 mdata/M220/rom/objset/kaiitm709.farc ; 459825 13:53.06 2016-11-07 mdata/M220/rom/objset/kaiitm730.farc ; 448522 13:53.06 2016-11-07 mdata/M220/rom/objset/kaiitm731.farc ; 324435 13:53.06 2016-11-07 mdata/M220/rom/objset/kaiitm832.farc ; 92457 13:33.50 2016-11-07 mdata/M220/rom/objset/kaiitm843.farc ; 324253 13:53.05 2016-11-07 mdata/M220/rom/objset/kaiitm844.farc ; 7087145 09:10.48 2016-11-08 mdata/M220/rom/objset/lenitm038.farc ; 12586321 09:48.21 2016-12-06 mdata/M220/rom/objset/lenitm041.farc ; 137442 05:05.42 2016-12-06 mdata/M220/rom/objset/lenitm341.farc ; 1944721 06:57.05 2016-12-07 mdata/M220/rom/objset/lenitm541.farc ; 489274 05:05.41 2016-12-06 mdata/M220/rom/objset/lenitm705.farc ; 39659 05:05.41 2016-12-06 mdata/M220/rom/objset/lenitm841.farc ; 9474364 12:43.19 2016-11-15 mdata/M220/rom/objset/lukitm043.farc ; 143436 07:38.58 2016-11-08 mdata/M220/rom/objset/lukitm343.farc ; 1091807 12:43.19 2016-11-15 mdata/M220/rom/objset/lukitm543.farc ; 471966 07:38.58 2016-11-08 mdata/M220/rom/objset/lukitm707.farc ; 29100 07:38.58 2016-11-08 mdata/M220/rom/objset/lukitm843.farc ; 63200 08:54.27 2016-12-08 mdata/M220/rom/objset/mdata_obj_db.bin ; 35232 08:54.27 2016-12-08 mdata/M220/rom/objset/mdata_tex_db.bin ; 9666260 08:47.34 2016-12-05 mdata/M220/rom/objset/meiitm034.farc ; 138075 07:38.58 2016-11-08 mdata/M220/rom/objset/meiitm334.farc ; 492348 07:45.23 2016-11-08 mdata/M220/rom/objset/meiitm534.farc ; 469300 07:38.58 2016-11-08 mdata/M220/rom/objset/meiitm708.farc ; 1463975 08:54.27 2016-12-08 mdata/M220/rom/objset/meiitm809.farc ; 1801717 08:54.27 2016-12-08 mdata/M220/rom/objset/meiitm823.farc ; 1467 07:38.58 2016-11-08 mdata/M220/rom/objset/meiitm834.farc ; 9713960 14:26.18 2016-11-10 mdata/M220/rom/objset/mikitm143.farc ; 9212987 13:15.59 2016-11-30 mdata/M220/rom/objset/mikitm171.farc ; 12721318 07:14.42 2016-11-11 mdata/M220/rom/objset/mikitm172.farc ; 7504045 14:26.17 2016-11-10 mdata/M220/rom/objset/mikitm174.farc ; 581503 06:44.10 2016-11-07 mdata/M220/rom/objset/mikitm443.farc ; 137797 13:33.49 2016-11-07 mdata/M220/rom/objset/mikitm471.farc ; 1150298 06:48.20 2016-11-11 mdata/M220/rom/objset/mikitm472.farc ; 541380 06:44.10 2016-11-07 mdata/M220/rom/objset/mikitm474.farc ; 3010677 06:44.09 2016-11-07 mdata/M220/rom/objset/mikitm643.farc ; 2446745 11:28.24 2016-11-30 mdata/M220/rom/objset/mikitm671.farc ; 2435746 06:50.03 2016-11-11 mdata/M220/rom/objset/mikitm672.farc ; 2595564 06:44.09 2016-11-07 mdata/M220/rom/objset/mikitm674.farc ; 1045852 06:44.08 2016-11-07 mdata/M220/rom/objset/mikitm730.farc ; 907524 06:44.08 2016-11-07 mdata/M220/rom/objset/mikitm731.farc ; 500407 13:33.49 2016-11-07 mdata/M220/rom/objset/mikitm739.farc ; 493172 06:44.08 2016-11-07 mdata/M220/rom/objset/mikitm943.farc ; 91227 13:33.49 2016-11-07 mdata/M220/rom/objset/mikitm971.farc ; 97602 06:48.20 2016-11-11 mdata/M220/rom/objset/mikitm972.farc ; 501616 06:44.08 2016-11-07 mdata/M220/rom/objset/mikitm974.farc ; 8881257 11:55.23 2016-11-30 mdata/M220/rom/objset/rinitm042.farc ; 7504007 09:10.48 2016-11-08 mdata/M220/rom/objset/rinitm045.farc ; 13886062 10:54.27 2016-11-29 mdata/M220/rom/objset/rinitm049.farc ; 159768 11:35.13 2016-11-08 mdata/M220/rom/objset/rinitm342.farc ; 154172 12:04.25 2016-11-08 mdata/M220/rom/objset/rinitm349.farc ; 1299669 09:59.08 2016-11-15 mdata/M220/rom/objset/rinitm542.farc ; 2129942 12:11.25 2016-11-08 mdata/M220/rom/objset/rinitm549.farc ; 1007314 11:59.15 2016-11-14 mdata/M220/rom/objset/rinitm722.farc ; 476353 12:04.25 2016-11-08 mdata/M220/rom/objset/rinitm723.farc ; 482328 11:49.58 2016-11-08 mdata/M220/rom/objset/rinitm778.farc ; 92761 11:35.12 2016-11-08 mdata/M220/rom/objset/rinitm842.farc ; 37396 12:04.25 2016-11-08 mdata/M220/rom/objset/rinitm849.farc ; 47070816 07:23.49 2016-12-05 mdata/M220/rom/objset/stgpv254.farc ; 18053129 07:50.17 2016-11-28 mdata/M220/rom/objset/stgpv254s01.farc ; 1522299 10:16.27 2016-12-01 mdata/M220/rom/objset/stgpv254s02.farc ; 195424 06:55.07 2016-11-28 mdata/M220/rom/objset/stgpv254s03.farc ; 10938262 07:50.17 2016-11-28 mdata/M220/rom/objset/stgpv254s04.farc ; 3753932 07:08.16 2016-11-28 mdata/M220/rom/objset/stgpv254s05.farc ; 4109714 07:29.46 2016-11-29 mdata/M220/rom/objset/stgpv254s08.farc ; 31156 07:11.22 2016-11-28 mdata/M220/rom/objset/stgpv254s09.farc ; 10878 07:13.30 2016-11-28 mdata/M220/rom/objset/stgpv254s12.farc ; 90857 07:25.37 2016-11-28 mdata/M220/rom/objset/stgpv254s13.farc ; 45687 07:23.49 2016-12-05 mdata/M220/rom/objset/stgpv254s17.farc ; 14835919 06:33.18 2016-12-05 mdata/M220/rom/objset/stgpv263.farc ; 392185 06:42.20 2016-11-14 mdata/M220/rom/objset/stgpv263hrc.farc ; 196382 05:44.14 2016-11-14 mdata/M220/rom/objset/stgpv263s01.farc ; 6948960 06:33.17 2016-12-05 mdata/M220/rom/objset/stgpv263s02.farc ; 156409 05:55.16 2016-11-14 mdata/M220/rom/objset/stgpv263s03.farc ; 22143 05:55.16 2016-11-14 mdata/M220/rom/objset/stgpv263s04.farc ; 4762283 05:55.16 2016-11-14 mdata/M220/rom/objset/stgpv263s05.farc ; 784427 06:01.20 2016-11-14 mdata/M220/rom/objset/stgpv263s06.farc ; 796871 06:01.20 2016-11-14 mdata/M220/rom/objset/stgpv263s07.farc ; 10024 06:01.20 2016-11-14 mdata/M220/rom/objset/stgpv263s08.farc ; 23388133 06:37.31 2016-11-14 mdata/M220/rom/objset/stgpv263s09.farc ; 9121837 06:37.30 2016-11-14 mdata/M220/rom/objset/stgpv263s10.farc ; 1162843 06:37.30 2016-11-14 mdata/M220/rom/objset/stgpv263s11.farc ; 791085 06:37.30 2016-11-14 mdata/M220/rom/objset/stgpv263s12.farc ; 57684 05:17.22 2016-12-01 mdata/M220/rom/script/pv_041_easy.dsc ; 67284 05:17.22 2016-12-01 mdata/M220/rom/script/pv_041_extreme.dsc ; 84644 05:17.22 2016-12-01 mdata/M220/rom/script/pv_041_extreme_1.dsc ; 64492 05:17.22 2016-12-01 mdata/M220/rom/script/pv_041_hard.dsc ; 61324 05:17.22 2016-12-01 mdata/M220/rom/script/pv_041_normal.dsc ; 36840 08:39.30 2016-12-06 mdata/M220/rom/script/pv_218_extreme.dsc ; 57272 08:39.30 2016-12-06 mdata/M220/rom/script/pv_218_extreme_1.dsc ; 34288 08:39.30 2016-12-06 mdata/M220/rom/script/pv_218_hard.dsc ; 29400 08:39.30 2016-12-06 mdata/M220/rom/script/pv_218_normal.dsc ; 49692 15:30.01 2016-11-30 mdata/M220/rom/script/pv_222_extreme.dsc ; 85684 15:30.01 2016-11-30 mdata/M220/rom/script/pv_222_extreme_1.dsc ; 45972 15:30.01 2016-11-30 mdata/M220/rom/script/pv_222_hard.dsc ; 41036 15:30.01 2016-11-30 mdata/M220/rom/script/pv_222_normal.dsc ; 62868 09:11.48 2016-12-05 mdata/M220/rom/script/pv_254_easy.dsc ; 94852 09:11.48 2016-12-05 mdata/M220/rom/script/pv_254_extreme.dsc ; 82732 09:11.48 2016-12-05 mdata/M220/rom/script/pv_254_hard.dsc ; 68100 09:11.48 2016-12-05 mdata/M220/rom/script/pv_254_normal.dsc ; 18460 08:14.27 2016-12-06 mdata/M220/rom/script/pv_263_easy.dsc ; 42716 08:14.27 2016-12-06 mdata/M220/rom/script/pv_263_extreme.dsc ; 30988 08:14.27 2016-12-06 mdata/M220/rom/script/pv_263_hard.dsc ; 21236 08:14.27 2016-12-06 mdata/M220/rom/script/pv_263_normal.dsc ; 30268 08:58.14 2016-12-05 mdata/M220/rom/script/pv_431_extreme.dsc ; 48660 08:58.14 2016-12-05 mdata/M220/rom/script/pv_431_extreme_1.dsc ; 22812 08:58.14 2016-12-05 mdata/M220/rom/script/pv_431_hard.dsc ; 19100 08:58.14 2016-12-05 mdata/M220/rom/script/pv_431_normal.dsc ; 48424 13:14.05 2016-11-15 mdata/M220/rom/script/pv_602_easy.dsc ; 60096 13:14.05 2016-11-15 mdata/M220/rom/script/pv_602_extreme.dsc ; 57800 13:14.05 2016-11-15 mdata/M220/rom/script/pv_602_hard.dsc ; 52544 13:14.05 2016-11-15 mdata/M220/rom/script/pv_602_normal.dsc ; 33164 08:51.03 2016-12-02 mdata/M220/rom/script/pv_630_easy.dsc ; 43580 08:51.03 2016-12-02 mdata/M220/rom/script/pv_630_extreme.dsc ; 40556 08:51.03 2016-12-02 mdata/M220/rom/script/pv_630_hard.dsc ; 37540 08:51.03 2016-12-02 mdata/M220/rom/script/pv_630_normal.dsc ; 2444 12:06.48 2016-11-29 mdata/M220/rom/pv_expression/exp_PV254.bin ; 6540 14:04.55 2016-11-14 mdata/M220/rom/pv_expression/exp_PV263.bin ; 1599 09:15.44 2016-12-01 mdata/M220/rom/rob/mdata_mot_db.farc ; 13135030 12:11.48 2016-11-29 mdata/M220/rom/rob/mot_PV254.farc ; 7486095 10:03.27 2016-11-15 mdata/M220/rom/rob/mot_PV263.farc ; 10835915 09:15.44 2016-12-01 mdata/M220/rom/rob/mot_PV728.farc ; 13376 09:37.47 2016-12-09 mdata/M220/rom/rob/mothead_PV254.bin ; 11680 15:40.20 2016-12-09 mdata/M220/rom/rob/mothead_PV263.bin ; 371028 05:29.08 2016-12-01 mdata/M220/rom/auth_3d/CAMPV254.farc ; 141029 10:43.09 2016-11-10 mdata/M220/rom/auth_3d/CAMPV263.farc ; 664077 08:10.00 2016-12-02 mdata/M220/rom/auth_3d/EFFSTGPV254.farc ; 2261797 10:37.39 2016-12-02 mdata/M220/rom/auth_3d/EFFSTGPV263.farc ; 4171 10:37.38 2016-12-02 mdata/M220/rom/auth_3d/mdata_auth_3d_db.bin ; 225775 16:23.14 2016-12-01 mdata/M220/rom/skin_param/ext_skp_kaiitm043_joha_outer_43__divskn.txt ; 181925 08:52.30 2016-11-11 mdata/M220/rom/skin_param/ext_skp_kaiitm044_joha_outer_44__divskn.txt ; 21184 08:48.48 2016-12-01 mdata/M220/rom/skin_param/ext_skp_kaiitm543_atam_atama_43__divskn.txt ; 29683 13:55.24 2016-11-07 mdata/M220/rom/skin_param/ext_skp_kaiitm544_atam_atama_44__divskn.txt ; 12718 13:55.24 2016-11-07 mdata/M220/rom/skin_param/ext_skp_kaiitm708_atam_zujo_08__divskn.txt ; 65883 09:47.56 2016-12-06 mdata/M220/rom/skin_param/ext_skp_lenitm041_joha_outer_41__divskn.txt ; 14967 06:56.47 2016-12-07 mdata/M220/rom/skin_param/ext_skp_lenitm541_atam_atama_41__divskn.txt ; 133072 12:43.01 2016-11-15 mdata/M220/rom/skin_param/ext_skp_lukitm043_joha_outer_43__divskn.txt ; 99386 12:43.01 2016-11-15 mdata/M220/rom/skin_param/ext_skp_lukitm543_atam_atama_43__divskn.txt ; 59984 08:47.15 2016-12-05 mdata/M220/rom/skin_param/ext_skp_meiitm034_joha_outer_34__divskn.txt ; 25591 07:45.23 2016-11-08 mdata/M220/rom/skin_param/ext_skp_meiitm534_atam_atama_34__divskn.txt ; 118388 13:15.40 2016-11-30 mdata/M220/rom/skin_param/ext_skp_mikitm171_joha_outer_171__divskn.txt ; 347548 07:14.29 2016-11-11 mdata/M220/rom/skin_param/ext_skp_mikitm172_joha_outer_172__divskn.txt ; 434749 14:25.33 2016-11-10 mdata/M220/rom/skin_param/ext_skp_mikitm174_joha_outer_174__divskn.txt ; 64401 11:28.00 2016-11-30 mdata/M220/rom/skin_param/ext_skp_mikitm671_atam_atama_171__divskn.txt ; 63063 06:50.03 2016-11-11 mdata/M220/rom/skin_param/ext_skp_mikitm672_atam_atama_172__divskn.txt ; 57912 06:43.04 2016-11-07 mdata/M220/rom/skin_param/ext_skp_mikitm674_atam_atama_174__divskn.txt ; 303532 11:55.02 2016-11-30 mdata/M220/rom/skin_param/ext_skp_rinitm042_joha_outer_42__divskn.txt ; 142181 10:54.09 2016-11-29 mdata/M220/rom/skin_param/ext_skp_rinitm049_joha_outer_49__divskn.txt ; 43569 09:59.08 2016-11-15 mdata/M220/rom/skin_param/ext_skp_rinitm542_atam_atama_42__divskn.txt ; 13377 12:11.25 2016-11-08 mdata/M220/rom/skin_param/ext_skp_rinitm549_atam_atama_49__divskn.txt ; 1493 11:59.15 2016-11-14 mdata/M220/rom/skin_param/ext_skp_rinitm722_atam_zujo_22__divskn.txt ; 11678 11:49.57 2016-11-08 mdata/M220/rom/skin_param/ext_skp_rinitm778_joha_ushiro_78__divskn.txt ; 18005 04:17.46 2016-11-10 mdata/M220/rom/skin_param/mdata_osage_setting.txt ; 137592774 11:10.45 2016-12-09 mdata/M220/rom/skin_param/mdata_sp_skp.farc ; 849273 11:10.45 2016-12-09 mdata/M220/rom/skin_param/mdata_sp_skp_db.txt ; 282 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s01.txt ; 280 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s02.txt ; 280 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s03.txt ; 280 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s05.txt ; 280 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s06.txt ; 280 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s07.txt ; 280 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s09.txt ; 280 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s13.txt ; 280 05:20.01 2016-12-01 mdata/M220/rom/stage_param/star_pv254s17.txt ; 19561460 12:08.05 2016-12-06 mdata/M220/rom/sound/song/pv_254.ogg ; 9728258 06:34.15 2016-12-06 mdata/M220/rom/sound/song/pv_263.ogg ; 9453567 06:35.45 2016-12-06 mdata/M220/rom/sound/song/pv_263_kai.ogg ; 9776917 06:37.03 2016-12-06 mdata/M220/rom/sound/song/pv_263_len.ogg ; 9453732 06:39.51 2016-12-06 mdata/M220/rom/sound/song/pv_263_luk.ogg ; 9496233 06:41.51 2016-12-06 mdata/M220/rom/sound/song/pv_263_mei.ogg ; 9768042 06:43.10 2016-12-06 mdata/M220/rom/sound/song/pv_263_rin.ogg ; 549580 10:31.36 2016-12-01 mdata/M220/rom/2d/aet_gam_pv254.bin ; 280784 03:41.29 2016-11-28 mdata/M220/rom/2d/aet_gam_pv255.bin ; 228344 12:02.16 2016-12-05 mdata/M220/rom/2d/aet_gam_pv263.bin ; 379348 02:18.31 2016-11-17 mdata/M220/rom/2d/aet_gam_pv724.bin ; 172108 08:33.12 2016-11-17 mdata/M220/rom/2d/aet_gam_pv832.bin ; 1500 11:40.25 2016-12-02 mdata/M220/rom/2d/aet_gam_skin739.bin ; 568 12:02.21 2016-12-05 mdata/M220/rom/2d/mdata_aet_db.bin ; 23756 12:23.10 2016-12-05 mdata/M220/rom/2d/mdata_spr_db.bin ; 44314 03:13.57 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0634.farc ; 28280 03:13.58 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0635.farc ; 45537 03:13.58 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0636.farc ; 45679 03:13.58 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0637.farc ; 44993 03:13.58 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0638.farc ; 45561 03:13.58 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0639.farc ; 45670 03:13.58 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0640.farc ; 45472 03:13.59 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0641.farc ; 45773 03:13.59 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0642.farc ; 46877 03:13.59 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0643.farc ; 45386 03:13.59 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0644.farc ; 43554 03:13.59 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0645.farc ; 44628 03:13.59 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0646.farc ; 44827 03:13.54 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0647.farc ; 46027 03:13.54 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0648.farc ; 43918 03:13.54 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0649.farc ; 45204 03:13.54 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0650.farc ; 43114 03:13.55 2016-12-05 mdata/M220/rom/2d/spr_clt_crd0651.farc ; 3853499 11:11.45 2016-12-01 mdata/M220/rom/2d/spr_gam_pv254.farc ; 1871482 04:13.42 2016-11-28 mdata/M220/rom/2d/spr_gam_pv255.farc ; 4581583 12:22.56 2016-12-05 mdata/M220/rom/2d/spr_gam_pv263.farc ; 381440 02:29.41 2016-11-17 mdata/M220/rom/2d/spr_gam_pv724.farc ; 1106829 08:39.14 2016-11-17 mdata/M220/rom/2d/spr_gam_pv832.farc ; 166837 11:47.56 2016-12-02 mdata/M220/rom/2d/spr_gam_skin739.farc ; 21254 03:13.55 2016-12-05 mdata/M220/rom/2d/spr_sel_md399cmn.farc ; 17710 03:13.55 2016-12-05 mdata/M220/rom/2d/spr_sel_md413cmn.farc ; 14533 03:13.55 2016-12-05 mdata/M220/rom/2d/spr_sel_md414cmn.farc ; 16938 03:13.55 2016-12-05 mdata/M220/rom/2d/spr_sel_md415cmn.farc ; 14756 03:13.55 2016-12-05 mdata/M220/rom/2d/spr_sel_md416cmn.farc ; 20349 03:13.55 2016-12-05 mdata/M220/rom/2d/spr_sel_md417cmn.farc ; 14218 03:13.55 2016-12-05 mdata/M220/rom/2d/spr_sel_md418cmn.farc ; 25269 03:13.56 2016-12-05 mdata/M220/rom/2d/spr_sel_md419cmn.farc ; 29859 03:13.56 2016-12-05 mdata/M220/rom/2d/spr_sel_md424cmn.farc ; 19769 03:13.57 2016-12-05 mdata/M220/rom/2d/spr_sel_md425cmn.farc ; 557786 11:18.58 2016-11-07 mdata/M220/rom/2d/spr_sel_pv254.farc ; 276313 13:11.39 2016-11-17 mdata/M220/rom/2d/spr_sel_pv263.farc ; 34511 08:53.59 2016-12-09 mdata/M220/rom/particle/eff_pv254_c34_korobi.farc ; 28767 08:54.00 2016-12-09 mdata/M220/rom/particle/eff_pv254_c36_korobi.farc ; 354088 08:54.00 2016-12-09 mdata/M220/rom/particle/eff_pv254_c37_kusarakka.farc ; 808796 08:54.01 2016-12-09 mdata/M220/rom/particle/eff_pv254_c43_onibi.farc ; 209045 08:54.01 2016-12-09 mdata/M220/rom/particle/eff_pv254_jinja_tourou.farc ; 49560 08:54.02 2016-12-09 mdata/M220/rom/particle/eff_pv254_kirakira_aura.farc ; 120362 08:54.02 2016-12-09 mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut15.farc ; 256378 08:54.03 2016-12-09 mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut31.farc ; 575898 08:54.03 2016-12-09 mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut39.farc ; 179082 08:54.04 2016-12-09 mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut42.farc ; 130010 08:54.04 2016-12-09 mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut44.farc ; 49575 08:54.05 2016-12-09 mdata/M220/rom/particle/eff_pv254_kirakira_aura_test.farc ; 658286 08:54.05 2016-12-09 mdata/M220/rom/particle/eff_pv254_lightball_cut29.farc ; 1460541 08:54.06 2016-12-09 mdata/M220/rom/particle/eff_pv254_moon.farc ; 62737 08:54.06 2016-12-09 mdata/M220/rom/particle/eff_pv254_nagarebosi_cut11.farc ; 738432 08:54.07 2016-12-09 mdata/M220/rom/particle/eff_pv254_rakka.farc ; 74700 08:53.58 2016-12-09 mdata/M220/rom/particle/eff_pv254s01_hotaru.farc ; 466172 08:53.59 2016-12-09 mdata/M220/rom/particle/eff_pv254S04_spirit.farc ; 343 07:07.48 2016-11-30 mdata/M220/rom/light_param/fog_pv254s01.txt ; 338 07:07.48 2016-11-30 mdata/M220/rom/light_param/fog_pv254s02.txt ; 338 07:07.49 2016-11-30 mdata/M220/rom/light_param/fog_pv254s03.txt ; 338 07:07.49 2016-11-30 mdata/M220/rom/light_param/fog_pv254s05.txt ; 338 08:57.40 2016-12-01 mdata/M220/rom/light_param/fog_pv254s06.txt ; 338 07:07.49 2016-11-30 mdata/M220/rom/light_param/fog_pv254s07.txt ; 338 07:07.49 2016-11-30 mdata/M220/rom/light_param/fog_pv254s08.txt ; 343 07:07.49 2016-11-30 mdata/M220/rom/light_param/fog_pv254s09.txt ; 342 07:07.49 2016-11-30 mdata/M220/rom/light_param/fog_pv254s13.txt ; 341 06:15.49 2016-11-10 mdata/M220/rom/light_param/fog_pv263s01.txt ; 341 05:26.04 2016-11-10 mdata/M220/rom/light_param/fog_pv263s03.txt ; 341 05:26.04 2016-11-10 mdata/M220/rom/light_param/fog_pv263s07.txt ; 343 05:26.04 2016-11-10 mdata/M220/rom/light_param/fog_pv263s10.txt ; 339 05:26.05 2016-11-10 mdata/M220/rom/light_param/fog_pv263s11.txt ; 321 07:07.48 2016-11-30 mdata/M220/rom/light_param/glow_pv254s01.txt ; 321 07:07.48 2016-11-30 mdata/M220/rom/light_param/glow_pv254s02.txt ; 321 07:07.49 2016-11-30 mdata/M220/rom/light_param/glow_pv254s03.txt ; 321 07:07.49 2016-11-30 mdata/M220/rom/light_param/glow_pv254s05.txt ; 321 08:57.40 2016-12-01 mdata/M220/rom/light_param/glow_pv254s06.txt ; 321 07:07.49 2016-11-30 mdata/M220/rom/light_param/glow_pv254s07.txt ; 321 07:07.49 2016-11-30 mdata/M220/rom/light_param/glow_pv254s08.txt ; 321 07:07.49 2016-11-30 mdata/M220/rom/light_param/glow_pv254s09.txt ; 323 07:07.49 2016-11-30 mdata/M220/rom/light_param/glow_pv254s13.txt ; 319 07:07.49 2016-11-30 mdata/M220/rom/light_param/glow_pv254s17.txt ; 321 06:15.49 2016-11-10 mdata/M220/rom/light_param/glow_pv263s01.txt ; 321 05:26.04 2016-11-10 mdata/M220/rom/light_param/glow_pv263s03.txt ; 321 05:26.04 2016-11-10 mdata/M220/rom/light_param/glow_pv263s05.txt ; 320 05:26.04 2016-11-10 mdata/M220/rom/light_param/glow_pv263s07.txt ; 322 05:26.05 2016-11-10 mdata/M220/rom/light_param/glow_pv263s10.txt ; 319 05:26.05 2016-11-10 mdata/M220/rom/light_param/glow_pv263s11.txt ; 13907 08:34.46 2016-12-05 mdata/M220/rom/light_param/light_pv254.farc ; 1708 07:07.48 2016-11-30 mdata/M220/rom/light_param/light_pv254s01.txt ; 1709 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s02.txt ; 1709 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s03.txt ; 1706 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s05.txt ; 1709 08:57.40 2016-12-01 mdata/M220/rom/light_param/light_pv254s06.txt ; 1709 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s07.txt ; 1705 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s08.txt ; 1705 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s09.txt ; 1693 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s12.txt ; 1708 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s13.txt ; 1698 07:07.49 2016-11-30 mdata/M220/rom/light_param/light_pv254s17.txt ; 21467 05:26.17 2016-11-10 mdata/M220/rom/light_param/light_pv263.farc ; 1693 06:15.49 2016-11-10 mdata/M220/rom/light_param/light_pv263s01.txt ; 1695 05:26.04 2016-11-10 mdata/M220/rom/light_param/light_pv263s03.txt ; 1696 05:26.04 2016-11-10 mdata/M220/rom/light_param/light_pv263s04.txt ; 1697 05:26.04 2016-11-10 mdata/M220/rom/light_param/light_pv263s07.txt ; 1693 05:26.05 2016-11-10 mdata/M220/rom/light_param/light_pv263s10.txt ; 206 07:07.48 2016-11-30 mdata/M220/rom/light_param/wind_pv254s01.txt ; 219 07:07.49 2016-11-30 mdata/M220/rom/light_param/wind_pv254s02.txt ; 206 08:57.40 2016-12-01 mdata/M220/rom/light_param/wind_pv254s06.txt ; 206 07:07.49 2016-11-30 mdata/M220/rom/light_param/wind_pv254s17.txt ; 202 06:15.49 2016-11-10 mdata/M220/rom/light_param/wind_pv263s01.txt ; 213 05:26.04 2016-11-10 mdata/M220/rom/light_param/wind_pv263s02.txt ; 217 06:41.45 2016-11-10 mdata/M220/rom/light_param/wind_pv263s06.txt ; 220 06:53.40 2016-11-10 mdata/M220/rom/light_param/wind_pv263s09.txt ; 217 06:58.52 2016-11-10 mdata/M220/rom/light_param/wind_pv263s12.txt ; 73 07:22.09 2016-12-27 mdata/M230/info.txt ; 263201 10:04.28 2017-09-25 mdata/M230/rom/mdata_chritm_prop.farc ; 54658 10:58.41 2017-10-02 mdata/M230/rom/mdata_gm_collection_card_tbl.farc ; 22065 03:05.52 2017-09-27 mdata/M230/rom/mdata_gm_module_tbl.farc ; 181582 08:26.40 2017-10-12 mdata/M230/rom/mdata_pv_db.txt ; 1110153 09:49.18 2017-10-12 mdata/M230/rom/mdata_pv_field.txt ; 55116 03:03.07 2017-09-27 mdata/M230/rom/mdata_rob_sleeve_data.txt ; 267420 09:17.57 2017-09-25 mdata/M230/rom/mdata_stage_data.bin ; 1909 11:17.40 2017-10-03 mdata/M230/rom/osage_play_data/mdata_opd_db.txt ; 4637742 11:17.42 2017-10-03 mdata/M230/rom/osage_play_data/mikitm175_joha_outer_175__divskn.farc ; 8430851 11:17.42 2017-10-03 mdata/M230/rom/osage_play_data/mikitm176_joha_outer_176__divskn.farc ; 20269212 11:17.42 2017-10-03 mdata/M230/rom/osage_play_data/mikitm675_atam_atama_175__divskn.farc ; 27079446 11:17.42 2017-10-03 mdata/M230/rom/osage_play_data/mikitm676_atam_atama_176__divskn.farc ; 8025029 11:17.42 2017-10-03 mdata/M230/rom/osage_play_data/mikitm785_joha_ushiro_85__divskn.farc ; 269312 02:54.45 2017-10-02 mdata/M230/rom/photo_print/card/CLT_CRD0652_01.jpg ; 205792 02:54.35 2017-10-02 mdata/M230/rom/photo_print/card/CLT_CRD0653_01.jpg ; 266721 02:54.57 2017-10-02 mdata/M230/rom/photo_print/card/CLT_CRD0654_01.jpg ; 299566 02:55.20 2017-10-02 mdata/M230/rom/photo_print/card/CLT_CRD0655_01.jpg ; 341184 02:58.20 2017-09-26 mdata/M230/rom/photo_print/stamp/pv/stamp_pv266_logo266_00.tga ; 354188 02:58.21 2017-09-26 mdata/M230/rom/photo_print/stamp/pv/stamp_pv267_logo267_00.tga ; 921644 02:54.25 2017-09-26 mdata/M230/rom/photo_print/stamp/module/stamp_md_sub_426_00.tga ; 921644 02:54.26 2017-09-26 mdata/M230/rom/photo_print/stamp/module/stamp_md_sub_427_00.tga ; 93232304 03:33.17 2017-08-29 mdata/M230/rom/movie/adv_sega_cm.wmv ; 163446513 13:42.26 2017-07-07 mdata/M230/rom/movie/pv_267.wmv ; 72928 08:19.25 2017-09-27 mdata/M230/rom/objset/mdata_obj_db.bin ; 45792 08:19.25 2017-09-27 mdata/M230/rom/objset/mdata_tex_db.bin ; 2648067 10:01.56 2017-09-25 mdata/M230/rom/objset/mikitm175.farc ; 6143775 10:01.56 2017-09-25 mdata/M230/rom/objset/mikitm176.farc ; 733533 09:48.43 2017-09-25 mdata/M230/rom/objset/mikitm475.farc ; 1892721 10:01.56 2017-09-25 mdata/M230/rom/objset/mikitm675.farc ; 2347341 10:01.56 2017-09-25 mdata/M230/rom/objset/mikitm676.farc ; 893021 10:01.56 2017-09-25 mdata/M230/rom/objset/mikitm785.farc ; 42599 09:48.43 2017-09-25 mdata/M230/rom/objset/mikitm975.farc ; 44492164 08:19.25 2017-09-27 mdata/M230/rom/objset/stgpv266.farc ; 2232182 10:55.11 2017-09-25 mdata/M230/rom/objset/stgpv266hrc.farc ; 4411867 11:49.20 2017-09-25 mdata/M230/rom/objset/stgpv266s01.farc ; 13198530 08:19.24 2017-09-27 mdata/M230/rom/objset/stgpv266s02.farc ; 79489 07:44.12 2017-09-25 mdata/M230/rom/objset/stgpv266s03.farc ; 1382 07:44.12 2017-09-25 mdata/M230/rom/objset/stgpv266s04.farc ; 2668 07:46.59 2017-09-25 mdata/M230/rom/objset/stgpv266s05.farc ; 50824 06:55.10 2017-10-10 mdata/M230/rom/script/pv_044_easy.dsc ; 61256 06:55.10 2017-10-10 mdata/M230/rom/script/pv_044_extreme.dsc ; 69928 09:49.18 2017-10-12 mdata/M230/rom/script/pv_044_extreme_1.dsc ; 57176 06:55.10 2017-10-10 mdata/M230/rom/script/pv_044_hard.dsc ; 53288 06:55.10 2017-10-10 mdata/M230/rom/script/pv_044_normal.dsc ; 27612 06:59.35 2017-10-10 mdata/M230/rom/script/pv_091_easy.dsc ; 58708 06:59.35 2017-10-10 mdata/M230/rom/script/pv_091_extreme.dsc ; 73828 09:49.18 2017-10-12 mdata/M230/rom/script/pv_091_extreme_1.dsc ; 48500 06:59.35 2017-10-10 mdata/M230/rom/script/pv_091_hard.dsc ; 43484 06:59.35 2017-10-10 mdata/M230/rom/script/pv_091_normal.dsc ; 24584 07:02.35 2017-10-10 mdata/M230/rom/script/pv_204_easy.dsc ; 33528 07:02.35 2017-10-10 mdata/M230/rom/script/pv_204_extreme.dsc ; 49280 07:02.35 2017-10-10 mdata/M230/rom/script/pv_204_extreme_1.dsc ; 28680 07:02.35 2017-10-10 mdata/M230/rom/script/pv_204_hard.dsc ; 27224 07:02.35 2017-10-10 mdata/M230/rom/script/pv_204_normal.dsc ; 24504 07:06.01 2017-10-10 mdata/M230/rom/script/pv_215_extreme.dsc ; 38872 07:06.01 2017-10-10 mdata/M230/rom/script/pv_215_extreme_1.dsc ; 20600 07:06.01 2017-10-10 mdata/M230/rom/script/pv_215_hard.dsc ; 17784 07:06.01 2017-10-10 mdata/M230/rom/script/pv_215_normal.dsc ; 37748 04:00.16 2017-09-27 mdata/M230/rom/script/pv_262_easy.dsc ; 70924 04:00.16 2017-09-27 mdata/M230/rom/script/pv_262_extreme.dsc ; 51884 04:00.16 2017-09-27 mdata/M230/rom/script/pv_262_hard.dsc ; 42164 04:00.16 2017-09-27 mdata/M230/rom/script/pv_262_normal.dsc ; 52104 10:02.47 2017-10-13 mdata/M230/rom/script/pv_266_easy.dsc ; 75936 10:02.47 2017-10-13 mdata/M230/rom/script/pv_266_extreme.dsc ; 72144 10:02.47 2017-10-13 mdata/M230/rom/script/pv_266_hard.dsc ; 59744 10:02.47 2017-10-13 mdata/M230/rom/script/pv_266_normal.dsc ; 17496 04:41.18 2017-09-25 mdata/M230/rom/script/pv_267_easy.dsc ; 45552 04:41.18 2017-09-25 mdata/M230/rom/script/pv_267_extreme.dsc ; 40864 04:41.18 2017-09-25 mdata/M230/rom/script/pv_267_hard.dsc ; 28392 04:41.18 2017-09-25 mdata/M230/rom/script/pv_267_normal.dsc ; 62840 07:10.35 2017-10-10 mdata/M230/rom/script/pv_417_extreme.dsc ; 74504 07:10.35 2017-10-10 mdata/M230/rom/script/pv_417_extreme_1.dsc ; 57352 07:10.35 2017-10-10 mdata/M230/rom/script/pv_417_hard.dsc ; 55120 07:10.35 2017-10-10 mdata/M230/rom/script/pv_417_normal.dsc ; 106984 07:13.44 2017-10-10 mdata/M230/rom/script/pv_425_extreme.dsc ; 125616 07:13.44 2017-10-10 mdata/M230/rom/script/pv_425_extreme_1.dsc ; 103888 07:13.44 2017-10-10 mdata/M230/rom/script/pv_425_hard.dsc ; 99696 07:13.44 2017-10-10 mdata/M230/rom/script/pv_425_normal.dsc ; 42188 07:16.49 2017-10-10 mdata/M230/rom/script/pv_427_easy.dsc ; 49060 07:16.49 2017-10-10 mdata/M230/rom/script/pv_427_extreme.dsc ; 68004 07:16.49 2017-10-10 mdata/M230/rom/script/pv_427_extreme_1.dsc ; 47284 07:16.49 2017-10-10 mdata/M230/rom/script/pv_427_hard.dsc ; 45636 07:16.49 2017-10-10 mdata/M230/rom/script/pv_427_normal.dsc ; 63196 08:06.18 2017-09-26 mdata/M230/rom/script/pv_727_easy.dsc ; 75604 08:06.18 2017-09-26 mdata/M230/rom/script/pv_727_extreme.dsc ; 73068 08:06.18 2017-09-26 mdata/M230/rom/script/pv_727_hard.dsc ; 68372 08:06.18 2017-09-26 mdata/M230/rom/script/pv_727_normal.dsc ; 8268 11:59.47 2017-09-25 mdata/M230/rom/pv_expression/exp_PV266.bin ; 1626 08:05.15 2017-09-25 mdata/M230/rom/rob/mdata_mot_db.farc ; 7147482 08:05.15 2017-09-25 mdata/M230/rom/rob/mot_PV266.farc ; 16576 09:39.30 2017-10-03 mdata/M230/rom/rob/mothead_PV266.bin ; 698676 10:02.47 2017-10-13 mdata/M230/rom/auth_3d/CAMPV266.farc ; 37622128 10:02.47 2017-10-13 mdata/M230/rom/auth_3d/EFFSTGPV266.farc ; 10748 14:34.15 2017-09-25 mdata/M230/rom/auth_3d/mdata_auth_3d_db.bin ; 65513 10:01.56 2017-09-25 mdata/M230/rom/skin_param/ext_skp_mikitm175_joha_outer_175__divskn.txt ; 180292 10:01.56 2017-09-25 mdata/M230/rom/skin_param/ext_skp_mikitm176_joha_outer_176__divskn.txt ; 80163 10:01.56 2017-09-25 mdata/M230/rom/skin_param/ext_skp_mikitm675_atam_atama_175__divskn.txt ; 97791 10:01.56 2017-09-25 mdata/M230/rom/skin_param/ext_skp_mikitm676_atam_atama_176__divskn.txt ; 33725 10:01.55 2017-09-25 mdata/M230/rom/skin_param/ext_skp_mikitm785_joha_ushiro_85__divskn.txt ; 18141 10:23.54 2017-09-26 mdata/M230/rom/skin_param/mdata_osage_setting.txt ; 146641565 09:22.31 2017-09-26 mdata/M230/rom/skin_param/mdata_sp_skp.farc ; 937211 09:22.35 2017-09-26 mdata/M230/rom/skin_param/mdata_sp_skp_db.txt ; 21064803 03:41.27 2017-10-04 mdata/M230/rom/sound/song/pv_266.ogg ; 25096749 12:07.14 2017-10-05 mdata/M230/rom/sound/song/pv_267.ogg ; 177948 04:37.57 2017-09-25 mdata/M230/rom/2d/aet_gam_pv266.bin ; 652 04:38.02 2017-09-25 mdata/M230/rom/2d/mdata_aet_db.bin ; 34408 12:31.51 2017-10-02 mdata/M230/rom/2d/mdata_spr_db.bin ; 47138 12:31.34 2017-10-02 mdata/M230/rom/2d/spr_clt_crd0652.farc ; 38180 12:31.33 2017-10-02 mdata/M230/rom/2d/spr_clt_crd0653.farc ; 46010 12:31.33 2017-10-02 mdata/M230/rom/2d/spr_clt_crd0654.farc ; 47297 12:31.33 2017-10-02 mdata/M230/rom/2d/spr_clt_crd0655.farc ; 4449478 05:12.28 2017-09-25 mdata/M230/rom/2d/spr_gam_pv266.farc ; 19164 05:26.18 2017-09-25 mdata/M230/rom/2d/spr_sel_md426cmn.farc ; 42235 05:26.18 2017-09-25 mdata/M230/rom/2d/spr_sel_md427cmn.farc ; 589905 05:26.18 2017-09-25 mdata/M230/rom/2d/spr_sel_pv266.farc ; 262935 05:26.18 2017-09-25 mdata/M230/rom/2d/spr_sel_pv267.farc ; 1704678 12:56.06 2017-09-25 mdata/M230/rom/particle/eff_PV266_thunder.farc ; 349748 12:56.01 2017-09-25 mdata/M230/rom/particle/eff_pv266s01_addfloor_rouya.farc ; 1918518 12:56.02 2017-09-25 mdata/M230/rom/particle/eff_pv266s01_fire.farc ; 173564 12:56.02 2017-09-25 mdata/M230/rom/particle/eff_pv266s01_kuzure.farc ; 1570751 12:56.03 2017-09-25 mdata/M230/rom/particle/eff_pv266s01_otimono.farc ; 597558 12:56.03 2017-09-25 mdata/M230/rom/particle/eff_pv266s01_susu.farc ; 3775442 12:56.04 2017-09-25 mdata/M230/rom/particle/eff_pv266s02_kirakira.farc ; 3599281 12:56.05 2017-09-25 mdata/M230/rom/particle/eff_pv266s02_kirakira_stop.farc ; 2693929 12:56.05 2017-09-25 mdata/M230/rom/particle/eff_pv266s02_rakka.farc ; 341 09:22.05 2017-09-25 mdata/M230/rom/light_param/fog_pv266s01.txt ; 341 09:22.00 2017-09-25 mdata/M230/rom/light_param/fog_pv266s02.txt ; 340 09:22.00 2017-09-25 mdata/M230/rom/light_param/fog_pv266s03.txt ; 323 09:22.05 2017-09-25 mdata/M230/rom/light_param/glow_pv266s01.txt ; 318 09:22.00 2017-09-25 mdata/M230/rom/light_param/glow_pv266s02.txt ; 319 09:22.00 2017-09-25 mdata/M230/rom/light_param/glow_pv266s03.txt ; 40445 09:22.33 2017-09-25 mdata/M230/rom/light_param/light_pv266.farc ; 1698 09:22.05 2017-09-25 mdata/M230/rom/light_param/light_pv266s01.txt ; 1806 09:22.00 2017-09-25 mdata/M230/rom/light_param/light_pv266s02.txt ; 1699 09:22.00 2017-09-25 mdata/M230/rom/light_param/light_pv266s03.txt ; 129 09:32.15 2018-11-07 mdata/M270/info.txt ; 264343 05:17.40 2019-01-17 mdata/M270/rom/mdata_chritm_prop.farc ; 54920 11:04.04 2019-02-20 mdata/M270/rom/mdata_gm_collection_card_tbl.farc ; 22204 11:04.18 2019-02-20 mdata/M270/rom/mdata_gm_module_tbl.farc ; 314876 09:49.48 2019-02-22 mdata/M270/rom/mdata_pv_db.txt ; 1615003 13:05.50 2019-02-22 mdata/M270/rom/mdata_pv_field.txt ; 55821 07:37.11 2018-12-19 mdata/M270/rom/mdata_rob_sleeve_data.txt ; 2392 09:49.02 2019-02-20 mdata/M270/rom/osage_play_data/mdata_opd_db.txt ; 23998503 09:49.05 2019-02-20 mdata/M270/rom/osage_play_data/mikitm177_joha_outer_177__divskn.farc ; 13958428 09:49.05 2019-02-20 mdata/M270/rom/osage_play_data/mikitm178_joha_outer_178__divskn.farc ; 23998355 09:49.05 2019-02-20 mdata/M270/rom/osage_play_data/mikitm179_joha_outer_179__divskn.farc ; 14482744 09:49.05 2019-02-20 mdata/M270/rom/osage_play_data/mikitm677_atam_atama_177__divskn.farc ; 8514135 09:49.05 2019-02-20 mdata/M270/rom/osage_play_data/mikitm678_atam_atama_178__divskn.farc ; 14482724 09:49.05 2019-02-20 mdata/M270/rom/osage_play_data/mikitm679_atam_atama_179__divskn.farc ; 7611325 09:49.06 2019-02-20 mdata/M270/rom/osage_play_data/mikitm786_joha_ushiro_86__divskn.farc ; 236114 09:46.12 2019-02-19 mdata/M270/rom/photo_print/card/CLT_CRD0656_01.jpg ; 236866 09:46.04 2019-02-19 mdata/M270/rom/photo_print/card/CLT_CRD0657_01.jpg ; 238289 09:45.55 2019-02-19 mdata/M270/rom/photo_print/card/CLT_CRD0658_01.jpg ; 921644 11:41.19 2019-02-14 mdata/M270/rom/photo_print/stamp/module/stamp_md_sub_428_00.tga ; 921644 11:41.20 2019-02-14 mdata/M270/rom/photo_print/stamp/module/stamp_md_sub_429_00.tga ; 921644 11:41.21 2019-02-14 mdata/M270/rom/photo_print/stamp/module/stamp_md_sub_430_00.tga ; 74848 09:49.26 2019-02-14 mdata/M270/rom/objset/mdata_obj_db.bin ; 50656 09:49.27 2019-02-14 mdata/M270/rom/objset/mdata_tex_db.bin ; 7934180 09:49.26 2019-02-14 mdata/M270/rom/objset/mikitm177.farc ; 7168839 09:49.26 2019-02-14 mdata/M270/rom/objset/mikitm178.farc ; 8992497 09:49.26 2019-02-14 mdata/M270/rom/objset/mikitm179.farc ; 258158 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm477.farc ; 129490 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm478.farc ; 3239727 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm677.farc ; 3229377 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm678.farc ; 3237869 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm679.farc ; 29898 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm774.farc ; 1201167 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm786.farc ; 25424 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm789.farc ; 276291 09:49.25 2019-02-14 mdata/M270/rom/objset/mikitm792.farc ; 440406 09:49.24 2019-02-14 mdata/M270/rom/objset/mikitm976.farc ; 459908 09:49.24 2019-02-14 mdata/M270/rom/objset/mikitm977.farc ; 35156 11:35.55 2019-02-22 mdata/M270/rom/script/pv_016_easy.dsc ; 44564 11:35.55 2019-02-22 mdata/M270/rom/script/pv_016_extreme.dsc ; 62560 04:45.35 2019-02-27 mdata/M270/rom/script/pv_016_extreme_1.dsc ; 39244 11:35.55 2019-02-22 mdata/M270/rom/script/pv_016_hard.dsc ; 24052 04:31.49 2019-02-25 mdata/M270/rom/script/pv_020_easy.dsc ; 32004 04:31.49 2019-02-25 mdata/M270/rom/script/pv_020_extreme.dsc ; 70088 04:45.35 2019-02-27 mdata/M270/rom/script/pv_020_extreme_1.dsc ; 28988 04:31.49 2019-02-25 mdata/M270/rom/script/pv_020_hard.dsc ; 28860 04:31.49 2019-02-25 mdata/M270/rom/script/pv_020_normal.dsc ; 33944 11:43.34 2019-02-22 mdata/M270/rom/script/pv_086_easy.dsc ; 42416 11:43.34 2019-02-22 mdata/M270/rom/script/pv_086_extreme.dsc ; 53312 04:45.35 2019-02-27 mdata/M270/rom/script/pv_086_extreme_1.dsc ; 40824 11:43.34 2019-02-22 mdata/M270/rom/script/pv_086_hard.dsc ; 37024 11:43.34 2019-02-22 mdata/M270/rom/script/pv_086_normal.dsc ; 29568 08:47.27 2019-02-20 mdata/M270/rom/script/pv_219_easy.dsc ; 46352 08:47.27 2019-02-20 mdata/M270/rom/script/pv_219_extreme.dsc ; 50088 08:47.27 2019-02-20 mdata/M270/rom/script/pv_219_extreme_1.dsc ; 39968 08:47.27 2019-02-20 mdata/M270/rom/script/pv_219_hard.dsc ; 35960 08:47.27 2019-02-20 mdata/M270/rom/script/pv_219_normal.dsc ; 39788 11:47.05 2019-02-22 mdata/M270/rom/script/pv_225_easy.dsc ; 54404 11:47.05 2019-02-22 mdata/M270/rom/script/pv_225_extreme.dsc ; 70916 04:45.35 2019-02-27 mdata/M270/rom/script/pv_225_extreme_1.dsc ; 51964 11:47.05 2019-02-22 mdata/M270/rom/script/pv_225_hard.dsc ; 48644 11:47.05 2019-02-22 mdata/M270/rom/script/pv_225_normal.dsc ; 49168 11:50.58 2019-02-22 mdata/M270/rom/script/pv_410_easy.dsc ; 56744 11:50.58 2019-02-22 mdata/M270/rom/script/pv_410_extreme.dsc ; 69084 11:50.58 2019-02-22 mdata/M270/rom/script/pv_410_extreme_1.dsc ; 54936 11:50.58 2019-02-22 mdata/M270/rom/script/pv_410_hard.dsc ; 50984 11:50.58 2019-02-22 mdata/M270/rom/script/pv_410_normal.dsc ; 88552 11:55.23 2019-02-22 mdata/M270/rom/script/pv_441_extreme.dsc ; 121832 04:45.35 2019-02-27 mdata/M270/rom/script/pv_441_extreme_1.dsc ; 86768 11:55.23 2019-02-22 mdata/M270/rom/script/pv_441_hard.dsc ; 79160 11:55.23 2019-02-22 mdata/M270/rom/script/pv_441_normal.dsc ; 63196 05:20.09 2019-01-23 mdata/M270/rom/script/pv_727_easy.dsc ; 75604 05:20.09 2019-01-23 mdata/M270/rom/script/pv_727_extreme.dsc ; 73068 05:20.09 2019-01-23 mdata/M270/rom/script/pv_727_hard.dsc ; 68372 05:20.09 2019-01-23 mdata/M270/rom/script/pv_727_normal.dsc ; 10976 10:23.58 2019-02-21 mdata/M270/rom/rob/mothead_PV002.bin ; 10976 11:45.40 2019-01-23 mdata/M270/rom/rob/mothead_PV020.bin ; 91680 11:18.46 2019-02-21 mdata/M270/rom/rob/mothead_PV044.bin ; 11616 08:52.14 2019-01-31 mdata/M270/rom/rob/mothead_PV065.bin ; 44800 04:57.01 2019-02-05 mdata/M270/rom/rob/mothead_PV081.bin ; 17888 14:38.54 2019-02-21 mdata/M270/rom/rob/mothead_PV205.bin ; 24096 11:45.29 2019-03-04 mdata/M270/rom/rob/mothead_PV240.bin ; 28512 14:47.27 2019-02-21 mdata/M270/rom/rob/mothead_PV262.bin ; 19808 14:27.46 2019-02-21 mdata/M270/rom/rob/mothead_PV604.bin ; 19200 11:22.21 2019-03-04 mdata/M270/rom/rob/mothead_PV605.bin ; 15584 07:48.53 2019-02-25 mdata/M270/rom/rob/mothead_PV618.bin ; 120192 15:36.09 2019-02-21 mdata/M270/rom/rob/mothead_PV637.bin ; 85824 09:41.39 2019-02-21 mdata/M270/rom/rob/mothead_PV739.bin ; 10496 11:27.57 2019-01-20 mdata/M270/rom/rob/rob_mot_tbl.bin ; 254354 09:48.26 2019-02-14 mdata/M270/rom/skin_param/ext_skp_mikitm177_joha_outer_177__divskn.txt ; 198912 09:48.26 2019-02-14 mdata/M270/rom/skin_param/ext_skp_mikitm178_joha_outer_178__divskn.txt ; 254354 09:48.25 2019-02-14 mdata/M270/rom/skin_param/ext_skp_mikitm179_joha_outer_179__divskn.txt ; 66442 09:48.25 2019-02-14 mdata/M270/rom/skin_param/ext_skp_mikitm677_atam_atama_177__divskn.txt ; 36600 09:48.25 2019-02-14 mdata/M270/rom/skin_param/ext_skp_mikitm678_atam_atama_178__divskn.txt ; 66442 09:48.25 2019-02-14 mdata/M270/rom/skin_param/ext_skp_mikitm679_atam_atama_179__divskn.txt ; 56760 09:48.24 2019-02-14 mdata/M270/rom/skin_param/ext_skp_mikitm786_joha_ushiro_86__divskn.txt ; 18345 07:35.44 2018-12-19 mdata/M270/rom/skin_param/mdata_osage_setting.txt ; 228823578 06:46.25 2019-03-05 mdata/M270/rom/skin_param/mdata_sp_skp.farc ; 1494383 06:46.25 2019-03-05 mdata/M270/rom/skin_param/mdata_sp_skp_db.txt ; 73488 13:25.56 2019-02-20 mdata/M270/rom/2d/mdata_spr_db.bin ; 45750 13:25.03 2019-02-20 mdata/M270/rom/2d/spr_clt_crd0656.farc ; 45847 13:25.03 2019-02-20 mdata/M270/rom/2d/spr_clt_crd0657.farc ; 46205 13:25.03 2019-02-20 mdata/M270/rom/2d/spr_clt_crd0658.farc ; 31127 12:19.47 2019-02-14 mdata/M270/rom/2d/spr_sel_md428cmn.farc ; 32570 12:19.47 2019-02-14 mdata/M270/rom/2d/spr_sel_md429cmn.farc ; 31127 12:19.47 2019-02-14 mdata/M270/rom/2d/spr_sel_md430cmn.farc ; 87 11:29.57 2017-10-23 mdata/M240/info.txt ; 196001 10:06.57 2017-11-02 mdata/M240/rom/mdata_pv_db.txt ; 1120195 05:17.38 2017-11-02 mdata/M240/rom/mdata_pv_field.txt ; 259892 12:09.11 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0000_01.jpg ; 260162 12:09.11 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0003_01.jpg ; 257852 12:09.12 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0004_01.jpg ; 240627 12:09.12 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0005_01.jpg ; 248987 12:09.13 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0006_01.jpg ; 257898 12:09.13 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0007_01.jpg ; 244116 12:09.14 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0008_01.jpg ; 237280 12:09.15 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0009_01.jpg ; 241633 12:09.15 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0010_01.jpg ; 249890 12:09.16 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0011_01.jpg ; 252611 12:09.16 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0012_01.jpg ; 255925 12:09.17 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0013_01.jpg ; 251227 12:09.17 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0014_01.jpg ; 259220 12:09.18 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0015_01.jpg ; 255599 12:09.18 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0016_01.jpg ; 258076 12:09.19 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0017_01.jpg ; 246428 12:09.20 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0018_01.jpg ; 256944 12:09.20 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0019_01.jpg ; 252205 12:09.21 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0020_01.jpg ; 247319 12:09.21 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0021_01.jpg ; 259679 12:09.22 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0022_01.jpg ; 266117 12:09.22 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0023_01.jpg ; 261180 12:09.23 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0024_01.jpg ; 256770 12:09.24 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0025_01.jpg ; 253424 12:09.24 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0026_01.jpg ; 257119 12:09.25 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0027_01.jpg ; 270670 12:09.25 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0028_01.jpg ; 245446 12:09.26 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0029_01.jpg ; 248755 12:09.26 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0030_01.jpg ; 264979 12:09.27 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0031_01.jpg ; 249951 12:09.27 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0032_01.jpg ; 257406 12:09.28 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0033_01.jpg ; 252663 12:09.29 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0034_01.jpg ; 253262 12:09.29 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0035_01.jpg ; 258439 12:09.30 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0036_01.jpg ; 261515 12:09.30 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0037_01.jpg ; 257332 12:09.31 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0038_01.jpg ; 248559 12:09.31 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0039_01.jpg ; 243712 12:09.32 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0046_01.jpg ; 247717 12:09.32 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0047_01.jpg ; 255872 12:09.33 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0053_01.jpg ; 242589 12:09.33 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0054_01.jpg ; 251695 12:09.34 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0055_01.jpg ; 249808 12:09.34 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0056_01.jpg ; 262308 12:09.35 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0057_01.jpg ; 255595 12:09.36 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0059_01.jpg ; 260806 12:09.36 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0065_01.jpg ; 254379 12:09.37 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0068_01.jpg ; 256502 12:09.37 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0069_01.jpg ; 257615 12:09.38 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0070_01.jpg ; 251085 12:09.38 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0072_01.jpg ; 262136 12:09.39 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0073_01.jpg ; 264924 12:09.39 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0078_01.jpg ; 258342 12:09.40 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0079_01.jpg ; 246821 12:09.41 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0088_01.jpg ; 248120 12:09.41 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0089_01.jpg ; 240925 12:09.42 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0090_01.jpg ; 253823 12:09.42 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0091_01.jpg ; 258510 12:09.43 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0102_01.jpg ; 248814 12:09.43 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0103_01.jpg ; 256311 12:09.44 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0107_01.jpg ; 240966 12:09.44 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0108_01.jpg ; 246525 12:09.45 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0115_01.jpg ; 256813 12:09.45 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0118_01.jpg ; 250922 12:09.46 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0121_01.jpg ; 244105 12:09.47 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0124_01.jpg ; 252695 12:09.47 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0129_01.jpg ; 255757 12:09.48 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0132_01.jpg ; 247053 12:09.48 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0133_01.jpg ; 255095 12:09.49 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0136_01.jpg ; 248360 12:09.49 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0139_01.jpg ; 257130 12:09.50 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0146_01.jpg ; 261014 12:09.50 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0147_01.jpg ; 258605 12:09.51 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0148_01.jpg ; 258748 12:09.52 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0152_01.jpg ; 249857 12:09.52 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0153_01.jpg ; 236147 12:09.53 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0156_01.jpg ; 242395 12:09.53 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0157_01.jpg ; 257793 12:09.54 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0158_01.jpg ; 267733 12:09.54 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0160_01.jpg ; 274725 12:09.55 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0161_01.jpg ; 263043 12:09.55 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0165_01.jpg ; 251205 12:09.56 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0166_01.jpg ; 240749 12:09.56 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0169_01.jpg ; 242430 12:09.57 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0170_01.jpg ; 248576 12:09.58 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0175_01.jpg ; 269849 12:09.58 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0177_01.jpg ; 265476 12:09.59 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0183_01.jpg ; 251703 12:09.59 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0188_01.jpg ; 250450 12:10.00 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0192_01.jpg ; 258743 12:10.00 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0198_01.jpg ; 275290 12:10.01 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0202_01.jpg ; 256866 12:10.02 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0209_01.jpg ; 265230 12:10.02 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0212_01.jpg ; 248073 12:10.03 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0213_01.jpg ; 265727 12:10.03 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0214_01.jpg ; 264183 12:10.04 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0215_01.jpg ; 256214 12:10.04 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0221_01.jpg ; 262491 12:10.05 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0228_01.jpg ; 248554 12:10.05 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0229_01.jpg ; 253930 12:10.06 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0231_01.jpg ; 257525 12:10.07 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0235_01.jpg ; 261841 12:10.07 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0236_01.jpg ; 250581 12:10.08 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0237_01.jpg ; 270351 12:10.08 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0238_01.jpg ; 264725 12:10.09 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0239_01.jpg ; 250792 12:10.09 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0246_01.jpg ; 252945 12:10.10 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0247_01.jpg ; 253389 12:10.10 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0420_01.jpg ; 239319 12:10.11 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0421_01.jpg ; 269927 12:10.12 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0432_01.jpg ; 245812 12:10.12 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0440_01.jpg ; 258572 12:10.13 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0441_01.jpg ; 266802 12:10.13 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0442_01.jpg ; 271333 12:10.14 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0443_01.jpg ; 257604 12:10.14 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0444_01.jpg ; 243513 12:10.15 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0445_01.jpg ; 264380 12:10.15 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0447_01.jpg ; 264810 12:10.16 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0469_01.jpg ; 248341 12:10.16 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0471_01.jpg ; 247179 12:10.17 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0491_01.jpg ; 238763 12:10.17 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0492_01.jpg ; 222739 12:10.18 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0493_01.jpg ; 260277 12:10.18 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0505_01.jpg ; 255155 12:10.19 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0506_01.jpg ; 260993 12:10.19 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0510_01.jpg ; 239676 12:10.20 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0511_01.jpg ; 269265 12:10.20 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0512_01.jpg ; 239780 12:10.21 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0517_01.jpg ; 239526 12:10.21 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0518_01.jpg ; 250983 12:10.22 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0524_01.jpg ; 265406 12:10.22 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0525_01.jpg ; 253634 12:10.23 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0526_01.jpg ; 257260 12:10.23 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0528_01.jpg ; 255445 12:10.24 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0537_01.jpg ; 278419 12:10.24 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0538_01.jpg ; 263755 12:10.25 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0539_01.jpg ; 236324 12:10.25 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0543_01.jpg ; 258771 12:10.26 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0544_01.jpg ; 268404 12:10.26 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0545_01.jpg ; 260208 12:10.27 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0547_01.jpg ; 244862 12:10.27 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0557_01.jpg ; 241814 12:10.28 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0558_01.jpg ; 246265 12:10.29 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0559_01.jpg ; 259765 12:10.29 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0560_01.jpg ; 252241 12:10.29 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0566_01.jpg ; 260829 12:10.30 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0575_01.jpg ; 238366 12:10.30 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0578_01.jpg ; 264394 12:10.31 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0581_01.jpg ; 243213 12:10.32 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0582_01.jpg ; 259478 12:10.32 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0589_01.jpg ; 255405 12:10.33 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0590_01.jpg ; 289479 12:10.33 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0595_01.jpg ; 233834 12:10.34 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0598_01.jpg ; 279899 12:10.34 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0602_01.jpg ; 243064 12:10.35 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0604_01.jpg ; 259365 12:10.35 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0607_01.jpg ; 256626 12:10.36 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0608_01.jpg ; 242792 12:10.36 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0609_01.jpg ; 251554 12:10.37 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0611_01.jpg ; 268779 12:10.37 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0620_01.jpg ; 264944 12:10.38 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0621_01.jpg ; 241924 12:10.38 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0622_01.jpg ; 256553 12:10.39 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0631_01.jpg ; 257450 12:10.39 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0637_01.jpg ; 275433 12:10.40 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0643_01.jpg ; 251037 12:10.40 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0644_01.jpg ; 247356 12:10.40 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0646_01.jpg ; 259050 12:10.41 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0654_01.jpg ; 290144 12:10.42 2017-10-31 mdata/M240/rom/photo_print/card/CLT_CRD0655_01.jpg ; 489484 14:43.42 2017-10-30 mdata/M240/rom/photo_print/stamp/stamp030_02.tga ; 93470704 03:38.07 2017-08-29 mdata/M240/rom/movie/adv_sega_cm.wmv ; 49984 10:17.25 2017-11-07 mdata/M240/rom/script/pv_042_easy.dsc ; 68224 10:17.25 2017-11-07 mdata/M240/rom/script/pv_042_extreme.dsc ; 83112 10:17.25 2017-11-07 mdata/M240/rom/script/pv_042_extreme_1.dsc ; 59856 10:17.25 2017-11-07 mdata/M240/rom/script/pv_042_hard.dsc ; 55752 10:17.25 2017-11-07 mdata/M240/rom/script/pv_042_normal.dsc ; 33208 09:38.28 2017-11-02 mdata/M240/rom/script/pv_048_easy.dsc ; 40920 09:38.28 2017-11-02 mdata/M240/rom/script/pv_048_extreme.dsc ; 56756 09:38.28 2017-11-02 mdata/M240/rom/script/pv_048_extreme_1.dsc ; 38744 09:38.28 2017-11-02 mdata/M240/rom/script/pv_048_hard.dsc ; 36176 09:38.28 2017-11-02 mdata/M240/rom/script/pv_048_normal.dsc ; 50900 14:01.37 2017-11-07 mdata/M240/rom/script/pv_227_extreme.dsc ; 87588 14:01.37 2017-11-07 mdata/M240/rom/script/pv_227_extreme_1.dsc ; 45636 14:01.37 2017-11-07 mdata/M240/rom/script/pv_227_hard.dsc ; 41812 14:01.37 2017-11-07 mdata/M240/rom/script/pv_227_normal.dsc ; 52104 12:10.04 2017-10-30 mdata/M240/rom/script/pv_266_easy.dsc ; 75936 12:10.04 2017-10-30 mdata/M240/rom/script/pv_266_extreme.dsc ; 72144 12:10.04 2017-10-30 mdata/M240/rom/script/pv_266_hard.dsc ; 59744 12:10.04 2017-10-30 mdata/M240/rom/script/pv_266_normal.dsc ; 328784 09:40.08 2017-10-31 mdata/M240/rom/2d/aet_sel_module.bin ; 62260 09:40.08 2017-10-31 mdata/M240/rom/2d/aet_sel_qst.bin ; 888 09:40.12 2017-10-31 mdata/M240/rom/2d/mdata_aet_db.bin ; 72664 11:19.49 2017-11-01 mdata/M240/rom/2d/mdata_spr_db.bin ; 45752 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0000.farc ; 45962 05:07.14 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0003.farc ; 45935 05:07.02 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0004.farc ; 45370 05:07.03 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0005.farc ; 45960 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0006.farc ; 46197 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0007.farc ; 45394 05:07.11 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0008.farc ; 45097 05:07.11 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0009.farc ; 45459 05:07.11 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0010.farc ; 45744 05:07.11 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0011.farc ; 45722 05:07.11 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0012.farc ; 45864 05:07.11 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0013.farc ; 45588 05:07.11 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0014.farc ; 46014 05:07.11 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0015.farc ; 45895 05:07.12 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0016.farc ; 46030 05:07.12 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0017.farc ; 46047 05:07.12 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0018.farc ; 46159 05:07.12 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0019.farc ; 45526 05:07.12 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0020.farc ; 44802 05:07.12 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0021.farc ; 46029 05:07.12 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0022.farc ; 46179 05:07.03 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0023.farc ; 46023 05:07.03 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0024.farc ; 45792 05:07.03 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0025.farc ; 45881 05:07.03 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0026.farc ; 45561 05:07.03 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0027.farc ; 45897 05:07.03 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0028.farc ; 45355 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0029.farc ; 45601 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0030.farc ; 46241 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0031.farc ; 45975 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0032.farc ; 46025 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0033.farc ; 45828 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0034.farc ; 45817 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0035.farc ; 45845 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0036.farc ; 46197 05:07.04 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0037.farc ; 45978 05:07.05 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0038.farc ; 45563 05:07.05 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0039.farc ; 45671 05:07.05 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0046.farc ; 45628 05:07.05 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0047.farc ; 46345 05:07.05 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0053.farc ; 45434 05:07.05 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0054.farc ; 45576 05:07.05 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0055.farc ; 45585 05:07.05 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0056.farc ; 46218 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0057.farc ; 45963 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0059.farc ; 46080 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0065.farc ; 45669 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0068.farc ; 46084 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0069.farc ; 46172 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0070.farc ; 45270 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0072.farc ; 46600 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0073.farc ; 45855 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0078.farc ; 45929 05:07.06 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0079.farc ; 45483 05:07.07 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0088.farc ; 45962 05:07.07 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0089.farc ; 45833 05:07.07 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0090.farc ; 45783 05:07.07 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0091.farc ; 45683 05:07.07 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0102.farc ; 45588 05:07.07 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0103.farc ; 45915 05:07.07 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0107.farc ; 45594 05:07.07 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0108.farc ; 45921 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0115.farc ; 45888 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0118.farc ; 45500 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0121.farc ; 45563 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0124.farc ; 45895 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0129.farc ; 45970 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0132.farc ; 45851 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0133.farc ; 45954 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0136.farc ; 45766 05:07.08 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0139.farc ; 45985 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0146.farc ; 46213 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0147.farc ; 45907 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0148.farc ; 45911 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0152.farc ; 45620 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0153.farc ; 45116 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0156.farc ; 45876 04:43.25 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0157.farc ; 46170 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0158.farc ; 46508 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0160.farc ; 46608 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0161.farc ; 46304 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0165.farc ; 46490 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0166.farc ; 44771 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0169.farc ; 45286 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0170.farc ; 45970 04:43.25 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0175.farc ; 46377 04:43.25 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0177.farc ; 46223 04:43.25 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0183.farc ; 45788 04:43.25 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0188.farc ; 45939 05:07.12 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0192.farc ; 46035 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0198.farc ; 46377 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0202.farc ; 45888 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0209.farc ; 46122 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0212.farc ; 45899 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0213.farc ; 46412 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0214.farc ; 46282 04:50.15 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0215.farc ; 46425 04:50.15 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0221.farc ; 46143 04:50.15 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0228.farc ; 46465 04:50.15 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0229.farc ; 45659 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0231.farc ; 46608 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0235.farc ; 46168 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0236.farc ; 45669 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0237.farc ; 47028 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0238.farc ; 46663 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0239.farc ; 45605 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0246.farc ; 44995 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0247.farc ; 45934 04:43.27 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0420.farc ; 45460 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0421.farc ; 46280 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0432.farc ; 45432 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0440.farc ; 46125 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0441.farc ; 46412 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0442.farc ; 46400 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0443.farc ; 46171 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0444.farc ; 44758 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0445.farc ; 46609 04:43.28 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0447.farc ; 46446 04:43.29 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0469.farc ; 44170 04:43.29 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0471.farc ; 45779 04:43.29 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0491.farc ; 45804 04:43.29 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0492.farc ; 42653 04:43.29 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0493.farc ; 46291 04:43.29 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0505.farc ; 46005 04:43.29 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0506.farc ; 45846 04:43.29 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0510.farc ; 44360 04:43.30 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0511.farc ; 46579 04:43.30 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0512.farc ; 45051 04:43.30 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0517.farc ; 45096 04:43.30 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0518.farc ; 45915 04:43.30 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0524.farc ; 46252 04:43.30 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0525.farc ; 45815 04:43.30 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0526.farc ; 46238 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0528.farc ; 45580 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0537.farc ; 46481 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0538.farc ; 46214 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0539.farc ; 45687 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0543.farc ; 46325 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0544.farc ; 45970 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0545.farc ; 46613 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0547.farc ; 45605 04:43.31 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0557.farc ; 45253 04:43.32 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0558.farc ; 45806 04:43.32 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0559.farc ; 46386 04:43.32 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0560.farc ; 45684 04:43.23 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0566.farc ; 46092 04:43.23 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0575.farc ; 45284 04:43.23 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0578.farc ; 46388 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0581.farc ; 45822 04:43.24 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0582.farc ; 45949 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0589.farc ; 46036 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0590.farc ; 46956 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0595.farc ; 44684 05:07.09 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0598.farc ; 46497 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0602.farc ; 46232 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0604.farc ; 45671 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0607.farc ; 46056 05:07.13 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0608.farc ; 45471 04:43.25 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0609.farc ; 45769 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0611.farc ; 46816 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0620.farc ; 46355 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0621.farc ; 45563 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0622.farc ; 46178 05:07.10 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0631.farc ; 46074 11:18.57 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0637.farc ; 47196 11:18.57 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0643.farc ; 45865 11:18.57 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0644.farc ; 45234 11:18.58 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0646.farc ; 46010 11:18.58 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0654.farc ; 47294 11:18.58 2017-11-01 mdata/M240/rom/2d/spr_clt_crd0655.farc ; 24398 14:07.35 2017-10-31 mdata/M240/rom/2d/spr_sel_mdrmikcmn.farc ; 3370784 10:31.58 2017-10-31 mdata/M240/rom/2d/spr_sel_module.farc ; 358000 14:07.35 2017-10-31 mdata/M240/rom/2d/spr_sel_qst.farc ; 101 15:29.30 2018-04-02 mdata/M250/info.txt ; 251522 19:54.02 2018-04-10 mdata/M250/rom/mdata_pv_db.txt ; 251522 17:16.14 2018-04-04 mdata/M250/rom/mdata_pv_db.txt.bak ; 1450594 15:29.32 2018-04-02 mdata/M250/rom/mdata_pv_field.txt ; 43372 15:29.32 2018-04-02 mdata/M250/rom/script/pv_012_extreme.dsc ; 72736 19:53.20 2018-04-10 mdata/M250/rom/script/pv_012_extreme_1.dsc ; 38092 15:29.32 2018-04-02 mdata/M250/rom/script/pv_012_hard.dsc ; 34388 15:29.32 2018-04-02 mdata/M250/rom/script/pv_012_normal.dsc ; 70560 15:29.32 2018-04-02 mdata/M250/rom/script/pv_220_easy.dsc ; 97376 15:29.32 2018-04-02 mdata/M250/rom/script/pv_220_extreme.dsc ; 112624 19:53.20 2018-04-10 mdata/M250/rom/script/pv_220_extreme_1.dsc ; 89016 15:29.32 2018-04-02 mdata/M250/rom/script/pv_220_hard.dsc ; 78672 15:29.32 2018-04-02 mdata/M250/rom/script/pv_220_normal.dsc ; 60092 15:29.32 2018-04-02 mdata/M250/rom/script/pv_435_extreme.dsc ; 65708 19:53.20 2018-04-10 mdata/M250/rom/script/pv_435_extreme_1.dsc ; 55100 15:29.32 2018-04-02 mdata/M250/rom/script/pv_435_hard.dsc ; 48556 15:29.32 2018-04-02 mdata/M250/rom/script/pv_435_normal.dsc ; 41140 15:29.32 2018-04-02 mdata/M250/rom/script/pv_600_easy.dsc ; 58820 15:29.32 2018-04-02 mdata/M250/rom/script/pv_600_extreme.dsc ; 67132 19:53.20 2018-04-10 mdata/M250/rom/script/pv_600_extreme_1.dsc ; 57996 15:29.32 2018-04-02 mdata/M250/rom/script/pv_600_hard.dsc ; 47532 15:29.32 2018-04-02 mdata/M250/rom/script/pv_600_normal.dsc ; 29472 15:29.32 2018-04-02 mdata/M250/rom/script/pv_605_easy.dsc ; 46432 15:29.32 2018-04-02 mdata/M250/rom/script/pv_605_extreme.dsc ; 50768 19:53.20 2018-04-10 mdata/M250/rom/script/pv_605_extreme_1.dsc ; 39560 15:29.32 2018-04-02 mdata/M250/rom/script/pv_605_hard.dsc ; 33664 15:29.32 2018-04-02 mdata/M250/rom/script/pv_605_normal.dsc ; 44400 15:29.32 2018-04-02 mdata/M250/rom/script/pv_615_easy.dsc ; 57088 15:29.32 2018-04-02 mdata/M250/rom/script/pv_615_extreme.dsc ; 76344 21:12.32 2018-04-05 mdata/M250/rom/script/pv_615_extreme_1.dsc ; 52320 15:29.32 2018-04-02 mdata/M250/rom/script/pv_615_hard.dsc ; 48848 15:29.32 2018-04-02 mdata/M250/rom/script/pv_615_normal.dsc ; 85436 15:29.32 2018-04-02 mdata/M250/rom/script/pv_616_easy.dsc ; 114964 15:29.32 2018-04-02 mdata/M250/rom/script/pv_616_extreme.dsc ; 121044 19:53.20 2018-04-10 mdata/M250/rom/script/pv_616_extreme_1.dsc ; 107420 15:29.32 2018-04-02 mdata/M250/rom/script/pv_616_hard.dsc ; 95452 15:29.32 2018-04-02 mdata/M250/rom/script/pv_616_normal.dsc ; 62732 15:29.32 2018-04-02 mdata/M250/rom/script/pv_617_extreme.dsc ; 73044 21:12.32 2018-04-05 mdata/M250/rom/script/pv_617_extreme_1.dsc ; 58876 15:29.32 2018-04-02 mdata/M250/rom/script/pv_617_hard.dsc ; 49740 15:29.32 2018-04-02 mdata/M250/rom/script/pv_617_normal.dsc ; 60636 15:29.32 2018-04-02 mdata/M250/rom/script/pv_625_extreme.dsc ; 74340 19:53.20 2018-04-10 mdata/M250/rom/script/pv_625_extreme_1.dsc ; 48852 15:29.32 2018-04-02 mdata/M250/rom/script/pv_625_hard.dsc ; 43860 15:29.32 2018-04-02 mdata/M250/rom/script/pv_625_normal.dsc ; 47196 15:29.32 2018-04-02 mdata/M250/rom/script/pv_639_extreme.dsc ; 71972 19:53.20 2018-04-10 mdata/M250/rom/script/pv_639_extreme_1.dsc ; 45332 15:29.32 2018-04-02 mdata/M250/rom/script/pv_639_hard.dsc ; 41732 15:29.32 2018-04-02 mdata/M250/rom/script/pv_639_normal.dsc ; 115 14:57.58 2018-09-07 mdata/M260/info.txt ; 281667 14:57.58 2018-09-07 mdata/M260/rom/mdata_pv_db.txt ; 1599596 14:57.58 2018-09-07 mdata/M260/rom/mdata_pv_field.txt ; 44932 14:57.58 2018-09-07 mdata/M260/rom/script/pv_213_easy.dsc ; 57324 14:57.58 2018-09-07 mdata/M260/rom/script/pv_213_extreme.dsc ; 69108 16:22.20 2018-09-10 mdata/M260/rom/script/pv_213_extreme_1.dsc ; 53324 14:57.58 2018-09-07 mdata/M260/rom/script/pv_213_hard.dsc ; 47348 14:57.58 2018-09-07 mdata/M260/rom/script/pv_213_normal.dsc ; 58104 14:57.58 2018-09-07 mdata/M260/rom/script/pv_412_extreme.dsc ; 82036 16:22.20 2018-09-10 mdata/M260/rom/script/pv_412_extreme_1.dsc ; 54888 14:57.58 2018-09-07 mdata/M260/rom/script/pv_412_hard.dsc ; 51784 14:57.58 2018-09-07 mdata/M260/rom/script/pv_412_normal.dsc ; 48424 14:57.58 2018-09-07 mdata/M260/rom/script/pv_602_easy.dsc ; 60096 14:57.58 2018-09-07 mdata/M260/rom/script/pv_602_extreme.dsc ; 82928 16:22.20 2018-09-10 mdata/M260/rom/script/pv_602_extreme_1.dsc ; 57800 14:57.58 2018-09-07 mdata/M260/rom/script/pv_602_hard.dsc ; 52544 14:57.58 2018-09-07 mdata/M260/rom/script/pv_602_normal.dsc ; 42696 14:57.58 2018-09-07 mdata/M260/rom/script/pv_613_easy.dsc ; 63224 14:57.58 2018-09-07 mdata/M260/rom/script/pv_613_extreme.dsc ; 71984 16:22.20 2018-09-10 mdata/M260/rom/script/pv_613_extreme_1.dsc ; 56440 14:57.58 2018-09-07 mdata/M260/rom/script/pv_613_hard.dsc ; 48344 14:57.58 2018-09-07 mdata/M260/rom/script/pv_613_normal.dsc ; 28920 14:57.58 2018-09-07 mdata/M260/rom/script/pv_638_easy.dsc ; 40312 14:57.58 2018-09-07 mdata/M260/rom/script/pv_638_extreme.dsc ; 60216 16:22.20 2018-09-10 mdata/M260/rom/script/pv_638_extreme_1.dsc ; 38816 14:57.58 2018-09-07 mdata/M260/rom/script/pv_638_hard.dsc ; 34952 14:57.58 2018-09-07 mdata/M260/rom/script/pv_638_normal.dsc ; 39812 14:57.58 2018-09-07 mdata/M260/rom/script/pv_730_easy.dsc ; 50116 14:57.58 2018-09-07 mdata/M260/rom/script/pv_730_extreme.dsc ; 79020 16:22.20 2018-09-10 mdata/M260/rom/script/pv_730_extreme_1.dsc ; 47948 14:57.58 2018-09-07 mdata/M260/rom/script/pv_730_hard.dsc ; 42404 14:57.58 2018-09-07 mdata/M260/rom/script/pv_730_normal.dsc ; 143 15:22.32 2021-10-14 mdata/M271/info.txt ; 75136 15:22.32 2021-10-14 mdata/M271/rom/objset/mdata_obj_db.bin ; 50912 15:22.32 2021-10-14 mdata/M271/rom/objset/mdata_tex_db.bin ; 3814265 15:22.32 2021-10-14 mdata/M271/rom/objset/stgd2pv208.farc ; 13552 15:22.32 2021-10-14 mdata/M271/rom/objset/stgd2pv208s01.farc mdata/M215/info.txt D2D971B8 mdata/M215/rom/objset/mdata_obj_db.bin 46C9B86E mdata/M215/rom/objset/mdata_tex_db.bin D160D1D0 mdata/M215/rom/objset/meiitm809.farc D8722468 mdata/M215/rom/objset/meiitm823.farc 3C428B97 mdata/M220/info.txt 8F94F729 mdata/M220/rom/mdata_chritm_prop.farc 19A678CF mdata/M220/rom/mdata_gm_collection_card_tbl.farc 2C75349E mdata/M220/rom/mdata_gm_module_tbl.farc 632CCABB mdata/M220/rom/mdata_pv_db.txt 9E122C68 mdata/M220/rom/mdata_pv_field.txt 05C5661F mdata/M220/rom/mdata_rob_sleeve_data.txt 3FC5CE63 mdata/M220/rom/mdata_stage_data.bin 5E2554B6 mdata/M220/rom/osage_play_data/kaiitm043_joha_outer_43__divskn.farc 608B729F mdata/M220/rom/osage_play_data/kaiitm044_joha_outer_44__divskn.farc 7E265562 mdata/M220/rom/osage_play_data/kaiitm543_atam_atama_43__divskn.farc AE2F0AC7 mdata/M220/rom/osage_play_data/kaiitm544_atam_atama_44__divskn.farc 7B1AFF68 mdata/M220/rom/osage_play_data/kaiitm708_atam_zujo_08__divskn.farc E3FD0A2D mdata/M220/rom/osage_play_data/lenitm041_joha_outer_41__divskn.farc BC462BAA mdata/M220/rom/osage_play_data/lenitm541_atam_atama_41__divskn.farc 4DAEB987 mdata/M220/rom/osage_play_data/lukitm043_joha_outer_43__divskn.farc 9B83ED9B mdata/M220/rom/osage_play_data/lukitm543_atam_atama_43__divskn.farc AE058EBB mdata/M220/rom/osage_play_data/mdata_opd_db.txt 2B478DE7 mdata/M220/rom/osage_play_data/meiitm034_joha_outer_34__divskn.farc A63ED287 mdata/M220/rom/osage_play_data/meiitm534_atam_atama_34__divskn.farc CB8AA613 mdata/M220/rom/osage_play_data/mikitm171_joha_outer_171__divskn.farc 91FEF0AE mdata/M220/rom/osage_play_data/mikitm172_joha_outer_172__divskn.farc CD36C72C mdata/M220/rom/osage_play_data/mikitm174_joha_outer_174__divskn.farc 8EB48C97 mdata/M220/rom/osage_play_data/mikitm671_atam_atama_171__divskn.farc 5376FD44 mdata/M220/rom/osage_play_data/mikitm672_atam_atama_172__divskn.farc F82F4706 mdata/M220/rom/osage_play_data/mikitm674_atam_atama_174__divskn.farc 2CD9D41F mdata/M220/rom/osage_play_data/rinitm042_joha_outer_42__divskn.farc B8AC3F86 mdata/M220/rom/osage_play_data/rinitm049_joha_outer_49__divskn.farc C260900C mdata/M220/rom/osage_play_data/rinitm542_atam_atama_42__divskn.farc 8A7E70A1 mdata/M220/rom/osage_play_data/rinitm549_atam_atama_49__divskn.farc FAF1E895 mdata/M220/rom/osage_play_data/rinitm722_atam_zujo_22__divskn.farc FB64A29A mdata/M220/rom/osage_play_data/rinitm778_joha_ushiro_78__divskn.farc EB80659E mdata/M220/rom/photo_print/card/CLT_CRD0634_01.jpg 18A29C90 mdata/M220/rom/photo_print/card/CLT_CRD0635_01.jpg 4F4541AE mdata/M220/rom/photo_print/card/CLT_CRD0636_01.jpg 2C324544 mdata/M220/rom/photo_print/card/CLT_CRD0637_01.jpg A495760D mdata/M220/rom/photo_print/card/CLT_CRD0638_01.jpg 2034F271 mdata/M220/rom/photo_print/card/CLT_CRD0639_01.jpg 038020B5 mdata/M220/rom/photo_print/card/CLT_CRD0640_01.jpg 1399FE55 mdata/M220/rom/photo_print/card/CLT_CRD0641_01.jpg 0419729D mdata/M220/rom/photo_print/card/CLT_CRD0642_01.jpg 332F0712 mdata/M220/rom/photo_print/card/CLT_CRD0643_01.jpg DADDAA27 mdata/M220/rom/photo_print/card/CLT_CRD0644_01.jpg 5ED64CAF mdata/M220/rom/photo_print/card/CLT_CRD0645_01.jpg 66711547 mdata/M220/rom/photo_print/card/CLT_CRD0646_01.jpg AD1A71C7 mdata/M220/rom/photo_print/card/CLT_CRD0647_01.jpg 3298895A mdata/M220/rom/photo_print/card/CLT_CRD0648_01.jpg 4D3C5CCA mdata/M220/rom/photo_print/card/CLT_CRD0649_01.jpg 9ACEC957 mdata/M220/rom/photo_print/card/CLT_CRD0650_01.jpg A67A9C4A mdata/M220/rom/photo_print/card/CLT_CRD0651_01.jpg 869F05EE mdata/M220/rom/photo_print/stamp/pv/stamp_pv254_logo254_00.tga FB52CFF9 mdata/M220/rom/photo_print/stamp/pv/stamp_pv263_logo263_00.tga 964A12F1 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_399_00.tga FEF855A4 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_413_00.tga 648DA0C3 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_414_00.tga 561E612D mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_415_00.tga E4E35B2E mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_416_00.tga CDB7589E mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_417_00.tga 7AECE108 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_418_00.tga 2570A9C8 mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_419_00.tga 91338E0A mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_424_00.tga B513766D mdata/M220/rom/photo_print/stamp/module/stamp_md_sub_425_00.tga 6730C678 mdata/M220/rom/objset/kaiitm003.farc 992FD293 mdata/M220/rom/objset/kaiitm032.farc C769632E mdata/M220/rom/objset/kaiitm043.farc AFE6498B mdata/M220/rom/objset/kaiitm044.farc 19131E35 mdata/M220/rom/objset/kaiitm332.farc 35078154 mdata/M220/rom/objset/kaiitm343.farc C76B4BF9 mdata/M220/rom/objset/kaiitm344.farc F6915374 mdata/M220/rom/objset/kaiitm543.farc C8F5B5F4 mdata/M220/rom/objset/kaiitm544.farc 59CE14A7 mdata/M220/rom/objset/kaiitm705.farc 2AA068CD mdata/M220/rom/objset/kaiitm708.farc 5A478EF0 mdata/M220/rom/objset/kaiitm709.farc 39A08422 mdata/M220/rom/objset/kaiitm730.farc 653EAE15 mdata/M220/rom/objset/kaiitm731.farc 12A6009A mdata/M220/rom/objset/kaiitm832.farc 95CFDEAB mdata/M220/rom/objset/kaiitm843.farc 9E1994CC mdata/M220/rom/objset/kaiitm844.farc 6FC91D9E mdata/M220/rom/objset/lenitm038.farc 0477ABB9 mdata/M220/rom/objset/lenitm041.farc 734F50FA mdata/M220/rom/objset/lenitm341.farc 1F62BFB8 mdata/M220/rom/objset/lenitm541.farc 5AFA2A05 mdata/M220/rom/objset/lenitm705.farc 9DE0708A mdata/M220/rom/objset/lenitm841.farc C20FF5A6 mdata/M220/rom/objset/lukitm043.farc 784498F4 mdata/M220/rom/objset/lukitm343.farc F5E1D2F1 mdata/M220/rom/objset/lukitm543.farc 59749405 mdata/M220/rom/objset/lukitm707.farc F31D804C mdata/M220/rom/objset/lukitm843.farc 07D4C27B mdata/M220/rom/objset/mdata_obj_db.bin B4D6F27B mdata/M220/rom/objset/mdata_tex_db.bin 9B867055 mdata/M220/rom/objset/meiitm034.farc 8B42492E mdata/M220/rom/objset/meiitm334.farc C6EC143A mdata/M220/rom/objset/meiitm534.farc 0746D41D mdata/M220/rom/objset/meiitm708.farc A37D88D5 mdata/M220/rom/objset/meiitm809.farc DAEDB2A8 mdata/M220/rom/objset/meiitm823.farc 20B65D04 mdata/M220/rom/objset/meiitm834.farc F5179837 mdata/M220/rom/objset/mikitm143.farc B155D5BE mdata/M220/rom/objset/mikitm171.farc 5C89B443 mdata/M220/rom/objset/mikitm172.farc 651EDF8C mdata/M220/rom/objset/mikitm174.farc 7071AF6C mdata/M220/rom/objset/mikitm443.farc B05AFAFD mdata/M220/rom/objset/mikitm471.farc 4313BB91 mdata/M220/rom/objset/mikitm472.farc F76E21AF mdata/M220/rom/objset/mikitm474.farc 0F323797 mdata/M220/rom/objset/mikitm643.farc DF784802 mdata/M220/rom/objset/mikitm671.farc C31A371C mdata/M220/rom/objset/mikitm672.farc 3CB0A519 mdata/M220/rom/objset/mikitm674.farc 3FF43BB7 mdata/M220/rom/objset/mikitm730.farc 5617AA87 mdata/M220/rom/objset/mikitm731.farc 30ECB337 mdata/M220/rom/objset/mikitm739.farc CB97AFCD mdata/M220/rom/objset/mikitm943.farc 87ECAC73 mdata/M220/rom/objset/mikitm971.farc 91A87F13 mdata/M220/rom/objset/mikitm972.farc ACDB0BBC mdata/M220/rom/objset/mikitm974.farc 8912F7AE mdata/M220/rom/objset/rinitm042.farc 57DA4584 mdata/M220/rom/objset/rinitm045.farc 69BCD69C mdata/M220/rom/objset/rinitm049.farc D55232D0 mdata/M220/rom/objset/rinitm342.farc 0EF6BF4C mdata/M220/rom/objset/rinitm349.farc E5BC7D82 mdata/M220/rom/objset/rinitm542.farc FFCF56B0 mdata/M220/rom/objset/rinitm549.farc 316D0BA3 mdata/M220/rom/objset/rinitm722.farc C5387543 mdata/M220/rom/objset/rinitm723.farc FB4D5B0D mdata/M220/rom/objset/rinitm778.farc 222DF88B mdata/M220/rom/objset/rinitm842.farc 3421405B mdata/M220/rom/objset/rinitm849.farc D09F13B1 mdata/M220/rom/objset/stgpv254.farc 89D42D51 mdata/M220/rom/objset/stgpv254s01.farc 74E3401A mdata/M220/rom/objset/stgpv254s02.farc B3CFA1CA mdata/M220/rom/objset/stgpv254s03.farc E837ABD4 mdata/M220/rom/objset/stgpv254s04.farc C65B4366 mdata/M220/rom/objset/stgpv254s05.farc 181C0082 mdata/M220/rom/objset/stgpv254s08.farc E5AC2CBF mdata/M220/rom/objset/stgpv254s09.farc 310019B5 mdata/M220/rom/objset/stgpv254s12.farc 983D01FF mdata/M220/rom/objset/stgpv254s13.farc B853A846 mdata/M220/rom/objset/stgpv254s17.farc B5C55F89 mdata/M220/rom/objset/stgpv263.farc C4CAE4E6 mdata/M220/rom/objset/stgpv263hrc.farc 689EA935 mdata/M220/rom/objset/stgpv263s01.farc 8D8DC17B mdata/M220/rom/objset/stgpv263s02.farc 19FB91F1 mdata/M220/rom/objset/stgpv263s03.farc D3C4234E mdata/M220/rom/objset/stgpv263s04.farc 3ECCDE63 mdata/M220/rom/objset/stgpv263s05.farc 4DD684B8 mdata/M220/rom/objset/stgpv263s06.farc 14142C5E mdata/M220/rom/objset/stgpv263s07.farc 8C967CC7 mdata/M220/rom/objset/stgpv263s08.farc E0511C96 mdata/M220/rom/objset/stgpv263s09.farc D78E02CC mdata/M220/rom/objset/stgpv263s10.farc 0B9004E5 mdata/M220/rom/objset/stgpv263s11.farc BF51AFD6 mdata/M220/rom/objset/stgpv263s12.farc 391F6DBC mdata/M220/rom/script/pv_041_easy.dsc A1F88E8F mdata/M220/rom/script/pv_041_extreme.dsc 915265B2 mdata/M220/rom/script/pv_041_extreme_1.dsc C9F7A38C mdata/M220/rom/script/pv_041_hard.dsc CC7E57CD mdata/M220/rom/script/pv_041_normal.dsc 4D128B77 mdata/M220/rom/script/pv_218_extreme.dsc FAE7FCE2 mdata/M220/rom/script/pv_218_extreme_1.dsc 1CB9C344 mdata/M220/rom/script/pv_218_hard.dsc A0C8490D mdata/M220/rom/script/pv_218_normal.dsc 4CFD150A mdata/M220/rom/script/pv_222_extreme.dsc AEFD27B7 mdata/M220/rom/script/pv_222_extreme_1.dsc 63FE28A2 mdata/M220/rom/script/pv_222_hard.dsc ABD26AD2 mdata/M220/rom/script/pv_222_normal.dsc AC727BDA mdata/M220/rom/script/pv_254_easy.dsc 522E952A mdata/M220/rom/script/pv_254_extreme.dsc FAA6F7BA mdata/M220/rom/script/pv_254_hard.dsc F43A72B3 mdata/M220/rom/script/pv_254_normal.dsc 6202DB31 mdata/M220/rom/script/pv_263_easy.dsc F0BC9784 mdata/M220/rom/script/pv_263_extreme.dsc 42BCCD8C mdata/M220/rom/script/pv_263_hard.dsc B54D508A mdata/M220/rom/script/pv_263_normal.dsc 9B78AEAB mdata/M220/rom/script/pv_431_extreme.dsc C3A1D64D mdata/M220/rom/script/pv_431_extreme_1.dsc 45D0C375 mdata/M220/rom/script/pv_431_hard.dsc 29A7E005 mdata/M220/rom/script/pv_431_normal.dsc 10A9FD23 mdata/M220/rom/script/pv_602_easy.dsc E9C3E018 mdata/M220/rom/script/pv_602_extreme.dsc 753D7E14 mdata/M220/rom/script/pv_602_hard.dsc AE1CCD96 mdata/M220/rom/script/pv_602_normal.dsc DD7F4831 mdata/M220/rom/script/pv_630_easy.dsc D63ABCC9 mdata/M220/rom/script/pv_630_extreme.dsc 90BF7F1A mdata/M220/rom/script/pv_630_hard.dsc 64E70773 mdata/M220/rom/script/pv_630_normal.dsc 3FC53755 mdata/M220/rom/pv_expression/exp_PV254.bin 71E13554 mdata/M220/rom/pv_expression/exp_PV263.bin 10DF65C7 mdata/M220/rom/rob/mdata_mot_db.farc D93D85E1 mdata/M220/rom/rob/mot_PV254.farc 9507D56A mdata/M220/rom/rob/mot_PV263.farc BF250E85 mdata/M220/rom/rob/mot_PV728.farc 16449FB2 mdata/M220/rom/rob/mothead_PV254.bin 9D8A024F mdata/M220/rom/rob/mothead_PV263.bin D7694B59 mdata/M220/rom/auth_3d/CAMPV254.farc 625CB441 mdata/M220/rom/auth_3d/CAMPV263.farc 305A260A mdata/M220/rom/auth_3d/EFFSTGPV254.farc 302FB880 mdata/M220/rom/auth_3d/EFFSTGPV263.farc 7DD3C87D mdata/M220/rom/auth_3d/mdata_auth_3d_db.bin 79FB6630 mdata/M220/rom/skin_param/ext_skp_kaiitm043_joha_outer_43__divskn.txt 9633EB75 mdata/M220/rom/skin_param/ext_skp_kaiitm044_joha_outer_44__divskn.txt 6F873B6A mdata/M220/rom/skin_param/ext_skp_kaiitm543_atam_atama_43__divskn.txt F90064C4 mdata/M220/rom/skin_param/ext_skp_kaiitm544_atam_atama_44__divskn.txt 4A4C23E4 mdata/M220/rom/skin_param/ext_skp_kaiitm708_atam_zujo_08__divskn.txt 52322115 mdata/M220/rom/skin_param/ext_skp_lenitm041_joha_outer_41__divskn.txt F1E5A686 mdata/M220/rom/skin_param/ext_skp_lenitm541_atam_atama_41__divskn.txt 92F68624 mdata/M220/rom/skin_param/ext_skp_lukitm043_joha_outer_43__divskn.txt C77F8E35 mdata/M220/rom/skin_param/ext_skp_lukitm543_atam_atama_43__divskn.txt B282F070 mdata/M220/rom/skin_param/ext_skp_meiitm034_joha_outer_34__divskn.txt 354D0ED8 mdata/M220/rom/skin_param/ext_skp_meiitm534_atam_atama_34__divskn.txt 8CC0FA0B mdata/M220/rom/skin_param/ext_skp_mikitm171_joha_outer_171__divskn.txt 489DEC9C mdata/M220/rom/skin_param/ext_skp_mikitm172_joha_outer_172__divskn.txt CBA3E86C mdata/M220/rom/skin_param/ext_skp_mikitm174_joha_outer_174__divskn.txt 281A50C6 mdata/M220/rom/skin_param/ext_skp_mikitm671_atam_atama_171__divskn.txt 92175D84 mdata/M220/rom/skin_param/ext_skp_mikitm672_atam_atama_172__divskn.txt 3D08F5C5 mdata/M220/rom/skin_param/ext_skp_mikitm674_atam_atama_174__divskn.txt 1181EB67 mdata/M220/rom/skin_param/ext_skp_rinitm042_joha_outer_42__divskn.txt 3203A637 mdata/M220/rom/skin_param/ext_skp_rinitm049_joha_outer_49__divskn.txt 43EEAA8B mdata/M220/rom/skin_param/ext_skp_rinitm542_atam_atama_42__divskn.txt 93F65521 mdata/M220/rom/skin_param/ext_skp_rinitm549_atam_atama_49__divskn.txt 8A849C3A mdata/M220/rom/skin_param/ext_skp_rinitm722_atam_zujo_22__divskn.txt BB680410 mdata/M220/rom/skin_param/ext_skp_rinitm778_joha_ushiro_78__divskn.txt 3646DA93 mdata/M220/rom/skin_param/mdata_osage_setting.txt 8B1E9C77 mdata/M220/rom/skin_param/mdata_sp_skp.farc FBA755F8 mdata/M220/rom/skin_param/mdata_sp_skp_db.txt C4618957 mdata/M220/rom/stage_param/star_pv254s01.txt C36D7ADE mdata/M220/rom/stage_param/star_pv254s02.txt 2345F878 mdata/M220/rom/stage_param/star_pv254s03.txt 2345F878 mdata/M220/rom/stage_param/star_pv254s05.txt 2345F878 mdata/M220/rom/stage_param/star_pv254s06.txt 2345F878 mdata/M220/rom/stage_param/star_pv254s07.txt 2345F878 mdata/M220/rom/stage_param/star_pv254s09.txt 2345F878 mdata/M220/rom/stage_param/star_pv254s13.txt 2345F878 mdata/M220/rom/stage_param/star_pv254s17.txt 84F0A87C mdata/M220/rom/sound/song/pv_254.ogg ED0FF001 mdata/M220/rom/sound/song/pv_263.ogg CE3207D5 mdata/M220/rom/sound/song/pv_263_kai.ogg C998CD56 mdata/M220/rom/sound/song/pv_263_len.ogg 15A13F47 mdata/M220/rom/sound/song/pv_263_luk.ogg 07ED8CF9 mdata/M220/rom/sound/song/pv_263_mei.ogg 75482355 mdata/M220/rom/sound/song/pv_263_rin.ogg 75B8AD37 mdata/M220/rom/2d/aet_gam_pv254.bin B1ECE908 mdata/M220/rom/2d/aet_gam_pv255.bin 317B458A mdata/M220/rom/2d/aet_gam_pv263.bin BAE96059 mdata/M220/rom/2d/aet_gam_pv724.bin AEEBB308 mdata/M220/rom/2d/aet_gam_pv832.bin 4352A46F mdata/M220/rom/2d/aet_gam_skin739.bin 6DB67ECF mdata/M220/rom/2d/mdata_aet_db.bin 0ABA1074 mdata/M220/rom/2d/mdata_spr_db.bin 34AB39A0 mdata/M220/rom/2d/spr_clt_crd0634.farc EF27272A mdata/M220/rom/2d/spr_clt_crd0635.farc BC0DA4AB mdata/M220/rom/2d/spr_clt_crd0636.farc 96DBE784 mdata/M220/rom/2d/spr_clt_crd0637.farc 1DD8D9F9 mdata/M220/rom/2d/spr_clt_crd0638.farc 71B88B75 mdata/M220/rom/2d/spr_clt_crd0639.farc 53EA3B68 mdata/M220/rom/2d/spr_clt_crd0640.farc BA4D176E mdata/M220/rom/2d/spr_clt_crd0641.farc F32D26A6 mdata/M220/rom/2d/spr_clt_crd0642.farc E28FB3A3 mdata/M220/rom/2d/spr_clt_crd0643.farc 6CD3F607 mdata/M220/rom/2d/spr_clt_crd0644.farc E1E4CB8D mdata/M220/rom/2d/spr_clt_crd0645.farc A12A4CFB mdata/M220/rom/2d/spr_clt_crd0646.farc B5A22CF6 mdata/M220/rom/2d/spr_clt_crd0647.farc 85D7F6DE mdata/M220/rom/2d/spr_clt_crd0648.farc 3FCFDEF5 mdata/M220/rom/2d/spr_clt_crd0649.farc 4E9EA1C7 mdata/M220/rom/2d/spr_clt_crd0650.farc C383249B mdata/M220/rom/2d/spr_clt_crd0651.farc D30CF20E mdata/M220/rom/2d/spr_gam_pv254.farc 6DFA3C8A mdata/M220/rom/2d/spr_gam_pv255.farc 139E64C0 mdata/M220/rom/2d/spr_gam_pv263.farc 4773401D mdata/M220/rom/2d/spr_gam_pv724.farc 64F7DDB2 mdata/M220/rom/2d/spr_gam_pv832.farc 13E45DD4 mdata/M220/rom/2d/spr_gam_skin739.farc FD2DF145 mdata/M220/rom/2d/spr_sel_md399cmn.farc 0DBCA5DD mdata/M220/rom/2d/spr_sel_md413cmn.farc BFF045A1 mdata/M220/rom/2d/spr_sel_md414cmn.farc 6175FE09 mdata/M220/rom/2d/spr_sel_md415cmn.farc BB5FC217 mdata/M220/rom/2d/spr_sel_md416cmn.farc A4A740CC mdata/M220/rom/2d/spr_sel_md417cmn.farc 7152DA68 mdata/M220/rom/2d/spr_sel_md418cmn.farc 9A6CBFBE mdata/M220/rom/2d/spr_sel_md419cmn.farc 7AD00D9A mdata/M220/rom/2d/spr_sel_md424cmn.farc 4BADFEF7 mdata/M220/rom/2d/spr_sel_md425cmn.farc 2E10E30E mdata/M220/rom/2d/spr_sel_pv254.farc 9EF12FF9 mdata/M220/rom/2d/spr_sel_pv263.farc 362E04DE mdata/M220/rom/particle/eff_pv254_c34_korobi.farc E5FD55BC mdata/M220/rom/particle/eff_pv254_c36_korobi.farc 71028680 mdata/M220/rom/particle/eff_pv254_c37_kusarakka.farc E70BFBFB mdata/M220/rom/particle/eff_pv254_c43_onibi.farc F2C2F716 mdata/M220/rom/particle/eff_pv254_jinja_tourou.farc 792568EC mdata/M220/rom/particle/eff_pv254_kirakira_aura.farc A31A2AC5 mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut15.farc 42D64D48 mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut31.farc 75E184EA mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut39.farc DEC97C30 mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut42.farc D19F1ADC mdata/M220/rom/particle/eff_pv254_kirakira_aura_cut44.farc A0AED811 mdata/M220/rom/particle/eff_pv254_kirakira_aura_test.farc 541ACAC8 mdata/M220/rom/particle/eff_pv254_lightball_cut29.farc 1806F4BB mdata/M220/rom/particle/eff_pv254_moon.farc 805D6016 mdata/M220/rom/particle/eff_pv254_nagarebosi_cut11.farc 9083CEE8 mdata/M220/rom/particle/eff_pv254_rakka.farc 070537B8 mdata/M220/rom/particle/eff_pv254s01_hotaru.farc 0B958F99 mdata/M220/rom/particle/eff_pv254S04_spirit.farc D34064B8 mdata/M220/rom/light_param/fog_pv254s01.txt 6BBEA2F7 mdata/M220/rom/light_param/fog_pv254s02.txt 3533E95C mdata/M220/rom/light_param/fog_pv254s03.txt 5F8365CF mdata/M220/rom/light_param/fog_pv254s05.txt CFC54D6A mdata/M220/rom/light_param/fog_pv254s06.txt 3533E95C mdata/M220/rom/light_param/fog_pv254s07.txt 3533E95C mdata/M220/rom/light_param/fog_pv254s08.txt 8A6C2003 mdata/M220/rom/light_param/fog_pv254s09.txt F5E222E3 mdata/M220/rom/light_param/fog_pv254s13.txt 256E2188 mdata/M220/rom/light_param/fog_pv263s01.txt 2EC61590 mdata/M220/rom/light_param/fog_pv263s03.txt 24850A30 mdata/M220/rom/light_param/fog_pv263s07.txt 24850A30 mdata/M220/rom/light_param/fog_pv263s10.txt DD388043 mdata/M220/rom/light_param/fog_pv263s11.txt 24B0147F mdata/M220/rom/light_param/glow_pv254s01.txt 8C5E3474 mdata/M220/rom/light_param/glow_pv254s02.txt 8C5E3474 mdata/M220/rom/light_param/glow_pv254s03.txt 8C5E3474 mdata/M220/rom/light_param/glow_pv254s05.txt 8C5E3474 mdata/M220/rom/light_param/glow_pv254s06.txt 8C5E3474 mdata/M220/rom/light_param/glow_pv254s07.txt 8C5E3474 mdata/M220/rom/light_param/glow_pv254s08.txt 8C5E3474 mdata/M220/rom/light_param/glow_pv254s09.txt 203B6B00 mdata/M220/rom/light_param/glow_pv254s13.txt B8714142 mdata/M220/rom/light_param/glow_pv254s17.txt 4D966286 mdata/M220/rom/light_param/glow_pv263s01.txt 1B5A25A3 mdata/M220/rom/light_param/glow_pv263s03.txt C323E52E mdata/M220/rom/light_param/glow_pv263s05.txt 00AC9A9D mdata/M220/rom/light_param/glow_pv263s07.txt 14CF86DB mdata/M220/rom/light_param/glow_pv263s10.txt E2CE1EBA mdata/M220/rom/light_param/glow_pv263s11.txt 2C0BEC0A mdata/M220/rom/light_param/light_pv254.farc D8B86BC4 mdata/M220/rom/light_param/light_pv254s01.txt E30814AD mdata/M220/rom/light_param/light_pv254s02.txt 8696E506 mdata/M220/rom/light_param/light_pv254s03.txt 9EF238FE mdata/M220/rom/light_param/light_pv254s05.txt E04E1E8C mdata/M220/rom/light_param/light_pv254s06.txt 8696E506 mdata/M220/rom/light_param/light_pv254s07.txt 8696E506 mdata/M220/rom/light_param/light_pv254s08.txt 61F90327 mdata/M220/rom/light_param/light_pv254s09.txt 6859F65F mdata/M220/rom/light_param/light_pv254s12.txt D9C9F464 mdata/M220/rom/light_param/light_pv254s13.txt 61E94D55 mdata/M220/rom/light_param/light_pv254s17.txt 2DABAE85 mdata/M220/rom/light_param/light_pv263.farc 9F5072A6 mdata/M220/rom/light_param/light_pv263s01.txt F2D08731 mdata/M220/rom/light_param/light_pv263s03.txt 1E5C5925 mdata/M220/rom/light_param/light_pv263s04.txt C11081E7 mdata/M220/rom/light_param/light_pv263s07.txt D02EB2FB mdata/M220/rom/light_param/light_pv263s10.txt 0813CB75 mdata/M220/rom/light_param/wind_pv254s01.txt 96B6ABBF mdata/M220/rom/light_param/wind_pv254s02.txt B5D0A9C0 mdata/M220/rom/light_param/wind_pv254s06.txt 96B6ABBF mdata/M220/rom/light_param/wind_pv254s17.txt 96B6ABBF mdata/M220/rom/light_param/wind_pv263s01.txt 23B0225D mdata/M220/rom/light_param/wind_pv263s02.txt 76424932 mdata/M220/rom/light_param/wind_pv263s06.txt E6E50A7F mdata/M220/rom/light_param/wind_pv263s09.txt BBD4F24D mdata/M220/rom/light_param/wind_pv263s12.txt E6E50A7F mdata/M230/info.txt F337A2AF mdata/M230/rom/mdata_chritm_prop.farc 60946254 mdata/M230/rom/mdata_gm_collection_card_tbl.farc 6D5B32AD mdata/M230/rom/mdata_gm_module_tbl.farc 583B1E5A mdata/M230/rom/mdata_pv_db.txt 7C2B381D mdata/M230/rom/mdata_pv_field.txt 68F9A0A7 mdata/M230/rom/mdata_rob_sleeve_data.txt F42908F8 mdata/M230/rom/mdata_stage_data.bin EB4F10AA mdata/M230/rom/osage_play_data/mdata_opd_db.txt 91DB233E mdata/M230/rom/osage_play_data/mikitm175_joha_outer_175__divskn.farc E169B7CD mdata/M230/rom/osage_play_data/mikitm176_joha_outer_176__divskn.farc 224F09DF mdata/M230/rom/osage_play_data/mikitm675_atam_atama_175__divskn.farc 10DBF133 mdata/M230/rom/osage_play_data/mikitm676_atam_atama_176__divskn.farc 58E3DE4E mdata/M230/rom/osage_play_data/mikitm785_joha_ushiro_85__divskn.farc 941C863A mdata/M230/rom/photo_print/card/CLT_CRD0652_01.jpg 195B82A6 mdata/M230/rom/photo_print/card/CLT_CRD0653_01.jpg B57519DD mdata/M230/rom/photo_print/card/CLT_CRD0654_01.jpg 35421C6B mdata/M230/rom/photo_print/card/CLT_CRD0655_01.jpg 98C75E4D mdata/M230/rom/photo_print/stamp/pv/stamp_pv266_logo266_00.tga B6B6DDA3 mdata/M230/rom/photo_print/stamp/pv/stamp_pv267_logo267_00.tga D1E8A487 mdata/M230/rom/photo_print/stamp/module/stamp_md_sub_426_00.tga 6F84F7FF mdata/M230/rom/photo_print/stamp/module/stamp_md_sub_427_00.tga 3B451943 mdata/M230/rom/movie/adv_sega_cm.wmv 6657DB68 mdata/M230/rom/movie/pv_267.wmv 35151951 mdata/M230/rom/objset/mdata_obj_db.bin 6C646EBB mdata/M230/rom/objset/mdata_tex_db.bin 81D3F44E mdata/M230/rom/objset/mikitm175.farc BE1788C0 mdata/M230/rom/objset/mikitm176.farc 27C9179A mdata/M230/rom/objset/mikitm475.farc 138DCB3B mdata/M230/rom/objset/mikitm675.farc FAF32C93 mdata/M230/rom/objset/mikitm676.farc D66A2D96 mdata/M230/rom/objset/mikitm785.farc A0DA6C5F mdata/M230/rom/objset/mikitm975.farc 77C6B7A9 mdata/M230/rom/objset/stgpv266.farc 6CEC35B9 mdata/M230/rom/objset/stgpv266hrc.farc 3E7C4F4F mdata/M230/rom/objset/stgpv266s01.farc B89EEE48 mdata/M230/rom/objset/stgpv266s02.farc 1DA6305A mdata/M230/rom/objset/stgpv266s03.farc C3795BAF mdata/M230/rom/objset/stgpv266s04.farc C04BE16E mdata/M230/rom/objset/stgpv266s05.farc F7B66F13 mdata/M230/rom/script/pv_044_easy.dsc AA1D3A2A mdata/M230/rom/script/pv_044_extreme.dsc 8BBE512E mdata/M230/rom/script/pv_044_extreme_1.dsc 9EBA5D81 mdata/M230/rom/script/pv_044_hard.dsc CA851FAC mdata/M230/rom/script/pv_044_normal.dsc C52CC30C mdata/M230/rom/script/pv_091_easy.dsc 2C44962E mdata/M230/rom/script/pv_091_extreme.dsc E3FDA25B mdata/M230/rom/script/pv_091_extreme_1.dsc 9F74895E mdata/M230/rom/script/pv_091_hard.dsc 97C8A053 mdata/M230/rom/script/pv_091_normal.dsc 381652B1 mdata/M230/rom/script/pv_204_easy.dsc 03BC3A1A mdata/M230/rom/script/pv_204_extreme.dsc 408BC49D mdata/M230/rom/script/pv_204_extreme_1.dsc 54945392 mdata/M230/rom/script/pv_204_hard.dsc 400519C7 mdata/M230/rom/script/pv_204_normal.dsc EFAB9F24 mdata/M230/rom/script/pv_215_extreme.dsc 8BFC1581 mdata/M230/rom/script/pv_215_extreme_1.dsc 311F128B mdata/M230/rom/script/pv_215_hard.dsc FE94AE7A mdata/M230/rom/script/pv_215_normal.dsc 84F165B7 mdata/M230/rom/script/pv_262_easy.dsc AEB3B4B4 mdata/M230/rom/script/pv_262_extreme.dsc B296A886 mdata/M230/rom/script/pv_262_hard.dsc F3F81BC6 mdata/M230/rom/script/pv_262_normal.dsc B9C6EAC1 mdata/M230/rom/script/pv_266_easy.dsc 6E56682A mdata/M230/rom/script/pv_266_extreme.dsc 7629FF82 mdata/M230/rom/script/pv_266_hard.dsc 07439DAA mdata/M230/rom/script/pv_266_normal.dsc FED217AC mdata/M230/rom/script/pv_267_easy.dsc 2DB0B161 mdata/M230/rom/script/pv_267_extreme.dsc 6CD5BAE7 mdata/M230/rom/script/pv_267_hard.dsc 971A54E4 mdata/M230/rom/script/pv_267_normal.dsc 1783F081 mdata/M230/rom/script/pv_417_extreme.dsc 3F846113 mdata/M230/rom/script/pv_417_extreme_1.dsc A2B331C1 mdata/M230/rom/script/pv_417_hard.dsc 9DB0E949 mdata/M230/rom/script/pv_417_normal.dsc 01EABDBE mdata/M230/rom/script/pv_425_extreme.dsc A497E66C mdata/M230/rom/script/pv_425_extreme_1.dsc B9E08F2C mdata/M230/rom/script/pv_425_hard.dsc 1879895C mdata/M230/rom/script/pv_425_normal.dsc 5AE0021E mdata/M230/rom/script/pv_427_easy.dsc 6E327597 mdata/M230/rom/script/pv_427_extreme.dsc DC05244B mdata/M230/rom/script/pv_427_extreme_1.dsc 9FC8AC7F mdata/M230/rom/script/pv_427_hard.dsc 745F6D1E mdata/M230/rom/script/pv_427_normal.dsc CCA73ED3 mdata/M230/rom/script/pv_727_easy.dsc C8255222 mdata/M230/rom/script/pv_727_extreme.dsc D3E0B33E mdata/M230/rom/script/pv_727_hard.dsc 7F978EB0 mdata/M230/rom/script/pv_727_normal.dsc C5EF78AC mdata/M230/rom/pv_expression/exp_PV266.bin 4BFEB54A mdata/M230/rom/rob/mdata_mot_db.farc AD88D1C6 mdata/M230/rom/rob/mot_PV266.farc 69180AC2 mdata/M230/rom/rob/mothead_PV266.bin 5CD178A8 mdata/M230/rom/auth_3d/CAMPV266.farc 1385A1BA mdata/M230/rom/auth_3d/EFFSTGPV266.farc 14626DB6 mdata/M230/rom/auth_3d/mdata_auth_3d_db.bin C160868B mdata/M230/rom/skin_param/ext_skp_mikitm175_joha_outer_175__divskn.txt 38E582C6 mdata/M230/rom/skin_param/ext_skp_mikitm176_joha_outer_176__divskn.txt C6E0DB57 mdata/M230/rom/skin_param/ext_skp_mikitm675_atam_atama_175__divskn.txt 107CC956 mdata/M230/rom/skin_param/ext_skp_mikitm676_atam_atama_176__divskn.txt A0A9F5CE mdata/M230/rom/skin_param/ext_skp_mikitm785_joha_ushiro_85__divskn.txt BFD79F10 mdata/M230/rom/skin_param/mdata_osage_setting.txt 9762BF6C mdata/M230/rom/skin_param/mdata_sp_skp.farc B409C5B3 mdata/M230/rom/skin_param/mdata_sp_skp_db.txt 9F3D0AC2 mdata/M230/rom/sound/song/pv_266.ogg 18BB70A8 mdata/M230/rom/sound/song/pv_267.ogg DA9D426F mdata/M230/rom/2d/aet_gam_pv266.bin 3C3DFB4E mdata/M230/rom/2d/mdata_aet_db.bin 12B1F3BD mdata/M230/rom/2d/mdata_spr_db.bin 327CBFB0 mdata/M230/rom/2d/spr_clt_crd0652.farc 705C56EB mdata/M230/rom/2d/spr_clt_crd0653.farc A3D18732 mdata/M230/rom/2d/spr_clt_crd0654.farc 98A06216 mdata/M230/rom/2d/spr_clt_crd0655.farc CD6F0F2F mdata/M230/rom/2d/spr_gam_pv266.farc 3E94C6F3 mdata/M230/rom/2d/spr_sel_md426cmn.farc 0822AF39 mdata/M230/rom/2d/spr_sel_md427cmn.farc 5D6431D5 mdata/M230/rom/2d/spr_sel_pv266.farc F389389F mdata/M230/rom/2d/spr_sel_pv267.farc B6DD2831 mdata/M230/rom/particle/eff_PV266_thunder.farc 58675E1C mdata/M230/rom/particle/eff_pv266s01_addfloor_rouya.farc D99E8518 mdata/M230/rom/particle/eff_pv266s01_fire.farc F1E4C947 mdata/M230/rom/particle/eff_pv266s01_kuzure.farc 49CD8E1D mdata/M230/rom/particle/eff_pv266s01_otimono.farc 09B94884 mdata/M230/rom/particle/eff_pv266s01_susu.farc E4071592 mdata/M230/rom/particle/eff_pv266s02_kirakira.farc 60DF0764 mdata/M230/rom/particle/eff_pv266s02_kirakira_stop.farc A1957DC2 mdata/M230/rom/particle/eff_pv266s02_rakka.farc 324C01A8 mdata/M230/rom/light_param/fog_pv266s01.txt 573B0F33 mdata/M230/rom/light_param/fog_pv266s02.txt 55B03272 mdata/M230/rom/light_param/fog_pv266s03.txt 59EBB550 mdata/M230/rom/light_param/glow_pv266s01.txt DC617978 mdata/M230/rom/light_param/glow_pv266s02.txt ED31DFF8 mdata/M230/rom/light_param/glow_pv266s03.txt D0A0DFE7 mdata/M230/rom/light_param/light_pv266.farc F3F07DDE mdata/M230/rom/light_param/light_pv266s01.txt 1ED1C364 mdata/M230/rom/light_param/light_pv266s02.txt A1B4FBE9 mdata/M230/rom/light_param/light_pv266s03.txt 3716233F mdata/M270/info.txt FEDB2043 mdata/M270/rom/mdata_chritm_prop.farc 1957777B mdata/M270/rom/mdata_gm_collection_card_tbl.farc C4864064 mdata/M270/rom/mdata_gm_module_tbl.farc FA2369B3 mdata/M270/rom/mdata_pv_db.txt 54A2D1F2 mdata/M270/rom/mdata_pv_field.txt 960B6262 mdata/M270/rom/mdata_rob_sleeve_data.txt 72BB4249 mdata/M270/rom/osage_play_data/mdata_opd_db.txt 77B4CEE2 mdata/M270/rom/osage_play_data/mikitm177_joha_outer_177__divskn.farc 8D637D84 mdata/M270/rom/osage_play_data/mikitm178_joha_outer_178__divskn.farc 8DA5A305 mdata/M270/rom/osage_play_data/mikitm179_joha_outer_179__divskn.farc D994CC1A mdata/M270/rom/osage_play_data/mikitm677_atam_atama_177__divskn.farc 1BB31002 mdata/M270/rom/osage_play_data/mikitm678_atam_atama_178__divskn.farc 99916FFC mdata/M270/rom/osage_play_data/mikitm679_atam_atama_179__divskn.farc AC0C3EC3 mdata/M270/rom/osage_play_data/mikitm786_joha_ushiro_86__divskn.farc B3ACDF1B mdata/M270/rom/photo_print/card/CLT_CRD0656_01.jpg E25422DC mdata/M270/rom/photo_print/card/CLT_CRD0657_01.jpg 309286A5 mdata/M270/rom/photo_print/card/CLT_CRD0658_01.jpg 96A2CFE6 mdata/M270/rom/photo_print/stamp/module/stamp_md_sub_428_00.tga EA98809F mdata/M270/rom/photo_print/stamp/module/stamp_md_sub_429_00.tga 9835C7F0 mdata/M270/rom/photo_print/stamp/module/stamp_md_sub_430_00.tga B8E71DE4 mdata/M270/rom/objset/mdata_obj_db.bin 5D06E3EC mdata/M270/rom/objset/mdata_tex_db.bin 37348FF6 mdata/M270/rom/objset/mikitm177.farc 6A4244B9 mdata/M270/rom/objset/mikitm178.farc 4BB8FEC6 mdata/M270/rom/objset/mikitm179.farc 2B6F128A mdata/M270/rom/objset/mikitm477.farc 0E2694CF mdata/M270/rom/objset/mikitm478.farc B0D3C783 mdata/M270/rom/objset/mikitm677.farc E8882D28 mdata/M270/rom/objset/mikitm678.farc C0E73A31 mdata/M270/rom/objset/mikitm679.farc 123F9BED mdata/M270/rom/objset/mikitm774.farc C4E518C7 mdata/M270/rom/objset/mikitm786.farc 9C719B6A mdata/M270/rom/objset/mikitm789.farc C9D11CFC mdata/M270/rom/objset/mikitm792.farc A6427F8D mdata/M270/rom/objset/mikitm976.farc B25472D4 mdata/M270/rom/objset/mikitm977.farc 90B07618 mdata/M270/rom/script/pv_016_easy.dsc A5F48A04 mdata/M270/rom/script/pv_016_extreme.dsc 37E9181F mdata/M270/rom/script/pv_016_extreme_1.dsc 4EBEA835 mdata/M270/rom/script/pv_016_hard.dsc 1A78289B mdata/M270/rom/script/pv_020_easy.dsc E9B939FD mdata/M270/rom/script/pv_020_extreme.dsc 30F6DC25 mdata/M270/rom/script/pv_020_extreme_1.dsc 77B68160 mdata/M270/rom/script/pv_020_hard.dsc 6B553F1B mdata/M270/rom/script/pv_020_normal.dsc ACE6B7FC mdata/M270/rom/script/pv_086_easy.dsc E532CD14 mdata/M270/rom/script/pv_086_extreme.dsc 3727578D mdata/M270/rom/script/pv_086_extreme_1.dsc B2237E36 mdata/M270/rom/script/pv_086_hard.dsc 1C97DDAF mdata/M270/rom/script/pv_086_normal.dsc E4B630E3 mdata/M270/rom/script/pv_219_easy.dsc BCF12AC4 mdata/M270/rom/script/pv_219_extreme.dsc F120F3E9 mdata/M270/rom/script/pv_219_extreme_1.dsc 5263AC66 mdata/M270/rom/script/pv_219_hard.dsc DD48E899 mdata/M270/rom/script/pv_219_normal.dsc 1B5902E9 mdata/M270/rom/script/pv_225_easy.dsc 038EB300 mdata/M270/rom/script/pv_225_extreme.dsc 2729F052 mdata/M270/rom/script/pv_225_extreme_1.dsc C694DF0D mdata/M270/rom/script/pv_225_hard.dsc 56F457BD mdata/M270/rom/script/pv_225_normal.dsc D7EB305F mdata/M270/rom/script/pv_410_easy.dsc 7B65EC13 mdata/M270/rom/script/pv_410_extreme.dsc CA798B16 mdata/M270/rom/script/pv_410_extreme_1.dsc 5B59BD93 mdata/M270/rom/script/pv_410_hard.dsc 34BB2BA4 mdata/M270/rom/script/pv_410_normal.dsc 8D73F595 mdata/M270/rom/script/pv_441_extreme.dsc 20788505 mdata/M270/rom/script/pv_441_extreme_1.dsc 2EDB518F mdata/M270/rom/script/pv_441_hard.dsc E3404CBD mdata/M270/rom/script/pv_441_normal.dsc AE923292 mdata/M270/rom/script/pv_727_easy.dsc 4ED4FAAF mdata/M270/rom/script/pv_727_extreme.dsc 5A10BB8C mdata/M270/rom/script/pv_727_hard.dsc 2B2FA143 mdata/M270/rom/script/pv_727_normal.dsc 2AC37404 mdata/M270/rom/rob/mothead_PV002.bin 12214A3A mdata/M270/rom/rob/mothead_PV020.bin 336CB1D4 mdata/M270/rom/rob/mothead_PV044.bin E1435397 mdata/M270/rom/rob/mothead_PV065.bin 0A329F5C mdata/M270/rom/rob/mothead_PV081.bin E9955111 mdata/M270/rom/rob/mothead_PV205.bin DE2DDC7E mdata/M270/rom/rob/mothead_PV240.bin 0328D80B mdata/M270/rom/rob/mothead_PV262.bin D21C107B mdata/M270/rom/rob/mothead_PV604.bin 87FD04D2 mdata/M270/rom/rob/mothead_PV605.bin B8105DE9 mdata/M270/rom/rob/mothead_PV618.bin 1D511C5B mdata/M270/rom/rob/mothead_PV637.bin 449310C6 mdata/M270/rom/rob/mothead_PV739.bin 8EE3AC6A mdata/M270/rom/rob/rob_mot_tbl.bin 38345C72 mdata/M270/rom/skin_param/ext_skp_mikitm177_joha_outer_177__divskn.txt 0D5E67EE mdata/M270/rom/skin_param/ext_skp_mikitm178_joha_outer_178__divskn.txt A5BF1B50 mdata/M270/rom/skin_param/ext_skp_mikitm179_joha_outer_179__divskn.txt 0D5E67EE mdata/M270/rom/skin_param/ext_skp_mikitm677_atam_atama_177__divskn.txt 0F3DBB7E mdata/M270/rom/skin_param/ext_skp_mikitm678_atam_atama_178__divskn.txt F98B6487 mdata/M270/rom/skin_param/ext_skp_mikitm679_atam_atama_179__divskn.txt 0F3DBB7E mdata/M270/rom/skin_param/ext_skp_mikitm786_joha_ushiro_86__divskn.txt 0567E3E5 mdata/M270/rom/skin_param/mdata_osage_setting.txt 3367EBAE mdata/M270/rom/skin_param/mdata_sp_skp.farc E6045F82 mdata/M270/rom/skin_param/mdata_sp_skp_db.txt 5CE9689D mdata/M270/rom/2d/mdata_spr_db.bin 93BA0BFA mdata/M270/rom/2d/spr_clt_crd0656.farc 9D021A52 mdata/M270/rom/2d/spr_clt_crd0657.farc 58B3F4E0 mdata/M270/rom/2d/spr_clt_crd0658.farc 37210F68 mdata/M270/rom/2d/spr_sel_md428cmn.farc 40740CD2 mdata/M270/rom/2d/spr_sel_md429cmn.farc 86E17421 mdata/M270/rom/2d/spr_sel_md430cmn.farc EA1F8169 mdata/M240/info.txt 544A7115 mdata/M240/rom/mdata_pv_db.txt CB892C33 mdata/M240/rom/mdata_pv_field.txt E67DBC36 mdata/M240/rom/photo_print/card/CLT_CRD0000_01.jpg 92110EDF mdata/M240/rom/photo_print/card/CLT_CRD0003_01.jpg B25CA717 mdata/M240/rom/photo_print/card/CLT_CRD0004_01.jpg 2746079E mdata/M240/rom/photo_print/card/CLT_CRD0005_01.jpg 53FC4180 mdata/M240/rom/photo_print/card/CLT_CRD0006_01.jpg F8F18E60 mdata/M240/rom/photo_print/card/CLT_CRD0007_01.jpg 00569D6D mdata/M240/rom/photo_print/card/CLT_CRD0008_01.jpg B4C6C2EA mdata/M240/rom/photo_print/card/CLT_CRD0009_01.jpg A0290A79 mdata/M240/rom/photo_print/card/CLT_CRD0010_01.jpg B1DB2EF9 mdata/M240/rom/photo_print/card/CLT_CRD0011_01.jpg 113D48DD mdata/M240/rom/photo_print/card/CLT_CRD0012_01.jpg 8C371D38 mdata/M240/rom/photo_print/card/CLT_CRD0013_01.jpg 0917E76A mdata/M240/rom/photo_print/card/CLT_CRD0014_01.jpg 5E556625 mdata/M240/rom/photo_print/card/CLT_CRD0015_01.jpg F4306B16 mdata/M240/rom/photo_print/card/CLT_CRD0016_01.jpg 445D04BA mdata/M240/rom/photo_print/card/CLT_CRD0017_01.jpg 37EA0B1F mdata/M240/rom/photo_print/card/CLT_CRD0018_01.jpg 489B92AD mdata/M240/rom/photo_print/card/CLT_CRD0019_01.jpg 2C01CE1B mdata/M240/rom/photo_print/card/CLT_CRD0020_01.jpg 7023A7FF mdata/M240/rom/photo_print/card/CLT_CRD0021_01.jpg 77595D75 mdata/M240/rom/photo_print/card/CLT_CRD0022_01.jpg 5DA35089 mdata/M240/rom/photo_print/card/CLT_CRD0023_01.jpg C65AA76D mdata/M240/rom/photo_print/card/CLT_CRD0024_01.jpg 1AD57D6E mdata/M240/rom/photo_print/card/CLT_CRD0025_01.jpg F40AD5A0 mdata/M240/rom/photo_print/card/CLT_CRD0026_01.jpg 6BE52F97 mdata/M240/rom/photo_print/card/CLT_CRD0027_01.jpg 6954D011 mdata/M240/rom/photo_print/card/CLT_CRD0028_01.jpg 8BD92472 mdata/M240/rom/photo_print/card/CLT_CRD0029_01.jpg 7739A57D mdata/M240/rom/photo_print/card/CLT_CRD0030_01.jpg 0727490C mdata/M240/rom/photo_print/card/CLT_CRD0031_01.jpg 78BF80CE mdata/M240/rom/photo_print/card/CLT_CRD0032_01.jpg A0F0D1D0 mdata/M240/rom/photo_print/card/CLT_CRD0033_01.jpg 23B7CEBE mdata/M240/rom/photo_print/card/CLT_CRD0034_01.jpg CA716251 mdata/M240/rom/photo_print/card/CLT_CRD0035_01.jpg 77D6F5A0 mdata/M240/rom/photo_print/card/CLT_CRD0036_01.jpg 8D8BB573 mdata/M240/rom/photo_print/card/CLT_CRD0037_01.jpg 40196840 mdata/M240/rom/photo_print/card/CLT_CRD0038_01.jpg 74333A1E mdata/M240/rom/photo_print/card/CLT_CRD0039_01.jpg 54886CD5 mdata/M240/rom/photo_print/card/CLT_CRD0046_01.jpg 4899AE36 mdata/M240/rom/photo_print/card/CLT_CRD0047_01.jpg 639B8AAE mdata/M240/rom/photo_print/card/CLT_CRD0053_01.jpg C86EECBE mdata/M240/rom/photo_print/card/CLT_CRD0054_01.jpg 27D2488B mdata/M240/rom/photo_print/card/CLT_CRD0055_01.jpg 12AA166C mdata/M240/rom/photo_print/card/CLT_CRD0056_01.jpg 18636C0B mdata/M240/rom/photo_print/card/CLT_CRD0057_01.jpg E9D83986 mdata/M240/rom/photo_print/card/CLT_CRD0059_01.jpg F72444DB mdata/M240/rom/photo_print/card/CLT_CRD0065_01.jpg 6788171B mdata/M240/rom/photo_print/card/CLT_CRD0068_01.jpg 8BBC6DB9 mdata/M240/rom/photo_print/card/CLT_CRD0069_01.jpg BC890A47 mdata/M240/rom/photo_print/card/CLT_CRD0070_01.jpg 5BE57F4A mdata/M240/rom/photo_print/card/CLT_CRD0072_01.jpg 86CBF536 mdata/M240/rom/photo_print/card/CLT_CRD0073_01.jpg BCE103BF mdata/M240/rom/photo_print/card/CLT_CRD0078_01.jpg 6BD6519A mdata/M240/rom/photo_print/card/CLT_CRD0079_01.jpg 921D24FD mdata/M240/rom/photo_print/card/CLT_CRD0088_01.jpg F38A71C9 mdata/M240/rom/photo_print/card/CLT_CRD0089_01.jpg 37122D8C mdata/M240/rom/photo_print/card/CLT_CRD0090_01.jpg C93FB926 mdata/M240/rom/photo_print/card/CLT_CRD0091_01.jpg 8F6BAB45 mdata/M240/rom/photo_print/card/CLT_CRD0102_01.jpg 6C200927 mdata/M240/rom/photo_print/card/CLT_CRD0103_01.jpg 0F892732 mdata/M240/rom/photo_print/card/CLT_CRD0107_01.jpg 95920219 mdata/M240/rom/photo_print/card/CLT_CRD0108_01.jpg 4F48839F mdata/M240/rom/photo_print/card/CLT_CRD0115_01.jpg 3975A36F mdata/M240/rom/photo_print/card/CLT_CRD0118_01.jpg D01BDEA3 mdata/M240/rom/photo_print/card/CLT_CRD0121_01.jpg 67757FB6 mdata/M240/rom/photo_print/card/CLT_CRD0124_01.jpg 68416D35 mdata/M240/rom/photo_print/card/CLT_CRD0129_01.jpg FC1C6D4B mdata/M240/rom/photo_print/card/CLT_CRD0132_01.jpg 86E3F0E6 mdata/M240/rom/photo_print/card/CLT_CRD0133_01.jpg 32E0448A mdata/M240/rom/photo_print/card/CLT_CRD0136_01.jpg 76CAED24 mdata/M240/rom/photo_print/card/CLT_CRD0139_01.jpg DDEF3EA8 mdata/M240/rom/photo_print/card/CLT_CRD0146_01.jpg 3CDA354A mdata/M240/rom/photo_print/card/CLT_CRD0147_01.jpg 02BAE7A5 mdata/M240/rom/photo_print/card/CLT_CRD0148_01.jpg 95E81CF3 mdata/M240/rom/photo_print/card/CLT_CRD0152_01.jpg 1E7CA5AF mdata/M240/rom/photo_print/card/CLT_CRD0153_01.jpg 324107F3 mdata/M240/rom/photo_print/card/CLT_CRD0156_01.jpg FAEBFFB3 mdata/M240/rom/photo_print/card/CLT_CRD0157_01.jpg A4A7DC7F mdata/M240/rom/photo_print/card/CLT_CRD0158_01.jpg 678EF528 mdata/M240/rom/photo_print/card/CLT_CRD0160_01.jpg F86ABD80 mdata/M240/rom/photo_print/card/CLT_CRD0161_01.jpg 311508E6 mdata/M240/rom/photo_print/card/CLT_CRD0165_01.jpg A2248866 mdata/M240/rom/photo_print/card/CLT_CRD0166_01.jpg 685E425A mdata/M240/rom/photo_print/card/CLT_CRD0169_01.jpg 0C887938 mdata/M240/rom/photo_print/card/CLT_CRD0170_01.jpg 693905A2 mdata/M240/rom/photo_print/card/CLT_CRD0175_01.jpg 60190BA4 mdata/M240/rom/photo_print/card/CLT_CRD0177_01.jpg 610C3F75 mdata/M240/rom/photo_print/card/CLT_CRD0183_01.jpg 6C288EC4 mdata/M240/rom/photo_print/card/CLT_CRD0188_01.jpg 5089ABAD mdata/M240/rom/photo_print/card/CLT_CRD0192_01.jpg EDEFA8F1 mdata/M240/rom/photo_print/card/CLT_CRD0198_01.jpg 0FE54CB3 mdata/M240/rom/photo_print/card/CLT_CRD0202_01.jpg F7B746B9 mdata/M240/rom/photo_print/card/CLT_CRD0209_01.jpg CFABB355 mdata/M240/rom/photo_print/card/CLT_CRD0212_01.jpg 52E113B0 mdata/M240/rom/photo_print/card/CLT_CRD0213_01.jpg 445E518B mdata/M240/rom/photo_print/card/CLT_CRD0214_01.jpg D532DD6D mdata/M240/rom/photo_print/card/CLT_CRD0215_01.jpg 8346D52E mdata/M240/rom/photo_print/card/CLT_CRD0221_01.jpg A2AD798A mdata/M240/rom/photo_print/card/CLT_CRD0228_01.jpg 104CA09C mdata/M240/rom/photo_print/card/CLT_CRD0229_01.jpg 4C6EA4E6 mdata/M240/rom/photo_print/card/CLT_CRD0231_01.jpg 3D5C2D15 mdata/M240/rom/photo_print/card/CLT_CRD0235_01.jpg 82EBC51B mdata/M240/rom/photo_print/card/CLT_CRD0236_01.jpg 82B1C491 mdata/M240/rom/photo_print/card/CLT_CRD0237_01.jpg FC6D24E0 mdata/M240/rom/photo_print/card/CLT_CRD0238_01.jpg 0F034037 mdata/M240/rom/photo_print/card/CLT_CRD0239_01.jpg 15F6BFE4 mdata/M240/rom/photo_print/card/CLT_CRD0246_01.jpg F394EF6E mdata/M240/rom/photo_print/card/CLT_CRD0247_01.jpg 272E0A38 mdata/M240/rom/photo_print/card/CLT_CRD0420_01.jpg EA91059F mdata/M240/rom/photo_print/card/CLT_CRD0421_01.jpg 896CF259 mdata/M240/rom/photo_print/card/CLT_CRD0432_01.jpg 2BDB9721 mdata/M240/rom/photo_print/card/CLT_CRD0440_01.jpg AD8BA3F9 mdata/M240/rom/photo_print/card/CLT_CRD0441_01.jpg 7CD27C5F mdata/M240/rom/photo_print/card/CLT_CRD0442_01.jpg 55730CF0 mdata/M240/rom/photo_print/card/CLT_CRD0443_01.jpg E307693A mdata/M240/rom/photo_print/card/CLT_CRD0444_01.jpg 0C386F48 mdata/M240/rom/photo_print/card/CLT_CRD0445_01.jpg E3F97E97 mdata/M240/rom/photo_print/card/CLT_CRD0447_01.jpg 7B51A8C4 mdata/M240/rom/photo_print/card/CLT_CRD0469_01.jpg 1A78DA5F mdata/M240/rom/photo_print/card/CLT_CRD0471_01.jpg 6F3E0C40 mdata/M240/rom/photo_print/card/CLT_CRD0491_01.jpg 0AE22353 mdata/M240/rom/photo_print/card/CLT_CRD0492_01.jpg 4C7B7E1E mdata/M240/rom/photo_print/card/CLT_CRD0493_01.jpg 3AEB5CC9 mdata/M240/rom/photo_print/card/CLT_CRD0505_01.jpg 8872D9BE mdata/M240/rom/photo_print/card/CLT_CRD0506_01.jpg 72FC9A5C mdata/M240/rom/photo_print/card/CLT_CRD0510_01.jpg 6D54B1BB mdata/M240/rom/photo_print/card/CLT_CRD0511_01.jpg 664125C8 mdata/M240/rom/photo_print/card/CLT_CRD0512_01.jpg 313F4CCA mdata/M240/rom/photo_print/card/CLT_CRD0517_01.jpg 7D0510BC mdata/M240/rom/photo_print/card/CLT_CRD0518_01.jpg D5B6B325 mdata/M240/rom/photo_print/card/CLT_CRD0524_01.jpg 9AB849B6 mdata/M240/rom/photo_print/card/CLT_CRD0525_01.jpg 783FF0C4 mdata/M240/rom/photo_print/card/CLT_CRD0526_01.jpg 15F1564B mdata/M240/rom/photo_print/card/CLT_CRD0528_01.jpg E3FEF7C0 mdata/M240/rom/photo_print/card/CLT_CRD0537_01.jpg 8A62D3B2 mdata/M240/rom/photo_print/card/CLT_CRD0538_01.jpg F9C9B471 mdata/M240/rom/photo_print/card/CLT_CRD0539_01.jpg 1942FBE6 mdata/M240/rom/photo_print/card/CLT_CRD0543_01.jpg FA155329 mdata/M240/rom/photo_print/card/CLT_CRD0544_01.jpg 07A963E5 mdata/M240/rom/photo_print/card/CLT_CRD0545_01.jpg 02DCC87E mdata/M240/rom/photo_print/card/CLT_CRD0547_01.jpg AD0C897C mdata/M240/rom/photo_print/card/CLT_CRD0557_01.jpg 00F7D7A3 mdata/M240/rom/photo_print/card/CLT_CRD0558_01.jpg 85FC9453 mdata/M240/rom/photo_print/card/CLT_CRD0559_01.jpg E85396B3 mdata/M240/rom/photo_print/card/CLT_CRD0560_01.jpg 525E7CDA mdata/M240/rom/photo_print/card/CLT_CRD0566_01.jpg 58E8F681 mdata/M240/rom/photo_print/card/CLT_CRD0575_01.jpg D93CD6BF mdata/M240/rom/photo_print/card/CLT_CRD0578_01.jpg 82DEBA45 mdata/M240/rom/photo_print/card/CLT_CRD0581_01.jpg 2C399C97 mdata/M240/rom/photo_print/card/CLT_CRD0582_01.jpg 5EE21A45 mdata/M240/rom/photo_print/card/CLT_CRD0589_01.jpg 9DF5D5C6 mdata/M240/rom/photo_print/card/CLT_CRD0590_01.jpg 4AF12642 mdata/M240/rom/photo_print/card/CLT_CRD0595_01.jpg 2DE31143 mdata/M240/rom/photo_print/card/CLT_CRD0598_01.jpg 09275F8C mdata/M240/rom/photo_print/card/CLT_CRD0602_01.jpg CAA665C9 mdata/M240/rom/photo_print/card/CLT_CRD0604_01.jpg 590E815E mdata/M240/rom/photo_print/card/CLT_CRD0607_01.jpg 8E16D41B mdata/M240/rom/photo_print/card/CLT_CRD0608_01.jpg 9E03327B mdata/M240/rom/photo_print/card/CLT_CRD0609_01.jpg 0D5F9B57 mdata/M240/rom/photo_print/card/CLT_CRD0611_01.jpg FBE3E8E6 mdata/M240/rom/photo_print/card/CLT_CRD0620_01.jpg 0A7531D0 mdata/M240/rom/photo_print/card/CLT_CRD0621_01.jpg B003CC97 mdata/M240/rom/photo_print/card/CLT_CRD0622_01.jpg 56C94A2C mdata/M240/rom/photo_print/card/CLT_CRD0631_01.jpg EA887058 mdata/M240/rom/photo_print/card/CLT_CRD0637_01.jpg 49A90187 mdata/M240/rom/photo_print/card/CLT_CRD0643_01.jpg 8C2CDF0C mdata/M240/rom/photo_print/card/CLT_CRD0644_01.jpg 998FC985 mdata/M240/rom/photo_print/card/CLT_CRD0646_01.jpg B5DF7CED mdata/M240/rom/photo_print/card/CLT_CRD0654_01.jpg 1D521E74 mdata/M240/rom/photo_print/card/CLT_CRD0655_01.jpg 4739C2CA mdata/M240/rom/photo_print/stamp/stamp030_02.tga 4CB3FB8A mdata/M240/rom/movie/adv_sega_cm.wmv 63C38E0E mdata/M240/rom/script/pv_042_easy.dsc 5EA918A7 mdata/M240/rom/script/pv_042_extreme.dsc 07B247D4 mdata/M240/rom/script/pv_042_extreme_1.dsc F1445ACA mdata/M240/rom/script/pv_042_hard.dsc 3258AFAB mdata/M240/rom/script/pv_042_normal.dsc C47E1700 mdata/M240/rom/script/pv_048_easy.dsc 543B8FCA mdata/M240/rom/script/pv_048_extreme.dsc DA2E3577 mdata/M240/rom/script/pv_048_extreme_1.dsc C1EC279E mdata/M240/rom/script/pv_048_hard.dsc B5A9A935 mdata/M240/rom/script/pv_048_normal.dsc 4D750B82 mdata/M240/rom/script/pv_227_extreme.dsc 32FE60A1 mdata/M240/rom/script/pv_227_extreme_1.dsc 474E294F mdata/M240/rom/script/pv_227_hard.dsc 7AC87CB1 mdata/M240/rom/script/pv_227_normal.dsc BBEE850F mdata/M240/rom/script/pv_266_easy.dsc 49485124 mdata/M240/rom/script/pv_266_extreme.dsc 7629FF82 mdata/M240/rom/script/pv_266_hard.dsc 07439DAA mdata/M240/rom/script/pv_266_normal.dsc FED217AC mdata/M240/rom/2d/aet_sel_module.bin A926F5DB mdata/M240/rom/2d/aet_sel_qst.bin C51EDE22 mdata/M240/rom/2d/mdata_aet_db.bin 5C5587C3 mdata/M240/rom/2d/mdata_spr_db.bin 81319D64 mdata/M240/rom/2d/spr_clt_crd0000.farc FAAC3ED9 mdata/M240/rom/2d/spr_clt_crd0003.farc 901DCA8A mdata/M240/rom/2d/spr_clt_crd0004.farc DA8DEC29 mdata/M240/rom/2d/spr_clt_crd0005.farc F136C16C mdata/M240/rom/2d/spr_clt_crd0006.farc 1BC9A4B8 mdata/M240/rom/2d/spr_clt_crd0007.farc B4BE1728 mdata/M240/rom/2d/spr_clt_crd0008.farc 63960A61 mdata/M240/rom/2d/spr_clt_crd0009.farc 1A5C83C6 mdata/M240/rom/2d/spr_clt_crd0010.farc 8DFCC02D mdata/M240/rom/2d/spr_clt_crd0011.farc 921C4E20 mdata/M240/rom/2d/spr_clt_crd0012.farc 624F8441 mdata/M240/rom/2d/spr_clt_crd0013.farc 2E415B66 mdata/M240/rom/2d/spr_clt_crd0014.farc 7CD41037 mdata/M240/rom/2d/spr_clt_crd0015.farc 4EC2EA70 mdata/M240/rom/2d/spr_clt_crd0016.farc 651C0996 mdata/M240/rom/2d/spr_clt_crd0017.farc 50FF0738 mdata/M240/rom/2d/spr_clt_crd0018.farc 9EBD0000 mdata/M240/rom/2d/spr_clt_crd0019.farc 78DA39BE mdata/M240/rom/2d/spr_clt_crd0020.farc 8C013B12 mdata/M240/rom/2d/spr_clt_crd0021.farc 34F1AB45 mdata/M240/rom/2d/spr_clt_crd0022.farc 214DCBB2 mdata/M240/rom/2d/spr_clt_crd0023.farc 5A297BB7 mdata/M240/rom/2d/spr_clt_crd0024.farc 213A8F00 mdata/M240/rom/2d/spr_clt_crd0025.farc 16A99C87 mdata/M240/rom/2d/spr_clt_crd0026.farc 0D6AF764 mdata/M240/rom/2d/spr_clt_crd0027.farc 59D468E3 mdata/M240/rom/2d/spr_clt_crd0028.farc CA4D9DC7 mdata/M240/rom/2d/spr_clt_crd0029.farc 822BE887 mdata/M240/rom/2d/spr_clt_crd0030.farc 16845491 mdata/M240/rom/2d/spr_clt_crd0031.farc 2CE821BE mdata/M240/rom/2d/spr_clt_crd0032.farc BC3FDA5B mdata/M240/rom/2d/spr_clt_crd0033.farc 04C2981A mdata/M240/rom/2d/spr_clt_crd0034.farc C131AD7E mdata/M240/rom/2d/spr_clt_crd0035.farc 3698204D mdata/M240/rom/2d/spr_clt_crd0036.farc B85A8CA0 mdata/M240/rom/2d/spr_clt_crd0037.farc 05EB1B5B mdata/M240/rom/2d/spr_clt_crd0038.farc F01A7F51 mdata/M240/rom/2d/spr_clt_crd0039.farc 8A2922E0 mdata/M240/rom/2d/spr_clt_crd0046.farc 0D6C1E08 mdata/M240/rom/2d/spr_clt_crd0047.farc 19CDD679 mdata/M240/rom/2d/spr_clt_crd0053.farc 71926429 mdata/M240/rom/2d/spr_clt_crd0054.farc BEC5E6BD mdata/M240/rom/2d/spr_clt_crd0055.farc 6D5B31FB mdata/M240/rom/2d/spr_clt_crd0056.farc 7AD3BDF8 mdata/M240/rom/2d/spr_clt_crd0057.farc 8FC84CD0 mdata/M240/rom/2d/spr_clt_crd0059.farc 680DBA29 mdata/M240/rom/2d/spr_clt_crd0065.farc 9EC890EB mdata/M240/rom/2d/spr_clt_crd0068.farc 800906A9 mdata/M240/rom/2d/spr_clt_crd0069.farc BDA8AA15 mdata/M240/rom/2d/spr_clt_crd0070.farc EE846757 mdata/M240/rom/2d/spr_clt_crd0072.farc 1882649F mdata/M240/rom/2d/spr_clt_crd0073.farc 25BE87EA mdata/M240/rom/2d/spr_clt_crd0078.farc C74341A3 mdata/M240/rom/2d/spr_clt_crd0079.farc 31E1FAAE mdata/M240/rom/2d/spr_clt_crd0088.farc 185FE152 mdata/M240/rom/2d/spr_clt_crd0089.farc 8BFE7AB2 mdata/M240/rom/2d/spr_clt_crd0090.farc 7AE5D2F4 mdata/M240/rom/2d/spr_clt_crd0091.farc BEC5B71E mdata/M240/rom/2d/spr_clt_crd0102.farc ECF077C2 mdata/M240/rom/2d/spr_clt_crd0103.farc 6F8019D0 mdata/M240/rom/2d/spr_clt_crd0107.farc 0AA7DE6C mdata/M240/rom/2d/spr_clt_crd0108.farc 4CCF6E06 mdata/M240/rom/2d/spr_clt_crd0115.farc 351A231E mdata/M240/rom/2d/spr_clt_crd0118.farc 386EDB6A mdata/M240/rom/2d/spr_clt_crd0121.farc 5604587A mdata/M240/rom/2d/spr_clt_crd0124.farc EC418EFC mdata/M240/rom/2d/spr_clt_crd0129.farc 49C6B7DD mdata/M240/rom/2d/spr_clt_crd0132.farc 0BF3B964 mdata/M240/rom/2d/spr_clt_crd0133.farc 32C25BD9 mdata/M240/rom/2d/spr_clt_crd0136.farc 037DB34E mdata/M240/rom/2d/spr_clt_crd0139.farc 9A1EE584 mdata/M240/rom/2d/spr_clt_crd0146.farc D88D3C08 mdata/M240/rom/2d/spr_clt_crd0147.farc E6ED1E50 mdata/M240/rom/2d/spr_clt_crd0148.farc B3F20005 mdata/M240/rom/2d/spr_clt_crd0152.farc 376AEDA6 mdata/M240/rom/2d/spr_clt_crd0153.farc 0324D665 mdata/M240/rom/2d/spr_clt_crd0156.farc 3DD8074C mdata/M240/rom/2d/spr_clt_crd0157.farc DC6DA4DB mdata/M240/rom/2d/spr_clt_crd0158.farc A6AFB37C mdata/M240/rom/2d/spr_clt_crd0160.farc 60EB1511 mdata/M240/rom/2d/spr_clt_crd0161.farc 3898D6D8 mdata/M240/rom/2d/spr_clt_crd0165.farc AF41B64E mdata/M240/rom/2d/spr_clt_crd0166.farc 00818124 mdata/M240/rom/2d/spr_clt_crd0169.farc 4A4F0D75 mdata/M240/rom/2d/spr_clt_crd0170.farc 7170283B mdata/M240/rom/2d/spr_clt_crd0175.farc 469828FD mdata/M240/rom/2d/spr_clt_crd0177.farc 6DCE2827 mdata/M240/rom/2d/spr_clt_crd0183.farc 1FEE5F36 mdata/M240/rom/2d/spr_clt_crd0188.farc 6230EF78 mdata/M240/rom/2d/spr_clt_crd0192.farc FA48647E mdata/M240/rom/2d/spr_clt_crd0198.farc 76BF62E3 mdata/M240/rom/2d/spr_clt_crd0202.farc 00498FC7 mdata/M240/rom/2d/spr_clt_crd0209.farc 6EBF668E mdata/M240/rom/2d/spr_clt_crd0212.farc 9AAAC37B mdata/M240/rom/2d/spr_clt_crd0213.farc 74E182BB mdata/M240/rom/2d/spr_clt_crd0214.farc 90212CD5 mdata/M240/rom/2d/spr_clt_crd0215.farc 25445F88 mdata/M240/rom/2d/spr_clt_crd0221.farc E2364537 mdata/M240/rom/2d/spr_clt_crd0228.farc 341CC528 mdata/M240/rom/2d/spr_clt_crd0229.farc 3C7C77A2 mdata/M240/rom/2d/spr_clt_crd0231.farc 35C954C0 mdata/M240/rom/2d/spr_clt_crd0235.farc 07AB66AF mdata/M240/rom/2d/spr_clt_crd0236.farc 9F47C411 mdata/M240/rom/2d/spr_clt_crd0237.farc 0EC86F41 mdata/M240/rom/2d/spr_clt_crd0238.farc 702FAED8 mdata/M240/rom/2d/spr_clt_crd0239.farc 10F43A82 mdata/M240/rom/2d/spr_clt_crd0246.farc 8055CEEB mdata/M240/rom/2d/spr_clt_crd0247.farc FEEADEFF mdata/M240/rom/2d/spr_clt_crd0420.farc 60C95389 mdata/M240/rom/2d/spr_clt_crd0421.farc C8E3D6B1 mdata/M240/rom/2d/spr_clt_crd0432.farc C922DF22 mdata/M240/rom/2d/spr_clt_crd0440.farc D215B4C4 mdata/M240/rom/2d/spr_clt_crd0441.farc 535A6F0D mdata/M240/rom/2d/spr_clt_crd0442.farc 59D60D06 mdata/M240/rom/2d/spr_clt_crd0443.farc 9EF59B51 mdata/M240/rom/2d/spr_clt_crd0444.farc B9CDA993 mdata/M240/rom/2d/spr_clt_crd0445.farc F6AF1571 mdata/M240/rom/2d/spr_clt_crd0447.farc 816F8F04 mdata/M240/rom/2d/spr_clt_crd0469.farc F7C7C99E mdata/M240/rom/2d/spr_clt_crd0471.farc 653EF857 mdata/M240/rom/2d/spr_clt_crd0491.farc CCA3D87A mdata/M240/rom/2d/spr_clt_crd0492.farc 7A84C96F mdata/M240/rom/2d/spr_clt_crd0493.farc A6C4A8FF mdata/M240/rom/2d/spr_clt_crd0505.farc 661BE1EB mdata/M240/rom/2d/spr_clt_crd0506.farc 837B1C7F mdata/M240/rom/2d/spr_clt_crd0510.farc D31DF876 mdata/M240/rom/2d/spr_clt_crd0511.farc 3452F958 mdata/M240/rom/2d/spr_clt_crd0512.farc 1F280C33 mdata/M240/rom/2d/spr_clt_crd0517.farc 12118557 mdata/M240/rom/2d/spr_clt_crd0518.farc FE073CE0 mdata/M240/rom/2d/spr_clt_crd0524.farc 87A52749 mdata/M240/rom/2d/spr_clt_crd0525.farc 54E4D510 mdata/M240/rom/2d/spr_clt_crd0526.farc 66F2380C mdata/M240/rom/2d/spr_clt_crd0528.farc B4426B85 mdata/M240/rom/2d/spr_clt_crd0537.farc 604BBE23 mdata/M240/rom/2d/spr_clt_crd0538.farc CE7FCC97 mdata/M240/rom/2d/spr_clt_crd0539.farc 991369AC mdata/M240/rom/2d/spr_clt_crd0543.farc EBC2DFC8 mdata/M240/rom/2d/spr_clt_crd0544.farc 834A13CA mdata/M240/rom/2d/spr_clt_crd0545.farc E18A540D mdata/M240/rom/2d/spr_clt_crd0547.farc 285559B8 mdata/M240/rom/2d/spr_clt_crd0557.farc 4560BCCA mdata/M240/rom/2d/spr_clt_crd0558.farc E3C00C4D mdata/M240/rom/2d/spr_clt_crd0559.farc DAC0D3B1 mdata/M240/rom/2d/spr_clt_crd0560.farc 76BBD5F1 mdata/M240/rom/2d/spr_clt_crd0566.farc DE8BB6C3 mdata/M240/rom/2d/spr_clt_crd0575.farc E27BC41D mdata/M240/rom/2d/spr_clt_crd0578.farc E8F3D35B mdata/M240/rom/2d/spr_clt_crd0581.farc 547133F2 mdata/M240/rom/2d/spr_clt_crd0582.farc 9051C8D1 mdata/M240/rom/2d/spr_clt_crd0589.farc C6AA3CF2 mdata/M240/rom/2d/spr_clt_crd0590.farc 95F7857E mdata/M240/rom/2d/spr_clt_crd0595.farc 267F45E0 mdata/M240/rom/2d/spr_clt_crd0598.farc E4E84F3B mdata/M240/rom/2d/spr_clt_crd0602.farc B6FB5971 mdata/M240/rom/2d/spr_clt_crd0604.farc 229839A3 mdata/M240/rom/2d/spr_clt_crd0607.farc 21625D35 mdata/M240/rom/2d/spr_clt_crd0608.farc 13E62B6C mdata/M240/rom/2d/spr_clt_crd0609.farc DB7C255F mdata/M240/rom/2d/spr_clt_crd0611.farc 82928DB3 mdata/M240/rom/2d/spr_clt_crd0620.farc 250FEEF5 mdata/M240/rom/2d/spr_clt_crd0621.farc 6727ABE5 mdata/M240/rom/2d/spr_clt_crd0622.farc AED2C43D mdata/M240/rom/2d/spr_clt_crd0631.farc 8373297A mdata/M240/rom/2d/spr_clt_crd0637.farc 694A0106 mdata/M240/rom/2d/spr_clt_crd0643.farc 69EA8849 mdata/M240/rom/2d/spr_clt_crd0644.farc C5CB5CAA mdata/M240/rom/2d/spr_clt_crd0646.farc F762BFA9 mdata/M240/rom/2d/spr_clt_crd0654.farc D383E518 mdata/M240/rom/2d/spr_clt_crd0655.farc 50B72282 mdata/M240/rom/2d/spr_sel_mdrmikcmn.farc 133DD7F0 mdata/M240/rom/2d/spr_sel_module.farc 0A6332E6 mdata/M240/rom/2d/spr_sel_qst.farc BA817C8A mdata/M250/info.txt 5769FB37 mdata/M250/rom/mdata_pv_db.txt 494CA00A mdata/M250/rom/mdata_pv_db.txt.bak FBEFC5CA mdata/M250/rom/mdata_pv_field.txt 3DC5401D mdata/M250/rom/script/pv_012_extreme.dsc 796C708E mdata/M250/rom/script/pv_012_extreme_1.dsc 34D9697F mdata/M250/rom/script/pv_012_hard.dsc 136785CF mdata/M250/rom/script/pv_012_normal.dsc FF693CA0 mdata/M250/rom/script/pv_220_easy.dsc EFA9E5EA mdata/M250/rom/script/pv_220_extreme.dsc 2C9BFA5D mdata/M250/rom/script/pv_220_extreme_1.dsc 4B8177B4 mdata/M250/rom/script/pv_220_hard.dsc 735A4DFC mdata/M250/rom/script/pv_220_normal.dsc 1F48A811 mdata/M250/rom/script/pv_435_extreme.dsc 3DCA160D mdata/M250/rom/script/pv_435_extreme_1.dsc F465D9E9 mdata/M250/rom/script/pv_435_hard.dsc 94865B92 mdata/M250/rom/script/pv_435_normal.dsc 957ED391 mdata/M250/rom/script/pv_600_easy.dsc B2D1BF25 mdata/M250/rom/script/pv_600_extreme.dsc 94F6C9A4 mdata/M250/rom/script/pv_600_extreme_1.dsc A2EA35BA mdata/M250/rom/script/pv_600_hard.dsc 5E63204E mdata/M250/rom/script/pv_600_normal.dsc A8E7C500 mdata/M250/rom/script/pv_605_easy.dsc 0BA84D51 mdata/M250/rom/script/pv_605_extreme.dsc 55EDAB30 mdata/M250/rom/script/pv_605_extreme_1.dsc AF0B149A mdata/M250/rom/script/pv_605_hard.dsc 29B15118 mdata/M250/rom/script/pv_605_normal.dsc 56D21C93 mdata/M250/rom/script/pv_615_easy.dsc 0028FDEE mdata/M250/rom/script/pv_615_extreme.dsc FB70BAFA mdata/M250/rom/script/pv_615_extreme_1.dsc D4E7498A mdata/M250/rom/script/pv_615_hard.dsc CA581E62 mdata/M250/rom/script/pv_615_normal.dsc B1976F72 mdata/M250/rom/script/pv_616_easy.dsc 3D3BE048 mdata/M250/rom/script/pv_616_extreme.dsc D19D0FF5 mdata/M250/rom/script/pv_616_extreme_1.dsc A6F03EC6 mdata/M250/rom/script/pv_616_hard.dsc CA18960F mdata/M250/rom/script/pv_616_normal.dsc C927455F mdata/M250/rom/script/pv_617_extreme.dsc 3CE78EDB mdata/M250/rom/script/pv_617_extreme_1.dsc A78F90A5 mdata/M250/rom/script/pv_617_hard.dsc E780ADD6 mdata/M250/rom/script/pv_617_normal.dsc DE865F01 mdata/M250/rom/script/pv_625_extreme.dsc 4A16766A mdata/M250/rom/script/pv_625_extreme_1.dsc 29B8BC7D mdata/M250/rom/script/pv_625_hard.dsc 0FAD740F mdata/M250/rom/script/pv_625_normal.dsc FB16AA4B mdata/M250/rom/script/pv_639_extreme.dsc 643B97FF mdata/M250/rom/script/pv_639_extreme_1.dsc B6D8D06D mdata/M250/rom/script/pv_639_hard.dsc 78318B00 mdata/M250/rom/script/pv_639_normal.dsc 29BE261A mdata/M260/info.txt 2F693E39 mdata/M260/rom/mdata_pv_db.txt 6D95B081 mdata/M260/rom/mdata_pv_field.txt 8FDEC694 mdata/M260/rom/script/pv_213_easy.dsc DC41A5A5 mdata/M260/rom/script/pv_213_extreme.dsc CB05EE3C mdata/M260/rom/script/pv_213_extreme_1.dsc C1B123A3 mdata/M260/rom/script/pv_213_hard.dsc 59A4B2BA mdata/M260/rom/script/pv_213_normal.dsc 39A3B85F mdata/M260/rom/script/pv_412_extreme.dsc A48E0388 mdata/M260/rom/script/pv_412_extreme_1.dsc A68EF58A mdata/M260/rom/script/pv_412_hard.dsc CB624198 mdata/M260/rom/script/pv_412_normal.dsc 02BF645C mdata/M260/rom/script/pv_602_easy.dsc E9C3E018 mdata/M260/rom/script/pv_602_extreme.dsc 753D7E14 mdata/M260/rom/script/pv_602_extreme_1.dsc DA105312 mdata/M260/rom/script/pv_602_hard.dsc AE1CCD96 mdata/M260/rom/script/pv_602_normal.dsc DD7F4831 mdata/M260/rom/script/pv_613_easy.dsc D94A6422 mdata/M260/rom/script/pv_613_extreme.dsc CE628CA6 mdata/M260/rom/script/pv_613_extreme_1.dsc 48E3C1F5 mdata/M260/rom/script/pv_613_hard.dsc 1DD06CE7 mdata/M260/rom/script/pv_613_normal.dsc A2C75A7B mdata/M260/rom/script/pv_638_easy.dsc BED6C494 mdata/M260/rom/script/pv_638_extreme.dsc 65180ED8 mdata/M260/rom/script/pv_638_extreme_1.dsc A2FFDB36 mdata/M260/rom/script/pv_638_hard.dsc 62989EB2 mdata/M260/rom/script/pv_638_normal.dsc 4AC28AF1 mdata/M260/rom/script/pv_730_easy.dsc 826C1846 mdata/M260/rom/script/pv_730_extreme.dsc 8ABCE140 mdata/M260/rom/script/pv_730_extreme_1.dsc C56C3515 mdata/M260/rom/script/pv_730_hard.dsc 62F64B99 mdata/M260/rom/script/pv_730_normal.dsc 07C0F154 mdata/M271/info.txt ED5F46A7 mdata/M271/rom/objset/mdata_obj_db.bin EE6937E7 mdata/M271/rom/objset/mdata_tex_db.bin 4E964215 mdata/M271/rom/objset/stgd2pv208.farc 4A9B65A9 mdata/M271/rom/objset/stgd2pv208s01.farc ECBE7E9C ================================================ FILE: source-code/dependencies/GPUModel/GPUModel.h ================================================ /* Simple header for detecting Nvidia GPU models */ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include #include #pragma comment(lib, "advapi32") namespace GPUModel { std::wstring ExePath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); return std::wstring(buffer); } std::wstring DirPath() { std::wstring exepath = ExePath(); std::wstring::size_type pos = exepath.find_last_of(L"\\/"); return exepath.substr(0, pos); } std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\config.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); void*(*NvAPI_QueryInterface)(unsigned int offset) = NULL; int(*NvAPI_Initialize)() = NULL; int(*NvAPI_Unload)() = NULL; int(*NvAPI_EnumPhysicalGPUs)(int64_t** handle, int* count) = NULL; int(*NvAPI_GPU_GetShortName)(int64_t* handle, char* name) = NULL; // returns the nvidia GPU die/chip name if one is installed, else "AMD" if an AMD driver is found, else "Unknown" // note that the used GL context may differ std::string getGpuName() { // detected model can be overridden -- 0: Kepler, 1: Maxwell, 2: Turing, 3: Ampere, 4: Ada Lovelace, 5: Blackwell int nGPUModel = GetPrivateProfileIntW(L"gpu", L"model", -1, CONFIG_FILE); if (nGPUModel >= 0 && nGPUModel <= 4) { std::string arch; switch (nGPUModel) { case 0: arch = "GK000"; break; case 1: arch = "GM000"; break; case 2: arch = "TU000"; break; case 3: arch = "GA000"; break; case 4: arch = "AD000"; break; case 5: arch = "GB000"; break; } printf("[GPUModel] GPU Model override: %s\n", arch.c_str()); return arch; } std::string non_nv_name = "Unknown"; // detect installed AMD driver //DWORD dwAttrib = GetFileAttributesW(L"amdgfxinfo64.dll"); //if (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) struct stat buffer; // for some reason winapi version wasn't working if (stat("amdgfxinfo64.dll", &buffer) == 0) { non_nv_name = "AMD"; } printf("[GPUModel] Checking GPU model\n"); HMODULE hdlNvapi = LoadLibraryW(L"nvapi64.dll"); if (hdlNvapi == NULL) return non_nv_name; NvAPI_QueryInterface = (void* (*)(unsigned int offset))GetProcAddress(hdlNvapi, "nvapi_QueryInterface"); if (NvAPI_QueryInterface == nullptr) return non_nv_name; NvAPI_Initialize = (int(*)())NvAPI_QueryInterface(0x0150E828); NvAPI_Unload = (int(*)()) NvAPI_QueryInterface(0xD22BDD7E); NvAPI_EnumPhysicalGPUs = (int(*)(int64_t * *handle, int* count))NvAPI_QueryInterface(0xE5AC921F); NvAPI_GPU_GetShortName = (int(*)(int64_t * handle, char* name))NvAPI_QueryInterface(0xD988F0F3); if (NvAPI_Initialize == nullptr || NvAPI_Unload == nullptr || NvAPI_EnumPhysicalGPUs == nullptr || NvAPI_GPU_GetShortName == nullptr) return non_nv_name; int64_t* hdlGpu[64] = { 0 }; int nGpu = 0; NvAPI_Initialize(); NvAPI_EnumPhysicalGPUs(hdlGpu, &nGpu); //printf("[ShaderPatch] nGpu: %d\n", nGpu); if (nGpu < 1) { NvAPI_Unload(); return non_nv_name; } char nameBuf[64]; NvAPI_GPU_GetShortName(hdlGpu[0], nameBuf); NvAPI_Unload(); return std::string(nameBuf); } } ================================================ FILE: source-code/dependencies/PluginConfigApi/PluginConfigApi.h ================================================ /* PD Loader Launcher Plugin Information Structs */ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include // resolution class to store and sort the width and height easily class resolution { public: unsigned int width; unsigned int height; resolution() { width = 0; height = 0; } resolution(unsigned int width, unsigned int height) { resolution::width = width; resolution::height = height; } bool operator ==(const resolution &res2) { return width == res2.width && height == res2.height; } // in comparisons width takes priority because it's usually displayed first bool operator <(const resolution &res2) { if (width == res2.width) return height < res2.height; else return width < res2.width; } bool operator >(const resolution &res2) { if (width == res2.width) return height > res2.height; else return width > res2.width; } }; namespace PluginConfig { #pragma pack(push, 1) enum ConfigType { CONFIG_BOOLEAN, CONFIG_NUMERIC, CONFIG_STRING, CONFIG_DROPDOWN_INDEX, CONFIG_DROPDOWN_TEXT, CONFIG_DROPDOWN_NUMBER, CONFIG_RESOLUTION, CONFIG_GROUP_START, CONFIG_GROUP_END, CONFIG_BUTTON, CONFIG_SPACER }; struct PluginConfigBooleanData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; bool defaultVal; bool saveAsString; }; struct PluginConfigNumericData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; int minVal; int maxVal; }; struct PluginConfigStringData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; LPCWSTR defaultVal; bool useUtf8; }; struct PluginConfigDropdownIndexData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; std::vector valueStrings; }; struct PluginConfigDropdownTextData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; LPCWSTR defaultVal; std::vector valueStrings; bool editable; bool useUtf8; }; struct PluginConfigDropdownNumberData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; std::vector valueInts; bool editable; }; struct PluginConfigResolutionData { LPCWSTR iniVarName; LPCWSTR iniVarName2; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; resolution defaultVal; std::vector valueResolutions; bool editable; }; struct PluginConfigGroupData { LPCWSTR name; int height; }; struct PluginConfigButtonData { LPCWSTR friendlyName; LPCWSTR description; void(*func)(); }; struct PluginConfigSpacerData { int height; }; struct PluginConfigOption { ConfigType cfgType; void* data; }; struct PluginConfigArray { int len; PluginConfigOption* options; }; #pragma pack(pop) // note: this is actually the build date of PluginConfigApi -- make sure this isn't cached for CI extern "C" __declspec(dllexport) LPCWSTR GetBuildDate(void) { WCHAR utf16buf[128]; MultiByteToWideChar(CP_UTF8, 0, __DATE__, -1, utf16buf, 128); return _wcsdup(utf16buf); } } ================================================ FILE: source-code/dependencies/WineVer/WineVer.h ================================================ /* Simple header for detecting version of Wine */ namespace WineVer { #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include #include #pragma comment(lib, "advapi32") std::string getWineVer() { HMODULE hntdll = LoadLibraryW(L"ntdll.dll"); if (hntdll == NULL) return ""; char*(WINAPI * wine_get_version)() = (char*(WINAPI*)())GetProcAddress(hntdll, "wine_get_version"); if (wine_get_version) { //puts("Wine detected."); //printf("Running on Wine... %s\n", wine_get_version()); return std::string(wine_get_version()); } return ""; } } ================================================ FILE: source-code/dependencies/detours/include/detours.h ================================================ ///////////////////////////////////////////////////////////////////////////// // // Core Detours Functionality (detours.h of detours.lib) // // Microsoft Research Detours Package, Version 4.0.1 // // Copyright (c) Microsoft Corporation. All rights reserved. // #pragma once #ifndef _DETOURS_H_ #define _DETOURS_H_ #define DETOURS_VERSION 0x4c0c1 // 0xMAJORcMINORcPATCH ////////////////////////////////////////////////////////////////////////////// // #ifdef DETOURS_INTERNAL #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 #define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1 #pragma warning(disable:4068) // unknown pragma (suppress) #if _MSC_VER >= 1900 #pragma warning(push) #pragma warning(disable:4091) // empty typedef #endif #include #if (_MSC_VER < 1310) #else #pragma warning(push) #if _MSC_VER > 1400 #pragma warning(disable:6102 6103) // /analyze warnings #endif #include #pragma warning(pop) #endif #endif // DETOURS_INTERNAL ////////////////////////////////////////////////////////////////////////////// // #undef DETOURS_X64 #undef DETOURS_X86 #undef DETOURS_IA64 #undef DETOURS_ARM #undef DETOURS_ARM64 #undef DETOURS_BITS #undef DETOURS_32BIT #undef DETOURS_64BIT #if defined(_X86_) #define DETOURS_X86 #define DETOURS_OPTION_BITS 64 #elif defined(_AMD64_) #define DETOURS_X64 #define DETOURS_OPTION_BITS 32 #elif defined(_IA64_) #define DETOURS_IA64 #define DETOURS_OPTION_BITS 32 #elif defined(_ARM_) #define DETOURS_ARM #elif defined(_ARM64_) #define DETOURS_ARM64 #else #error Unknown architecture (x86, amd64, ia64, arm, arm64) #endif #ifdef _WIN64 #undef DETOURS_32BIT #define DETOURS_64BIT 1 #define DETOURS_BITS 64 // If all 64bit kernels can run one and only one 32bit architecture. //#define DETOURS_OPTION_BITS 32 #else #define DETOURS_32BIT 1 #undef DETOURS_64BIT #define DETOURS_BITS 32 // If all 64bit kernels can run one and only one 32bit architecture. //#define DETOURS_OPTION_BITS 32 #endif #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) ////////////////////////////////////////////////////////////////////////////// // #if (_MSC_VER < 1299) typedef LONG LONG_PTR; typedef ULONG ULONG_PTR; #endif ///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. // // These definitions are include so that Detours will build even if the // compiler doesn't have full SAL 2.0 support. // #ifndef DETOURS_DONT_REMOVE_SAL_20 #ifdef DETOURS_TEST_REMOVE_SAL_20 #undef _Analysis_assume_ #undef _Benign_race_begin_ #undef _Benign_race_end_ #undef _Field_range_ #undef _Field_size_ #undef _In_ #undef _In_bytecount_ #undef _In_count_ #undef _In_opt_ #undef _In_opt_bytecount_ #undef _In_opt_count_ #undef _In_opt_z_ #undef _In_range_ #undef _In_reads_ #undef _In_reads_bytes_ #undef _In_reads_opt_ #undef _In_reads_opt_bytes_ #undef _In_reads_or_z_ #undef _In_z_ #undef _Inout_ #undef _Inout_opt_ #undef _Inout_z_count_ #undef _Out_ #undef _Out_opt_ #undef _Out_writes_ #undef _Outptr_result_maybenull_ #undef _Readable_bytes_ #undef _Success_ #undef _Writable_bytes_ #undef _Pre_notnull_ #endif #if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) #define _Outptr_result_maybenull_ _Deref_out_opt_z_ #endif #if defined(_In_count_) && !defined(_In_reads_) #define _In_reads_(x) _In_count_(x) #endif #if defined(_In_opt_count_) && !defined(_In_reads_opt_) #define _In_reads_opt_(x) _In_opt_count_(x) #endif #if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) #define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) #endif #if defined(_In_bytecount_) && !defined(_In_reads_bytes_) #define _In_reads_bytes_(x) _In_bytecount_(x) #endif #ifndef _In_ #define _In_ #endif #ifndef _In_bytecount_ #define _In_bytecount_(x) #endif #ifndef _In_count_ #define _In_count_(x) #endif #ifndef _In_opt_ #define _In_opt_ #endif #ifndef _In_opt_bytecount_ #define _In_opt_bytecount_(x) #endif #ifndef _In_opt_count_ #define _In_opt_count_(x) #endif #ifndef _In_opt_z_ #define _In_opt_z_ #endif #ifndef _In_range_ #define _In_range_(x,y) #endif #ifndef _In_reads_ #define _In_reads_(x) #endif #ifndef _In_reads_bytes_ #define _In_reads_bytes_(x) #endif #ifndef _In_reads_opt_ #define _In_reads_opt_(x) #endif #ifndef _In_reads_opt_bytes_ #define _In_reads_opt_bytes_(x) #endif #ifndef _In_reads_or_z_ #define _In_reads_or_z_ #endif #ifndef _In_z_ #define _In_z_ #endif #ifndef _Inout_ #define _Inout_ #endif #ifndef _Inout_opt_ #define _Inout_opt_ #endif #ifndef _Inout_z_count_ #define _Inout_z_count_(x) #endif #ifndef _Out_ #define _Out_ #endif #ifndef _Out_opt_ #define _Out_opt_ #endif #ifndef _Out_writes_ #define _Out_writes_(x) #endif #ifndef _Outptr_result_maybenull_ #define _Outptr_result_maybenull_ #endif #ifndef _Writable_bytes_ #define _Writable_bytes_(x) #endif #ifndef _Readable_bytes_ #define _Readable_bytes_(x) #endif #ifndef _Success_ #define _Success_(x) #endif #ifndef _Pre_notnull_ #define _Pre_notnull_ #endif #ifdef DETOURS_INTERNAL #pragma warning(disable:4615) // unknown warning type (suppress with older compilers) #ifndef _Benign_race_begin_ #define _Benign_race_begin_ #endif #ifndef _Benign_race_end_ #define _Benign_race_end_ #endif #ifndef _Field_size_ #define _Field_size_(x) #endif #ifndef _Field_range_ #define _Field_range_(x,y) #endif #ifndef _Analysis_assume_ #define _Analysis_assume_(x) #endif #endif // DETOURS_INTERNAL #endif // DETOURS_DONT_REMOVE_SAL_20 ////////////////////////////////////////////////////////////////////////////// // #ifndef GUID_DEFINED #define GUID_DEFINED typedef struct _GUID { DWORD Data1; WORD Data2; WORD Data3; BYTE Data4[ 8 ]; } GUID; #ifdef INITGUID #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ const GUID name \ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } #else #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ const GUID name #endif // INITGUID #endif // !GUID_DEFINED #if defined(__cplusplus) #ifndef _REFGUID_DEFINED #define _REFGUID_DEFINED #define REFGUID const GUID & #endif // !_REFGUID_DEFINED #else // !__cplusplus #ifndef _REFGUID_DEFINED #define _REFGUID_DEFINED #define REFGUID const GUID * const #endif // !_REFGUID_DEFINED #endif // !__cplusplus #ifndef ARRAYSIZE #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) #endif // ////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus extern "C" { #endif // __cplusplus /////////////////////////////////////////////////// Instruction Target Macros. // #define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) #define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) #define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" extern const GUID DETOUR_EXE_RESTORE_GUID; extern const GUID DETOUR_EXE_HELPER_GUID; #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; /////////////////////////////////////////////////////////// Binary Structures. // #pragma pack(push, 8) typedef struct _DETOUR_SECTION_HEADER { DWORD cbHeaderSize; DWORD nSignature; DWORD nDataOffset; DWORD cbDataSize; DWORD nOriginalImportVirtualAddress; DWORD nOriginalImportSize; DWORD nOriginalBoundImportVirtualAddress; DWORD nOriginalBoundImportSize; DWORD nOriginalIatVirtualAddress; DWORD nOriginalIatSize; DWORD nOriginalSizeOfImage; DWORD cbPrePE; DWORD nOriginalClrFlags; DWORD reserved1; DWORD reserved2; DWORD reserved3; // Followed by cbPrePE bytes of data. } DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; typedef struct _DETOUR_SECTION_RECORD { DWORD cbBytes; DWORD nReserved; GUID guid; } DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; typedef struct _DETOUR_CLR_HEADER { // Header versioning ULONG cb; USHORT MajorRuntimeVersion; USHORT MinorRuntimeVersion; // Symbol table and startup information IMAGE_DATA_DIRECTORY MetaData; ULONG Flags; // Followed by the rest of the IMAGE_COR20_HEADER } DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER; typedef struct _DETOUR_EXE_RESTORE { DWORD cb; DWORD cbidh; DWORD cbinh; DWORD cbclr; PBYTE pidh; PBYTE pinh; PBYTE pclr; IMAGE_DOS_HEADER idh; union { IMAGE_NT_HEADERS inh; // all environments have this #ifdef IMAGE_NT_OPTIONAL_HDR32_MAGIC // some environments do not have this IMAGE_NT_HEADERS32 inh32; #endif #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC // some environments do not have this IMAGE_NT_HEADERS64 inh64; #endif #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC // some environments do not have this BYTE raw[sizeof(IMAGE_NT_HEADERS64) + sizeof(IMAGE_SECTION_HEADER) * 32]; #else BYTE raw[0x108 + sizeof(IMAGE_SECTION_HEADER) * 32]; #endif }; DETOUR_CLR_HEADER clr; } DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE; #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC C_ASSERT(sizeof(IMAGE_NT_HEADERS64) == 0x108); #endif // The size can change, but assert for clarity due to the muddying #ifdefs. #ifdef _WIN64 C_ASSERT(sizeof(DETOUR_EXE_RESTORE) == 0x688); #else C_ASSERT(sizeof(DETOUR_EXE_RESTORE) == 0x678); #endif typedef struct _DETOUR_EXE_HELPER { DWORD cb; DWORD pid; DWORD nDlls; CHAR rDlls[4]; } DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER; #pragma pack(pop) #define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ { \ sizeof(DETOUR_SECTION_HEADER),\ DETOUR_SECTION_HEADER_SIGNATURE,\ sizeof(DETOUR_SECTION_HEADER),\ (cbSectionSize),\ \ 0,\ 0,\ 0,\ 0,\ \ 0,\ 0,\ 0,\ 0,\ } /////////////////////////////////////////////////////////////// Helper Macros. // #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) #define DETOURS_STRINGIFY_(x) #x ///////////////////////////////////////////////////////////// Binary Typedefs. // typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( _In_opt_ PVOID pContext, _In_opt_ LPCSTR pszFile, _Outptr_result_maybenull_ LPCSTR *ppszOutFile); typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( _In_opt_ PVOID pContext, _In_ LPCSTR pszOrigFile, _In_ LPCSTR pszFile, _Outptr_result_maybenull_ LPCSTR *ppszOutFile); typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( _In_opt_ PVOID pContext, _In_ ULONG nOrigOrdinal, _In_ ULONG nOrdinal, _Out_ ULONG *pnOutOrdinal, _In_opt_ LPCSTR pszOrigSymbol, _In_opt_ LPCSTR pszSymbol, _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( _In_opt_ PVOID pContext); typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, _In_ ULONG nOrdinal, _In_opt_ LPCSTR pszName, _In_opt_ PVOID pCode); typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, _In_opt_ HMODULE hModule, _In_opt_ LPCSTR pszFile); typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, _In_ DWORD nOrdinal, _In_opt_ LPCSTR pszFunc, _In_opt_ PVOID pvFunc); // Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, _In_ DWORD nOrdinal, _In_opt_ LPCSTR pszFunc, _In_opt_ PVOID* ppvFunc); typedef VOID * PDETOUR_BINARY; typedef VOID * PDETOUR_LOADED_BINARY; //////////////////////////////////////////////////////////// Transaction APIs. // LONG WINAPI DetourTransactionBegin(VOID); LONG WINAPI DetourTransactionAbort(VOID); LONG WINAPI DetourTransactionCommit(VOID); LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, _In_ PVOID pDetour); LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, _In_ PVOID pDetour, _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, _Out_opt_ PVOID *ppRealTarget, _Out_opt_ PVOID *ppRealDetour); LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, _In_ PVOID pDetour); BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); ////////////////////////////////////////////////////////////// Code Functions. // PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, _In_ LPCSTR pszFunction); PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, _Out_opt_ PVOID *ppGlobals); PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, _Inout_opt_ PVOID *ppDstPool, _In_ PVOID pSrc, _Out_opt_ PVOID *ppTarget, _Out_opt_ LONG *plExtra); BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, _In_ BOOL fLimitReferencesToModule); PVOID WINAPI DetourAllocateRegionWithinJumpBounds(_In_ LPCVOID pbTarget, _Out_ PDWORD pcbAllocatedSize); ///////////////////////////////////////////////////// Loaded Binary Functions. // HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr); HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule); ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule); BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, _In_opt_ PVOID pContext, _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport); BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, _In_opt_ PVOID pContext, _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc); BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, _In_opt_ PVOID pContext, _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx); _Writable_bytes_(*pcbData) _Readable_bytes_(*pcbData) _Success_(return != NULL) PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, _In_ REFGUID rguid, _Out_ DWORD *pcbData); _Writable_bytes_(*pcbData) _Readable_bytes_(*pcbData) _Success_(return != NULL) PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, _Out_ DWORD * pcbData); DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); ///////////////////////////////////////////////// Persistent Binary Functions. // PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile); _Writable_bytes_(*pcbData) _Readable_bytes_(*pcbData) _Success_(return != NULL) PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, _Out_opt_ GUID *pGuid, _Out_ DWORD *pcbData, _Inout_ DWORD *pnIterator); _Writable_bytes_(*pcbData) _Readable_bytes_(*pcbData) _Success_(return != NULL) PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid, _Out_ DWORD *pcbData); PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid, _In_reads_opt_(cbData) PVOID pData, _In_ DWORD cbData); BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid); BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary); BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary); BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary, _In_opt_ PVOID pContext, _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile, _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit); BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile); BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary); /////////////////////////////////////////////////// Create Process & Load Dll. // typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( _In_opt_ LPCSTR lpApplicationName, _Inout_opt_ LPSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCSTR lpCurrentDirectory, _In_ LPSTARTUPINFOA lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation); typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)( _In_opt_ LPCWSTR lpApplicationName, _Inout_opt_ LPWSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCWSTR lpCurrentDirectory, _In_ LPSTARTUPINFOW lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation); BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, _Inout_opt_ LPSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCSTR lpCurrentDirectory, _In_ LPSTARTUPINFOA lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation, _In_ LPCSTR lpDllName, _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, _Inout_opt_ LPWSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCWSTR lpCurrentDirectory, _In_ LPSTARTUPINFOW lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation, _In_ LPCSTR lpDllName, _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); #ifdef UNICODE #define DetourCreateProcessWithDll DetourCreateProcessWithDllW #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW #else #define DetourCreateProcessWithDll DetourCreateProcessWithDllA #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA #endif // !UNICODE BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, _Inout_opt_ LPSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCSTR lpCurrentDirectory, _In_ LPSTARTUPINFOA lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation, _In_ LPCSTR lpDllName, _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, _Inout_opt_ LPWSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCWSTR lpCurrentDirectory, _In_ LPSTARTUPINFOW lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation, _In_ LPCSTR lpDllName, _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); #ifdef UNICODE #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExW #else #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExA #endif // !UNICODE BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, _Inout_opt_ LPSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCSTR lpCurrentDirectory, _In_ LPSTARTUPINFOA lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation, _In_ DWORD nDlls, _In_reads_(nDlls) LPCSTR *rlpDlls, _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, _Inout_opt_ LPWSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCWSTR lpCurrentDirectory, _In_ LPSTARTUPINFOW lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation, _In_ DWORD nDlls, _In_reads_(nDlls) LPCSTR *rlpDlls, _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); #ifdef UNICODE #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsW #else #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsA #endif // !UNICODE BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, _In_ LPCSTR lpDllName, _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, _In_ LPCSTR lpDllName, _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); #ifdef UNICODE #define DetourProcessViaHelper DetourProcessViaHelperW #else #define DetourProcessViaHelper DetourProcessViaHelperA #endif // !UNICODE BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, _In_ DWORD nDlls, _In_reads_(nDlls) LPCSTR *rlpDlls, _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, _In_ DWORD nDlls, _In_reads_(nDlls) LPCSTR *rlpDlls, _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); #ifdef UNICODE #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsW #else #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsA #endif // !UNICODE BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, _In_reads_(nDlls) LPCSTR *rlpDlls, _In_ DWORD nDlls); BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, _In_ HMODULE hImage, _In_ BOOL bIs32Bit, _In_reads_(nDlls) LPCSTR *rlpDlls, _In_ DWORD nDlls); BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, _In_ REFGUID rguid, _In_reads_bytes_(cbData) PVOID pvData, _In_ DWORD cbData); BOOL WINAPI DetourRestoreAfterWith(VOID); BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, _In_ DWORD cbData); BOOL WINAPI DetourIsHelperProcess(VOID); VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, _In_ HINSTANCE, _In_ LPSTR, _In_ INT); // ////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus } #endif // __cplusplus //////////////////////////////////////////////// Detours Internal Definitions. // #ifdef __cplusplus #ifdef DETOURS_INTERNAL #define NOTHROW // #define NOTHROW (nothrow) ////////////////////////////////////////////////////////////////////////////// // #if (_MSC_VER < 1299) #include typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; typedef IMAGEHLP_SYMBOL SYMBOL_INFO; typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO; static inline LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) { return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval); } #else #pragma warning(push) #pragma warning(disable:4091) // empty typedef #include #pragma warning(pop) #endif #ifdef IMAGEAPI // defined by DBGHELP.H typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion); typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess, _In_opt_ LPCSTR UserSearchPath, _In_ BOOL fInvadeProcess); typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions); typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess, _In_opt_ HANDLE hFile, _In_ LPSTR ImageName, _In_opt_ LPSTR ModuleName, _In_ DWORD64 BaseOfDll, _In_opt_ DWORD SizeOfDll); typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess, _In_ DWORD64 qwAddr, _Out_ PIMAGEHLP_MODULE64 ModuleInfo); typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess, _In_ LPSTR Name, _Out_ PSYMBOL_INFO Symbol); typedef struct _DETOUR_SYM_INFO { HANDLE hProcess; HMODULE hDbgHelp; PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; PF_SymInitialize pfSymInitialize; PF_SymSetOptions pfSymSetOptions; PF_SymGetOptions pfSymGetOptions; PF_SymLoadModule64 pfSymLoadModule64; PF_SymGetModuleInfo64 pfSymGetModuleInfo64; PF_SymFromName pfSymFromName; } DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); #endif // IMAGEAPI #if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) #error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) #endif #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 #ifndef DETOUR_TRACE #if DETOUR_DEBUG #define DETOUR_TRACE(x) printf x #define DETOUR_BREAK() __debugbreak() #include #include #else #define DETOUR_TRACE(x) #define DETOUR_BREAK() #endif #endif #if 1 || defined(DETOURS_IA64) // // IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. // #define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) #define DETOUR_IA64_TEMPLATE_OFFSET (0) #define DETOUR_IA64_TEMPLATE_SIZE (5) #define DETOUR_IA64_INSTRUCTION_SIZE (41) #define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) #define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) #define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); __declspec(align(16)) struct DETOUR_IA64_BUNDLE { public: union { BYTE data[16]; UINT64 wide[2]; }; enum { A_UNIT = 1u, I_UNIT = 2u, M_UNIT = 3u, B_UNIT = 4u, F_UNIT = 5u, L_UNIT = 6u, X_UNIT = 7u, }; struct DETOUR_IA64_METADATA { ULONG nTemplate : 8; // Instruction template. ULONG nUnit0 : 4; // Unit for slot 0 ULONG nUnit1 : 4; // Unit for slot 1 ULONG nUnit2 : 4; // Unit for slot 2 }; protected: static const DETOUR_IA64_METADATA s_rceCopyTable[33]; UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, _In_ BYTE slot, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. // 00 // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] BYTE GetTemplate() const; // Get 4 bit opcodes. BYTE GetInst0() const; BYTE GetInst1() const; BYTE GetInst2() const; BYTE GetUnit(BYTE slot) const; BYTE GetUnit0() const; BYTE GetUnit1() const; BYTE GetUnit2() const; // Get 37 bit data. UINT64 GetData0() const; UINT64 GetData1() const; UINT64 GetData2() const; // Get/set the full 41 bit instructions. UINT64 GetInstruction(BYTE slot) const; UINT64 GetInstruction0() const; UINT64 GetInstruction1() const; UINT64 GetInstruction2() const; void SetInstruction(BYTE slot, UINT64 instruction); void SetInstruction0(UINT64 instruction); void SetInstruction1(UINT64 instruction); void SetInstruction2(UINT64 instruction); // Get/set bitfields. static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); // Get specific read-only fields. static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode static UINT64 GetX(UINT64 instruction); // 1bit opcode extension static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension // Get/set specific fields. static UINT64 GetImm7a(UINT64 instruction); static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); static UINT64 GetImm13c(UINT64 instruction); static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); static UINT64 GetSignBit(UINT64 instruction); static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); static UINT64 GetImm20a(UINT64 instruction); static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); static UINT64 GetImm20b(UINT64 instruction); static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); static UINT64 SignExtend(UINT64 Value, UINT64 Offset); BOOL IsMovlGp() const; VOID SetInst(BYTE Slot, BYTE nInst); VOID SetInst0(BYTE nInst); VOID SetInst1(BYTE nInst); VOID SetInst2(BYTE nInst); VOID SetData(BYTE Slot, UINT64 nData); VOID SetData0(UINT64 nData); VOID SetData1(UINT64 nData); VOID SetData2(UINT64 nData); BOOL SetNop(BYTE Slot); BOOL SetNop0(); BOOL SetNop1(); BOOL SetNop2(); public: BOOL IsBrl() const; VOID SetBrl(); VOID SetBrl(UINT64 target); UINT64 GetBrlTarget() const; VOID SetBrlTarget(UINT64 target); VOID SetBrlImm(UINT64 imm); UINT64 GetBrlImm() const; UINT64 GetMovlGp() const; VOID SetMovlGp(UINT64 gp); VOID SetStop(); UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; }; #endif // DETOURS_IA64 #ifdef DETOURS_ARM #define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) #define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) #endif // DETOURS_ARM ////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus extern "C" { #endif // __cplusplus #define DETOUR_OFFLINE_LIBRARY(x) \ PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ _Inout_opt_ PVOID *ppDstPool, \ _In_ PVOID pSrc, \ _Out_opt_ PVOID *ppTarget, \ _Out_opt_ LONG *plExtra); \ \ BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ _In_ BOOL fLimitReferencesToModule); \ DETOUR_OFFLINE_LIBRARY(X86) DETOUR_OFFLINE_LIBRARY(X64) DETOUR_OFFLINE_LIBRARY(ARM) DETOUR_OFFLINE_LIBRARY(ARM64) DETOUR_OFFLINE_LIBRARY(IA64) #undef DETOUR_OFFLINE_LIBRARY ////////////////////////////////////////////////////////////////////////////// // // Helpers for manipulating page protection. // _Success_(return != FALSE) BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, _In_ PVOID pAddress, _In_ SIZE_T nSize, _In_ DWORD dwNewProtect, _Out_ PDWORD pdwOldProtect); _Success_(return != FALSE) BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, _In_ SIZE_T nSize, _In_ DWORD dwNewProtect, _Out_ PDWORD pdwOldProtect); #ifdef __cplusplus } #endif // __cplusplus ////////////////////////////////////////////////////////////////////////////// #define MM_ALLOCATION_GRANULARITY 0x10000 ////////////////////////////////////////////////////////////////////////////// #endif // DETOURS_INTERNAL #endif // __cplusplus #endif // _DETOURS_H_ // //////////////////////////////////////////////////////////////// End of File. ================================================ FILE: source-code/dependencies/detours/include/detver.h ================================================ ////////////////////////////////////////////////////////////////////////////// // // Common version parameters. // // Microsoft Research Detours Package, Version 4.0.1 // // Copyright (c) Microsoft Corporation. All rights reserved. // #define _USING_V110_SDK71_ 1 #include "winver.h" #if 0 #include #include #else #ifndef DETOURS_STRINGIFY #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) #define DETOURS_STRINGIFY_(x) #x #endif #define VER_FILEFLAGSMASK 0x3fL #define VER_FILEFLAGS 0x0L #define VER_FILEOS 0x00040004L #define VER_FILETYPE 0x00000002L #define VER_FILESUBTYPE 0x00000000L #endif #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) ================================================ FILE: source-code/dependencies/detours/include/syelog.h ================================================ ////////////////////////////////////////////////////////////////////////////// // // Detours Test Program (syelog.h of syelog.lib) // // Microsoft Research Detours Package // // Copyright (c) Microsoft Corporation. All rights reserved. // #pragma once #ifndef _SYELOGD_H_ #define _SYELOGD_H_ #include #pragma pack(push, 1) #pragma warning(push) #pragma warning(disable: 4200) ////////////////////////////////////////////////////////////////////////////// // // #define SYELOG_PIPE_NAMEA "\\\\.\\pipe\\syelog" #define SYELOG_PIPE_NAMEW L"\\\\.\\pipe\\syelog" #ifdef UNICODE #define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEW #else #define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEA #endif ////////////////////////////////////////////////////////////////////////////// // #define SYELOG_MAXIMUM_MESSAGE 4086 // 4096 - sizeof(header stuff) typedef struct _SYELOG_MESSAGE { USHORT nBytes; BYTE nFacility; BYTE nSeverity; DWORD nProcessId; FILETIME ftOccurance; BOOL fTerminate; CHAR szMessage[SYELOG_MAXIMUM_MESSAGE]; } SYELOG_MESSAGE, *PSYELOG_MESSAGE; // Facility Codes. // #define SYELOG_FACILITY_KERNEL 0x10 // OS Kernel #define SYELOG_FACILITY_SECURITY 0x20 // OS Security #define SYELOG_FACILITY_LOGGING 0x30 // OS Logging-internal #define SYELOG_FACILITY_SERVICE 0x40 // User-mode system daemon #define SYELOG_FACILITY_APPLICATION 0x50 // User-mode application #define SYELOG_FACILITY_USER 0x60 // User self-generated. #define SYELOG_FACILITY_LOCAL0 0x70 // Locally defined. #define SYELOG_FACILITY_LOCAL1 0x71 // Locally defined. #define SYELOG_FACILITY_LOCAL2 0x72 // Locally defined. #define SYELOG_FACILITY_LOCAL3 0x73 // Locally defined. #define SYELOG_FACILITY_LOCAL4 0x74 // Locally defined. #define SYELOG_FACILITY_LOCAL5 0x75 // Locally defined. #define SYELOG_FACILITY_LOCAL6 0x76 // Locally defined. #define SYELOG_FACILITY_LOCAL7 0x77 // Locally defined. #define SYELOG_FACILITY_LOCAL8 0x78 // Locally defined. #define SYELOG_FACILITY_LOCAL9 0x79 // Locally defined. // Severity Codes. // #define SYELOG_SEVERITY_FATAL 0x00 // System is dead. #define SYELOG_SEVERITY_ALERT 0x10 // Take action immediately. #define SYELOG_SEVERITY_CRITICAL 0x20 // Critical condition. #define SYELOG_SEVERITY_ERROR 0x30 // Error #define SYELOG_SEVERITY_WARNING 0x40 // Warning #define SYELOG_SEVERITY_NOTICE 0x50 // Significant condition. #define SYELOG_SEVERITY_INFORMATION 0x60 // Informational #define SYELOG_SEVERITY_AUDIT_FAIL 0x66 // Audit Failed #define SYELOG_SEVERITY_AUDIT_PASS 0x67 // Audit Succeeeded #define SYELOG_SEVERITY_DEBUG 0x70 // Debugging // Logging Functions. // VOID SyelogOpen(PCSTR pszIdentifier, BYTE nFacility); VOID Syelog(BYTE nSeverity, PCSTR pszMsgf, ...); VOID SyelogV(BYTE nSeverity, PCSTR pszMsgf, va_list args); VOID SyelogClose(BOOL fTerminate); #pragma warning(pop) #pragma pack(pop) #endif // _SYELOGD_H_ // ///////////////////////////////////////////////////////////////// End of File. ================================================ FILE: source-code/dependencies/freeglut/include/GL/freeglut.h ================================================ #ifndef __FREEGLUT_H__ #define __FREEGLUT_H__ /* * freeglut.h * * The freeglut library include file * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "freeglut_std.h" #include "freeglut_ext.h" /*** END OF FILE ***/ #endif /* __FREEGLUT_H__ */ ================================================ FILE: source-code/dependencies/freeglut/include/GL/freeglut_ext.h ================================================ #ifndef __FREEGLUT_EXT_H__ #define __FREEGLUT_EXT_H__ /* * freeglut_ext.h * * The non-GLUT-compatible extensions to the freeglut library include file * * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. * Written by Pawel W. Olszta, * Creation date: Thu Dec 2 1999 * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef __cplusplus extern "C" { #endif /* * Additional GLUT Key definitions for the Special key function */ #define GLUT_KEY_NUM_LOCK 0x006D #define GLUT_KEY_BEGIN 0x006E #define GLUT_KEY_DELETE 0x006F #define GLUT_KEY_SHIFT_L 0x0070 #define GLUT_KEY_SHIFT_R 0x0071 #define GLUT_KEY_CTRL_L 0x0072 #define GLUT_KEY_CTRL_R 0x0073 #define GLUT_KEY_ALT_L 0x0074 #define GLUT_KEY_ALT_R 0x0075 /* * GLUT API Extension macro definitions -- behaviour when the user clicks on an "x" to close a window */ #define GLUT_ACTION_EXIT 0 #define GLUT_ACTION_GLUTMAINLOOP_RETURNS 1 #define GLUT_ACTION_CONTINUE_EXECUTION 2 /* * Create a new rendering context when the user opens a new window? */ #define GLUT_CREATE_NEW_CONTEXT 0 #define GLUT_USE_CURRENT_CONTEXT 1 /* * Direct/Indirect rendering context options (has meaning only in Unix/X11) */ #define GLUT_FORCE_INDIRECT_CONTEXT 0 #define GLUT_ALLOW_DIRECT_CONTEXT 1 #define GLUT_TRY_DIRECT_CONTEXT 2 #define GLUT_FORCE_DIRECT_CONTEXT 3 /* * GLUT API Extension macro definitions -- the glutGet parameters */ #define GLUT_INIT_STATE 0x007C #define GLUT_ACTION_ON_WINDOW_CLOSE 0x01F9 #define GLUT_WINDOW_BORDER_WIDTH 0x01FA #define GLUT_WINDOW_BORDER_HEIGHT 0x01FB #define GLUT_WINDOW_HEADER_HEIGHT 0x01FB /* Docs say it should always have been GLUT_WINDOW_BORDER_HEIGHT, keep this for backward compatibility */ #define GLUT_VERSION 0x01FC #define GLUT_RENDERING_CONTEXT 0x01FD #define GLUT_DIRECT_RENDERING 0x01FE #define GLUT_FULL_SCREEN 0x01FF #define GLUT_SKIP_STALE_MOTION_EVENTS 0x0204 #define GLUT_GEOMETRY_VISUALIZE_NORMALS 0x0205 #define GLUT_STROKE_FONT_DRAW_JOIN_DOTS 0x0206 /* Draw dots between line segments of stroke fonts? */ #define GLUT_ALLOW_NEGATIVE_WINDOW_POSITION 0x0207 /* GLUT doesn't allow negative window positions by default */ #define GLUT_WINDOW_SRGB 0x007D /* * New tokens for glutInitDisplayMode. * Only one GLUT_AUXn bit may be used at a time. * Value 0x0400 is defined in OpenGLUT. */ #define GLUT_AUX 0x1000 #define GLUT_AUX1 0x1000 #define GLUT_AUX2 0x2000 #define GLUT_AUX3 0x4000 #define GLUT_AUX4 0x8000 /* * Context-related flags, see fg_state.c * Set the requested OpenGL version */ #define GLUT_INIT_MAJOR_VERSION 0x0200 #define GLUT_INIT_MINOR_VERSION 0x0201 #define GLUT_INIT_FLAGS 0x0202 #define GLUT_INIT_PROFILE 0x0203 /* * Flags for glutInitContextFlags, see fg_init.c */ #define GLUT_DEBUG 0x0001 #define GLUT_FORWARD_COMPATIBLE 0x0002 /* * Flags for glutInitContextProfile, see fg_init.c */ #define GLUT_CORE_PROFILE 0x0001 #define GLUT_COMPATIBILITY_PROFILE 0x0002 /* * GLUT API Extension macro definitions -- Spaceball button definitions */ #define GLUT_SPACEBALL_BUTTON_A 0x0001 #define GLUT_SPACEBALL_BUTTON_B 0x0002 #define GLUT_SPACEBALL_BUTTON_C 0x0004 #define GLUT_SPACEBALL_BUTTON_D 0x0008 #define GLUT_SPACEBALL_BUTTON_E 0x0010 /* * Process loop function, see fg_main.c */ FGAPI void FGAPIENTRY glutMainLoopEvent( void ); FGAPI void FGAPIENTRY glutLeaveMainLoop( void ); FGAPI void FGAPIENTRY glutExit ( void ); /* * Window management functions, see fg_window.c */ FGAPI void FGAPIENTRY glutFullScreenToggle( void ); FGAPI void FGAPIENTRY glutLeaveFullScreen( void ); /* * Menu functions */ FGAPI void FGAPIENTRY glutSetMenuFont( int menuID, void* font ); /* * Window-specific callback functions, see fg_callbacks.c */ FGAPI void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ); FGAPI void FGAPIENTRY glutPositionFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutCloseFunc( void (* callback)( void ) ); FGAPI void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) ); /* And also a destruction callback for menus */ FGAPI void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) ); /* * State setting and retrieval functions, see fg_state.c */ FGAPI void FGAPIENTRY glutSetOption ( GLenum option_flag, int value ); FGAPI int * FGAPIENTRY glutGetModeValues(GLenum mode, int * size); /* A.Donev: User-data manipulation */ FGAPI void* FGAPIENTRY glutGetWindowData( void ); FGAPI void FGAPIENTRY glutSetWindowData(void* data); FGAPI void* FGAPIENTRY glutGetMenuData( void ); FGAPI void FGAPIENTRY glutSetMenuData(void* data); /* * Font stuff, see fg_font.c */ FGAPI int FGAPIENTRY glutBitmapHeight( void* font ); FGAPI GLfloat FGAPIENTRY glutStrokeHeight( void* font ); FGAPI void FGAPIENTRY glutBitmapString( void* font, const unsigned char *string ); FGAPI void FGAPIENTRY glutStrokeString( void* font, const unsigned char *string ); /* * Geometry functions, see fg_geometry.c */ FGAPI void FGAPIENTRY glutWireRhombicDodecahedron( void ); FGAPI void FGAPIENTRY glutSolidRhombicDodecahedron( void ); FGAPI void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale ); FGAPI void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale ); FGAPI void FGAPIENTRY glutWireCylinder( double radius, double height, GLint slices, GLint stacks); FGAPI void FGAPIENTRY glutSolidCylinder( double radius, double height, GLint slices, GLint stacks); /* * Rest of functions for rendering Newell's teaset, found in fg_teapot.c * NB: front facing polygons have clockwise winding, not counter clockwise */ FGAPI void FGAPIENTRY glutWireTeacup( double size ); FGAPI void FGAPIENTRY glutSolidTeacup( double size ); FGAPI void FGAPIENTRY glutWireTeaspoon( double size ); FGAPI void FGAPIENTRY glutSolidTeaspoon( double size ); /* * Extension functions, see fg_ext.c */ typedef void (*GLUTproc)(); FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName ); /* * Multi-touch/multi-pointer extensions */ #define GLUT_HAS_MULTI 1 /* TODO: add device_id parameter, cf. http://sourceforge.net/mailarchive/forum.php?thread_name=20120518071314.GA28061%40perso.beuc.net&forum_name=freeglut-developer */ FGAPI void FGAPIENTRY glutMultiEntryFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutMultiButtonFunc( void (* callback)( int, int, int, int, int ) ); FGAPI void FGAPIENTRY glutMultiMotionFunc( void (* callback)( int, int, int ) ); FGAPI void FGAPIENTRY glutMultiPassiveFunc( void (* callback)( int, int, int ) ); /* * Joystick functions, see fg_joystick.c */ /* USE OF THESE FUNCTIONS IS DEPRECATED !!!!! */ /* If you have a serious need for these functions in your application, please either * contact the "freeglut" developer community at freeglut-developer@lists.sourceforge.net, * switch to the OpenGLUT library, or else port your joystick functionality over to PLIB's * "js" library. */ int glutJoystickGetNumAxes( int ident ); int glutJoystickGetNumButtons( int ident ); int glutJoystickNotWorking( int ident ); float glutJoystickGetDeadBand( int ident, int axis ); void glutJoystickSetDeadBand( int ident, int axis, float db ); float glutJoystickGetSaturation( int ident, int axis ); void glutJoystickSetSaturation( int ident, int axis, float st ); void glutJoystickSetMinRange( int ident, float *axes ); void glutJoystickSetMaxRange( int ident, float *axes ); void glutJoystickSetCenter( int ident, float *axes ); void glutJoystickGetMinRange( int ident, float *axes ); void glutJoystickGetMaxRange( int ident, float *axes ); void glutJoystickGetCenter( int ident, float *axes ); /* * Initialization functions, see fg_init.c */ /* to get the typedef for va_list */ #include FGAPI void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion ); FGAPI void FGAPIENTRY glutInitContextFlags( int flags ); FGAPI void FGAPIENTRY glutInitContextProfile( int profile ); FGAPI void FGAPIENTRY glutInitErrorFunc( void (* callback)( const char *fmt, va_list ap ) ); FGAPI void FGAPIENTRY glutInitWarningFunc( void (* callback)( const char *fmt, va_list ap ) ); /* OpenGL >= 2.0 support */ FGAPI void FGAPIENTRY glutSetVertexAttribCoord3( GLint attrib ); FGAPI void FGAPIENTRY glutSetVertexAttribNormal( GLint attrib ); FGAPI void FGAPIENTRY glutSetVertexAttribTexCoord2( GLint attrib ); /* Mobile platforms lifecycle */ FGAPI void FGAPIENTRY glutInitContextFunc( void (* callback)( void ) ); FGAPI void FGAPIENTRY glutAppStatusFunc( void (* callback)( int ) ); /* state flags that can be passed to callback set by glutAppStatusFunc */ #define GLUT_APPSTATUS_PAUSE 0x0001 #define GLUT_APPSTATUS_RESUME 0x0002 /* * GLUT API macro definitions -- the display mode definitions */ #define GLUT_CAPTIONLESS 0x0400 #define GLUT_BORDERLESS 0x0800 #define GLUT_SRGB 0x1000 /* User-argument callbacks and implementation */ #include "freeglut_ucall.h" #ifdef __cplusplus } #endif /*** END OF FILE ***/ #endif /* __FREEGLUT_EXT_H__ */ ================================================ FILE: source-code/dependencies/freeglut/include/GL/freeglut_std.h ================================================ #ifndef __FREEGLUT_STD_H__ #define __FREEGLUT_STD_H__ /* * freeglut_std.h * * The GLUT-compatible part of the freeglut library include file * * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. * Written by Pawel W. Olszta, * Creation date: Thu Dec 2 1999 * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef __cplusplus extern "C" { #endif /* * Under windows, we have to differentiate between static and dynamic libraries */ #ifdef _WIN32 /* #pragma may not be supported by some compilers. * Discussion by FreeGLUT developers suggests that * Visual C++ specific code involving pragmas may * need to move to a separate header. 24th Dec 2003 */ /* Define FREEGLUT_LIB_PRAGMAS to 1 to include library * pragmas or to 0 to exclude library pragmas. * The default behavior depends on the compiler/platform. */ # ifndef FREEGLUT_LIB_PRAGMAS # if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(_WIN32_WCE) # define FREEGLUT_LIB_PRAGMAS 1 # else # define FREEGLUT_LIB_PRAGMAS 0 # endif # endif # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 # endif # ifndef NOMINMAX # define NOMINMAX # endif # include /* Windows static library */ # ifdef FREEGLUT_STATIC # define FGAPI # define FGAPIENTRY /* Link with Win32 static freeglut lib */ # if FREEGLUT_LIB_PRAGMAS # ifdef NDEBUG # pragma comment (lib, "freeglut_static.lib") # else # pragma comment (lib, "freeglut_staticd.lib") # endif # endif /* Windows shared library (DLL) */ # else # define FGAPIENTRY __stdcall # if defined(FREEGLUT_EXPORTS) # define FGAPI __declspec(dllexport) # else # define FGAPI __declspec(dllimport) /* Link with Win32 shared freeglut lib */ # if FREEGLUT_LIB_PRAGMAS # ifdef NDEBUG # pragma comment (lib, "freeglut.lib") # else # pragma comment (lib, "freeglutd.lib") # endif # endif # endif # endif /* Drag in other Windows libraries as required by FreeGLUT */ # if FREEGLUT_LIB_PRAGMAS # pragma comment (lib, "glu32.lib") /* link OpenGL Utility lib */ # pragma comment (lib, "opengl32.lib") /* link Microsoft OpenGL lib */ # pragma comment (lib, "gdi32.lib") /* link Windows GDI lib */ # pragma comment (lib, "winmm.lib") /* link Windows MultiMedia lib */ # pragma comment (lib, "user32.lib") /* link Windows user lib */ # endif #else /* Non-Windows definition of FGAPI and FGAPIENTRY */ # define FGAPI # define FGAPIENTRY #endif /* * The freeglut and GLUT API versions */ #define FREEGLUT 1 #define GLUT_API_VERSION 4 #define GLUT_XLIB_IMPLEMENTATION 13 /* Deprecated: cf. http://sourceforge.net/mailarchive/forum.php?thread_name=CABcAi1hw7cr4xtigckaGXB5X8wddLfMcbA_rZ3NAuwMrX_zmsw%40mail.gmail.com&forum_name=freeglut-developer */ #define FREEGLUT_VERSION_2_0 1 /* * Always include OpenGL and GLU headers */ /* Note: FREEGLUT_GLES is only used to cleanly bootstrap headers inclusion here; use GLES constants directly (e.g. GL_ES_VERSION_2_0) for all other needs */ #ifdef FREEGLUT_GLES # include # include # include #elif __APPLE__ # include # include #else # include # include #endif /* * GLUT API macro definitions -- the special key codes: */ #define GLUT_KEY_F1 0x0001 #define GLUT_KEY_F2 0x0002 #define GLUT_KEY_F3 0x0003 #define GLUT_KEY_F4 0x0004 #define GLUT_KEY_F5 0x0005 #define GLUT_KEY_F6 0x0006 #define GLUT_KEY_F7 0x0007 #define GLUT_KEY_F8 0x0008 #define GLUT_KEY_F9 0x0009 #define GLUT_KEY_F10 0x000A #define GLUT_KEY_F11 0x000B #define GLUT_KEY_F12 0x000C #define GLUT_KEY_LEFT 0x0064 #define GLUT_KEY_UP 0x0065 #define GLUT_KEY_RIGHT 0x0066 #define GLUT_KEY_DOWN 0x0067 #define GLUT_KEY_PAGE_UP 0x0068 #define GLUT_KEY_PAGE_DOWN 0x0069 #define GLUT_KEY_HOME 0x006A #define GLUT_KEY_END 0x006B #define GLUT_KEY_INSERT 0x006C /* * GLUT API macro definitions -- mouse state definitions */ #define GLUT_LEFT_BUTTON 0x0000 #define GLUT_MIDDLE_BUTTON 0x0001 #define GLUT_RIGHT_BUTTON 0x0002 #define GLUT_DOWN 0x0000 #define GLUT_UP 0x0001 #define GLUT_LEFT 0x0000 #define GLUT_ENTERED 0x0001 /* * GLUT API macro definitions -- the display mode definitions */ #define GLUT_RGB 0x0000 #define GLUT_RGBA 0x0000 #define GLUT_INDEX 0x0001 #define GLUT_SINGLE 0x0000 #define GLUT_DOUBLE 0x0002 #define GLUT_ACCUM 0x0004 #define GLUT_ALPHA 0x0008 #define GLUT_DEPTH 0x0010 #define GLUT_STENCIL 0x0020 #define GLUT_MULTISAMPLE 0x0080 #define GLUT_STEREO 0x0100 #define GLUT_LUMINANCE 0x0200 /* * GLUT API macro definitions -- windows and menu related definitions */ #define GLUT_MENU_NOT_IN_USE 0x0000 #define GLUT_MENU_IN_USE 0x0001 #define GLUT_NOT_VISIBLE 0x0000 #define GLUT_VISIBLE 0x0001 #define GLUT_HIDDEN 0x0000 #define GLUT_FULLY_RETAINED 0x0001 #define GLUT_PARTIALLY_RETAINED 0x0002 #define GLUT_FULLY_COVERED 0x0003 /* * GLUT API macro definitions -- fonts definitions * * Steve Baker suggested to make it binary compatible with GLUT: */ #if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WATCOMC__) # define GLUT_STROKE_ROMAN ((void *)0x0000) # define GLUT_STROKE_MONO_ROMAN ((void *)0x0001) # define GLUT_BITMAP_9_BY_15 ((void *)0x0002) # define GLUT_BITMAP_8_BY_13 ((void *)0x0003) # define GLUT_BITMAP_TIMES_ROMAN_10 ((void *)0x0004) # define GLUT_BITMAP_TIMES_ROMAN_24 ((void *)0x0005) # define GLUT_BITMAP_HELVETICA_10 ((void *)0x0006) # define GLUT_BITMAP_HELVETICA_12 ((void *)0x0007) # define GLUT_BITMAP_HELVETICA_18 ((void *)0x0008) #else /* * I don't really know if it's a good idea... But here it goes: */ extern void* glutStrokeRoman; extern void* glutStrokeMonoRoman; extern void* glutBitmap9By15; extern void* glutBitmap8By13; extern void* glutBitmapTimesRoman10; extern void* glutBitmapTimesRoman24; extern void* glutBitmapHelvetica10; extern void* glutBitmapHelvetica12; extern void* glutBitmapHelvetica18; /* * Those pointers will be used by following definitions: */ # define GLUT_STROKE_ROMAN ((void *) &glutStrokeRoman) # define GLUT_STROKE_MONO_ROMAN ((void *) &glutStrokeMonoRoman) # define GLUT_BITMAP_9_BY_15 ((void *) &glutBitmap9By15) # define GLUT_BITMAP_8_BY_13 ((void *) &glutBitmap8By13) # define GLUT_BITMAP_TIMES_ROMAN_10 ((void *) &glutBitmapTimesRoman10) # define GLUT_BITMAP_TIMES_ROMAN_24 ((void *) &glutBitmapTimesRoman24) # define GLUT_BITMAP_HELVETICA_10 ((void *) &glutBitmapHelvetica10) # define GLUT_BITMAP_HELVETICA_12 ((void *) &glutBitmapHelvetica12) # define GLUT_BITMAP_HELVETICA_18 ((void *) &glutBitmapHelvetica18) #endif /* * GLUT API macro definitions -- the glutGet parameters */ #define GLUT_WINDOW_X 0x0064 #define GLUT_WINDOW_Y 0x0065 #define GLUT_WINDOW_WIDTH 0x0066 #define GLUT_WINDOW_HEIGHT 0x0067 #define GLUT_WINDOW_BUFFER_SIZE 0x0068 #define GLUT_WINDOW_STENCIL_SIZE 0x0069 #define GLUT_WINDOW_DEPTH_SIZE 0x006A #define GLUT_WINDOW_RED_SIZE 0x006B #define GLUT_WINDOW_GREEN_SIZE 0x006C #define GLUT_WINDOW_BLUE_SIZE 0x006D #define GLUT_WINDOW_ALPHA_SIZE 0x006E #define GLUT_WINDOW_ACCUM_RED_SIZE 0x006F #define GLUT_WINDOW_ACCUM_GREEN_SIZE 0x0070 #define GLUT_WINDOW_ACCUM_BLUE_SIZE 0x0071 #define GLUT_WINDOW_ACCUM_ALPHA_SIZE 0x0072 #define GLUT_WINDOW_DOUBLEBUFFER 0x0073 #define GLUT_WINDOW_RGBA 0x0074 #define GLUT_WINDOW_PARENT 0x0075 #define GLUT_WINDOW_NUM_CHILDREN 0x0076 #define GLUT_WINDOW_COLORMAP_SIZE 0x0077 #define GLUT_WINDOW_NUM_SAMPLES 0x0078 #define GLUT_WINDOW_STEREO 0x0079 #define GLUT_WINDOW_CURSOR 0x007A #define GLUT_SCREEN_WIDTH 0x00C8 #define GLUT_SCREEN_HEIGHT 0x00C9 #define GLUT_SCREEN_WIDTH_MM 0x00CA #define GLUT_SCREEN_HEIGHT_MM 0x00CB #define GLUT_MENU_NUM_ITEMS 0x012C #define GLUT_DISPLAY_MODE_POSSIBLE 0x0190 #define GLUT_INIT_WINDOW_X 0x01F4 #define GLUT_INIT_WINDOW_Y 0x01F5 #define GLUT_INIT_WINDOW_WIDTH 0x01F6 #define GLUT_INIT_WINDOW_HEIGHT 0x01F7 #define GLUT_INIT_DISPLAY_MODE 0x01F8 #define GLUT_ELAPSED_TIME 0x02BC #define GLUT_WINDOW_FORMAT_ID 0x007B /* * GLUT API macro definitions -- the glutDeviceGet parameters */ #define GLUT_HAS_KEYBOARD 0x0258 #define GLUT_HAS_MOUSE 0x0259 #define GLUT_HAS_SPACEBALL 0x025A #define GLUT_HAS_DIAL_AND_BUTTON_BOX 0x025B #define GLUT_HAS_TABLET 0x025C #define GLUT_NUM_MOUSE_BUTTONS 0x025D #define GLUT_NUM_SPACEBALL_BUTTONS 0x025E #define GLUT_NUM_BUTTON_BOX_BUTTONS 0x025F #define GLUT_NUM_DIALS 0x0260 #define GLUT_NUM_TABLET_BUTTONS 0x0261 #define GLUT_DEVICE_IGNORE_KEY_REPEAT 0x0262 #define GLUT_DEVICE_KEY_REPEAT 0x0263 #define GLUT_HAS_JOYSTICK 0x0264 #define GLUT_OWNS_JOYSTICK 0x0265 #define GLUT_JOYSTICK_BUTTONS 0x0266 #define GLUT_JOYSTICK_AXES 0x0267 #define GLUT_JOYSTICK_POLL_RATE 0x0268 /* * GLUT API macro definitions -- the glutLayerGet parameters */ #define GLUT_OVERLAY_POSSIBLE 0x0320 #define GLUT_LAYER_IN_USE 0x0321 #define GLUT_HAS_OVERLAY 0x0322 #define GLUT_TRANSPARENT_INDEX 0x0323 #define GLUT_NORMAL_DAMAGED 0x0324 #define GLUT_OVERLAY_DAMAGED 0x0325 /* * GLUT API macro definitions -- the glutVideoResizeGet parameters */ #define GLUT_VIDEO_RESIZE_POSSIBLE 0x0384 #define GLUT_VIDEO_RESIZE_IN_USE 0x0385 #define GLUT_VIDEO_RESIZE_X_DELTA 0x0386 #define GLUT_VIDEO_RESIZE_Y_DELTA 0x0387 #define GLUT_VIDEO_RESIZE_WIDTH_DELTA 0x0388 #define GLUT_VIDEO_RESIZE_HEIGHT_DELTA 0x0389 #define GLUT_VIDEO_RESIZE_X 0x038A #define GLUT_VIDEO_RESIZE_Y 0x038B #define GLUT_VIDEO_RESIZE_WIDTH 0x038C #define GLUT_VIDEO_RESIZE_HEIGHT 0x038D /* * GLUT API macro definitions -- the glutUseLayer parameters */ #define GLUT_NORMAL 0x0000 #define GLUT_OVERLAY 0x0001 /* * GLUT API macro definitions -- the glutGetModifiers parameters */ #define GLUT_ACTIVE_SHIFT 0x0001 #define GLUT_ACTIVE_CTRL 0x0002 #define GLUT_ACTIVE_ALT 0x0004 /* * GLUT API macro definitions -- the glutSetCursor parameters */ #define GLUT_CURSOR_RIGHT_ARROW 0x0000 #define GLUT_CURSOR_LEFT_ARROW 0x0001 #define GLUT_CURSOR_INFO 0x0002 #define GLUT_CURSOR_DESTROY 0x0003 #define GLUT_CURSOR_HELP 0x0004 #define GLUT_CURSOR_CYCLE 0x0005 #define GLUT_CURSOR_SPRAY 0x0006 #define GLUT_CURSOR_WAIT 0x0007 #define GLUT_CURSOR_TEXT 0x0008 #define GLUT_CURSOR_CROSSHAIR 0x0009 #define GLUT_CURSOR_UP_DOWN 0x000A #define GLUT_CURSOR_LEFT_RIGHT 0x000B #define GLUT_CURSOR_TOP_SIDE 0x000C #define GLUT_CURSOR_BOTTOM_SIDE 0x000D #define GLUT_CURSOR_LEFT_SIDE 0x000E #define GLUT_CURSOR_RIGHT_SIDE 0x000F #define GLUT_CURSOR_TOP_LEFT_CORNER 0x0010 #define GLUT_CURSOR_TOP_RIGHT_CORNER 0x0011 #define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 0x0012 #define GLUT_CURSOR_BOTTOM_LEFT_CORNER 0x0013 #define GLUT_CURSOR_INHERIT 0x0064 #define GLUT_CURSOR_NONE 0x0065 #define GLUT_CURSOR_FULL_CROSSHAIR 0x0066 /* * GLUT API macro definitions -- RGB color component specification definitions */ #define GLUT_RED 0x0000 #define GLUT_GREEN 0x0001 #define GLUT_BLUE 0x0002 /* * GLUT API macro definitions -- additional keyboard and joystick definitions */ #define GLUT_KEY_REPEAT_OFF 0x0000 #define GLUT_KEY_REPEAT_ON 0x0001 #define GLUT_KEY_REPEAT_DEFAULT 0x0002 #define GLUT_JOYSTICK_BUTTON_A 0x0001 #define GLUT_JOYSTICK_BUTTON_B 0x0002 #define GLUT_JOYSTICK_BUTTON_C 0x0004 #define GLUT_JOYSTICK_BUTTON_D 0x0008 /* * GLUT API macro definitions -- game mode definitions */ #define GLUT_GAME_MODE_ACTIVE 0x0000 #define GLUT_GAME_MODE_POSSIBLE 0x0001 #define GLUT_GAME_MODE_WIDTH 0x0002 #define GLUT_GAME_MODE_HEIGHT 0x0003 #define GLUT_GAME_MODE_PIXEL_DEPTH 0x0004 #define GLUT_GAME_MODE_REFRESH_RATE 0x0005 #define GLUT_GAME_MODE_DISPLAY_CHANGED 0x0006 /* * Initialization functions, see fglut_init.c */ FGAPI void FGAPIENTRY glutInit( int* pargc, char** argv ); FGAPI void FGAPIENTRY glutInitWindowPosition( int x, int y ); FGAPI void FGAPIENTRY glutInitWindowSize( int width, int height ); FGAPI void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode ); FGAPI void FGAPIENTRY glutInitDisplayString( const char* displayMode ); /* * Process loop function, see fg_main.c */ FGAPI void FGAPIENTRY glutMainLoop( void ); /* * Window management functions, see fg_window.c */ FGAPI int FGAPIENTRY glutCreateWindow( const char* title ); FGAPI int FGAPIENTRY glutCreateSubWindow( int window, int x, int y, int width, int height ); FGAPI void FGAPIENTRY glutDestroyWindow( int window ); FGAPI void FGAPIENTRY glutSetWindow( int window ); FGAPI int FGAPIENTRY glutGetWindow( void ); FGAPI void FGAPIENTRY glutSetWindowTitle( const char* title ); FGAPI void FGAPIENTRY glutSetIconTitle( const char* title ); FGAPI void FGAPIENTRY glutReshapeWindow( int width, int height ); FGAPI void FGAPIENTRY glutFitWindowSizeToDesktop(int width, int height); FGAPI void FGAPIENTRY glutPositionWindow( int x, int y ); FGAPI void FGAPIENTRY glutShowWindow( void ); FGAPI void FGAPIENTRY glutHideWindow( void ); FGAPI void FGAPIENTRY glutIconifyWindow( void ); FGAPI void FGAPIENTRY glutPushWindow( void ); FGAPI void FGAPIENTRY glutPopWindow( void ); FGAPI void FGAPIENTRY glutFullScreen( void ); /* * Display-related functions, see fg_display.c */ FGAPI void FGAPIENTRY glutPostWindowRedisplay( int window ); FGAPI void FGAPIENTRY glutPostRedisplay( void ); FGAPI void FGAPIENTRY glutSwapBuffers( void ); /* * Mouse cursor functions, see fg_cursor.c */ FGAPI void FGAPIENTRY glutWarpPointer( int x, int y ); FGAPI void FGAPIENTRY glutSetCursor( int cursor ); /* * Overlay stuff, see fg_overlay.c */ FGAPI void FGAPIENTRY glutEstablishOverlay( void ); FGAPI void FGAPIENTRY glutRemoveOverlay( void ); FGAPI void FGAPIENTRY glutUseLayer( GLenum layer ); FGAPI void FGAPIENTRY glutPostOverlayRedisplay( void ); FGAPI void FGAPIENTRY glutPostWindowOverlayRedisplay( int window ); FGAPI void FGAPIENTRY glutShowOverlay( void ); FGAPI void FGAPIENTRY glutHideOverlay( void ); /* * Menu stuff, see fg_menu.c */ FGAPI int FGAPIENTRY glutCreateMenu( void (* callback)( int menu ) ); FGAPI void FGAPIENTRY glutDestroyMenu( int menu ); FGAPI int FGAPIENTRY glutGetMenu( void ); FGAPI void FGAPIENTRY glutSetMenu( int menu ); FGAPI void FGAPIENTRY glutAddMenuEntry( const char* label, int value ); FGAPI void FGAPIENTRY glutAddSubMenu( const char* label, int subMenu ); FGAPI void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ); FGAPI void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, int value ); FGAPI void FGAPIENTRY glutRemoveMenuItem( int item ); FGAPI void FGAPIENTRY glutAttachMenu( int button ); FGAPI void FGAPIENTRY glutDetachMenu( int button ); /* * Global callback functions, see fg_callbacks.c */ FGAPI void FGAPIENTRY glutTimerFunc( unsigned int time, void (* callback)( int ), int value ); FGAPI void FGAPIENTRY glutIdleFunc( void (* callback)( void ) ); /* * Window-specific callback functions, see fg_callbacks.c */ FGAPI void FGAPIENTRY glutKeyboardFunc( void (* callback)( unsigned char, int, int ) ); FGAPI void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) ); FGAPI void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) ); FGAPI void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ); FGAPI void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) ); FGAPI void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutEntryFunc( void (* callback)( int ) ); FGAPI void FGAPIENTRY glutKeyboardUpFunc( void (* callback)( unsigned char, int, int ) ); FGAPI void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) ); FGAPI void FGAPIENTRY glutJoystickFunc( void (* callback)( unsigned int, int, int, int ), int pollInterval ); FGAPI void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) ); FGAPI void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) ); FGAPI void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) ); FGAPI void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) ); FGAPI void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) ); FGAPI void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) ); FGAPI void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) ); FGAPI void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) ); /* * State setting and retrieval functions, see fg_state.c */ FGAPI int FGAPIENTRY glutGet( GLenum query ); FGAPI int FGAPIENTRY glutDeviceGet( GLenum query ); FGAPI int FGAPIENTRY glutGetModifiers( void ); FGAPI int FGAPIENTRY glutLayerGet( GLenum query ); /* * Font stuff, see fg_font.c */ FGAPI void FGAPIENTRY glutBitmapCharacter( void* font, int character ); FGAPI int FGAPIENTRY glutBitmapWidth( void* font, int character ); FGAPI void FGAPIENTRY glutStrokeCharacter( void* font, int character ); FGAPI int FGAPIENTRY glutStrokeWidth( void* font, int character ); FGAPI GLfloat FGAPIENTRY glutStrokeWidthf( void* font, int character ); /* GLUT 3.8 */ FGAPI int FGAPIENTRY glutBitmapLength( void* font, const unsigned char* string ); FGAPI int FGAPIENTRY glutStrokeLength( void* font, const unsigned char* string ); FGAPI GLfloat FGAPIENTRY glutStrokeLengthf( void* font, const unsigned char *string ); /* GLUT 3.8 */ /* * Geometry functions, see fg_geometry.c */ FGAPI void FGAPIENTRY glutWireCube( double size ); FGAPI void FGAPIENTRY glutSolidCube( double size ); FGAPI void FGAPIENTRY glutWireSphere( double radius, GLint slices, GLint stacks ); FGAPI void FGAPIENTRY glutSolidSphere( double radius, GLint slices, GLint stacks ); FGAPI void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks ); FGAPI void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks ); FGAPI void FGAPIENTRY glutWireTorus( double innerRadius, double outerRadius, GLint sides, GLint rings ); FGAPI void FGAPIENTRY glutSolidTorus( double innerRadius, double outerRadius, GLint sides, GLint rings ); FGAPI void FGAPIENTRY glutWireDodecahedron( void ); FGAPI void FGAPIENTRY glutSolidDodecahedron( void ); FGAPI void FGAPIENTRY glutWireOctahedron( void ); FGAPI void FGAPIENTRY glutSolidOctahedron( void ); FGAPI void FGAPIENTRY glutWireTetrahedron( void ); FGAPI void FGAPIENTRY glutSolidTetrahedron( void ); FGAPI void FGAPIENTRY glutWireIcosahedron( void ); FGAPI void FGAPIENTRY glutSolidIcosahedron( void ); /* * Teapot rendering functions, found in fg_teapot.c * NB: front facing polygons have clockwise winding, not counter clockwise */ FGAPI void FGAPIENTRY glutWireTeapot( double size ); FGAPI void FGAPIENTRY glutSolidTeapot( double size ); /* * Game mode functions, see fg_gamemode.c */ FGAPI void FGAPIENTRY glutGameModeString( const char* string ); FGAPI int FGAPIENTRY glutEnterGameMode( void ); FGAPI void FGAPIENTRY glutLeaveGameMode( void ); FGAPI int FGAPIENTRY glutGameModeGet( GLenum query ); /* * Video resize functions, see fg_videoresize.c */ FGAPI int FGAPIENTRY glutVideoResizeGet( GLenum query ); FGAPI void FGAPIENTRY glutSetupVideoResizing( void ); FGAPI void FGAPIENTRY glutStopVideoResizing( void ); FGAPI void FGAPIENTRY glutVideoResize( int x, int y, int width, int height ); FGAPI void FGAPIENTRY glutVideoPan( int x, int y, int width, int height ); /* * Colormap functions, see fg_misc.c */ FGAPI void FGAPIENTRY glutSetColor( int color, GLfloat red, GLfloat green, GLfloat blue ); FGAPI GLfloat FGAPIENTRY glutGetColor( int color, int component ); FGAPI void FGAPIENTRY glutCopyColormap( int window ); /* * Misc keyboard and joystick functions, see fg_misc.c */ FGAPI void FGAPIENTRY glutIgnoreKeyRepeat( int ignore ); FGAPI void FGAPIENTRY glutSetKeyRepeat( int repeatMode ); FGAPI void FGAPIENTRY glutForceJoystickFunc( void ); /* * Misc functions, see fg_misc.c */ FGAPI int FGAPIENTRY glutExtensionSupported( const char* extension ); FGAPI void FGAPIENTRY glutReportErrors( void ); /* Comment from glut.h of classic GLUT: Win32 has an annoying issue where there are multiple C run-time libraries (CRTs). If the executable is linked with a different CRT from the GLUT DLL, the GLUT DLL will not share the same CRT static data seen by the executable. In particular, atexit callbacks registered in the executable will not be called if GLUT calls its (different) exit routine). GLUT is typically built with the "/MD" option (the CRT with multithreading DLL support), but the Visual C++ linker default is "/ML" (the single threaded CRT). One workaround to this issue is requiring users to always link with the same CRT as GLUT is compiled with. That requires users supply a non-standard option. GLUT 3.7 has its own built-in workaround where the executable's "exit" function pointer is covertly passed to GLUT. GLUT then calls the executable's exit function pointer to ensure that any "atexit" calls registered by the application are called if GLUT needs to exit. Note that the __glut*WithExit routines should NEVER be called directly. To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */ /* to get the prototype for exit() */ #include #if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) && !defined(__WATCOMC__) FGAPI void FGAPIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); FGAPI int FGAPIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int)); FGAPI int FGAPIENTRY __glutCreateMenuWithExit(void (* func)(int), void (__cdecl *exitfunc)(int)); #ifndef FREEGLUT_BUILDING_LIB #if defined(__GNUC__) #define FGUNUSED __attribute__((unused)) #else #define FGUNUSED #endif static void FGAPIENTRY FGUNUSED glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } #define glutInit glutInit_ATEXIT_HACK static int FGAPIENTRY FGUNUSED glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); } #define glutCreateWindow glutCreateWindow_ATEXIT_HACK static int FGAPIENTRY FGUNUSED glutCreateMenu_ATEXIT_HACK(void (* func)(int)) { return __glutCreateMenuWithExit(func, exit); } #define glutCreateMenu glutCreateMenu_ATEXIT_HACK #endif #endif #ifdef __cplusplus } #endif /*** END OF FILE ***/ #endif /* __FREEGLUT_STD_H__ */ ================================================ FILE: source-code/dependencies/freeglut/include/GL/freeglut_ucall.h ================================================ #ifndef __FREEGLUT_UCALL_H__ #define __FREEGLUT_UCALL_H__ /* * freeglut_ucall.h * * Callbacks with user data arguments. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef __cplusplus extern "C" { #endif /* * Menu stuff, see fg_menu.c */ FGAPI int FGAPIENTRY glutCreateMenuUcall( void (* callback)( int menu, void* user_data ), void* user_data ); /* * Global callback functions, see fg_callbacks.c */ FGAPI void FGAPIENTRY glutTimerFuncUcall( unsigned int time, void (* callback)( int, void* ), int value, void* user_data ); FGAPI void FGAPIENTRY glutIdleFuncUcall( void (* callback)( void* ), void* user_data ); /* * Window-specific callback functions, see fg_callbacks.c */ FGAPI void FGAPIENTRY glutKeyboardFuncUcall( void (* callback)( unsigned char, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutSpecialFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutReshapeFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutVisibilityFuncUcall( void (* callback)( int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutDisplayFuncUcall( void (* callback)( void* ), void* user_data ); FGAPI void FGAPIENTRY glutMouseFuncUcall( void (* callback)( int, int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutMotionFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutPassiveMotionFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutEntryFuncUcall( void (* callback)( int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutKeyboardUpFuncUcall( void (* callback)( unsigned char, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutSpecialUpFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutJoystickFuncUcall( void (* callback)( unsigned int, int, int, int, void* ), int pollInterval, void* user_data ); FGAPI void FGAPIENTRY glutMenuStatusFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutOverlayDisplayFuncUcall( void (* callback)( void* ), void* user_data ); FGAPI void FGAPIENTRY glutWindowStatusFuncUcall( void (* callback)( int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutSpaceballMotionFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutSpaceballRotateFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutSpaceballButtonFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutButtonBoxFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutDialsFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutTabletMotionFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutTabletButtonFuncUcall( void (* callback)( int, int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutMouseWheelFuncUcall( void (* callback)( int, int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutPositionFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutCloseFuncUcall( void (* callback)( void* ), void* user_data ); FGAPI void FGAPIENTRY glutWMCloseFuncUcall( void (* callback)( void* ), void* user_data ); FGAPI void FGAPIENTRY glutMenuDestroyFuncUcall( void (* callback)( void* ), void* user_data ); /* * Multi-touch/multi-pointer extensions */ FGAPI void FGAPIENTRY glutMultiEntryFuncUcall( void (* callback)( int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutMultiButtonFuncUcall( void (* callback)( int, int, int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutMultiMotionFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutMultiPassiveFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); /* * Initialization functions, see fg_init.c */ #include FGAPI void FGAPIENTRY glutInitErrorFuncUcall( void (* callback)( const char *fmt, va_list ap, void* user_data ), void* user_data ); FGAPI void FGAPIENTRY glutInitWarningFuncUcall( void (* callback)( const char *fmt, va_list ap, void* user_data ), void* user_data ); /* Mobile platforms lifecycle */ FGAPI void FGAPIENTRY glutInitContextFuncUcall( void (* callback)( void* ), void* user_data ); FGAPI void FGAPIENTRY glutAppStatusFuncUcall( void (* callback)( int, void* ), void* user_data ); /* * Continued "hack" from GLUT applied to Ucall functions. * For more info, see bottom of freeglut_std.h */ /* to get the prototype for exit() */ #include #if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) && !defined(__WATCOMC__) FGAPI int FGAPIENTRY __glutCreateMenuUcallWithExit(void(*func)(int, void*), void(__cdecl *exitfunc)(int), void* user_data); #ifndef FREEGLUT_BUILDING_LIB #if defined(__GNUC__) #define FGUNUSED __attribute__((unused)) #else #define FGUNUSED #endif static int FGAPIENTRY FGUNUSED glutCreateMenuUcall_ATEXIT_HACK(void(*func)(int, void*), void* user_data) { return __glutCreateMenuUcallWithExit(func, exit, user_data); } #define glutCreateMenuUcall glutCreateMenuUcall_ATEXIT_HACK #endif #endif #ifdef __cplusplus } #endif /*** END OF FILE ***/ #endif /* __FREEGLUT_UCALL_H__ */ ================================================ FILE: source-code/dependencies/freeglut/include/GL/glut.h ================================================ #ifndef __GLUT_H__ #define __GLUT_H__ /* * glut.h * * The freeglut library include file * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "freeglut_std.h" /*** END OF FILE ***/ #endif /* __GLUT_H__ */ ================================================ FILE: source-code/dependencies/simpleini/.gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ [Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Coverlet is a free, cross platform Code Coverage Tool coverage*[.json, .xml, .info] # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd ================================================ FILE: source-code/dependencies/simpleini/.travis.yml ================================================ language: cpp os: - linux - osx compiler: - gcc - clang script: - make all - make test ================================================ FILE: source-code/dependencies/simpleini/ConvertUTF.c ================================================ /* * Copyright 2001-2004 Unicode, Inc. * * Disclaimer * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine * applicability of information provided. If this file has been * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. * * Limitations on Rights to Redistribute This Code * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. */ /* --------------------------------------------------------------------- Conversions between UTF32, UTF-16, and UTF-8. Source code file. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Sept 2001: fixed const & error conditions per mods suggested by S. Parent & A. Lillich. June 2002: Tim Dodd added detection and handling of incomplete source sequences, enhanced error detection, added casts to eliminate compiler warnings. July 2003: slight mods to back out aggressive FFFE detection. Jan 2004: updated switches in from-UTF8 conversions. Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. See the header file "ConvertUTF.h" for complete documentation. ------------------------------------------------------------------------ */ #include "ConvertUTF.h" #ifdef CVTUTF_DEBUG #include #endif static const int halfShift = 10; /* used for shifting by 10 bits */ static const UTF32 halfBase = 0x0010000UL; static const UTF32 halfMask = 0x3FFUL; #define UNI_SUR_HIGH_START (UTF32)0xD800 #define UNI_SUR_HIGH_END (UTF32)0xDBFF #define UNI_SUR_LOW_START (UTF32)0xDC00 #define UNI_SUR_LOW_END (UTF32)0xDFFF #define false 0 #define true 1 /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF16 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF32* source = *sourceStart; UTF16* target = *targetStart; while (source < sourceEnd) { UTF32 ch; if (target >= targetEnd) { result = targetExhausted; break; } ch = *source++; if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = (UTF16)ch; /* normal case */ } } else if (ch > UNI_MAX_LEGAL_UTF32) { if (flags == strictConversion) { result = sourceIllegal; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { /* target is a character in range 0xFFFF - 0x10FFFF. */ if (target + 1 >= targetEnd) { --source; /* Back up source pointer! */ result = targetExhausted; break; } ch -= halfBase; *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF32 ( const UTF16** sourceStart, const UTF16* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF16* source = *sourceStart; UTF32* target = *targetStart; UTF32 ch, ch2; while (source < sourceEnd) { const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { /* If the 16 bits following the high surrogate are in the source buffer... */ if (source < sourceEnd) { ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; ++source; } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } else { /* We don't have the 16 bits following the high surrogate. */ --source; /* return to the high surrogate */ result = sourceExhausted; break; } } else if (flags == strictConversion) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } if (target >= targetEnd) { source = oldSource; /* Back up source pointer! */ result = targetExhausted; break; } *target++ = ch; } *sourceStart = source; *targetStart = target; #ifdef CVTUTF_DEBUG if (result == sourceIllegal) { fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); fflush(stderr); } #endif return result; } /* --------------------------------------------------------------------- */ /* * Index into the table below with the first byte of a UTF-8 sequence to * get the number of trailing bytes that are supposed to follow it. * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is * left as-is for anyone who may want to do such conversion, which was * allowed in earlier algorithms. */ static const char trailingBytesForUTF8[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; /* * Magic values subtracted from a buffer value during UTF8 conversion. * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; /* * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed * into the first byte, depending on how many bytes follow. There are * as many entries in this table as there are UTF-8 sequence types. * (I.e., one byte sequence, two byte... etc.). Remember that sequencs * for *legal* UTF-8 will be 4 or fewer bytes total. */ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; /* --------------------------------------------------------------------- */ /* The interface converts a whole buffer to avoid function-call overhead. * Constants have been gathered. Loops & conditionals have been removed as * much as possible for efficiency, in favor of drop-through switches. * (See "Note A" at the bottom of the file for equivalent code.) * If your compiler supports it, the "isLegalUTF8" call can be turned * into an inline function. */ /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF8 ( const UTF16** sourceStart, const UTF16* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF16* source = *sourceStart; UTF8* target = *targetStart; while (source < sourceEnd) { UTF32 ch; unsigned short bytesToWrite = 0; const UTF32 byteMask = 0xBF; const UTF32 byteMark = 0x80; const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { /* If the 16 bits following the high surrogate are in the source buffer... */ if (source < sourceEnd) { UTF32 ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; ++source; } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } else { /* We don't have the 16 bits following the high surrogate. */ --source; /* return to the high surrogate */ result = sourceExhausted; break; } } else if (flags == strictConversion) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } /* Figure out how many bytes the result will require */ if (ch < (UTF32)0x80) { bytesToWrite = 1; } else if (ch < (UTF32)0x800) { bytesToWrite = 2; } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; } else { bytesToWrite = 3; ch = UNI_REPLACEMENT_CHAR; } target += bytesToWrite; if (target > targetEnd) { source = oldSource; /* Back up source pointer! */ target -= bytesToWrite; result = targetExhausted; break; } switch (bytesToWrite) { /* note: everything falls through. */ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ /* * Utility routine to tell whether a sequence of bytes is legal UTF-8. * This must be called with the length pre-determined by the first byte. * If not calling this from ConvertUTF8to*, then the length can be set by: * length = trailingBytesForUTF8[*source]+1; * and the sequence is illegal right away if there aren't that many bytes * available. * If presented with a length > 4, this returns false. The Unicode * definition of UTF-8 goes up to 4-byte sequences. */ static Boolean isLegalUTF8(const UTF8 *source, int length) { UTF8 a; const UTF8 *srcptr = source+length; switch (length) { default: return false; /* Everything else falls through when "true"... */ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 2: if ((a = (*--srcptr)) > 0xBF) return false; switch (*source) { /* no fall-through in this inner switch */ case 0xE0: if (a < 0xA0) return false; break; case 0xED: if (a > 0x9F) return false; break; case 0xF0: if (a < 0x90) return false; break; case 0xF4: if (a > 0x8F) return false; break; default: if (a < 0x80) return false; } case 1: if (*source >= 0x80 && *source < 0xC2) return false; } if (*source > 0xF4) return false; return true; } /* --------------------------------------------------------------------- */ /* * Exported function to return whether a UTF-8 sequence is legal or not. * This is not used here; it's just exported. */ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { int length = trailingBytesForUTF8[*source]+1; if (source+length > sourceEnd) { return false; } return isLegalUTF8(source, length); } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF16 ( const UTF8** sourceStart, const UTF8* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF8* source = *sourceStart; UTF16* target = *targetStart; while (source < sourceEnd) { UTF32 ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { result = sourceExhausted; break; } /* Do this check whether lenient or strict */ if (! isLegalUTF8(source, extraBytesToRead+1)) { result = sourceIllegal; break; } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ case 3: ch += *source++; ch <<= 6; case 2: ch += *source++; ch <<= 6; case 1: ch += *source++; ch <<= 6; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { source -= (extraBytesToRead+1); /* Back up source pointer! */ result = targetExhausted; break; } if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { source -= (extraBytesToRead+1); /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = (UTF16)ch; /* normal case */ } } else if (ch > UNI_MAX_UTF16) { if (flags == strictConversion) { result = sourceIllegal; source -= (extraBytesToRead+1); /* return to the start */ break; /* Bail out; shouldn't continue */ } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { /* target is a character in range 0xFFFF - 0x10FFFF. */ if (target + 1 >= targetEnd) { source -= (extraBytesToRead+1); /* Back up source pointer! */ result = targetExhausted; break; } ch -= halfBase; *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF8 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF32* source = *sourceStart; UTF8* target = *targetStart; while (source < sourceEnd) { UTF32 ch; unsigned short bytesToWrite = 0; const UTF32 byteMask = 0xBF; const UTF32 byteMark = 0x80; ch = *source++; if (flags == strictConversion ) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } /* * Figure out how many bytes the result will require. Turn any * illegally large UTF32 things (> Plane 17) into replacement chars. */ if (ch < (UTF32)0x80) { bytesToWrite = 1; } else if (ch < (UTF32)0x800) { bytesToWrite = 2; } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; } else { bytesToWrite = 3; ch = UNI_REPLACEMENT_CHAR; result = sourceIllegal; } target += bytesToWrite; if (target > targetEnd) { --source; /* Back up source pointer! */ target -= bytesToWrite; result = targetExhausted; break; } switch (bytesToWrite) { /* note: everything falls through. */ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF32 ( const UTF8** sourceStart, const UTF8* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF8* source = *sourceStart; UTF32* target = *targetStart; while (source < sourceEnd) { UTF32 ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { result = sourceExhausted; break; } /* Do this check whether lenient or strict */ if (! isLegalUTF8(source, extraBytesToRead+1)) { result = sourceIllegal; break; } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { case 5: ch += *source++; ch <<= 6; case 4: ch += *source++; ch <<= 6; case 3: ch += *source++; ch <<= 6; case 2: ch += *source++; ch <<= 6; case 1: ch += *source++; ch <<= 6; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { source -= (extraBytesToRead+1); /* Back up the source pointer! */ result = targetExhausted; break; } if (ch <= UNI_MAX_LEGAL_UTF32) { /* * UTF-16 surrogate values are illegal in UTF-32, and anything * over Plane 17 (> 0x10FFFF) is illegal. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { source -= (extraBytesToRead+1); /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = ch; } } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ result = sourceIllegal; *target++ = UNI_REPLACEMENT_CHAR; } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- Note A. The fall-through switches in UTF-8 reading code save a temp variable, some decrements & conditionals. The switches are equivalent to the following loop: { int tmpBytesToRead = extraBytesToRead+1; do { ch += *source++; --tmpBytesToRead; if (tmpBytesToRead) ch <<= 6; } while (tmpBytesToRead > 0); } In UTF-8 writing code, the switches on "bytesToWrite" are similarly unrolled loops. --------------------------------------------------------------------- */ ================================================ FILE: source-code/dependencies/simpleini/ConvertUTF.h ================================================ /* * Copyright 2001-2004 Unicode, Inc. * * Disclaimer * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine * applicability of information provided. If this file has been * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. * * Limitations on Rights to Redistribute This Code * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. */ /* --------------------------------------------------------------------- Conversions between UTF32, UTF-16, and UTF-8. Header file. Several funtions are included here, forming a complete set of conversions between the three formats. UTF-7 is not included here, but is handled in a separate source file. Each of these routines takes pointers to input buffers and output buffers. The input buffers are const. Each routine converts the text between *sourceStart and sourceEnd, putting the result into the buffer between *targetStart and targetEnd. Note: the end pointers are *after* the last item: e.g. *(sourceEnd - 1) is the last item. The return result indicates whether the conversion was successful, and if not, whether the problem was in the source or target buffers. (Only the first encountered problem is indicated.) After the conversion, *sourceStart and *targetStart are both updated to point to the end of last text successfully converted in the respective buffers. Input parameters: sourceStart - pointer to a pointer to the source buffer. The contents of this are modified on return so that it points at the next thing to be converted. targetStart - similarly, pointer to pointer to the target buffer. sourceEnd, targetEnd - respectively pointers to the ends of the two buffers, for overflow checking only. These conversion functions take a ConversionFlags argument. When this flag is set to strict, both irregular sequences and isolated surrogates will cause an error. When the flag is set to lenient, both irregular sequences and isolated surrogates are converted. Whether the flag is strict or lenient, all illegal sequences will cause an error return. This includes sequences such as: , , or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code must check for illegal sequences. When the flag is set to lenient, characters over 0x10FFFF are converted to the replacement character; otherwise (when the flag is set to strict) they constitute an error. Output parameters: The value "sourceIllegal" is returned from some routines if the input sequence is malformed. When "sourceIllegal" is returned, the source value will point to the illegal value that caused the problem. E.g., in UTF-8 when a sequence is malformed, it points to the start of the malformed sequence. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Fixes & updates, Sept 2001. ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- The following 4 definitions are compiler-specific. The C standard does not guarantee that wchar_t has at least 16 bits, so wchar_t is no less portable than unsigned short! All should be unsigned values to avoid sign extension during bit mask & shift operations. ------------------------------------------------------------------------ */ typedef unsigned int UTF32; /* at least 32 bits */ typedef unsigned short UTF16; /* at least 16 bits */ typedef unsigned char UTF8; /* typically 8 bits */ typedef unsigned char Boolean; /* 0 or 1 */ /* Some fundamental constants */ #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD #define UNI_MAX_BMP (UTF32)0x0000FFFF #define UNI_MAX_UTF16 (UTF32)0x0010FFFF #define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF typedef enum { conversionOK, /* conversion successful */ sourceExhausted, /* partial character in source, but hit end */ targetExhausted, /* insuff. room in target for conversion */ sourceIllegal /* source sequence is illegal/malformed */ } ConversionResult; typedef enum { strictConversion = 0, lenientConversion } ConversionFlags; /* This is for C++ and does no harm in C */ #ifdef __cplusplus extern "C" { #endif ConversionResult ConvertUTF8toUTF16 ( const UTF8** sourceStart, const UTF8* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF8 ( const UTF16** sourceStart, const UTF16* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF8toUTF32 ( const UTF8** sourceStart, const UTF8* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF8 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF32 ( const UTF16** sourceStart, const UTF16* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF16 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); #ifdef __cplusplus } #endif /* --------------------------------------------------------------------- */ ================================================ FILE: source-code/dependencies/simpleini/LICENCE.txt ================================================ The MIT License (MIT) Copyright (c) 2006-2013 Brodie Thiesfield Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: source-code/dependencies/simpleini/Makefile ================================================ help: @echo This makefile is just for the test program \(use \"make clean all test\"\) @echo Just include the SimpleIni.h header file to use it. install: @echo No install required. Just include the SimpleIni.h header file to use it. TOPTARGETS := all clean test SUBDIRS := tests $(TOPTARGETS): $(SUBDIRS) $(SUBDIRS): $(MAKE) -C $@ $(MAKECMDGOALS) .PHONY: $(TOPTARGETS) $(SUBDIRS) ================================================ FILE: source-code/dependencies/simpleini/README.md ================================================ simpleini ========= [![Build Status](https://api.travis-ci.org/brofield/simpleini.svg?branch=master)](https://travis-ci.org/brofield/simpleini) A cross-platform library that provides a simple API to read and write INI-style configuration files. It supports data files in ASCII, MBCS and Unicode. It is designed explicitly to be portable to any platform and has been tested on Windows, WinCE and Linux. Released as open-source and free using the MIT licence. # Feature Summary - MIT Licence allows free use in all software (including GPL and commercial) - multi-platform (Windows 95 to Windows 10, Windows CE, Linux, Unix) - loading and saving of INI-style configuration files - configuration files can have any newline format on all platforms - liberal acceptance of file format * key/values with no section * removal of whitespace around sections, keys and values - support for multi-line values (values with embedded newline characters) - optional support for multiple keys with the same name - optional case-insensitive sections and keys (for ASCII characters only) - saves files with sections and keys in the same order as they were loaded - preserves comments on the file, section and keys where possible - supports both char or wchar_t programming interfaces - supports both MBCS (system locale) and UTF-8 file encodings - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file - support for non-ASCII characters in section, keys, values and comments - support for non-standard character types or file encodings via user-written converter classes - support for adding/modifying values programmatically - should compile with no warnings in most compilers # Documentation Full documentation of the interface is available in doxygen format. # Examples These snippets are included with the distribution in the automatic tests as ts-snippets.cpp. ### SIMPLE USAGE ```c++ // simple demonstration CSimpleIniA ini; ini.SetUnicode(); SI_Error rc = ini.LoadFile("example.ini"); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_OK); const char* pv; pv = ini.GetValue("section", "key", "default"); ASSERT_STREQ(pv, "value"); ini.SetValue("section", "key", "newvalue"); pv = ini.GetValue("section", "key", "default"); ASSERT_STREQ(pv, "newvalue"); ``` ### LOADING DATA ```c++ // load from a data file CSimpleIniA ini; SI_Error rc = ini.LoadFile("example.ini"); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_OK); // load from a string const std::string example = "[section]\nkey = value\n"; CSimpleIniA ini; SI_Error rc = ini.LoadData(example); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_OK); ``` ### GETTING SECTIONS AND KEYS ```c++ // get all sections CSimpleIniA::TNamesDepend sections; ini.GetAllSections(sections); // get all keys in a section CSimpleIniA::TNamesDepend keys; ini.GetAllKeys("section1", keys); ``` ### GETTING VALUES ```c++ // get the value of a key that doesn't exist const char* pv; pv = ini.GetValue("section1", "key99"); ASSERT_EQ(pv, nullptr); // get the value of a key that does exist pv = ini.GetValue("section1", "key1"); ASSERT_STREQ(pv, "value1"); // get the value of a key which may have multiple // values. If hasMultiple is true, then there are // multiple values and just one value has been returned bool hasMulti; pv = ini.GetValue("section1", "key1", nullptr, &hasMulti); ASSERT_STREQ(pv, "value1"); ASSERT_EQ(hasMulti, false); pv = ini.GetValue("section1", "key2", nullptr, &hasMulti); ASSERT_STREQ(pv, "value2.1"); ASSERT_EQ(hasMulti, true); // get all values of a key with multiple values CSimpleIniA::TNamesDepend values; ini.GetAllValues("section1", "key2", values); // sort the values into a known order, in this case we want // the original load order values.sort(CSimpleIniA::Entry::LoadOrder()); // output all of the items CSimpleIniA::TNamesDepend::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { printf("value = '%s'\n", it->pItem); } ``` ### MODIFYING DATA ```c++ // add a new section rc = ini.SetValue("section1", nullptr, nullptr); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_INSERTED); // not an error to add one that already exists rc = ini.SetValue("section1", nullptr, nullptr); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_UPDATED); // get the value of a key that doesn't exist const char* pv; pv = ini.GetValue("section2", "key1", "default-value"); ASSERT_STREQ(pv, "default-value"); // adding a key (the section will be added if needed) rc = ini.SetValue("section2", "key1", "value1"); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_INSERTED); // ensure it is set to expected value pv = ini.GetValue("section2", "key1", nullptr); ASSERT_STREQ(pv, "value1"); // change the value of a key rc = ini.SetValue("section2", "key1", "value2"); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_UPDATED); // ensure it is set to expected value pv = ini.GetValue("section2", "key1", nullptr); ASSERT_STREQ(pv, "value2"); ``` ### DELETING DATA ```c++ // deleting a key from a section. Optionally the entire // section may be deleted if it is now empty. bool done, deleteSectionIfEmpty = true; done = ini.Delete("section1", "key1", deleteSectionIfEmpty); ASSERT_EQ(done, true); done = ini.Delete("section1", "key1"); ASSERT_EQ(done, false); // deleting an entire section and all keys in it done = ini.Delete("section2", nullptr); ASSERT_EQ(done, true); done = ini.Delete("section2", nullptr); ASSERT_EQ(done, false); ``` ### SAVING DATA ```c++ // save the data to a string std::string data; rc = ini.Save(data); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_OK); // save the data back to the file rc = ini.SaveFile("example2.ini"); if (rc < 0) { /* handle error */ }; ASSERT_EQ(rc, SI_OK); ``` ================================================ FILE: source-code/dependencies/simpleini/SimpleIni.h ================================================ /** @mainpage
Library SimpleIni
File SimpleIni.h
Author Brodie Thiesfield [brofield at gmail dot com]
Source https://github.com/brofield/simpleini
Version 4.17
Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation. @section intro INTRODUCTION This component allows an INI-style configuration file to be used on both Windows and Linux/Unix. It is fast, simple and source code using this component will compile unchanged on either OS. @section features FEATURES - MIT Licence allows free use in all software (including GPL and commercial) - multi-platform (Windows CE/9x/NT..10/etc, Linux, MacOSX, Unix) - loading and saving of INI-style configuration files - configuration files can have any newline format on all platforms - liberal acceptance of file format - key/values with no section - removal of whitespace around sections, keys and values - support for multi-line values (values with embedded newline characters) - optional support for multiple keys with the same name - optional case-insensitive sections and keys (for ASCII characters only) - saves files with sections and keys in the same order as they were loaded - preserves comments on the file, section and keys where possible. - supports both char or wchar_t programming interfaces - supports both MBCS (system locale) and UTF-8 file encodings - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file - support for non-ASCII characters in section, keys, values and comments - support for non-standard character types or file encodings via user-written converter classes - support for adding/modifying values programmatically - compiles cleanly in the following compilers: - Windows/VC6 (warning level 3) - Windows/VC.NET 2003 (warning level 4) - Windows/VC 2005 (warning level 4) - Linux/gcc (-Wall) @section usage USAGE SUMMARY -# Define the appropriate symbol for the converter you wish to use and include the SimpleIni.h header file. If no specific converter is defined then the default converter is used. The default conversion mode uses SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other platforms. If you are using ICU then SI_CONVERT_ICU is supported on all platforms. -# Declare an instance the appropriate class. Note that the following definitions are just shortcuts for commonly used types. Other types (PRUnichar, unsigned short, unsigned char) are also possible.
Interface Case-sensitive Load UTF-8 Load MBCS Typedef
SI_CONVERT_GENERIC
char No Yes Yes #1 CSimpleIniA
char Yes Yes Yes CSimpleIniCaseA
wchar_t No Yes Yes CSimpleIniW
wchar_t Yes Yes Yes CSimpleIniCaseW
SI_CONVERT_WIN32
char No No #2 Yes CSimpleIniA
char Yes Yes Yes CSimpleIniCaseA
wchar_t No Yes Yes CSimpleIniW
wchar_t Yes Yes Yes CSimpleIniCaseW
SI_CONVERT_ICU
char No Yes Yes CSimpleIniA
char Yes Yes Yes CSimpleIniCaseA
UChar No Yes Yes CSimpleIniW
UChar Yes Yes Yes CSimpleIniCaseW
#1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.
#2 Only affects Windows. On Windows this uses MBCS functions and so may fold case incorrectly leading to uncertain results. -# Call LoadData() or LoadFile() to load and parse the INI configuration file -# Access and modify the data of the file using the following functions
GetAllSections Return all section names
GetAllKeys Return all key names within a section
GetAllValues Return all values within a section & key
GetSection Return all key names and values in a section
GetSectionSize Return the number of keys in a section
GetValue Return a value for a section & key
SetValue Add or update a value for a section & key
Delete Remove a section, or a key from a section
-# Call Save() or SaveFile() to save the INI configuration data @section iostreams IO STREAMS SimpleIni supports reading from and writing to STL IO streams. Enable this by defining SI_SUPPORT_IOSTREAMS before including the SimpleIni.h header file. Ensure that if the streams are backed by a file (e.g. ifstream or ofstream) then the flag ios_base::binary has been used when the file was opened. @section multiline MULTI-LINE VALUES Values that span multiple lines are created using the following format.
        key = <<

    Note the following:
    - The text used for ENDTAG can be anything and is used to find
      where the multi-line text ends.
    - The newline after ENDTAG in the start tag, and the newline
      before ENDTAG in the end tag is not included in the data value.
    - The ending tag must be on it's own line with no whitespace before
      or after it.
    - The multi-line value is modified at load so that each line in the value
      is delimited by a single '\\n' character on all platforms. At save time
      it will be converted into the newline format used by the current
      platform.

    @section comments COMMENTS

    Comments are preserved in the file within the following restrictions:
    - Every file may have a single "file comment". It must start with the
      first character in the file, and will end with the first non-comment
      line in the file.
    - Every section may have a single "section comment". It will start
      with the first comment line following the file comment, or the last
      data entry. It ends at the beginning of the section.
    - Every key may have a single "key comment". This comment will start
      with the first comment line following the section start, or the file
      comment if there is no section name.
    - Comments are set at the time that the file, section or key is first
      created. The only way to modify a comment on a section or a key is to
      delete that entry and recreate it with the new comment. There is no
      way to change the file comment.

    @section save SAVE ORDER

    The sections and keys are written out in the same order as they were
    read in from the file. Sections and keys added to the data after the
    file has been loaded will be added to the end of the file when it is
    written. There is no way to specify the location of a section or key
    other than in first-created, first-saved order.

    @section notes NOTES

    - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
      Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
    - When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
    - When using SI_CONVERT_ICU, ICU header files must be on the include
      path and icuuc.lib must be linked in.
    - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
      you should use SI_CONVERT_GENERIC.
    - The collation (sorting) order used for sections and keys returned from
      iterators is NOT DEFINED. If collation order of the text is important
      then it should be done yourself by either supplying a replacement
      SI_STRLESS class, or by sorting the strings external to this library.
    - Usage of the  header on Windows can be disabled by defining
      SI_NO_MBCS. This is defined automatically on Windows CE platforms.
    - Not thread-safe so manage your own locking

    @section contrib CONTRIBUTIONS
    
    - 2010/05/03: Tobias Gehrig: added GetDoubleValue()

    @section licence MIT LICENCE

    The licence text below is the boilerplate "MIT Licence" used from:
    http://www.opensource.org/licenses/mit-license.php

    Copyright (c) 2006-2012, Brodie Thiesfield

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is furnished
    to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef INCLUDED_SimpleIni_h
#define INCLUDED_SimpleIni_h

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

// Disable these warnings in MSVC:
//  4127 "conditional expression is constant" as the conversion classes trigger
//  it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
//  be optimized away in a release build.
//  4503 'insert' : decorated name length exceeded, name was truncated
//  4702 "unreachable code" as the MS STL header causes it in release mode.
//  Again, the code causing the warning will be cleaned up by the compiler.
//  4786 "identifier truncated to 256 characters" as this is thrown hundreds
//  of times VC6 as soon as STL is used.
#ifdef _MSC_VER
# pragma warning (push)
# pragma warning (disable: 4127 4503 4702 4786)
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifdef SI_SUPPORT_IOSTREAMS
# include 
#endif // SI_SUPPORT_IOSTREAMS

#ifdef _DEBUG
# ifndef assert
#  include 
# endif
# define SI_ASSERT(x)   assert(x)
#else
# define SI_ASSERT(x)
#endif

enum SI_Error {
    SI_OK       =  0,   //!< No error
    SI_UPDATED  =  1,   //!< An existing value was updated
    SI_INSERTED =  2,   //!< A new value was inserted

    // note: test for any error with (retval < 0)
    SI_FAIL     = -1,   //!< Generic failure
    SI_NOMEM    = -2,   //!< Out of memory error
    SI_FILE     = -3    //!< File error (see errno for detail error)
};

#define SI_UTF8_SIGNATURE     "\xEF\xBB\xBF"

#ifdef _WIN32
# define SI_NEWLINE_A   "\r\n"
# define SI_NEWLINE_W   L"\r\n"
#else // !_WIN32
# define SI_NEWLINE_A   "\n"
# define SI_NEWLINE_W   L"\n"
#endif // _WIN32

#if defined(SI_CONVERT_ICU)
# include 
#endif

#if defined(_WIN32)
# define SI_HAS_WIDE_FILE
# define SI_WCHAR_T     wchar_t
#elif defined(SI_CONVERT_ICU)
# define SI_HAS_WIDE_FILE
# define SI_WCHAR_T     UChar
#endif


// ---------------------------------------------------------------------------
//                              MAIN TEMPLATE CLASS
// ---------------------------------------------------------------------------

/** Simple INI file reader.

    This can be instantiated with the choice of unicode or native characterset,
    and case sensitive or insensitive comparisons of section and key names.
    The supported combinations are pre-defined with the following typedefs:

    
Interface Case-sensitive Typedef
char No CSimpleIniA
char Yes CSimpleIniCaseA
wchar_t No CSimpleIniW
wchar_t Yes CSimpleIniCaseW
Note that using other types for the SI_CHAR is supported. For instance, unsigned char, unsigned short, etc. Note that where the alternative type is a different size to char/wchar_t you may need to supply new helper classes for SI_STRLESS and SI_CONVERTER. */ template class CSimpleIniTempl { public: typedef SI_CHAR SI_CHAR_T; /** key entry */ struct Entry { const SI_CHAR * pItem; const SI_CHAR * pComment; int nOrder; Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0) : pItem(a_pszItem) , pComment(NULL) , nOrder(a_nOrder) { } Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder) : pItem(a_pszItem) , pComment(a_pszComment) , nOrder(a_nOrder) { } Entry(const Entry & rhs) { operator=(rhs); } Entry & operator=(const Entry & rhs) { pItem = rhs.pItem; pComment = rhs.pComment; nOrder = rhs.nOrder; return *this; } #if defined(_MSC_VER) && _MSC_VER <= 1200 /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); } bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); } #endif /** Strict less ordering by name of key only */ struct KeyOrder { bool operator()(const Entry & lhs, const Entry & rhs) const { const static SI_STRLESS isLess = SI_STRLESS(); return isLess(lhs.pItem, rhs.pItem); } }; /** Strict less ordering by order, and then name of key */ struct LoadOrder { bool operator()(const Entry & lhs, const Entry & rhs) const { if (lhs.nOrder != rhs.nOrder) { return lhs.nOrder < rhs.nOrder; } return KeyOrder()(lhs.pItem, rhs.pItem); } }; }; /** map keys to values */ typedef std::multimap TKeyVal; /** map sections to key/value map */ typedef std::map TSection; /** set of dependent string pointers. Note that these pointers are dependent on memory owned by CSimpleIni. */ typedef std::list TNamesDepend; /** interface definition for the OutputWriter object to pass to Save() in order to output the INI file data. */ class OutputWriter { public: OutputWriter() { } virtual ~OutputWriter() { } virtual void Write(const char * a_pBuf) = 0; private: OutputWriter(const OutputWriter &); // disable OutputWriter & operator=(const OutputWriter &); // disable }; /** OutputWriter class to write the INI data to a file */ class FileWriter : public OutputWriter { FILE * m_file; public: FileWriter(FILE * a_file) : m_file(a_file) { } void Write(const char * a_pBuf) { fputs(a_pBuf, m_file); } private: FileWriter(const FileWriter &); // disable FileWriter & operator=(const FileWriter &); // disable }; /** OutputWriter class to write the INI data to a string */ class StringWriter : public OutputWriter { std::string & m_string; public: StringWriter(std::string & a_string) : m_string(a_string) { } void Write(const char * a_pBuf) { m_string.append(a_pBuf); } private: StringWriter(const StringWriter &); // disable StringWriter & operator=(const StringWriter &); // disable }; #ifdef SI_SUPPORT_IOSTREAMS /** OutputWriter class to write the INI data to an ostream */ class StreamWriter : public OutputWriter { std::ostream & m_ostream; public: StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { } void Write(const char * a_pBuf) { m_ostream << a_pBuf; } private: StreamWriter(const StreamWriter &); // disable StreamWriter & operator=(const StreamWriter &); // disable }; #endif // SI_SUPPORT_IOSTREAMS /** Characterset conversion utility class to convert strings to the same format as is used for the storage. */ class Converter : private SI_CONVERTER { public: Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) { m_scratch.resize(1024); } Converter(const Converter & rhs) { operator=(rhs); } Converter & operator=(const Converter & rhs) { m_scratch = rhs.m_scratch; return *this; } bool ConvertToStore(const SI_CHAR * a_pszString) { size_t uLen = SI_CONVERTER::SizeToStore(a_pszString); if (uLen == (size_t)(-1)) { return false; } while (uLen > m_scratch.size()) { m_scratch.resize(m_scratch.size() * 2); } return SI_CONVERTER::ConvertToStore( a_pszString, const_cast(m_scratch.data()), m_scratch.size()); } const char * Data() { return m_scratch.data(); } private: std::string m_scratch; }; public: /*-----------------------------------------------------------------------*/ /** Default constructor. @param a_bIsUtf8 See the method SetUnicode() for details. @param a_bMultiKey See the method SetMultiKey() for details. @param a_bMultiLine See the method SetMultiLine() for details. */ CSimpleIniTempl( bool a_bIsUtf8 = false, bool a_bMultiKey = false, bool a_bMultiLine = false ); /** Destructor */ ~CSimpleIniTempl(); /** Deallocate all memory stored by this object */ void Reset(); /** Has any data been loaded */ bool IsEmpty() const { return m_data.empty(); } /*-----------------------------------------------------------------------*/ /** @{ @name Settings */ /** Set the storage format of the INI data. This affects both the loading and saving of the INI data using all of the Load/Save API functions. This value cannot be changed after any INI data has been loaded. If the file is not set to Unicode (UTF-8), then the data encoding is assumed to be the OS native encoding. This encoding is the system locale on Linux/Unix and the legacy MBCS encoding on Windows NT/2K/XP. If the storage format is set to Unicode then the file will be loaded as UTF-8 encoded data regardless of the native file encoding. If SI_CHAR == char then all of the char* parameters take and return UTF-8 encoded data regardless of the system locale. \param a_bIsUtf8 Assume UTF-8 encoding for the source? */ void SetUnicode(bool a_bIsUtf8 = true) { if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8; } /** Get the storage format of the INI data. */ bool IsUnicode() const { return m_bStoreIsUtf8; } /** Should multiple identical keys be permitted in the file. If set to false then the last value encountered will be used as the value of the key. If set to true, then all values will be available to be queried. For example, with the following input:
        [section]
        test=value1
        test=value2
        
Then with SetMultiKey(true), both of the values "value1" and "value2" will be returned for the key test. If SetMultiKey(false) is used, then the value for "test" will only be "value2". This value may be changed at any time. \param a_bAllowMultiKey Allow multi-keys in the source? */ void SetMultiKey(bool a_bAllowMultiKey = true) { m_bAllowMultiKey = a_bAllowMultiKey; } /** Get the storage format of the INI data. */ bool IsMultiKey() const { return m_bAllowMultiKey; } /** Should data values be permitted to span multiple lines in the file. If set to false then the multi-line construct << SI_CHAR FORMAT char same format as when loaded (MBCS or UTF-8) wchar_t UTF-8 other UTF-8 Note that comments from the original data is preserved as per the documentation on comments. The order of the sections and values from the original file will be preserved. Any data prepended or appended to the output device must use the the same format (MBCS or UTF-8). You may use the GetConverter() method to convert text to the correct format regardless of the output format being used by SimpleIni. To add a BOM to UTF-8 data, write it out manually at the very beginning like is done in SaveFile when a_bUseBOM is true. @param a_oOutput Output writer to write the data to. @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in UTF-8 format. If it is not UTF-8 then this value is ignored. Do not set this to true if anything has already been written to the OutputWriter. @return SI_Error See error definitions */ SI_Error Save( OutputWriter & a_oOutput, bool a_bAddSignature = false ) const; #ifdef SI_SUPPORT_IOSTREAMS /** Save the INI data to an ostream. See Save() for details. @param a_ostream String to have the INI data appended to. @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in UTF-8 format. If it is not UTF-8 then this value is ignored. Do not set this to true if anything has already been written to the stream. @return SI_Error See error definitions */ SI_Error Save( std::ostream & a_ostream, bool a_bAddSignature = false ) const { StreamWriter writer(a_ostream); return Save(writer, a_bAddSignature); } #endif // SI_SUPPORT_IOSTREAMS /** Append the INI data to a string. See Save() for details. @param a_sBuffer String to have the INI data appended to. @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in UTF-8 format. If it is not UTF-8 then this value is ignored. Do not set this to true if anything has already been written to the string. @return SI_Error See error definitions */ SI_Error Save( std::string & a_sBuffer, bool a_bAddSignature = false ) const { StringWriter writer(a_sBuffer); return Save(writer, a_bAddSignature); } /*-----------------------------------------------------------------------*/ /** @} @{ @name Accessing INI Data */ /** Retrieve all section names. The list is returned as an STL vector of names and can be iterated or searched as necessary. Note that the sort order of the returned strings is NOT DEFINED. You can sort the names into the load order if desired. Search this file for ".sort" for an example. NOTE! This structure contains only pointers to strings. The actual string data is stored in memory owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed or Reset() while these pointers are in use! @param a_names Vector that will receive all of the section names. See note above! */ void GetAllSections( TNamesDepend & a_names ) const; /** Retrieve all unique key names in a section. The sort order of the returned strings is NOT DEFINED. You can sort the names into the load order if desired. Search this file for ".sort" for an example. Only unique key names are returned. NOTE! This structure contains only pointers to strings. The actual string data is stored in memory owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed or Reset() while these strings are in use! @param a_pSection Section to request data for @param a_names List that will receive all of the key names. See note above! @return true Section was found. @return false Matching section was not found. */ bool GetAllKeys( const SI_CHAR * a_pSection, TNamesDepend & a_names ) const; /** Retrieve all values for a specific key. This method can be used when multiple keys are both enabled and disabled. Note that the sort order of the returned strings is NOT DEFINED. You can sort the names into the load order if desired. Search this file for ".sort" for an example. NOTE! The returned values are pointers to string data stored in memory owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed or Reset while you are using this pointer! @param a_pSection Section to search @param a_pKey Key to search for @param a_values List to return if the key is not found @return true Key was found. @return false Matching section/key was not found. */ bool GetAllValues( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, TNamesDepend & a_values ) const; /** Query the number of keys in a specific section. Note that if multiple keys are enabled, then this value may be different to the number of keys returned by GetAllKeys. @param a_pSection Section to request data for @return -1 Section does not exist in the file @return >=0 Number of keys in the section */ int GetSectionSize( const SI_CHAR * a_pSection ) const; /** Retrieve all key and value pairs for a section. The data is returned as a pointer to an STL map and can be iterated or searched as desired. Note that multiple entries for the same key may exist when multiple keys have been enabled. NOTE! This structure contains only pointers to strings. The actual string data is stored in memory owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed or Reset() while these strings are in use! @param a_pSection Name of the section to return @return boolean Was a section matching the supplied name found. */ const TKeyVal * GetSection( const SI_CHAR * a_pSection ) const; /** Retrieve the value for a specific key. If multiple keys are enabled (see SetMultiKey) then only the first value associated with that key will be returned, see GetAllValues for getting all values with multikey. NOTE! The returned value is a pointer to string data stored in memory owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed or Reset while you are using this pointer! @param a_pSection Section to search @param a_pKey Key to search for @param a_pDefault Value to return if the key is not found @param a_pHasMultiple Optionally receive notification of if there are multiple entries for this key. @return a_pDefault Key was not found in the section @return other Value of the key */ const SI_CHAR * GetValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, const SI_CHAR * a_pDefault = NULL, bool * a_pHasMultiple = NULL ) const; /** Retrieve a numeric value for a specific key. If multiple keys are enabled (see SetMultiKey) then only the first value associated with that key will be returned, see GetAllValues for getting all values with multikey. @param a_pSection Section to search @param a_pKey Key to search for @param a_nDefault Value to return if the key is not found @param a_pHasMultiple Optionally receive notification of if there are multiple entries for this key. @return a_nDefault Key was not found in the section @return other Value of the key */ long GetLongValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, long a_nDefault = 0, bool * a_pHasMultiple = NULL ) const; /** Retrieve a numeric value for a specific key. If multiple keys are enabled (see SetMultiKey) then only the first value associated with that key will be returned, see GetAllValues for getting all values with multikey. @param a_pSection Section to search @param a_pKey Key to search for @param a_nDefault Value to return if the key is not found @param a_pHasMultiple Optionally receive notification of if there are multiple entries for this key. @return a_nDefault Key was not found in the section @return other Value of the key */ double GetDoubleValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, double a_nDefault = 0, bool * a_pHasMultiple = NULL ) const; /** Retrieve a boolean value for a specific key. If multiple keys are enabled (see SetMultiKey) then only the first value associated with that key will be returned, see GetAllValues for getting all values with multikey. Strings starting with "t", "y", "on" or "1" are returned as logically true. Strings starting with "f", "n", "of" or "0" are returned as logically false. For all other values the default is returned. Character comparisons are case-insensitive. @param a_pSection Section to search @param a_pKey Key to search for @param a_bDefault Value to return if the key is not found @param a_pHasMultiple Optionally receive notification of if there are multiple entries for this key. @return a_nDefault Key was not found in the section @return other Value of the key */ bool GetBoolValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, bool a_bDefault = false, bool * a_pHasMultiple = NULL ) const; /** Add or update a section or value. This will always insert when multiple keys are enabled. @param a_pSection Section to add or update @param a_pKey Key to add or update. Set to NULL to create an empty section. @param a_pValue Value to set. Set to NULL to create an empty section. @param a_pComment Comment to be associated with the section or the key. If a_pKey is NULL then it will be associated with the section, otherwise the key. Note that a comment may be set ONLY when the section or key is first created (i.e. when this function returns the value SI_INSERTED). If you wish to create a section with a comment then you need to create the section separately to the key. The comment string must be in full comment form already (have a comment character starting every line). @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has no effect if not using multi-key files. The difference between Delete/SetValue and SetValue with a_bForceReplace = true, is that the load order and comment will be preserved this way. @return SI_Error See error definitions @return SI_UPDATED Value was updated @return SI_INSERTED Value was inserted */ SI_Error SetValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, const SI_CHAR * a_pValue, const SI_CHAR * a_pComment = NULL, bool a_bForceReplace = false ) { return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true); } /** Add or update a numeric value. This will always insert when multiple keys are enabled. @param a_pSection Section to add or update @param a_pKey Key to add or update. @param a_nValue Value to set. @param a_pComment Comment to be associated with the key. See the notes on SetValue() for comments. @param a_bUseHex By default the value will be written to the file in decimal format. Set this to true to write it as hexadecimal. @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has no effect if not using multi-key files. The difference between Delete/SetLongValue and SetLongValue with a_bForceReplace = true, is that the load order and comment will be preserved this way. @return SI_Error See error definitions @return SI_UPDATED Value was updated @return SI_INSERTED Value was inserted */ SI_Error SetLongValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, long a_nValue, const SI_CHAR * a_pComment = NULL, bool a_bUseHex = false, bool a_bForceReplace = false ); /** Add or update a double value. This will always insert when multiple keys are enabled. @param a_pSection Section to add or update @param a_pKey Key to add or update. @param a_nValue Value to set. @param a_pComment Comment to be associated with the key. See the notes on SetValue() for comments. @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has no effect if not using multi-key files. The difference between Delete/SetDoubleValue and SetDoubleValue with a_bForceReplace = true, is that the load order and comment will be preserved this way. @return SI_Error See error definitions @return SI_UPDATED Value was updated @return SI_INSERTED Value was inserted */ SI_Error SetDoubleValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, double a_nValue, const SI_CHAR * a_pComment = NULL, bool a_bForceReplace = false ); /** Add or update a boolean value. This will always insert when multiple keys are enabled. @param a_pSection Section to add or update @param a_pKey Key to add or update. @param a_bValue Value to set. @param a_pComment Comment to be associated with the key. See the notes on SetValue() for comments. @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has no effect if not using multi-key files. The difference between Delete/SetBoolValue and SetBoolValue with a_bForceReplace = true, is that the load order and comment will be preserved this way. @return SI_Error See error definitions @return SI_UPDATED Value was updated @return SI_INSERTED Value was inserted */ SI_Error SetBoolValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, bool a_bValue, const SI_CHAR * a_pComment = NULL, bool a_bForceReplace = false ); /** Delete an entire section, or a key from a section. Note that the data returned by GetSection is invalid and must not be used after anything has been deleted from that section using this method. Note when multiple keys is enabled, this will delete all keys with that name; to selectively delete individual key/values, use DeleteValue. @param a_pSection Section to delete key from, or if a_pKey is NULL, the section to remove. @param a_pKey Key to remove from the section. Set to NULL to remove the entire section. @param a_bRemoveEmpty If the section is empty after this key has been deleted, should the empty section be removed? @return true Key or section was deleted. @return false Key or section was not found. */ bool Delete( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, bool a_bRemoveEmpty = false ); /** Delete an entire section, or a key from a section. If value is provided, only remove keys with the value. Note that the data returned by GetSection is invalid and must not be used after anything has been deleted from that section using this method. Note when multiple keys is enabled, all keys with the value will be deleted. @param a_pSection Section to delete key from, or if a_pKey is NULL, the section to remove. @param a_pKey Key to remove from the section. Set to NULL to remove the entire section. @param a_pValue Value of key to remove from the section. Set to NULL to remove all keys. @param a_bRemoveEmpty If the section is empty after this key has been deleted, should the empty section be removed? @return true Key/value or section was deleted. @return false Key/value or section was not found. */ bool DeleteValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, const SI_CHAR * a_pValue, bool a_bRemoveEmpty = false ); /*-----------------------------------------------------------------------*/ /** @} @{ @name Converter */ /** Return a conversion object to convert text to the same encoding as is used by the Save(), SaveFile() and SaveString() functions. Use this to prepare the strings that you wish to append or prepend to the output INI data. */ Converter GetConverter() const { return Converter(m_bStoreIsUtf8); } /*-----------------------------------------------------------------------*/ /** @} */ private: // copying is not permitted CSimpleIniTempl(const CSimpleIniTempl &); // disabled CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled /** Parse the data looking for a file comment and store it if found. */ SI_Error FindFileComment( SI_CHAR *& a_pData, bool a_bCopyStrings ); /** Parse the data looking for the next valid entry. The memory pointed to by a_pData is modified by inserting NULL characters. The pointer is updated to the current location in the block of text. */ bool FindEntry( SI_CHAR *& a_pData, const SI_CHAR *& a_pSection, const SI_CHAR *& a_pKey, const SI_CHAR *& a_pVal, const SI_CHAR *& a_pComment ) const; /** Add the section/key/value to our data. @param a_pSection Section name. Sections will be created if they don't already exist. @param a_pKey Key name. May be NULL to create an empty section. Existing entries will be updated. New entries will be created. @param a_pValue Value for the key. @param a_pComment Comment to be associated with the section or the key. If a_pKey is NULL then it will be associated with the section, otherwise the key. This must be a string in full comment form already (have a comment character starting every line). @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has no effect if not using multi-key files. The difference between Delete/AddEntry and AddEntry with a_bForceReplace = true, is that the load order and comment will be preserved this way. @param a_bCopyStrings Should copies of the strings be made or not. If false then the pointers will be used as is. */ SI_Error AddEntry( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, const SI_CHAR * a_pValue, const SI_CHAR * a_pComment, bool a_bForceReplace, bool a_bCopyStrings ); /** Is the supplied character a whitespace character? */ inline bool IsSpace(SI_CHAR ch) const { return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); } /** Does the supplied character start a comment line? */ inline bool IsComment(SI_CHAR ch) const { return (ch == ';' || ch == '#'); } /** Skip over a newline character (or characters) for either DOS or UNIX */ inline void SkipNewLine(SI_CHAR *& a_pData) const { a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1; } /** Make a copy of the supplied string, replacing the original pointer */ SI_Error CopyString(const SI_CHAR *& a_pString); /** Delete a string from the copied strings buffer if necessary */ void DeleteString(const SI_CHAR * a_pString); /** Internal use of our string comparison function */ bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const { const static SI_STRLESS isLess = SI_STRLESS(); return isLess(a_pLeft, a_pRight); } bool IsMultiLineTag(const SI_CHAR * a_pData) const; bool IsMultiLineData(const SI_CHAR * a_pData) const; bool LoadMultiLineText( SI_CHAR *& a_pData, const SI_CHAR *& a_pVal, const SI_CHAR * a_pTagName, bool a_bAllowBlankLinesInComment = false ) const; bool IsNewLineChar(SI_CHAR a_c) const; bool OutputMultiLineText( OutputWriter & a_oOutput, Converter & a_oConverter, const SI_CHAR * a_pText ) const; private: /** Copy of the INI file data in our character format. This will be modified when parsed to have NULL characters added after all interesting string entries. All of the string pointers to sections, keys and values point into this block of memory. */ SI_CHAR * m_pData; /** Length of the data that we have stored. Used when deleting strings to determine if the string is stored here or in the allocated string buffer. */ size_t m_uDataLen; /** File comment for this data, if one exists. */ const SI_CHAR * m_pFileComment; /** Parsed INI data. Section -> (Key -> Value). */ TSection m_data; /** This vector stores allocated memory for copies of strings that have been supplied after the file load. It will be empty unless SetValue() has been called. */ TNamesDepend m_strings; /** Is the format of our datafile UTF-8 or MBCS? */ bool m_bStoreIsUtf8; /** Are multiple values permitted for the same key? */ bool m_bAllowMultiKey; /** Are data values permitted to span multiple lines? */ bool m_bAllowMultiLine; /** Should spaces be written out surrounding the equals sign? */ bool m_bSpaces; /** Next order value, used to ensure sections and keys are output in the same order that they are loaded/added. */ int m_nOrder; }; // --------------------------------------------------------------------------- // IMPLEMENTATION // --------------------------------------------------------------------------- template CSimpleIniTempl::CSimpleIniTempl( bool a_bIsUtf8, bool a_bAllowMultiKey, bool a_bAllowMultiLine ) : m_pData(0) , m_uDataLen(0) , m_pFileComment(NULL) , m_bStoreIsUtf8(a_bIsUtf8) , m_bAllowMultiKey(a_bAllowMultiKey) , m_bAllowMultiLine(a_bAllowMultiLine) , m_bSpaces(true) , m_nOrder(0) { } template CSimpleIniTempl::~CSimpleIniTempl() { Reset(); } template void CSimpleIniTempl::Reset() { // remove all data delete[] m_pData; m_pData = NULL; m_uDataLen = 0; m_pFileComment = NULL; if (!m_data.empty()) { m_data.erase(m_data.begin(), m_data.end()); } // remove all strings if (!m_strings.empty()) { typename TNamesDepend::iterator i = m_strings.begin(); for (; i != m_strings.end(); ++i) { delete[] const_cast(i->pItem); } m_strings.erase(m_strings.begin(), m_strings.end()); } } template SI_Error CSimpleIniTempl::LoadFile( const char * a_pszFile ) { FILE * fp = NULL; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE fopen_s(&fp, a_pszFile, "rb"); #else // !__STDC_WANT_SECURE_LIB__ fp = fopen(a_pszFile, "rb"); #endif // __STDC_WANT_SECURE_LIB__ if (!fp) { return SI_FILE; } SI_Error rc = LoadFile(fp); fclose(fp); return rc; } #ifdef SI_HAS_WIDE_FILE template SI_Error CSimpleIniTempl::LoadFile( const SI_WCHAR_T * a_pwszFile ) { #ifdef _WIN32 FILE * fp = NULL; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE _wfopen_s(&fp, a_pwszFile, L"rb"); #else // !__STDC_WANT_SECURE_LIB__ fp = _wfopen(a_pwszFile, L"rb"); #endif // __STDC_WANT_SECURE_LIB__ if (!fp) return SI_FILE; SI_Error rc = LoadFile(fp); fclose(fp); return rc; #else // !_WIN32 (therefore SI_CONVERT_ICU) char szFile[256]; u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); return LoadFile(szFile); #endif // _WIN32 } #endif // SI_HAS_WIDE_FILE template SI_Error CSimpleIniTempl::LoadFile( FILE * a_fpFile ) { // load the raw file data int retval = fseek(a_fpFile, 0, SEEK_END); if (retval != 0) { return SI_FILE; } long lSize = ftell(a_fpFile); if (lSize < 0) { return SI_FILE; } if (lSize == 0) { return SI_OK; } // allocate and ensure NULL terminated char * pData = new(std::nothrow) char[lSize+1]; if (!pData) { return SI_NOMEM; } pData[lSize] = 0; // load data into buffer fseek(a_fpFile, 0, SEEK_SET); size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile); if (uRead != (size_t) lSize) { delete[] pData; return SI_FILE; } // convert the raw data to unicode SI_Error rc = LoadData(pData, uRead); delete[] pData; return rc; } template SI_Error CSimpleIniTempl::LoadData( const char * a_pData, size_t a_uDataLen ) { if (!a_pData) { return SI_OK; } // if the UTF-8 BOM exists, consume it and set mode to unicode, if we have // already loaded data and try to change mode half-way through then this will // be ignored and we will assert in debug versions if (a_uDataLen >= 3 && memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) { a_pData += 3; a_uDataLen -= 3; SI_ASSERT(m_bStoreIsUtf8 || !m_pData); // we don't expect mixed mode data SetUnicode(); } if (a_uDataLen == 0) { return SI_OK; } // determine the length of the converted data SI_CONVERTER converter(m_bStoreIsUtf8); size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen); if (uLen == (size_t)(-1)) { return SI_FAIL; } // allocate memory for the data, ensure that there is a NULL // terminator wherever the converted data ends SI_CHAR * pData = new(std::nothrow) SI_CHAR[uLen+1]; if (!pData) { return SI_NOMEM; } memset(pData, 0, sizeof(SI_CHAR)*(uLen+1)); // convert the data if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) { delete[] pData; return SI_FAIL; } // parse it const static SI_CHAR empty = 0; SI_CHAR * pWork = pData; const SI_CHAR * pSection = ∅ const SI_CHAR * pItem = NULL; const SI_CHAR * pVal = NULL; const SI_CHAR * pComment = NULL; // We copy the strings if we are loading data into this class when we // already have stored some. bool bCopyStrings = (m_pData != NULL); // find a file comment if it exists, this is a comment that starts at the // beginning of the file and continues until the first blank line. SI_Error rc = FindFileComment(pWork, bCopyStrings); if (rc < 0) return rc; // add every entry in the file to the data table while (FindEntry(pWork, pSection, pItem, pVal, pComment)) { rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings); if (rc < 0) return rc; } // store these strings if we didn't copy them if (bCopyStrings) { delete[] pData; } else { m_pData = pData; m_uDataLen = uLen+1; } return SI_OK; } #ifdef SI_SUPPORT_IOSTREAMS template SI_Error CSimpleIniTempl::LoadData( std::istream & a_istream ) { std::string strData; char szBuf[512]; do { a_istream.get(szBuf, sizeof(szBuf), '\0'); strData.append(szBuf); } while (a_istream.good()); return LoadData(strData); } #endif // SI_SUPPORT_IOSTREAMS template SI_Error CSimpleIniTempl::FindFileComment( SI_CHAR *& a_pData, bool a_bCopyStrings ) { // there can only be a single file comment if (m_pFileComment) { return SI_OK; } // Load the file comment as multi-line text, this will modify all of // the newline characters to be single \n chars if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) { return SI_OK; } // copy the string if necessary if (a_bCopyStrings) { SI_Error rc = CopyString(m_pFileComment); if (rc < 0) return rc; } return SI_OK; } template bool CSimpleIniTempl::FindEntry( SI_CHAR *& a_pData, const SI_CHAR *& a_pSection, const SI_CHAR *& a_pKey, const SI_CHAR *& a_pVal, const SI_CHAR *& a_pComment ) const { a_pComment = NULL; SI_CHAR * pTrail = NULL; while (*a_pData) { // skip spaces and empty lines while (*a_pData && IsSpace(*a_pData)) { ++a_pData; } if (!*a_pData) { break; } // skip processing of comment lines but keep a pointer to // the start of the comment. if (IsComment(*a_pData)) { LoadMultiLineText(a_pData, a_pComment, NULL, true); continue; } // process section names if (*a_pData == '[') { // skip leading spaces ++a_pData; while (*a_pData && IsSpace(*a_pData)) { ++a_pData; } // find the end of the section name (it may contain spaces) // and convert it to lowercase as necessary a_pSection = a_pData; while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) { ++a_pData; } // if it's an invalid line, just skip it if (*a_pData != ']') { continue; } // remove trailing spaces from the section pTrail = a_pData - 1; while (pTrail >= a_pSection && IsSpace(*pTrail)) { --pTrail; } ++pTrail; *pTrail = 0; // skip to the end of the line ++a_pData; // safe as checked that it == ']' above while (*a_pData && !IsNewLineChar(*a_pData)) { ++a_pData; } a_pKey = NULL; a_pVal = NULL; return true; } // find the end of the key name (it may contain spaces) // and convert it to lowercase as necessary a_pKey = a_pData; while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) { ++a_pData; } // if it's an invalid line, just skip it if (*a_pData != '=') { continue; } // empty keys are invalid if (a_pKey == a_pData) { while (*a_pData && !IsNewLineChar(*a_pData)) { ++a_pData; } continue; } // remove trailing spaces from the key pTrail = a_pData - 1; while (pTrail >= a_pKey && IsSpace(*pTrail)) { --pTrail; } ++pTrail; *pTrail = 0; // skip leading whitespace on the value ++a_pData; // safe as checked that it == '=' above while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) { ++a_pData; } // find the end of the value which is the end of this line a_pVal = a_pData; while (*a_pData && !IsNewLineChar(*a_pData)) { ++a_pData; } // remove trailing spaces from the value pTrail = a_pData - 1; if (*a_pData) { // prepare for the next round SkipNewLine(a_pData); } while (pTrail >= a_pVal && IsSpace(*pTrail)) { --pTrail; } ++pTrail; *pTrail = 0; // check for multi-line entries if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) { // skip the "<<<" to get the tag that will end the multiline const SI_CHAR * pTagName = a_pVal + 3; return LoadMultiLineText(a_pData, a_pVal, pTagName); } // return the standard entry return true; } return false; } template bool CSimpleIniTempl::IsMultiLineTag( const SI_CHAR * a_pVal ) const { // check for the "<<<" prefix for a multi-line entry if (*a_pVal++ != '<') return false; if (*a_pVal++ != '<') return false; if (*a_pVal++ != '<') return false; return true; } template bool CSimpleIniTempl::IsMultiLineData( const SI_CHAR * a_pData ) const { // data is multi-line if it has any of the following features: // * whitespace prefix // * embedded newlines // * whitespace suffix // empty string if (!*a_pData) { return false; } // check for prefix if (IsSpace(*a_pData)) { return true; } // embedded newlines while (*a_pData) { if (IsNewLineChar(*a_pData)) { return true; } ++a_pData; } // check for suffix if (IsSpace(*--a_pData)) { return true; } return false; } template bool CSimpleIniTempl::IsNewLineChar( SI_CHAR a_c ) const { return (a_c == '\n' || a_c == '\r'); } template bool CSimpleIniTempl::LoadMultiLineText( SI_CHAR *& a_pData, const SI_CHAR *& a_pVal, const SI_CHAR * a_pTagName, bool a_bAllowBlankLinesInComment ) const { // we modify this data to strip all newlines down to a single '\n' // character. This means that on Windows we need to strip out some // characters which will make the data shorter. // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become // LINE1-LINE1\nLINE2-LINE2\0 // The pDataLine entry is the pointer to the location in memory that // the current line needs to start to run following the existing one. // This may be the same as pCurrLine in which case no move is needed. SI_CHAR * pDataLine = a_pData; SI_CHAR * pCurrLine; // value starts at the current line a_pVal = a_pData; // find the end tag. This tag must start in column 1 and be // followed by a newline. We ignore any whitespace after the end // tag but not whitespace before it. SI_CHAR cEndOfLineChar = *a_pData; for(;;) { // if we are loading comments then we need a comment character as // the first character on every line if (!a_pTagName && !IsComment(*a_pData)) { // if we aren't allowing blank lines then we're done if (!a_bAllowBlankLinesInComment) { break; } // if we are allowing blank lines then we only include them // in this comment if another comment follows, so read ahead // to find out. SI_CHAR * pCurr = a_pData; int nNewLines = 0; while (IsSpace(*pCurr)) { if (IsNewLineChar(*pCurr)) { ++nNewLines; SkipNewLine(pCurr); } else { ++pCurr; } } // we have a comment, add the blank lines to the output // and continue processing from here if (IsComment(*pCurr)) { for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n'; a_pData = pCurr; continue; } // the comment ends here break; } // find the end of this line pCurrLine = a_pData; while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData; // move this line down to the location that it should be if necessary if (pDataLine < pCurrLine) { size_t nLen = (size_t) (a_pData - pCurrLine); memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR)); pDataLine[nLen] = '\0'; } // end the line with a NULL cEndOfLineChar = *a_pData; *a_pData = 0; // if are looking for a tag then do the check now. This is done before // checking for end of the data, so that if we have the tag at the end // of the data then the tag is removed correctly. if (a_pTagName) { // strip whitespace from the end of this tag SI_CHAR* pc = a_pData - 1; while (pc > pDataLine && IsSpace(*pc)) --pc; SI_CHAR ch = *++pc; *pc = 0; if (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)) { break; } *pc = ch; } // if we are at the end of the data then we just automatically end // this entry and return the current data. if (!cEndOfLineChar) { return true; } // otherwise we need to process this newline to ensure that it consists // of just a single \n character. pDataLine += (a_pData - pCurrLine); *a_pData = cEndOfLineChar; SkipNewLine(a_pData); *pDataLine++ = '\n'; } // if we didn't find a comment at all then return false if (a_pVal == a_pData) { a_pVal = NULL; return false; } // the data (which ends at the end of the last line) needs to be // null-terminated BEFORE before the newline character(s). If the // user wants a new line in the multi-line data then they need to // add an empty line before the tag. *--pDataLine = '\0'; // if looking for a tag and if we aren't at the end of the data, // then move a_pData to the start of the next line. if (a_pTagName && cEndOfLineChar) { SI_ASSERT(IsNewLineChar(cEndOfLineChar)); *a_pData = cEndOfLineChar; SkipNewLine(a_pData); } return true; } template SI_Error CSimpleIniTempl::CopyString( const SI_CHAR *& a_pString ) { size_t uLen = 0; if (sizeof(SI_CHAR) == sizeof(char)) { uLen = strlen((const char *)a_pString); } else if (sizeof(SI_CHAR) == sizeof(wchar_t)) { uLen = wcslen((const wchar_t *)a_pString); } else { for ( ; a_pString[uLen]; ++uLen) /*loop*/ ; } ++uLen; // NULL character SI_CHAR * pCopy = new(std::nothrow) SI_CHAR[uLen]; if (!pCopy) { return SI_NOMEM; } memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen); m_strings.push_back(pCopy); a_pString = pCopy; return SI_OK; } template SI_Error CSimpleIniTempl::AddEntry( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, const SI_CHAR * a_pValue, const SI_CHAR * a_pComment, bool a_bForceReplace, bool a_bCopyStrings ) { SI_Error rc; bool bInserted = false; SI_ASSERT(!a_pComment || IsComment(*a_pComment)); // if we are copying strings then make a copy of the comment now // because we will need it when we add the entry. if (a_bCopyStrings && a_pComment) { rc = CopyString(a_pComment); if (rc < 0) return rc; } // create the section entry if necessary typename TSection::iterator iSection = m_data.find(a_pSection); if (iSection == m_data.end()) { // if the section doesn't exist then we need a copy as the // string needs to last beyond the end of this function if (a_bCopyStrings) { rc = CopyString(a_pSection); if (rc < 0) return rc; } // only set the comment if this is a section only entry Entry oSection(a_pSection, ++m_nOrder); if (a_pComment && (!a_pKey || !a_pValue)) { oSection.pComment = a_pComment; } typename TSection::value_type oEntry(oSection, TKeyVal()); typedef typename TSection::iterator SectionIterator; std::pair i = m_data.insert(oEntry); iSection = i.first; bInserted = true; } if (!a_pKey || !a_pValue) { // section only entries are specified with pItem and pVal as NULL return bInserted ? SI_INSERTED : SI_UPDATED; } // check for existence of the key TKeyVal & keyval = iSection->second; typename TKeyVal::iterator iKey = keyval.find(a_pKey); bInserted = iKey == keyval.end(); // remove all existing entries but save the load order and // comment of the first entry int nLoadOrder = ++m_nOrder; if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) { const SI_CHAR * pComment = NULL; while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) { if (iKey->first.nOrder < nLoadOrder) { nLoadOrder = iKey->first.nOrder; pComment = iKey->first.pComment; } ++iKey; } if (pComment) { DeleteString(a_pComment); a_pComment = pComment; CopyString(a_pComment); } Delete(a_pSection, a_pKey); iKey = keyval.end(); } // make string copies if necessary bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace; if (a_bCopyStrings) { if (bForceCreateNewKey || iKey == keyval.end()) { // if the key doesn't exist then we need a copy as the // string needs to last beyond the end of this function // because we will be inserting the key next rc = CopyString(a_pKey); if (rc < 0) return rc; } // we always need a copy of the value rc = CopyString(a_pValue); if (rc < 0) return rc; } // create the key entry if (iKey == keyval.end() || bForceCreateNewKey) { Entry oKey(a_pKey, nLoadOrder); if (a_pComment) { oKey.pComment = a_pComment; } typename TKeyVal::value_type oEntry(oKey, static_cast(NULL)); iKey = keyval.insert(oEntry); } iKey->second = a_pValue; return bInserted ? SI_INSERTED : SI_UPDATED; } template const SI_CHAR * CSimpleIniTempl::GetValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, const SI_CHAR * a_pDefault, bool * a_pHasMultiple ) const { if (a_pHasMultiple) { *a_pHasMultiple = false; } if (!a_pSection || !a_pKey) { return a_pDefault; } typename TSection::const_iterator iSection = m_data.find(a_pSection); if (iSection == m_data.end()) { return a_pDefault; } typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); if (iKeyVal == iSection->second.end()) { return a_pDefault; } // check for multiple entries with the same key if (m_bAllowMultiKey && a_pHasMultiple) { typename TKeyVal::const_iterator iTemp = iKeyVal; if (++iTemp != iSection->second.end()) { if (!IsLess(a_pKey, iTemp->first.pItem)) { *a_pHasMultiple = true; } } } return iKeyVal->second; } template long CSimpleIniTempl::GetLongValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, long a_nDefault, bool * a_pHasMultiple ) const { // return the default if we don't have a value const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); if (!pszValue || !*pszValue) return a_nDefault; // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII char szValue[64] = { 0 }; SI_CONVERTER c(m_bStoreIsUtf8); if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { return a_nDefault; } // handle the value as hex if prefaced with "0x" long nValue = a_nDefault; char * pszSuffix = szValue; if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) { if (!szValue[2]) return a_nDefault; nValue = strtol(&szValue[2], &pszSuffix, 16); } else { nValue = strtol(szValue, &pszSuffix, 10); } // any invalid strings will return the default value if (*pszSuffix) { return a_nDefault; } return nValue; } template SI_Error CSimpleIniTempl::SetLongValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, long a_nValue, const SI_CHAR * a_pComment, bool a_bUseHex, bool a_bForceReplace ) { // use SetValue to create sections if (!a_pSection || !a_pKey) return SI_FAIL; // convert to an ASCII string char szInput[64]; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); #else // !__STDC_WANT_SECURE_LIB__ sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); #endif // __STDC_WANT_SECURE_LIB__ // convert to output text SI_CHAR szOutput[64]; SI_CONVERTER c(m_bStoreIsUtf8); c.ConvertFromStore(szInput, strlen(szInput) + 1, szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); // actually add it return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); } template double CSimpleIniTempl::GetDoubleValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, double a_nDefault, bool * a_pHasMultiple ) const { // return the default if we don't have a value const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); if (!pszValue || !*pszValue) return a_nDefault; // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII char szValue[64] = { 0 }; SI_CONVERTER c(m_bStoreIsUtf8); if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { return a_nDefault; } char * pszSuffix = NULL; double nValue = strtod(szValue, &pszSuffix); // any invalid strings will return the default value if (!pszSuffix || *pszSuffix) { return a_nDefault; } return nValue; } template SI_Error CSimpleIniTempl::SetDoubleValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, double a_nValue, const SI_CHAR * a_pComment, bool a_bForceReplace ) { // use SetValue to create sections if (!a_pSection || !a_pKey) return SI_FAIL; // convert to an ASCII string char szInput[64]; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE sprintf_s(szInput, "%f", a_nValue); #else // !__STDC_WANT_SECURE_LIB__ sprintf(szInput, "%f", a_nValue); #endif // __STDC_WANT_SECURE_LIB__ // convert to output text SI_CHAR szOutput[64]; SI_CONVERTER c(m_bStoreIsUtf8); c.ConvertFromStore(szInput, strlen(szInput) + 1, szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); // actually add it return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); } template bool CSimpleIniTempl::GetBoolValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, bool a_bDefault, bool * a_pHasMultiple ) const { // return the default if we don't have a value const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); if (!pszValue || !*pszValue) return a_bDefault; // we only look at the minimum number of characters switch (pszValue[0]) { case 't': case 'T': // true case 'y': case 'Y': // yes case '1': // 1 (one) return true; case 'f': case 'F': // false case 'n': case 'N': // no case '0': // 0 (zero) return false; case 'o': case 'O': if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off break; } // no recognized value, return the default return a_bDefault; } template SI_Error CSimpleIniTempl::SetBoolValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, bool a_bValue, const SI_CHAR * a_pComment, bool a_bForceReplace ) { // use SetValue to create sections if (!a_pSection || !a_pKey) return SI_FAIL; // convert to an ASCII string const char * pszInput = a_bValue ? "true" : "false"; // convert to output text SI_CHAR szOutput[64]; SI_CONVERTER c(m_bStoreIsUtf8); c.ConvertFromStore(pszInput, strlen(pszInput) + 1, szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); // actually add it return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); } template bool CSimpleIniTempl::GetAllValues( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, TNamesDepend & a_values ) const { a_values.clear(); if (!a_pSection || !a_pKey) { return false; } typename TSection::const_iterator iSection = m_data.find(a_pSection); if (iSection == m_data.end()) { return false; } typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); if (iKeyVal == iSection->second.end()) { return false; } // insert all values for this key a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); if (m_bAllowMultiKey) { ++iKeyVal; while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) { a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); ++iKeyVal; } } return true; } template int CSimpleIniTempl::GetSectionSize( const SI_CHAR * a_pSection ) const { if (!a_pSection) { return -1; } typename TSection::const_iterator iSection = m_data.find(a_pSection); if (iSection == m_data.end()) { return -1; } const TKeyVal & section = iSection->second; // if multi-key isn't permitted then the section size is // the number of keys that we have. if (!m_bAllowMultiKey || section.empty()) { return (int) section.size(); } // otherwise we need to count them int nCount = 0; const SI_CHAR * pLastKey = NULL; typename TKeyVal::const_iterator iKeyVal = section.begin(); for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) { if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { ++nCount; pLastKey = iKeyVal->first.pItem; } } return nCount; } template const typename CSimpleIniTempl::TKeyVal * CSimpleIniTempl::GetSection( const SI_CHAR * a_pSection ) const { if (a_pSection) { typename TSection::const_iterator i = m_data.find(a_pSection); if (i != m_data.end()) { return &(i->second); } } return 0; } template void CSimpleIniTempl::GetAllSections( TNamesDepend & a_names ) const { a_names.clear(); typename TSection::const_iterator i = m_data.begin(); for (int n = 0; i != m_data.end(); ++i, ++n ) { a_names.push_back(i->first); } } template bool CSimpleIniTempl::GetAllKeys( const SI_CHAR * a_pSection, TNamesDepend & a_names ) const { a_names.clear(); if (!a_pSection) { return false; } typename TSection::const_iterator iSection = m_data.find(a_pSection); if (iSection == m_data.end()) { return false; } const TKeyVal & section = iSection->second; const SI_CHAR * pLastKey = NULL; typename TKeyVal::const_iterator iKeyVal = section.begin(); for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) { if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { a_names.push_back(iKeyVal->first); pLastKey = iKeyVal->first.pItem; } } return true; } template SI_Error CSimpleIniTempl::SaveFile( const char * a_pszFile, bool a_bAddSignature ) const { FILE * fp = NULL; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE fopen_s(&fp, a_pszFile, "wb"); #else // !__STDC_WANT_SECURE_LIB__ fp = fopen(a_pszFile, "wb"); #endif // __STDC_WANT_SECURE_LIB__ if (!fp) return SI_FILE; SI_Error rc = SaveFile(fp, a_bAddSignature); fclose(fp); return rc; } #ifdef SI_HAS_WIDE_FILE template SI_Error CSimpleIniTempl::SaveFile( const SI_WCHAR_T * a_pwszFile, bool a_bAddSignature ) const { #ifdef _WIN32 FILE * fp = NULL; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE _wfopen_s(&fp, a_pwszFile, L"wb"); #else // !__STDC_WANT_SECURE_LIB__ fp = _wfopen(a_pwszFile, L"wb"); #endif // __STDC_WANT_SECURE_LIB__ if (!fp) return SI_FILE; SI_Error rc = SaveFile(fp, a_bAddSignature); fclose(fp); return rc; #else // !_WIN32 (therefore SI_CONVERT_ICU) char szFile[256]; u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); return SaveFile(szFile, a_bAddSignature); #endif // _WIN32 } #endif // SI_HAS_WIDE_FILE template SI_Error CSimpleIniTempl::SaveFile( FILE * a_pFile, bool a_bAddSignature ) const { FileWriter writer(a_pFile); return Save(writer, a_bAddSignature); } template SI_Error CSimpleIniTempl::Save( OutputWriter & a_oOutput, bool a_bAddSignature ) const { Converter convert(m_bStoreIsUtf8); // add the UTF-8 signature if it is desired if (m_bStoreIsUtf8 && a_bAddSignature) { a_oOutput.Write(SI_UTF8_SIGNATURE); } // get all of the sections sorted in load order TNamesDepend oSections; GetAllSections(oSections); #if defined(_MSC_VER) && _MSC_VER <= 1200 oSections.sort(); #elif defined(__BORLANDC__) oSections.sort(Entry::LoadOrder()); #else oSections.sort(typename Entry::LoadOrder()); #endif // if there is an empty section name, then it must be written out first // regardless of the load order typename TNamesDepend::iterator is = oSections.begin(); for (; is != oSections.end(); ++is) { if (!*is->pItem) { // move the empty section name to the front of the section list if (is != oSections.begin()) { oSections.splice(oSections.begin(), oSections, is, std::next(is)); } break; } } // write the file comment if we have one bool bNeedNewLine = false; if (m_pFileComment) { if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) { return SI_FAIL; } bNeedNewLine = true; } // iterate through our sections and output the data typename TNamesDepend::const_iterator iSection = oSections.begin(); for ( ; iSection != oSections.end(); ++iSection ) { // write out the comment if there is one if (iSection->pComment) { if (bNeedNewLine) { a_oOutput.Write(SI_NEWLINE_A); a_oOutput.Write(SI_NEWLINE_A); } if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) { return SI_FAIL; } bNeedNewLine = false; } if (bNeedNewLine) { a_oOutput.Write(SI_NEWLINE_A); a_oOutput.Write(SI_NEWLINE_A); bNeedNewLine = false; } // write the section (unless there is no section name) if (*iSection->pItem) { if (!convert.ConvertToStore(iSection->pItem)) { return SI_FAIL; } a_oOutput.Write("["); a_oOutput.Write(convert.Data()); a_oOutput.Write("]"); a_oOutput.Write(SI_NEWLINE_A); } // get all of the keys sorted in load order TNamesDepend oKeys; GetAllKeys(iSection->pItem, oKeys); #if defined(_MSC_VER) && _MSC_VER <= 1200 oKeys.sort(); #elif defined(__BORLANDC__) oKeys.sort(Entry::LoadOrder()); #else oKeys.sort(typename Entry::LoadOrder()); #endif // write all keys and values typename TNamesDepend::const_iterator iKey = oKeys.begin(); for ( ; iKey != oKeys.end(); ++iKey) { // get all values for this key TNamesDepend oValues; GetAllValues(iSection->pItem, iKey->pItem, oValues); typename TNamesDepend::const_iterator iValue = oValues.begin(); for ( ; iValue != oValues.end(); ++iValue) { // write out the comment if there is one if (iValue->pComment) { a_oOutput.Write(SI_NEWLINE_A); if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) { return SI_FAIL; } } // write the key if (!convert.ConvertToStore(iKey->pItem)) { return SI_FAIL; } a_oOutput.Write(convert.Data()); // write the value if (!convert.ConvertToStore(iValue->pItem)) { return SI_FAIL; } a_oOutput.Write(m_bSpaces ? " = " : "="); if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) { // multi-line data needs to be processed specially to ensure // that we use the correct newline format for the current system a_oOutput.Write("<<pItem)) { return SI_FAIL; } a_oOutput.Write("END_OF_TEXT"); } else { a_oOutput.Write(convert.Data()); } a_oOutput.Write(SI_NEWLINE_A); } } bNeedNewLine = true; } return SI_OK; } template bool CSimpleIniTempl::OutputMultiLineText( OutputWriter & a_oOutput, Converter & a_oConverter, const SI_CHAR * a_pText ) const { const SI_CHAR * pEndOfLine; SI_CHAR cEndOfLineChar = *a_pText; while (cEndOfLineChar) { // find the end of this line pEndOfLine = a_pText; for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ; cEndOfLineChar = *pEndOfLine; // temporarily null terminate, convert and output the line *const_cast(pEndOfLine) = 0; if (!a_oConverter.ConvertToStore(a_pText)) { return false; } *const_cast(pEndOfLine) = cEndOfLineChar; a_pText += (pEndOfLine - a_pText) + 1; a_oOutput.Write(a_oConverter.Data()); a_oOutput.Write(SI_NEWLINE_A); } return true; } template bool CSimpleIniTempl::Delete( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, bool a_bRemoveEmpty ) { return DeleteValue(a_pSection, a_pKey, NULL, a_bRemoveEmpty); } template bool CSimpleIniTempl::DeleteValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, const SI_CHAR * a_pValue, bool a_bRemoveEmpty ) { if (!a_pSection) { return false; } typename TSection::iterator iSection = m_data.find(a_pSection); if (iSection == m_data.end()) { return false; } // remove a single key if we have a keyname if (a_pKey) { typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey); if (iKeyVal == iSection->second.end()) { return false; } const static SI_STRLESS isLess = SI_STRLESS(); // remove any copied strings and then the key typename TKeyVal::iterator iDelete; bool bDeleted = false; do { iDelete = iKeyVal++; if(a_pValue == NULL || (isLess(a_pValue, iDelete->second) == false && isLess(iDelete->second, a_pValue) == false)) { DeleteString(iDelete->first.pItem); DeleteString(iDelete->second); iSection->second.erase(iDelete); bDeleted = true; } } while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)); if(!bDeleted) { return false; } // done now if the section is not empty or we are not pruning away // the empty sections. Otherwise let it fall through into the section // deletion code if (!a_bRemoveEmpty || !iSection->second.empty()) { return true; } } else { // delete all copied strings from this section. The actual // entries will be removed when the section is removed. typename TKeyVal::iterator iKeyVal = iSection->second.begin(); for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) { DeleteString(iKeyVal->first.pItem); DeleteString(iKeyVal->second); } } // delete the section itself DeleteString(iSection->first.pItem); m_data.erase(iSection); return true; } template void CSimpleIniTempl::DeleteString( const SI_CHAR * a_pString ) { // strings may exist either inside the data block, or they will be // individually allocated and stored in m_strings. We only physically // delete those stored in m_strings. if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) { typename TNamesDepend::iterator i = m_strings.begin(); for (;i != m_strings.end(); ++i) { if (a_pString == i->pItem) { delete[] const_cast(i->pItem); m_strings.erase(i); break; } } } } // --------------------------------------------------------------------------- // CONVERSION FUNCTIONS // --------------------------------------------------------------------------- // Defines the conversion classes for different libraries. Before including // SimpleIni.h, set the converter that you wish you use by defining one of the // following symbols. // // SI_NO_CONVERSION Do not make the "W" wide character version of the // library available. Only CSimpleIniA etc is defined. // SI_CONVERT_GENERIC Use the Unicode reference conversion library in // the accompanying files ConvertUTF.h/c // SI_CONVERT_ICU Use the IBM ICU conversion library. Requires // ICU headers on include path and icuuc.lib // SI_CONVERT_WIN32 Use the Win32 API functions for conversion. #if !defined(SI_NO_CONVERSION) && !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU) # ifdef _WIN32 # define SI_CONVERT_WIN32 # else # define SI_CONVERT_GENERIC # endif #endif /** * Generic case-sensitive less than comparison. This class returns numerically * ordered ASCII case-sensitive text for all possible sizes and types of * SI_CHAR. */ template struct SI_GenericCase { bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { long cmp; for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { cmp = (long) *pLeft - (long) *pRight; if (cmp != 0) { return cmp < 0; } } return *pRight != 0; } }; /** * Generic ASCII case-insensitive less than comparison. This class returns * numerically ordered ASCII case-insensitive text for all possible sizes * and types of SI_CHAR. It is not safe for MBCS text comparison where * ASCII A-Z characters are used in the encoding of multi-byte characters. */ template struct SI_GenericNoCase { inline SI_CHAR locase(SI_CHAR ch) const { return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a'); } bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { long cmp; for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { cmp = (long) locase(*pLeft) - (long) locase(*pRight); if (cmp != 0) { return cmp < 0; } } return *pRight != 0; } }; /** * Null conversion class for MBCS/UTF-8 to char (or equivalent). */ template class SI_ConvertA { bool m_bStoreIsUtf8; protected: SI_ConvertA() { } public: SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } /* copy and assignment */ SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); } SI_ConvertA & operator=(const SI_ConvertA & rhs) { m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; return *this; } /** Calculate the number of SI_CHAR required for converting the input * from the storage format. The storage format is always UTF-8 or MBCS. * * @param a_pInputData Data in storage format to be converted to SI_CHAR. * @param a_uInputDataLen Length of storage format data in bytes. This * must be the actual length of the data, including * NULL byte if NULL terminated string is required. * @return Number of SI_CHAR required by the string when * converted. If there are embedded NULL bytes in the * input data, only the string up and not including * the NULL byte will be converted. * @return -1 cast to size_t on a conversion error. */ size_t SizeFromStore( const char * a_pInputData, size_t a_uInputDataLen) { (void)a_pInputData; SI_ASSERT(a_uInputDataLen != (size_t) -1); // ASCII/MBCS/UTF-8 needs no conversion return a_uInputDataLen; } /** Convert the input string from the storage format to SI_CHAR. * The storage format is always UTF-8 or MBCS. * * @param a_pInputData Data in storage format to be converted to SI_CHAR. * @param a_uInputDataLen Length of storage format data in bytes. This * must be the actual length of the data, including * NULL byte if NULL terminated string is required. * @param a_pOutputData Pointer to the output buffer to received the * converted data. * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. * @return true if all of the input data was successfully * converted. */ bool ConvertFromStore( const char * a_pInputData, size_t a_uInputDataLen, SI_CHAR * a_pOutputData, size_t a_uOutputDataSize) { // ASCII/MBCS/UTF-8 needs no conversion if (a_uInputDataLen > a_uOutputDataSize) { return false; } memcpy(a_pOutputData, a_pInputData, a_uInputDataLen); return true; } /** Calculate the number of char required by the storage format of this * data. The storage format is always UTF-8 or MBCS. * * @param a_pInputData NULL terminated string to calculate the number of * bytes required to be converted to storage format. * @return Number of bytes required by the string when * converted to storage format. This size always * includes space for the terminating NULL character. * @return -1 cast to size_t on a conversion error. */ size_t SizeToStore( const SI_CHAR * a_pInputData) { // ASCII/MBCS/UTF-8 needs no conversion return strlen((const char *)a_pInputData) + 1; } /** Convert the input string to the storage format of this data. * The storage format is always UTF-8 or MBCS. * * @param a_pInputData NULL terminated source string to convert. All of * the data will be converted including the * terminating NULL character. * @param a_pOutputData Pointer to the buffer to receive the converted * string. * @param a_uOutputDataSize Size of the output buffer in char. * @return true if all of the input data, including the * terminating NULL character was successfully * converted. */ bool ConvertToStore( const SI_CHAR * a_pInputData, char * a_pOutputData, size_t a_uOutputDataSize) { // calc input string length (SI_CHAR type and size independent) size_t uInputLen = strlen((const char *)a_pInputData) + 1; if (uInputLen > a_uOutputDataSize) { return false; } // ascii/UTF-8 needs no conversion memcpy(a_pOutputData, a_pInputData, uInputLen); return true; } }; // --------------------------------------------------------------------------- // SI_CONVERT_GENERIC // --------------------------------------------------------------------------- #ifdef SI_CONVERT_GENERIC #define SI_Case SI_GenericCase #define SI_NoCase SI_GenericNoCase #include #include "ConvertUTF.h" /** * Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference * library functions. This can be used on all platforms. */ template class SI_ConvertW { bool m_bStoreIsUtf8; protected: SI_ConvertW() { } public: SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } /* copy and assignment */ SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } SI_ConvertW & operator=(const SI_ConvertW & rhs) { m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; return *this; } /** Calculate the number of SI_CHAR required for converting the input * from the storage format. The storage format is always UTF-8 or MBCS. * * @param a_pInputData Data in storage format to be converted to SI_CHAR. * @param a_uInputDataLen Length of storage format data in bytes. This * must be the actual length of the data, including * NULL byte if NULL terminated string is required. * @return Number of SI_CHAR required by the string when * converted. If there are embedded NULL bytes in the * input data, only the string up and not including * the NULL byte will be converted. * @return -1 cast to size_t on a conversion error. */ size_t SizeFromStore( const char * a_pInputData, size_t a_uInputDataLen) { SI_ASSERT(a_uInputDataLen != (size_t) -1); if (m_bStoreIsUtf8) { // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t // so we just return the same number of characters required as for // the source text. return a_uInputDataLen; } #if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux)) // fall back processing for platforms that don't support a NULL dest to mbstowcs // worst case scenario is 1:1, this will be a sufficient buffer size (void)a_pInputData; return a_uInputDataLen; #else // get the actual required buffer size return mbstowcs(NULL, a_pInputData, a_uInputDataLen); #endif } /** Convert the input string from the storage format to SI_CHAR. * The storage format is always UTF-8 or MBCS. * * @param a_pInputData Data in storage format to be converted to SI_CHAR. * @param a_uInputDataLen Length of storage format data in bytes. This * must be the actual length of the data, including * NULL byte if NULL terminated string is required. * @param a_pOutputData Pointer to the output buffer to received the * converted data. * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. * @return true if all of the input data was successfully * converted. */ bool ConvertFromStore( const char * a_pInputData, size_t a_uInputDataLen, SI_CHAR * a_pOutputData, size_t a_uOutputDataSize) { if (m_bStoreIsUtf8) { // This uses the Unicode reference implementation to do the // conversion from UTF-8 to wchar_t. The required files are // ConvertUTF.h and ConvertUTF.c which should be included in // the distribution but are publically available from unicode.org // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ ConversionResult retval; const UTF8 * pUtf8 = (const UTF8 *) a_pInputData; if (sizeof(wchar_t) == sizeof(UTF32)) { UTF32 * pUtf32 = (UTF32 *) a_pOutputData; retval = ConvertUTF8toUTF32( &pUtf8, pUtf8 + a_uInputDataLen, &pUtf32, pUtf32 + a_uOutputDataSize, lenientConversion); } else if (sizeof(wchar_t) == sizeof(UTF16)) { UTF16 * pUtf16 = (UTF16 *) a_pOutputData; retval = ConvertUTF8toUTF16( &pUtf8, pUtf8 + a_uInputDataLen, &pUtf16, pUtf16 + a_uOutputDataSize, lenientConversion); } return retval == conversionOK; } // convert to wchar_t size_t retval = mbstowcs(a_pOutputData, a_pInputData, a_uOutputDataSize); return retval != (size_t)(-1); } /** Calculate the number of char required by the storage format of this * data. The storage format is always UTF-8 or MBCS. * * @param a_pInputData NULL terminated string to calculate the number of * bytes required to be converted to storage format. * @return Number of bytes required by the string when * converted to storage format. This size always * includes space for the terminating NULL character. * @return -1 cast to size_t on a conversion error. */ size_t SizeToStore( const SI_CHAR * a_pInputData) { if (m_bStoreIsUtf8) { // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char size_t uLen = 0; while (a_pInputData[uLen]) { ++uLen; } return (6 * uLen) + 1; } else { size_t uLen = wcstombs(NULL, a_pInputData, 0); if (uLen == (size_t)(-1)) { return uLen; } return uLen + 1; // include NULL terminator } } /** Convert the input string to the storage format of this data. * The storage format is always UTF-8 or MBCS. * * @param a_pInputData NULL terminated source string to convert. All of * the data will be converted including the * terminating NULL character. * @param a_pOutputData Pointer to the buffer to receive the converted * string. * @param a_uOutputDataSize Size of the output buffer in char. * @return true if all of the input data, including the * terminating NULL character was successfully * converted. */ bool ConvertToStore( const SI_CHAR * a_pInputData, char * a_pOutputData, size_t a_uOutputDataSize ) { if (m_bStoreIsUtf8) { // calc input string length (SI_CHAR type and size independent) size_t uInputLen = 0; while (a_pInputData[uInputLen]) { ++uInputLen; } ++uInputLen; // include the NULL char // This uses the Unicode reference implementation to do the // conversion from wchar_t to UTF-8. The required files are // ConvertUTF.h and ConvertUTF.c which should be included in // the distribution but are publically available from unicode.org // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ ConversionResult retval; UTF8 * pUtf8 = (UTF8 *) a_pOutputData; if (sizeof(wchar_t) == sizeof(UTF32)) { const UTF32 * pUtf32 = (const UTF32 *) a_pInputData; retval = ConvertUTF32toUTF8( &pUtf32, pUtf32 + uInputLen, &pUtf8, pUtf8 + a_uOutputDataSize, lenientConversion); } else if (sizeof(wchar_t) == sizeof(UTF16)) { const UTF16 * pUtf16 = (const UTF16 *) a_pInputData; retval = ConvertUTF16toUTF8( &pUtf16, pUtf16 + uInputLen, &pUtf8, pUtf8 + a_uOutputDataSize, lenientConversion); } return retval == conversionOK; } else { size_t retval = wcstombs(a_pOutputData, a_pInputData, a_uOutputDataSize); return retval != (size_t) -1; } } }; #endif // SI_CONVERT_GENERIC // --------------------------------------------------------------------------- // SI_CONVERT_ICU // --------------------------------------------------------------------------- #ifdef SI_CONVERT_ICU #define SI_Case SI_GenericCase #define SI_NoCase SI_GenericNoCase #include /** * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms. */ template class SI_ConvertW { const char * m_pEncoding; UConverter * m_pConverter; protected: SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { } public: SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) { m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL; } /* copy and assignment */ SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } SI_ConvertW & operator=(const SI_ConvertW & rhs) { m_pEncoding = rhs.m_pEncoding; m_pConverter = NULL; return *this; } ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); } /** Calculate the number of UChar required for converting the input * from the storage format. The storage format is always UTF-8 or MBCS. * * @param a_pInputData Data in storage format to be converted to UChar. * @param a_uInputDataLen Length of storage format data in bytes. This * must be the actual length of the data, including * NULL byte if NULL terminated string is required. * @return Number of UChar required by the string when * converted. If there are embedded NULL bytes in the * input data, only the string up and not including * the NULL byte will be converted. * @return -1 cast to size_t on a conversion error. */ size_t SizeFromStore( const char * a_pInputData, size_t a_uInputDataLen) { SI_ASSERT(a_uInputDataLen != (size_t) -1); UErrorCode nError; if (!m_pConverter) { nError = U_ZERO_ERROR; m_pConverter = ucnv_open(m_pEncoding, &nError); if (U_FAILURE(nError)) { return (size_t) -1; } } nError = U_ZERO_ERROR; int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, a_pInputData, (int32_t) a_uInputDataLen, &nError); if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { return (size_t) -1; } return (size_t) nLen; } /** Convert the input string from the storage format to UChar. * The storage format is always UTF-8 or MBCS. * * @param a_pInputData Data in storage format to be converted to UChar. * @param a_uInputDataLen Length of storage format data in bytes. This * must be the actual length of the data, including * NULL byte if NULL terminated string is required. * @param a_pOutputData Pointer to the output buffer to received the * converted data. * @param a_uOutputDataSize Size of the output buffer in UChar. * @return true if all of the input data was successfully * converted. */ bool ConvertFromStore( const char * a_pInputData, size_t a_uInputDataLen, UChar * a_pOutputData, size_t a_uOutputDataSize) { UErrorCode nError; if (!m_pConverter) { nError = U_ZERO_ERROR; m_pConverter = ucnv_open(m_pEncoding, &nError); if (U_FAILURE(nError)) { return false; } } nError = U_ZERO_ERROR; ucnv_toUChars(m_pConverter, a_pOutputData, (int32_t) a_uOutputDataSize, a_pInputData, (int32_t) a_uInputDataLen, &nError); if (U_FAILURE(nError)) { return false; } return true; } /** Calculate the number of char required by the storage format of this * data. The storage format is always UTF-8 or MBCS. * * @param a_pInputData NULL terminated string to calculate the number of * bytes required to be converted to storage format. * @return Number of bytes required by the string when * converted to storage format. This size always * includes space for the terminating NULL character. * @return -1 cast to size_t on a conversion error. */ size_t SizeToStore( const UChar * a_pInputData) { UErrorCode nError; if (!m_pConverter) { nError = U_ZERO_ERROR; m_pConverter = ucnv_open(m_pEncoding, &nError); if (U_FAILURE(nError)) { return (size_t) -1; } } nError = U_ZERO_ERROR; int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0, a_pInputData, -1, &nError); if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { return (size_t) -1; } return (size_t) nLen + 1; } /** Convert the input string to the storage format of this data. * The storage format is always UTF-8 or MBCS. * * @param a_pInputData NULL terminated source string to convert. All of * the data will be converted including the * terminating NULL character. * @param a_pOutputData Pointer to the buffer to receive the converted * string. * @param a_pOutputDataSize Size of the output buffer in char. * @return true if all of the input data, including the * terminating NULL character was successfully * converted. */ bool ConvertToStore( const UChar * a_pInputData, char * a_pOutputData, size_t a_uOutputDataSize) { UErrorCode nError; if (!m_pConverter) { nError = U_ZERO_ERROR; m_pConverter = ucnv_open(m_pEncoding, &nError); if (U_FAILURE(nError)) { return false; } } nError = U_ZERO_ERROR; ucnv_fromUChars(m_pConverter, a_pOutputData, (int32_t) a_uOutputDataSize, a_pInputData, -1, &nError); if (U_FAILURE(nError)) { return false; } return true; } }; #endif // SI_CONVERT_ICU // --------------------------------------------------------------------------- // SI_CONVERT_WIN32 // --------------------------------------------------------------------------- #ifdef SI_CONVERT_WIN32 #define SI_Case SI_GenericCase // Windows CE doesn't have errno or MBCS libraries #ifdef _WIN32_WCE # ifndef SI_NO_MBCS # define SI_NO_MBCS # endif #endif #include #ifdef SI_NO_MBCS # define SI_NoCase SI_GenericNoCase #else // !SI_NO_MBCS /** * Case-insensitive comparison class using Win32 MBCS functions. This class * returns a case-insensitive semi-collation order for MBCS text. It may not * be safe for UTF-8 text returned in char format as we don't know what * characters will be folded by the function! Therefore, if you are using * SI_CHAR == char and SetUnicode(true), then you need to use the generic * SI_NoCase class instead. */ #include template struct SI_NoCase { bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { if (sizeof(SI_CHAR) == sizeof(char)) { return _mbsicmp((const unsigned char *)pLeft, (const unsigned char *)pRight) < 0; } if (sizeof(SI_CHAR) == sizeof(wchar_t)) { return _wcsicmp((const wchar_t *)pLeft, (const wchar_t *)pRight) < 0; } return SI_GenericNoCase()(pLeft, pRight); } }; #endif // SI_NO_MBCS /** * Converts MBCS and UTF-8 to a wchar_t (or equivalent) on Windows. This uses * only the Win32 functions and doesn't require the external Unicode UTF-8 * conversion library. It will not work on Windows 95 without using Microsoft * Layer for Unicode in your application. */ template class SI_ConvertW { UINT m_uCodePage; protected: SI_ConvertW() { } public: SI_ConvertW(bool a_bStoreIsUtf8) { m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP; } /* copy and assignment */ SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } SI_ConvertW & operator=(const SI_ConvertW & rhs) { m_uCodePage = rhs.m_uCodePage; return *this; } /** Calculate the number of SI_CHAR required for converting the input * from the storage format. The storage format is always UTF-8 or MBCS. * * @param a_pInputData Data in storage format to be converted to SI_CHAR. * @param a_uInputDataLen Length of storage format data in bytes. This * must be the actual length of the data, including * NULL byte if NULL terminated string is required. * @return Number of SI_CHAR required by the string when * converted. If there are embedded NULL bytes in the * input data, only the string up and not including * the NULL byte will be converted. * @return -1 cast to size_t on a conversion error. */ size_t SizeFromStore( const char * a_pInputData, size_t a_uInputDataLen) { SI_ASSERT(a_uInputDataLen != (size_t) -1); int retval = MultiByteToWideChar( m_uCodePage, 0, a_pInputData, (int) a_uInputDataLen, 0, 0); return (size_t)(retval > 0 ? retval : -1); } /** Convert the input string from the storage format to SI_CHAR. * The storage format is always UTF-8 or MBCS. * * @param a_pInputData Data in storage format to be converted to SI_CHAR. * @param a_uInputDataLen Length of storage format data in bytes. This * must be the actual length of the data, including * NULL byte if NULL terminated string is required. * @param a_pOutputData Pointer to the output buffer to received the * converted data. * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. * @return true if all of the input data was successfully * converted. */ bool ConvertFromStore( const char * a_pInputData, size_t a_uInputDataLen, SI_CHAR * a_pOutputData, size_t a_uOutputDataSize) { int nSize = MultiByteToWideChar( m_uCodePage, 0, a_pInputData, (int) a_uInputDataLen, (wchar_t *) a_pOutputData, (int) a_uOutputDataSize); return (nSize > 0); } /** Calculate the number of char required by the storage format of this * data. The storage format is always UTF-8. * * @param a_pInputData NULL terminated string to calculate the number of * bytes required to be converted to storage format. * @return Number of bytes required by the string when * converted to storage format. This size always * includes space for the terminating NULL character. * @return -1 cast to size_t on a conversion error. */ size_t SizeToStore( const SI_CHAR * a_pInputData) { int retval = WideCharToMultiByte( m_uCodePage, 0, (const wchar_t *) a_pInputData, -1, 0, 0, 0, 0); return (size_t) (retval > 0 ? retval : -1); } /** Convert the input string to the storage format of this data. * The storage format is always UTF-8 or MBCS. * * @param a_pInputData NULL terminated source string to convert. All of * the data will be converted including the * terminating NULL character. * @param a_pOutputData Pointer to the buffer to receive the converted * string. * @param a_pOutputDataSize Size of the output buffer in char. * @return true if all of the input data, including the * terminating NULL character was successfully * converted. */ bool ConvertToStore( const SI_CHAR * a_pInputData, char * a_pOutputData, size_t a_uOutputDataSize) { int retval = WideCharToMultiByte( m_uCodePage, 0, (const wchar_t *) a_pInputData, -1, a_pOutputData, (int) a_uOutputDataSize, 0, 0); return retval > 0; } }; #endif // SI_CONVERT_WIN32 // --------------------------------------------------------------------------- // TYPE DEFINITIONS // --------------------------------------------------------------------------- typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniA; typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniCaseA; #if defined(SI_NO_CONVERSION) // if there is no wide char conversion then we don't need to define the // widechar "W" versions of CSimpleIni # define CSimpleIni CSimpleIniA # define CSimpleIniCase CSimpleIniCaseA # define SI_NEWLINE SI_NEWLINE_A #else # if defined(SI_CONVERT_ICU) typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; # else typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; # endif # ifdef _UNICODE # define CSimpleIni CSimpleIniW # define CSimpleIniCase CSimpleIniCaseW # define SI_NEWLINE SI_NEWLINE_W # else // !_UNICODE # define CSimpleIni CSimpleIniA # define CSimpleIniCase CSimpleIniCaseA # define SI_NEWLINE SI_NEWLINE_A # endif // _UNICODE #endif #ifdef _MSC_VER # pragma warning (pop) #endif #endif // INCLUDED_SimpleIni_h ================================================ FILE: source-code/dependencies/simpleini/other/package.cmd ================================================ set VERSION=4.15 set SEVENZIP="C:\Program Files\7-Zip\7z.exe" FOR /F "tokens=*" %%G IN ('DIR /AD /B /S Debug*') DO ( DEL /S /Q "%%G" RD "%%G" ) FOR /F "tokens=*" %%G IN ('DIR /AD /B /S Release*') DO ( DEL /S /Q "%%G" RD "%%G" ) DEL /Q "SimpleIni.ncb" ATTRIB -H "SimpleIni.suo" DEL /Q "SimpleIni.suo" DEL /Q "SimpleIni.opt" DEL /Q testsi-out*.ini DEL /Q test1-blah.ini DEL /Q test1-output.ini START "Generate documentation" /WAIT "C:\Program Files (x86)\doxygen\bin\doxygen.exe" SimpleIni.doxy cd .. del simpleini-%VERSION%.zip %SEVENZIP% a -tzip -r- -x!simpleini\.svn simpleini-%VERSION%.zip simpleini\* del simpleini-doc.zip %SEVENZIP% a -tzip -r simpleini-doc.zip simpleini-doc\* cd simpleini ================================================ FILE: source-code/dependencies/simpleini/other/simpleini.doxy ================================================ # Doxyfile 1.5.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = SimpleIni # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = D:/src/simpleini-doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class " \ "The $name widget " \ "The $name file " \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = "D:/src/simpleini/ " # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct (or union) is # documented as struct with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code where the coding convention is that all structs are # typedef'ed and only the typedef is referenced never the struct's name. TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be extracted # and appear in the documentation as a namespace called 'anonymous_namespace{file}', # where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file($line) : $text " # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = D:/src/simpleini/SimpleIni.h # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH # then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = SI_HAS_WIDE_FILE \ SI_SUPPORT_IOSTREAMS # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the number # of direct children of the root node in a graph is already larger than # MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 1000 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO ================================================ FILE: source-code/dependencies/simpleini/vcproj/SimpleIni.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30204.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Library Files", "Library Files", "{C1F8A145-78E7-42C6-95D5-23C746C2BC56}" ProjectSection(SolutionItems) = preProject ..\ConvertUTF.c = ..\ConvertUTF.c ..\ConvertUTF.h = ..\ConvertUTF.h ..\SimpleIni.h = ..\SimpleIni.h EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Information Files", "Information Files", "{E40DD170-6D17-49D2-9BB2-8546658F0A37}" ProjectSection(SolutionItems) = preProject ..\LICENCE.txt = ..\LICENCE.txt ..\README.md = ..\README.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Other Files", "Other Files", "{560B512C-6D1C-4E65-83C1-049110E5DEF6}" ProjectSection(SolutionItems) = preProject ..\other\.travis.yml = ..\other\.travis.yml ..\other\Makefile = ..\other\Makefile ..\other\package.cmd = ..\other\package.cmd ..\other\simpleini.doxy = ..\other\simpleini.doxy EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "..\tests\tests.vcxproj", "{8F30A5DC-B942-4C9A-BA75-91C906FF85FA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {8F30A5DC-B942-4C9A-BA75-91C906FF85FA}.Debug|x64.ActiveCfg = Debug|x64 {8F30A5DC-B942-4C9A-BA75-91C906FF85FA}.Debug|x64.Build.0 = Debug|x64 {8F30A5DC-B942-4C9A-BA75-91C906FF85FA}.Debug|x86.ActiveCfg = Debug|Win32 {8F30A5DC-B942-4C9A-BA75-91C906FF85FA}.Debug|x86.Build.0 = Debug|Win32 {8F30A5DC-B942-4C9A-BA75-91C906FF85FA}.Release|x64.ActiveCfg = Release|x64 {8F30A5DC-B942-4C9A-BA75-91C906FF85FA}.Release|x64.Build.0 = Release|x64 {8F30A5DC-B942-4C9A-BA75-91C906FF85FA}.Release|x86.ActiveCfg = Release|Win32 {8F30A5DC-B942-4C9A-BA75-91C906FF85FA}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {ABD2CECE-EA8B-455B-8AE7-00E499634EC2} EndGlobalSection EndGlobal ================================================ FILE: source-code/dependencies/simpleini/vcproj/SimpleIni.vcxproj ================================================ Debug Win32 Release Win32 Debug x64 Release x64 16.0 Win32Proj {9a59fc4f-ad32-4bd3-b6b5-9bb0ddc6138d} SimpleIni 10.0 Application true v142 Unicode Application false v142 true Unicode Application true v142 Unicode Application false v142 true Unicode true false true false Level3 true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true Level3 true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level3 true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true ================================================ FILE: source-code/dependencies/simpleini/vcproj/SimpleIni.vcxproj.filters ================================================  {353054bc-f2a3-46d2-a9cb-df767fe52289} Tests Tests ================================================ FILE: source-code/dependencies/xdelta3/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ================================================ FILE: source-code/dependencies/xdelta3/Makefile.am ================================================ ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = xdelta3 noinst_PROGRAMS = xdelta3regtest xdelta3decode xdelta3checksum export AFL_HARDEN common_SOURCES = \ xdelta3-blkcache.h \ xdelta3-decode.h \ xdelta3-djw.h \ xdelta3-fgk.h \ xdelta3-hash.h \ xdelta3-internal.h \ xdelta3-list.h \ xdelta3-lzma.h \ xdelta3-main.h \ xdelta3-merge.h \ xdelta3-second.h \ xdelta3-test.h \ xdelta3-cfgs.h \ xdelta3.h xdelta3_SOURCES = $(common_SOURCES) xdelta3.c xdelta3decode_SOURCES = $(common_SOURCES) xdelta3.c xdelta3regtest_SOURCES = $(common_SOURCES) \ testing/cmp.h \ testing/delta.h \ testing/file.h \ testing/modify.h \ testing/random.h \ testing/regtest.cc \ testing/regtest_c.c \ testing/segment.h \ testing/sizes.h \ testing/test.h xdelta3checksum_SOURCES = $(common_SOURCES) \ testing/checksum_test.cc \ testing/checksum_test_c.c # These sources constitute a regression test written in Go, that is # not automatically built or run. Install Go-1.5.x or later, add # `pwd`/go in $GOPATH, and (cd go/src && go run regtest.go). # TODO(jmacd): replace hard-coded path names in regtest.go w/ flags. GOLANG_SRCS = \ go/src/xdelta/test.go \ go/src/xdelta/rstream.go \ go/src/xdelta/tgroup.go \ go/src/xdelta/run.go \ go/src/regtest.go # Note: for extra sanity checks, enable -Wconversion. Note there # are a lot of false positives. WFLAGS = -Wall -Wshadow -fno-builtin -Wextra -Wsign-compare \ -Wformat=2 -Wno-format-nonliteral \ -Wno-unused-parameter -Wno-unused-function # -Weverything \ # -Wc++11-compat-reserved-user-defined-literal \ # -Wno-padded \ # -Wno-format-nonliteral \ # -Wno-cast-align \ # -Wno-unused-parameter \ # -Wno-sign-conversion \ # -Wno-conversion \ # -Wno-switch-enum \ # -Wno-covered-switch-default \ # -Wno-disabled-macro-expansion \ # -Wno-variadic-macros \ # -Wno-c++98-compat-pedantic C_WFLAGS = $(WFLAGS) -std=c99 CXX_WFLAGS = $(WFLAGS) -std=c++11 common_CFLAGS = \ -DREGRESSION_TEST=1 \ -DSECONDARY_DJW=1 \ -DSECONDARY_FGK=1 \ -DXD3_MAIN=1 if DEBUG_SYMBOLS common_CFLAGS += -g endif #common_CFLAGS += -fsanitize=address -fno-omit-frame-pointer #common_CFLAGS += -O2 # For additional debugging, add -DXD3_DEBUG=1, 2, 3, ... xdelta3_CFLAGS = $(C_WFLAGS) $(common_CFLAGS) -DXD3_DEBUG=0 xdelta3_LDADD = -lm xdelta3decode_CFLAGS = \ $(C_WFLAGS) \ -DREGRESSION_TEST=0 \ -DSECONDARY_DJW=0 \ -DSECONDARY_FGK=0 \ -DSECONDARY_LZMA=0 \ -DXD3_MAIN=1 \ -DXD3_ENCODER=0 \ -DXD3_STDIO=1 \ -DEXTERNAL_COMPRESSION=0 \ -DVCDIFF_TOOLS=0 xdelta3regtest_CXXFLAGS = \ $(CXX_WFLAGS) $(common_CFLAGS) -DNOT_MAIN=1 -DXD3_DEBUG=1 xdelta3regtest_CFLAGS = \ $(C_WFLAGS) $(common_CFLAGS) -DNOT_MAIN=1 -DXD3_DEBUG=1 xdelta3regtest_LDADD = -lm xdelta3checksum_CXXFLAGS = \ $(CXX_WFLAGS) $(common_CFLAGS) -DNOT_MAIN=1 -DXD3_MAIN=1 -std=c++11 xdelta3checksum_CFLAGS = \ $(C_WFLAGS) $(common_CFLAGS) -DNOT_MAIN=1 -DXD3_MAIN=1 man1_MANS = xdelta3.1 EXTRA_DIST = \ README.md \ run_release.sh \ draft-korn-vcdiff.txt \ $(GOLANG_SRCS) \ examples/Makefile \ examples/README.md \ examples/compare_test.c \ examples/encode_decode_test.c \ examples/small_page_test.c \ examples/speed_test.c \ examples/test.h \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test.xcodeproj/project.pbxproj \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSAppDelegate.h \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSAppDelegate.m \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSViewController.h \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSViewController.m \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/InfoPlist.strings \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/MainStoryboard_iPad.storyboard \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/MainStoryboard_iPhone.storyboard \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/file_v1.bin \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/file_v1_to_v2.bin \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/file_v2.bin \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/main.m \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/xdelta3-ios-test-Info.plist \ examples/iOS/xdelta3-ios-test/xdelta3-ios-test/xdelta3-ios-test-Prefix.pch \ cpp-btree/CMakeLists.txt \ cpp-btree/COPYING \ cpp-btree/README \ cpp-btree/btree.h \ cpp-btree/btree_bench.cc \ cpp-btree/btree_container.h \ cpp-btree/btree_map.h \ cpp-btree/btree_set.h \ cpp-btree/btree_test.cc \ cpp-btree/btree_test.h \ cpp-btree/btree_test_flags.cc \ cpp-btree/safe_btree.h \ cpp-btree/safe_btree_map.h \ cpp-btree/safe_btree_set.h \ cpp-btree/safe_btree_test.cc \ testing/xdelta3-regtest.py \ testing/xdelta3-test.py \ xdelta3.1 \ xdelta3.i \ xdelta3.vcxproj \ xdelta3.wxi \ xdelta3.wxs # Broken, removed from distribution: # xdelta3_pywrap.c # xdelta3.py #PYFILES = xdelta3_pywrap.c xdelta3.py #XDELTA3PY = xdelta3.py #XDELTA3PYLIB = xdelta3.la #BUILT_SOURCES = $(PYFILES) #xdelta3_pywrap.c xdelta3.py : xdelta3.i # $(SWIG) -python -o xdelta3_pywrap.c xdelta3.i # OS X for some reason requires: # pythondir = $(PYTHON_SITE_PKG) # pyexecdir = $(PYTHON_SITE_PKG) #python_PYTHON = $(XDELTA3PY) #pyexec_LTLIBRARIES = $(XDELTA3PYLIB) #_xdelta3_la_SOURCES = $(srcdir)/xdelta3_pywrap.c $(xdelta3_SOURCES) #_xdelta3_la_CFLAGS = $(common_CFLAGS) -DNOT_MAIN=1 $(PYTHON_CPPFLAGS) #_xdelta3_la_LDFLAGS = -module ================================================ FILE: source-code/dependencies/xdelta3/README.md ================================================ Xdelta 3.x readme.txt Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Thanks for downloading Xdelta! This directory contains the Xdelta3 command-line interface (CLI) and source distribution for VCDIFF differential compression, a.k.a. delta compression. The latest information and downloads are available here: http://xdelta.org/ http://github.com/jmacd/xdelta/ Xdelta can be configured to use XZ Utils for secondary compression: http://tukaani.org/xz/ The command-line syntax is detailed here: https://github.com/jmacd/xdelta/blob/wiki/CommandLineSyntax.md Run 'xdelta3 -h' for brief help. Run 'xdelta3 test' for built-in tests. Sample commands (like gzip, -e means encode, -d means decode) xdelta3 -9 -S lzma -e -f -s OLD_FILE NEW_FILE DELTA_FILE xdelta3 -d -s OLD_FILE DELTA_FILE DECODED_FILE File bug reports and browse open support issues here: https://github.com/jmacd/xdelta/issues The source distribution contains the C/C++/Python APIs, Unix, Microsoft VC++ and Cygwin builds. Xdelta3 is covered under the terms of the APL, see LICENSE. ================================================ FILE: source-code/dependencies/xdelta3/badcopy.c ================================================ #include #include #include #define BUFSZ (1 << 22) #ifdef WIN32 // whatever static double drand48() { double r = rand() / (double)RAND_MAX; return r; } long lrand48() { long l = 0; int i; for (i = 0; i < 32; i++) { l = l ^ (l << 2) ^ (l << 1) ^ rand(); } return l; } #endif #ifdef _WIN32 #define XD3_WIN32 1 #else #define XD3_POSIX 1 #endif #define XD3_MAIN 1 #define main notmain #define EXTERNAL_COMPRESSION 0 #define XD3_USE_LARGEFILE64 1 #include "xdelta3.c" #undef main double error_prob = 0.0001; usize_t mean_change = 100; xoff_t total_change = 0; xoff_t total_size = 0; usize_t max_change = 0; usize_t num_change = 0; static usize_t edist (usize_t mean, usize_t max) { double mean_d = mean; double erand = log (1.0 / drand48 ()); usize_t x = (usize_t) (mean_d * erand + 0.5); return (x < max) ? (x > 0 ? x : 1) : max; } void modify (char *buf, usize_t size) { usize_t bufpos = 0, j; usize_t last_end = 0; for (;; /* bufpos and j are incremented in the inner loop */) { /* The size of the next modification. */ usize_t next_size = edist (mean_change, 1 << 31); /* The expected interval of such a change. */ double expect_interval = ((double) next_size * (1.0 - error_prob)) / error_prob; /* The number of bytes until the next modification. */ usize_t next_mod = edist ((usize_t)expect_interval, 1 << 31); if (next_size + next_mod + bufpos > size) { break; } if (max_change < next_size) { max_change = next_size; } bufpos += next_mod; fprintf (stderr, "COPY: %I64u-%I64u (%u)\n", total_size + (xoff_t)last_end, total_size + (xoff_t)bufpos, bufpos - last_end); fprintf (stderr, "ADD: %I64u-%I64u (%u) is change %u\n", total_size + (xoff_t)bufpos, total_size + (xoff_t)(bufpos + next_size), next_size, num_change); total_change += next_size; num_change += 1; for (j = 0; j < next_size; j += 1, bufpos += 1) { buf[bufpos] = (char)(lrand48 () >> 3); } last_end = bufpos; } fprintf (stderr, "COPY: %I64u-%I64u (%u)\n", total_size + last_end, total_size + size, size - last_end); total_size += size; } int main(int argc, char **argv) { main_file inp, out; char *buf = malloc(BUFSZ); int c, ret; main_file_init(&inp); main_file_init(&out); option_force = 1; if (argc > 5) { fprintf (stderr, "usage: badcopy [byte_error_prob [mean_error_size]]\n"); return 1; } if (argc > 4) { mean_change = atoi (argv[4]); } if (argc > 3) { error_prob = atof (argv[3]); } fprintf (stderr, "mean change = %u; error_prob = %0.10f\n", mean_change, error_prob); if ((ret = main_file_open (&inp, argv[1], XO_READ)) != 0) { return 1; } if ((ret = main_file_open (&out, argv[2], XO_WRITE)) != 0) { return 1; } if (error_prob < 0.0 || error_prob > 1.0) { fprintf (stderr, "warning: error probability out of range\n"); return 1; } do { if ((ret = main_file_read (&inp, buf, BUFSZ, &c, "read failed")) != 0) { return 1; } if (c == 0) { break; } modify (buf, c); if ((ret = main_file_write (&out, buf, c, "write failed")) != 0) { return 1; } } while (c == BUFSZ); if ((ret = main_file_close (&out))) { return 1; } fprintf (stderr, "add_prob %f; %u adds; total_change %u of %u bytes; add percentage %f; max add size %u\n", error_prob, num_change, total_change, total_size, (double) total_change / (double) total_size, max_change); return 0; } ================================================ FILE: source-code/dependencies/xdelta3/configure.ac ================================================ AC_INIT([Xdelta3], [3.1.1], [josh.macdonald@gmail.com], [xdelta3], [http://xdelta.org/]) AC_PREREQ([2.68]) AC_CONFIG_MACRO_DIR([m4]) LT_INIT AM_INIT_AUTOMAKE([1.15 no-define foreign tar-ustar subdir-objects]) AC_CONFIG_MACRO_DIRS([m4]) AX_CHECK_ALIGNED_ACCESS_REQUIRED AC_PROG_CC AC_PROG_CXX AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(unsigned int) AC_CHECK_SIZEOF(unsigned long) AC_CHECK_SIZEOF(unsigned long long) AC_ARG_WITH( [liblzma], [AC_HELP_STRING( [--with-liblzma], [build with liblzma support @<:@default=autodetect@:>@])], [USE_LIBLZMA=$withval], [USE_LIBLZMA=auto]) if test "x$USE_LIBLZMA" != xno ; then AC_CHECK_HEADERS([lzma.h],,[ if test "x$with_liblzma" = xyes ; then AC_MSG_FAILURE([liblzma includes were not found]) fi]) AC_CHECK_LIB([lzma], [lzma_easy_buffer_encode],,[ if test "x$with_liblzma" = xyes ; then AC_MSG_FAILURE([liblzma library were not found]) fi]) fi #AM_PATH_PYTHON(,, [:]) #AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :]) #AX_PYTHON_DEVEL() #AX_PKG_SWIG(2.0.0,,) #AX_SWIG_PYTHON dnl --enable-debug-symbols : build with debug symbols? AC_ARG_ENABLE(debug-symbols, AS_HELP_STRING(--enable-debug-symbols,[Build with debug symbols (default is NO)]),,enableval=no) AM_CONDITIONAL([DEBUG_SYMBOLS], [test ${enableval} = "yes"]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/CMakeLists.txt ================================================ # Copyright 2013 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. cmake_minimum_required(VERSION 2.6) project(cppbtree CXX) option(build_tests "Build B-tree tests" OFF) add_definitions(-std=c++11) set(CMAKE_CXX_FLAGS "-g -O2") # CMake doesn't have a way to pure template library, # add_library(cppbtree btree.h btree_map.h btree_set.h # safe_btree.h safe_btree_map.h safe_btree_set.h) # set_target_properties(cppbtree PROPERTIES LINKER_LANGUAGE CXX) if(build_tests) enable_testing() include_directories($ENV{GTEST_ROOT}/include) link_directories($ENV{GTEST_ROOT}) include_directories($ENV{GFLAGS_ROOT}/include) link_directories($ENV{GFLAGS_ROOT}/lib) add_executable(btree_test btree_test.cc btree_test_flags.cc) add_executable(safe_btree_test safe_btree_test.cc btree_test_flags.cc) add_executable(btree_bench btree_bench.cc btree_test_flags.cc) target_link_libraries(btree_test gtest_main gtest gflags) target_link_libraries(safe_btree_test gtest_main gtest gflags) target_link_libraries(btree_bench gflags gtest) endif() ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/COPYING ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/README ================================================ This library is a C++ template library and, as such, there is no library to build and install. Copy the .h files and use them! See http://code.google.com/p/cpp-btree/wiki/UsageInstructions for details. ---- To build and run the provided tests, however, you will need to install CMake, the Google C++ Test framework, and the Google flags package. Download and install CMake from http://www.cmake.org Download and build the GoogleTest framework from http://code.google.com/p/googletest Download and install gflags from https://code.google.com/p/gflags Set GTEST_ROOT to the directory where GTEST was built. Set GFLAGS_ROOT to the directory prefix where GFLAGS is installed. export GTEST_ROOT=/path/for/gtest-x.y export GFLAGS_ROOT=/opt cmake . -Dbuild_tests=ON For example, to build on a Unix system with the clang++ compiler, export GTEST_ROOT=$(HOME)/src/googletest export GFLAGS_ROOT=/opt cmake . -G "Unix Makefiles" -Dbuild_tests=ON -DCMAKE_CXX_COMPILER=clang++ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/btree.h ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // A btree implementation of the STL set and map interfaces. A btree is both // smaller and faster than STL set/map. The red-black tree implementation of // STL set/map has an overhead of 3 pointers (left, right and parent) plus the // node color information for each stored value. So a set consumes 20 // bytes for each value stored. This btree implementation stores multiple // values on fixed size nodes (usually 256 bytes) and doesn't store child // pointers for leaf nodes. The result is that a btree_set may use much // less memory per stored value. For the random insertion benchmark in // btree_test.cc, a btree_set with node-size of 256 uses 4.9 bytes per // stored value. // // The packing of multiple values on to each node of a btree has another effect // besides better space utilization: better cache locality due to fewer cache // lines being accessed. Better cache locality translates into faster // operations. // // CAVEATS // // Insertions and deletions on a btree can cause splitting, merging or // rebalancing of btree nodes. And even without these operations, insertions // and deletions on a btree will move values around within a node. In both // cases, the result is that insertions and deletions can invalidate iterators // pointing to values other than the one being inserted/deleted. This is // notably different from STL set/map which takes care to not invalidate // iterators on insert/erase except, of course, for iterators pointing to the // value being erased. A partial workaround when erasing is available: // erase() returns an iterator pointing to the item just after the one that was // erased (or end() if none exists). See also safe_btree. // PERFORMANCE // // btree_bench --benchmarks=. 2>&1 | ./benchmarks.awk // // Run on pmattis-warp.nyc (4 X 2200 MHz CPUs); 2010/03/04-15:23:06 // Benchmark STL(ns) B-Tree(ns) @ // -------------------------------------------------------- // BM_set_int32_insert 1516 608 +59.89% <256> [40.0, 5.2] // BM_set_int32_lookup 1160 414 +64.31% <256> [40.0, 5.2] // BM_set_int32_fulllookup 960 410 +57.29% <256> [40.0, 4.4] // BM_set_int32_delete 1741 528 +69.67% <256> [40.0, 5.2] // BM_set_int32_queueaddrem 3078 1046 +66.02% <256> [40.0, 5.5] // BM_set_int32_mixedaddrem 3600 1384 +61.56% <256> [40.0, 5.3] // BM_set_int32_fifo 227 113 +50.22% <256> [40.0, 4.4] // BM_set_int32_fwditer 158 26 +83.54% <256> [40.0, 5.2] // BM_map_int32_insert 1551 636 +58.99% <256> [48.0, 10.5] // BM_map_int32_lookup 1200 508 +57.67% <256> [48.0, 10.5] // BM_map_int32_fulllookup 989 487 +50.76% <256> [48.0, 8.8] // BM_map_int32_delete 1794 628 +64.99% <256> [48.0, 10.5] // BM_map_int32_queueaddrem 3189 1266 +60.30% <256> [48.0, 11.6] // BM_map_int32_mixedaddrem 3822 1623 +57.54% <256> [48.0, 10.9] // BM_map_int32_fifo 151 134 +11.26% <256> [48.0, 8.8] // BM_map_int32_fwditer 161 32 +80.12% <256> [48.0, 10.5] // BM_set_int64_insert 1546 636 +58.86% <256> [40.0, 10.5] // BM_set_int64_lookup 1200 512 +57.33% <256> [40.0, 10.5] // BM_set_int64_fulllookup 971 487 +49.85% <256> [40.0, 8.8] // BM_set_int64_delete 1745 616 +64.70% <256> [40.0, 10.5] // BM_set_int64_queueaddrem 3163 1195 +62.22% <256> [40.0, 11.6] // BM_set_int64_mixedaddrem 3760 1564 +58.40% <256> [40.0, 10.9] // BM_set_int64_fifo 146 103 +29.45% <256> [40.0, 8.8] // BM_set_int64_fwditer 162 31 +80.86% <256> [40.0, 10.5] // BM_map_int64_insert 1551 720 +53.58% <256> [48.0, 20.7] // BM_map_int64_lookup 1214 612 +49.59% <256> [48.0, 20.7] // BM_map_int64_fulllookup 994 592 +40.44% <256> [48.0, 17.2] // BM_map_int64_delete 1778 764 +57.03% <256> [48.0, 20.7] // BM_map_int64_queueaddrem 3189 1547 +51.49% <256> [48.0, 20.9] // BM_map_int64_mixedaddrem 3779 1887 +50.07% <256> [48.0, 21.6] // BM_map_int64_fifo 147 145 +1.36% <256> [48.0, 17.2] // BM_map_int64_fwditer 162 41 +74.69% <256> [48.0, 20.7] // BM_set_string_insert 1989 1966 +1.16% <256> [64.0, 44.5] // BM_set_string_lookup 1709 1600 +6.38% <256> [64.0, 44.5] // BM_set_string_fulllookup 1573 1529 +2.80% <256> [64.0, 35.4] // BM_set_string_delete 2520 1920 +23.81% <256> [64.0, 44.5] // BM_set_string_queueaddrem 4706 4309 +8.44% <256> [64.0, 48.3] // BM_set_string_mixedaddrem 5080 4654 +8.39% <256> [64.0, 46.7] // BM_set_string_fifo 318 512 -61.01% <256> [64.0, 35.4] // BM_set_string_fwditer 182 93 +48.90% <256> [64.0, 44.5] // BM_map_string_insert 2600 2227 +14.35% <256> [72.0, 55.8] // BM_map_string_lookup 2068 1730 +16.34% <256> [72.0, 55.8] // BM_map_string_fulllookup 1859 1618 +12.96% <256> [72.0, 44.0] // BM_map_string_delete 3168 2080 +34.34% <256> [72.0, 55.8] // BM_map_string_queueaddrem 5840 4701 +19.50% <256> [72.0, 59.4] // BM_map_string_mixedaddrem 6400 5200 +18.75% <256> [72.0, 57.8] // BM_map_string_fifo 398 596 -49.75% <256> [72.0, 44.0] // BM_map_string_fwditer 243 113 +53.50% <256> [72.0, 55.8] #ifndef UTIL_BTREE_BTREE_H__ #define UTIL_BTREE_BTREE_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NDEBUG #define NDEBUG 1 #endif namespace btree { // Inside a btree method, if we just call swap(), it will choose the // btree::swap method, which we don't want. And we can't say ::swap // because then MSVC won't pickup any std::swap() implementations. We // can't just use std::swap() directly because then we don't get the // specialization for types outside the std namespace. So the solution // is to have a special swap helper function whose name doesn't // collide with other swap functions defined by the btree classes. template inline void btree_swap_helper(T &a, T &b) { using std::swap; swap(a, b); } // A template helper used to select A or B based on a condition. template struct if_{ typedef A type; }; template struct if_ { typedef B type; }; // Types small_ and big_ are promise that sizeof(small_) < sizeof(big_) typedef char small_; struct big_ { char dummy[2]; }; // A compile-time assertion. template struct CompileAssert { }; #define COMPILE_ASSERT(expr, msg) \ typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // A helper type used to indicate that a key-compare-to functor has been // provided. A user can specify a key-compare-to functor by doing: // // struct MyStringComparer // : public util::btree::btree_key_compare_to_tag { // int operator()(const string &a, const string &b) const { // return a.compare(b); // } // }; // // Note that the return type is an int and not a bool. There is a // COMPILE_ASSERT which enforces this return type. struct btree_key_compare_to_tag { }; // A helper class that indicates if the Compare parameter is derived from // btree_key_compare_to_tag. template struct btree_is_key_compare_to : public std::is_convertible { }; // A helper class to convert a boolean comparison into a three-way // "compare-to" comparison that returns a negative value to indicate // less-than, zero to indicate equality and a positive value to // indicate greater-than. This helper class is specialized for // less and greater. The btree_key_compare_to_adapter // class is provided so that btree users automatically get the more // efficient compare-to code when using common google string types // with common comparison functors. template struct btree_key_compare_to_adapter : Compare { btree_key_compare_to_adapter() { } btree_key_compare_to_adapter(const Compare &c) : Compare(c) { } btree_key_compare_to_adapter(const btree_key_compare_to_adapter &c) : Compare(c) { } }; template <> struct btree_key_compare_to_adapter > : public btree_key_compare_to_tag { btree_key_compare_to_adapter() {} btree_key_compare_to_adapter(const std::less&) {} btree_key_compare_to_adapter( const btree_key_compare_to_adapter >&) {} int operator()(const std::string &a, const std::string &b) const { return a.compare(b); } }; template <> struct btree_key_compare_to_adapter > : public btree_key_compare_to_tag { btree_key_compare_to_adapter() {} btree_key_compare_to_adapter(const std::greater&) {} btree_key_compare_to_adapter( const btree_key_compare_to_adapter >&) {} int operator()(const std::string &a, const std::string &b) const { return b.compare(a); } }; // A helper class that allows a compare-to functor to behave like a plain // compare functor. This specialization is used when we do not have a // compare-to functor. template struct btree_key_comparer { btree_key_comparer() {} btree_key_comparer(Compare c) : comp(c) {} static bool bool_compare(const Compare &comp, const Key &x, const Key &y) { return comp(x, y); } bool operator()(const Key &x, const Key &y) const { return bool_compare(comp, x, y); } Compare comp; }; // A specialization of btree_key_comparer when a compare-to functor is // present. We need a plain (boolean) comparison in some parts of the btree // code, such as insert-with-hint. template struct btree_key_comparer { btree_key_comparer() {} btree_key_comparer(Compare c) : comp(c) {} static bool bool_compare(const Compare &comp, const Key &x, const Key &y) { return comp(x, y) < 0; } bool operator()(const Key &x, const Key &y) const { return bool_compare(comp, x, y); } Compare comp; }; // A helper function to compare to keys using the specified compare // functor. This dispatches to the appropriate btree_key_comparer comparison, // depending on whether we have a compare-to functor or not (which depends on // whether Compare is derived from btree_key_compare_to_tag). template static bool btree_compare_keys( const Compare &comp, const Key &x, const Key &y) { typedef btree_key_comparer::value> key_comparer; return key_comparer::bool_compare(comp, x, y); } template struct btree_common_params { // If Compare is derived from btree_key_compare_to_tag then use it as the // key_compare type. Otherwise, use btree_key_compare_to_adapter<> which will // fall-back to Compare if we don't have an appropriate specialization. typedef typename if_< btree_is_key_compare_to::value, Compare, btree_key_compare_to_adapter >::type key_compare; // A type which indicates if we have a key-compare-to functor or a plain old // key-compare functor. typedef btree_is_key_compare_to is_key_compare_to; typedef Alloc allocator_type; typedef Key key_type; typedef ssize_t size_type; typedef ptrdiff_t difference_type; enum { kTargetNodeSize = TargetNodeSize, // Available space for values. This is largest for leaf nodes, // which has overhead no fewer than two pointers. kNodeValueSpace = TargetNodeSize - 2 * sizeof(void*), }; // This is an integral type large enough to hold as many // ValueSize-values as will fit a node of TargetNodeSize bytes. typedef typename if_< (kNodeValueSpace / ValueSize) >= 256, uint16_t, uint8_t>::type node_count_type; }; // A parameters structure for holding the type parameters for a btree_map. template struct btree_map_params : public btree_common_params { typedef Data data_type; typedef Data mapped_type; typedef std::pair value_type; typedef std::pair mutable_value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; enum { kValueSize = sizeof(Key) + sizeof(data_type), }; static const Key& key(const value_type &x) { return x.first; } static const Key& key(const mutable_value_type &x) { return x.first; } static void swap(mutable_value_type *a, mutable_value_type *b) { btree_swap_helper(a->first, b->first); btree_swap_helper(a->second, b->second); } }; // A parameters structure for holding the type parameters for a btree_set. template struct btree_set_params : public btree_common_params { typedef std::false_type data_type; typedef std::false_type mapped_type; typedef Key value_type; typedef value_type mutable_value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; enum { kValueSize = sizeof(Key), }; static const Key& key(const value_type &x) { return x; } static void swap(mutable_value_type *a, mutable_value_type *b) { btree_swap_helper(*a, *b); } }; // An adapter class that converts a lower-bound compare into an upper-bound // compare. template struct btree_upper_bound_adapter : public Compare { btree_upper_bound_adapter(Compare c) : Compare(c) {} bool operator()(const Key &a, const Key &b) const { return !static_cast(*this)(b, a); } }; template struct btree_upper_bound_compare_to_adapter : public CompareTo { btree_upper_bound_compare_to_adapter(CompareTo c) : CompareTo(c) {} int operator()(const Key &a, const Key &b) const { return static_cast(*this)(b, a); } }; // Dispatch helper class for using linear search with plain compare. template struct btree_linear_search_plain_compare { static int lower_bound(const K &k, const N &n, Compare comp) { return n.linear_search_plain_compare(k, 0, n.count(), comp); } static int upper_bound(const K &k, const N &n, Compare comp) { typedef btree_upper_bound_adapter upper_compare; return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp)); } }; // Dispatch helper class for using linear search with compare-to template struct btree_linear_search_compare_to { static int lower_bound(const K &k, const N &n, CompareTo comp) { return n.linear_search_compare_to(k, 0, n.count(), comp); } static int upper_bound(const K &k, const N &n, CompareTo comp) { typedef btree_upper_bound_adapter > upper_compare; return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp)); } }; // Dispatch helper class for using binary search with plain compare. template struct btree_binary_search_plain_compare { static int lower_bound(const K &k, const N &n, Compare comp) { return n.binary_search_plain_compare(k, 0, n.count(), comp); } static int upper_bound(const K &k, const N &n, Compare comp) { typedef btree_upper_bound_adapter upper_compare; return n.binary_search_plain_compare(k, 0, n.count(), upper_compare(comp)); } }; // Dispatch helper class for using binary search with compare-to. template struct btree_binary_search_compare_to { static int lower_bound(const K &k, const N &n, CompareTo comp) { return n.binary_search_compare_to(k, 0, n.count(), CompareTo()); } static int upper_bound(const K &k, const N &n, CompareTo comp) { typedef btree_upper_bound_adapter > upper_compare; return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp)); } }; // A node in the btree holding. The same node type is used for both internal // and leaf nodes in the btree, though the nodes are allocated in such a way // that the children array is only valid in internal nodes. template class btree_node { public: typedef Params params_type; typedef btree_node self_type; typedef typename Params::key_type key_type; typedef typename Params::data_type data_type; typedef typename Params::value_type value_type; typedef typename Params::mutable_value_type mutable_value_type; typedef typename Params::pointer pointer; typedef typename Params::const_pointer const_pointer; typedef typename Params::reference reference; typedef typename Params::const_reference const_reference; typedef typename Params::key_compare key_compare; typedef typename Params::size_type size_type; typedef typename Params::difference_type difference_type; // Typedefs for the various types of node searches. typedef btree_linear_search_plain_compare< key_type, self_type, key_compare> linear_search_plain_compare_type; typedef btree_linear_search_compare_to< key_type, self_type, key_compare> linear_search_compare_to_type; typedef btree_binary_search_plain_compare< key_type, self_type, key_compare> binary_search_plain_compare_type; typedef btree_binary_search_compare_to< key_type, self_type, key_compare> binary_search_compare_to_type; // If we have a valid key-compare-to type, use linear_search_compare_to, // otherwise use linear_search_plain_compare. typedef typename if_< Params::is_key_compare_to::value, linear_search_compare_to_type, linear_search_plain_compare_type>::type linear_search_type; // If we have a valid key-compare-to type, use binary_search_compare_to, // otherwise use binary_search_plain_compare. typedef typename if_< Params::is_key_compare_to::value, binary_search_compare_to_type, binary_search_plain_compare_type>::type binary_search_type; // If the key is an integral or floating point type, use linear search which // is faster than binary search for such types. Might be wise to also // configure linear search based on node-size. typedef typename if_< std::is_integral::value || std::is_floating_point::value, linear_search_type, binary_search_type>::type search_type; struct base_fields { typedef typename Params::node_count_type field_type; // A boolean indicating whether the node is a leaf or not. bool leaf; // The position of the node in the node's parent. field_type position; // The maximum number of values the node can hold. field_type max_count; // The count of the number of values in the node. field_type count; // A pointer to the node's parent. btree_node *parent; }; enum { kValueSize = params_type::kValueSize, kTargetNodeSize = params_type::kTargetNodeSize, // Compute how many values we can fit onto a leaf node. kNodeTargetValues = (kTargetNodeSize - sizeof(base_fields)) / kValueSize, // We need a minimum of 3 values per internal node in order to perform // splitting (1 value for the two nodes involved in the split and 1 value // propagated to the parent as the delimiter for the split). kNodeValues = kNodeTargetValues >= 3 ? kNodeTargetValues : 3, kExactMatch = 1 << 30, kMatchMask = kExactMatch - 1, }; struct leaf_fields : public base_fields { // The array of values. Only the first count of these values have been // constructed and are valid. mutable_value_type values[kNodeValues]; }; struct internal_fields : public leaf_fields { // The array of child pointers. The keys in children_[i] are all less than // key(i). The keys in children_[i + 1] are all greater than key(i). There // are always count + 1 children. btree_node *children[kNodeValues + 1]; }; struct root_fields : public internal_fields { btree_node *rightmost; size_type size; }; public: // Getter/setter for whether this is a leaf node or not. This value doesn't // change after the node is created. bool leaf() const { return fields_.leaf; } // Getter for the position of this node in its parent. int position() const { return fields_.position; } void set_position(int v) { fields_.position = v; } // Getter/setter for the number of values stored in this node. int count() const { return fields_.count; } void set_count(int v) { fields_.count = v; } int max_count() const { return fields_.max_count; } // Getter for the parent of this node. btree_node* parent() const { return fields_.parent; } // Getter for whether the node is the root of the tree. The parent of the // root of the tree is the leftmost node in the tree which is guaranteed to // be a leaf. bool is_root() const { return parent()->leaf(); } void make_root() { assert(parent()->is_root()); fields_.parent = fields_.parent->parent(); } // Getter for the rightmost root node field. Only valid on the root node. btree_node* rightmost() const { return fields_.rightmost; } btree_node** mutable_rightmost() { return &fields_.rightmost; } // Getter for the size root node field. Only valid on the root node. size_type size() const { return fields_.size; } size_type* mutable_size() { return &fields_.size; } // Getters for the key/value at position i in the node. const key_type& key(int i) const { return params_type::key(fields_.values[i]); } reference value(int i) { return reinterpret_cast(fields_.values[i]); } const_reference value(int i) const { return reinterpret_cast(fields_.values[i]); } mutable_value_type* mutable_value(int i) { return &fields_.values[i]; } // Swap value i in this node with value j in node x. void value_swap(int i, btree_node *x, int j) { params_type::swap(mutable_value(i), x->mutable_value(j)); } // Getters/setter for the child at position i in the node. btree_node* child(int i) const { return fields_.children[i]; } btree_node** mutable_child(int i) { return &fields_.children[i]; } void set_child(int i, btree_node *c) { *mutable_child(i) = c; c->fields_.parent = this; c->fields_.position = i; } // Returns the position of the first value whose key is not less than k. template int lower_bound(const key_type &k, const Compare &comp) const { return search_type::lower_bound(k, *this, comp); } // Returns the position of the first value whose key is greater than k. template int upper_bound(const key_type &k, const Compare &comp) const { return search_type::upper_bound(k, *this, comp); } // Returns the position of the first value whose key is not less than k using // linear search performed using plain compare. template int linear_search_plain_compare( const key_type &k, int s, int e, const Compare &comp) const { while (s < e) { if (!btree_compare_keys(comp, key(s), k)) { break; } ++s; } return s; } // Returns the position of the first value whose key is not less than k using // linear search performed using compare-to. template int linear_search_compare_to( const key_type &k, int s, int e, const Compare &comp) const { while (s < e) { int c = comp(key(s), k); if (c == 0) { return s | kExactMatch; } else if (c > 0) { break; } ++s; } return s; } // Returns the position of the first value whose key is not less than k using // binary search performed using plain compare. template int binary_search_plain_compare( const key_type &k, int s, int e, const Compare &comp) const { while (s != e) { int mid = (s + e) / 2; if (btree_compare_keys(comp, key(mid), k)) { s = mid + 1; } else { e = mid; } } return s; } // Returns the position of the first value whose key is not less than k using // binary search performed using compare-to. template int binary_search_compare_to( const key_type &k, int s, int e, const CompareTo &comp) const { while (s != e) { int mid = (s + e) / 2; int c = comp(key(mid), k); if (c < 0) { s = mid + 1; } else if (c > 0) { e = mid; } else { // Need to return the first value whose key is not less than k, which // requires continuing the binary search. Note that we are guaranteed // that the result is an exact match because if "key(mid-1) < k" the // call to binary_search_compare_to() will return "mid". s = binary_search_compare_to(k, s, mid, comp); return s | kExactMatch; } } return s; } // Inserts the value x at position i, shifting all existing values and // children at positions >= i to the right by 1. void insert_value(int i, const value_type &x); // Removes the value at position i, shifting all existing values and children // at positions > i to the left by 1. void remove_value(int i); // Rebalances a node with its right sibling. void rebalance_right_to_left(btree_node *sibling, int to_move); void rebalance_left_to_right(btree_node *sibling, int to_move); // Splits a node, moving a portion of the node's values to its right sibling. void split(btree_node *sibling, int insert_position); // Merges a node with its right sibling, moving all of the values and the // delimiting key in the parent node onto itself. void merge(btree_node *sibling); // Swap the contents of "this" and "src". void swap(btree_node *src); // Node allocation/deletion routines. static btree_node* init_leaf( leaf_fields *f, btree_node *parent, int max_count) { btree_node *n = reinterpret_cast(f); f->leaf = 1; f->position = 0; f->max_count = max_count; f->count = 0; f->parent = parent; if (!NDEBUG) { memset(&f->values, 0, max_count * sizeof(value_type)); } return n; } static btree_node* init_internal(internal_fields *f, btree_node *parent) { btree_node *n = init_leaf(f, parent, kNodeValues); f->leaf = 0; if (!NDEBUG) { memset(f->children, 0, sizeof(f->children)); } return n; } static btree_node* init_root(root_fields *f, btree_node *parent) { btree_node *n = init_internal(f, parent); f->rightmost = parent; f->size = parent->count(); return n; } void destroy() { for (int i = 0; i < count(); ++i) { value_destroy(i); } } private: void value_init(int i) { new (&fields_.values[i]) mutable_value_type; } void value_init(int i, const value_type &x) { new (&fields_.values[i]) mutable_value_type(x); } void value_destroy(int i) { fields_.values[i].~mutable_value_type(); } private: root_fields fields_; private: btree_node(const btree_node&); void operator=(const btree_node&); }; template struct btree_iterator { typedef typename Node::key_type key_type; typedef typename Node::size_type size_type; typedef typename Node::difference_type difference_type; typedef typename Node::params_type params_type; typedef Node node_type; typedef typename std::remove_const::type normal_node; typedef const Node const_node; typedef typename params_type::value_type value_type; typedef typename params_type::pointer normal_pointer; typedef typename params_type::reference normal_reference; typedef typename params_type::const_pointer const_pointer; typedef typename params_type::const_reference const_reference; typedef Pointer pointer; typedef Reference reference; typedef std::bidirectional_iterator_tag iterator_category; typedef btree_iterator< normal_node, normal_reference, normal_pointer> iterator; typedef btree_iterator< const_node, const_reference, const_pointer> const_iterator; typedef btree_iterator self_type; btree_iterator() : node(NULL), position(-1) { } btree_iterator(Node *n, int p) : node(n), position(p) { } btree_iterator(const iterator &x) : node(x.node), position(x.position) { } // Increment/decrement the iterator. void increment() { if (node->leaf() && ++position < node->count()) { return; } increment_slow(); } void increment_by(int count); void increment_slow(); void decrement() { if (node->leaf() && --position >= 0) { return; } decrement_slow(); } void decrement_slow(); bool operator==(const const_iterator &x) const { return node == x.node && position == x.position; } bool operator!=(const const_iterator &x) const { return node != x.node || position != x.position; } // Accessors for the key/value the iterator is pointing at. const key_type& key() const { return node->key(position); } reference operator*() const { return node->value(position); } pointer operator->() const { return &node->value(position); } self_type& operator++() { increment(); return *this; } self_type& operator--() { decrement(); return *this; } self_type operator++(int) { self_type tmp = *this; ++*this; return tmp; } self_type operator--(int) { self_type tmp = *this; --*this; return tmp; } // The node in the tree the iterator is pointing at. Node *node; // The position within the node of the tree the iterator is pointing at. int position; }; // Dispatch helper class for using btree::internal_locate with plain compare. struct btree_internal_locate_plain_compare { template static std::pair dispatch(const K &k, const T &t, Iter iter) { return t.internal_locate_plain_compare(k, iter); } }; // Dispatch helper class for using btree::internal_locate with compare-to. struct btree_internal_locate_compare_to { template static std::pair dispatch(const K &k, const T &t, Iter iter) { return t.internal_locate_compare_to(k, iter); } }; template class btree : public Params::key_compare { typedef btree self_type; typedef btree_node node_type; typedef typename node_type::base_fields base_fields; typedef typename node_type::leaf_fields leaf_fields; typedef typename node_type::internal_fields internal_fields; typedef typename node_type::root_fields root_fields; typedef typename Params::is_key_compare_to is_key_compare_to; friend struct btree_internal_locate_plain_compare; friend struct btree_internal_locate_compare_to; typedef typename if_< is_key_compare_to::value, btree_internal_locate_compare_to, btree_internal_locate_plain_compare>::type internal_locate_type; enum { kNodeValues = node_type::kNodeValues, kMinNodeValues = kNodeValues / 2, kValueSize = node_type::kValueSize, kExactMatch = node_type::kExactMatch, kMatchMask = node_type::kMatchMask, }; // A helper class to get the empty base class optimization for 0-size // allocators. Base is internal_allocator_type. // (e.g. empty_base_handle). If Base is // 0-size, the compiler doesn't have to reserve any space for it and // sizeof(empty_base_handle) will simply be sizeof(Data). Google [empty base // class optimization] for more details. template struct empty_base_handle : public Base { empty_base_handle(const Base &b, const Data &d) : Base(b), data(d) { } Data data; }; struct node_stats { node_stats(ssize_t l, ssize_t i) : leaf_nodes(l), internal_nodes(i) { } node_stats& operator+=(const node_stats &x) { leaf_nodes += x.leaf_nodes; internal_nodes += x.internal_nodes; return *this; } ssize_t leaf_nodes; ssize_t internal_nodes; }; public: typedef Params params_type; typedef typename Params::key_type key_type; typedef typename Params::data_type data_type; typedef typename Params::mapped_type mapped_type; typedef typename Params::value_type value_type; typedef typename Params::key_compare key_compare; typedef typename Params::pointer pointer; typedef typename Params::const_pointer const_pointer; typedef typename Params::reference reference; typedef typename Params::const_reference const_reference; typedef typename Params::size_type size_type; typedef typename Params::difference_type difference_type; typedef btree_iterator iterator; typedef typename iterator::const_iterator const_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef std::reverse_iterator reverse_iterator; typedef typename Params::allocator_type allocator_type; typedef typename allocator_type::template rebind::other internal_allocator_type; public: // Default constructor. btree(const key_compare &comp, const allocator_type &alloc); // Copy constructor. btree(const self_type &x); // Destructor. ~btree() { clear(); } // Iterator routines. iterator begin() { return iterator(leftmost(), 0); } const_iterator begin() const { return const_iterator(leftmost(), 0); } iterator end() { return iterator(rightmost(), rightmost() ? rightmost()->count() : 0); } const_iterator end() const { return const_iterator(rightmost(), rightmost() ? rightmost()->count() : 0); } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } // Finds the first element whose key is not less than key. iterator lower_bound(const key_type &key) { return internal_end( internal_lower_bound(key, iterator(root(), 0))); } const_iterator lower_bound(const key_type &key) const { return internal_end( internal_lower_bound(key, const_iterator(root(), 0))); } // Finds the first element whose key is greater than key. iterator upper_bound(const key_type &key) { return internal_end( internal_upper_bound(key, iterator(root(), 0))); } const_iterator upper_bound(const key_type &key) const { return internal_end( internal_upper_bound(key, const_iterator(root(), 0))); } // Finds the range of values which compare equal to key. The first member of // the returned pair is equal to lower_bound(key). The second member pair of // the pair is equal to upper_bound(key). std::pair equal_range(const key_type &key) { return std::make_pair(lower_bound(key), upper_bound(key)); } std::pair equal_range(const key_type &key) const { return std::make_pair(lower_bound(key), upper_bound(key)); } // Inserts a value into the btree only if it does not already exist. The // boolean return value indicates whether insertion succeeded or failed. The // ValuePointer type is used to avoid instatiating the value unless the key // is being inserted. Value is not dereferenced if the key already exists in // the btree. See btree_map::operator[]. template std::pair insert_unique(const key_type &key, ValuePointer value); // Inserts a value into the btree only if it does not already exist. The // boolean return value indicates whether insertion succeeded or failed. std::pair insert_unique(const value_type &v) { return insert_unique(params_type::key(v), &v); } // Insert with hint. Check to see if the value should be placed immediately // before position in the tree. If it does, then the insertion will take // amortized constant time. If not, the insertion will take amortized // logarithmic time as if a call to insert_unique(v) were made. iterator insert_unique(iterator position, const value_type &v); // Insert a range of values into the btree. template void insert_unique(InputIterator b, InputIterator e); // Inserts a value into the btree. The ValuePointer type is used to avoid // instatiating the value unless the key is being inserted. Value is not // dereferenced if the key already exists in the btree. See // btree_map::operator[]. template iterator insert_multi(const key_type &key, ValuePointer value); // Inserts a value into the btree. iterator insert_multi(const value_type &v) { return insert_multi(params_type::key(v), &v); } // Insert with hint. Check to see if the value should be placed immediately // before position in the tree. If it does, then the insertion will take // amortized constant time. If not, the insertion will take amortized // logarithmic time as if a call to insert_multi(v) were made. iterator insert_multi(iterator position, const value_type &v); // Insert a range of values into the btree. template void insert_multi(InputIterator b, InputIterator e); void assign(const self_type &x); // Erase the specified iterator from the btree. The iterator must be valid // (i.e. not equal to end()). Return an iterator pointing to the node after // the one that was erased (or end() if none exists). iterator erase(iterator iter); // Erases range. Returns the number of keys erased. int erase(iterator begin, iterator end); // Erases the specified key from the btree. Returns 1 if an element was // erased and 0 otherwise. int erase_unique(const key_type &key); // Erases all of the entries matching the specified key from the // btree. Returns the number of elements erased. int erase_multi(const key_type &key); // Finds the iterator corresponding to a key or returns end() if the key is // not present. iterator find_unique(const key_type &key) { return internal_end( internal_find_unique(key, iterator(root(), 0))); } const_iterator find_unique(const key_type &key) const { return internal_end( internal_find_unique(key, const_iterator(root(), 0))); } iterator find_multi(const key_type &key) { return internal_end( internal_find_multi(key, iterator(root(), 0))); } const_iterator find_multi(const key_type &key) const { return internal_end( internal_find_multi(key, const_iterator(root(), 0))); } // Returns a count of the number of times the key appears in the btree. size_type count_unique(const key_type &key) const { const_iterator b = internal_find_unique( key, const_iterator(root(), 0)); if (!b.node) { // The key doesn't exist in the tree. return 0; } return 1; } // Returns a count of the number of times the key appears in the btree. size_type count_multi(const key_type &key) const { return distance(lower_bound(key), upper_bound(key)); } // Clear the btree, deleting all of the values it contains. void clear(); // Swap the contents of *this and x. void swap(self_type &x); // Assign the contents of x to *this. self_type& operator=(const self_type &x) { if (&x == this) { // Don't copy onto ourselves. return *this; } assign(x); return *this; } key_compare* mutable_key_comp() { return this; } const key_compare& key_comp() const { return *this; } bool compare_keys(const key_type &x, const key_type &y) const { return btree_compare_keys(key_comp(), x, y); } // Dump the btree to the specified ostream. Requires that operator<< is // defined for Key and Value. void dump(std::ostream &os) const { if (root() != NULL) { internal_dump(os, root(), 0); } } // Verifies the structure of the btree. void verify() const; // Size routines. Note that empty() is slightly faster than doing size()==0. size_type size() const { if (empty()) return 0; if (root()->leaf()) return root()->count(); return root()->size(); } size_type max_size() const { return std::numeric_limits::max(); } bool empty() const { return root() == NULL; } // The height of the btree. An empty tree will have height 0. size_type height() const { size_type h = 0; if (root()) { // Count the length of the chain from the leftmost node up to the // root. We actually count from the root back around to the level below // the root, but the calculation is the same because of the circularity // of that traversal. const node_type *n = root(); do { ++h; n = n->parent(); } while (n != root()); } return h; } // The number of internal, leaf and total nodes used by the btree. size_type leaf_nodes() const { return internal_stats(root()).leaf_nodes; } size_type internal_nodes() const { return internal_stats(root()).internal_nodes; } size_type nodes() const { node_stats stats = internal_stats(root()); return stats.leaf_nodes + stats.internal_nodes; } // The total number of bytes used by the btree. size_type bytes_used() const { node_stats stats = internal_stats(root()); if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) { return sizeof(*this) + sizeof(base_fields) + root()->max_count() * sizeof(value_type); } else { return sizeof(*this) + sizeof(root_fields) - sizeof(internal_fields) + stats.leaf_nodes * sizeof(leaf_fields) + stats.internal_nodes * sizeof(internal_fields); } } // The average number of bytes used per value stored in the btree. static double average_bytes_per_value() { // Returns the number of bytes per value on a leaf node that is 75% // full. Experimentally, this matches up nicely with the computed number of // bytes per value in trees that had their values inserted in random order. return sizeof(leaf_fields) / (kNodeValues * 0.75); } // The fullness of the btree. Computed as the number of elements in the btree // divided by the maximum number of elements a tree with the current number // of nodes could hold. A value of 1 indicates perfect space // utilization. Smaller values indicate space wastage. double fullness() const { return double(size()) / (nodes() * kNodeValues); } // The overhead of the btree structure in bytes per node. Computed as the // total number of bytes used by the btree minus the number of bytes used for // storing elements divided by the number of elements. double overhead() const { if (empty()) { return 0.0; } return (bytes_used() - size() * kValueSize) / double(size()); } private: // Internal accessor routines. node_type* root() { return root_.data; } const node_type* root() const { return root_.data; } node_type** mutable_root() { return &root_.data; } // The rightmost node is stored in the root node. node_type* rightmost() { return (!root() || root()->leaf()) ? root() : root()->rightmost(); } const node_type* rightmost() const { return (!root() || root()->leaf()) ? root() : root()->rightmost(); } node_type** mutable_rightmost() { return root()->mutable_rightmost(); } // The leftmost node is stored as the parent of the root node. node_type* leftmost() { return root() ? root()->parent() : NULL; } const node_type* leftmost() const { return root() ? root()->parent() : NULL; } // The size of the tree is stored in the root node. size_type* mutable_size() { return root()->mutable_size(); } // Allocator routines. internal_allocator_type* mutable_internal_allocator() { return static_cast(&root_); } const internal_allocator_type& internal_allocator() const { return *static_cast(&root_); } // Node creation/deletion routines. node_type* new_internal_node(node_type *parent) { internal_fields *p = reinterpret_cast( mutable_internal_allocator()->allocate(sizeof(internal_fields))); return node_type::init_internal(p, parent); } node_type* new_internal_root_node() { root_fields *p = reinterpret_cast( mutable_internal_allocator()->allocate(sizeof(root_fields))); return node_type::init_root(p, root()->parent()); } node_type* new_leaf_node(node_type *parent) { leaf_fields *p = reinterpret_cast( mutable_internal_allocator()->allocate(sizeof(leaf_fields))); return node_type::init_leaf(p, parent, kNodeValues); } node_type* new_leaf_root_node(int max_count) { leaf_fields *p = reinterpret_cast( mutable_internal_allocator()->allocate( sizeof(base_fields) + max_count * sizeof(value_type))); return node_type::init_leaf(p, reinterpret_cast(p), max_count); } void delete_internal_node(node_type *node) { node->destroy(); assert(node != root()); mutable_internal_allocator()->deallocate( reinterpret_cast(node), sizeof(internal_fields)); } void delete_internal_root_node() { root()->destroy(); mutable_internal_allocator()->deallocate( reinterpret_cast(root()), sizeof(root_fields)); } void delete_leaf_node(node_type *node) { node->destroy(); mutable_internal_allocator()->deallocate( reinterpret_cast(node), sizeof(base_fields) + node->max_count() * sizeof(value_type)); } // Rebalances or splits the node iter points to. void rebalance_or_split(iterator *iter); // Merges the values of left, right and the delimiting key on their parent // onto left, removing the delimiting key and deleting right. void merge_nodes(node_type *left, node_type *right); // Tries to merge node with its left or right sibling, and failing that, // rebalance with its left or right sibling. Returns true if a merge // occurred, at which point it is no longer valid to access node. Returns // false if no merging took place. bool try_merge_or_rebalance(iterator *iter); // Tries to shrink the height of the tree by 1. void try_shrink(); iterator internal_end(iterator iter) { return iter.node ? iter : end(); } const_iterator internal_end(const_iterator iter) const { return iter.node ? iter : end(); } // Inserts a value into the btree immediately before iter. Requires that // key(v) <= iter.key() and (--iter).key() <= key(v). iterator internal_insert(iterator iter, const value_type &v); // Returns an iterator pointing to the first value >= the value "iter" is // pointing at. Note that "iter" might be pointing to an invalid location as // iter.position == iter.node->count(). This routine simply moves iter up in // the tree to a valid location. template static IterType internal_last(IterType iter); // Returns an iterator pointing to the leaf position at which key would // reside in the tree. We provide 2 versions of internal_locate. The first // version (internal_locate_plain_compare) always returns 0 for the second // field of the pair. The second version (internal_locate_compare_to) is for // the key-compare-to specialization and returns either kExactMatch (if the // key was found in the tree) or -kExactMatch (if it wasn't) in the second // field of the pair. The compare_to specialization allows the caller to // avoid a subsequent comparison to determine if an exact match was made, // speeding up string keys. template std::pair internal_locate( const key_type &key, IterType iter) const; template std::pair internal_locate_plain_compare( const key_type &key, IterType iter) const; template std::pair internal_locate_compare_to( const key_type &key, IterType iter) const; // Internal routine which implements lower_bound(). template IterType internal_lower_bound( const key_type &key, IterType iter) const; // Internal routine which implements upper_bound(). template IterType internal_upper_bound( const key_type &key, IterType iter) const; // Internal routine which implements find_unique(). template IterType internal_find_unique( const key_type &key, IterType iter) const; // Internal routine which implements find_multi(). template IterType internal_find_multi( const key_type &key, IterType iter) const; // Deletes a node and all of its children. void internal_clear(node_type *node); // Dumps a node and all of its children to the specified ostream. void internal_dump(std::ostream &os, const node_type *node, int level) const; // Verifies the tree structure of node. int internal_verify(const node_type *node, const key_type *lo, const key_type *hi) const; node_stats internal_stats(const node_type *node) const { if (!node) { return node_stats(0, 0); } if (node->leaf()) { return node_stats(1, 0); } node_stats res(0, 1); for (int i = 0; i <= node->count(); ++i) { res += internal_stats(node->child(i)); } return res; } private: empty_base_handle root_; private: // A never instantiated helper function that returns big_ if we have a // key-compare-to functor or if R is bool and small_ otherwise. template static typename if_< if_, std::is_same >::type::value, big_, small_>::type key_compare_checker(R); // A never instantiated helper function that returns the key comparison // functor. static key_compare key_compare_helper(); // Verify that key_compare returns a bool. This is similar to the way // is_convertible in base/type_traits.h works. Note that key_compare_checker // is never actually invoked. The compiler will select which // key_compare_checker() to instantiate and then figure out the size of the // return type of key_compare_checker() at compile time which we then check // against the sizeof of big_. COMPILE_ASSERT( sizeof(key_compare_checker(key_compare_helper()(key_type(), key_type()))) == sizeof(big_), key_comparison_function_must_return_bool); // Note: We insist on kTargetValues, which is computed from // Params::kTargetNodeSize, must fit the base_fields::field_type. COMPILE_ASSERT(kNodeValues < (1 << (8 * sizeof(typename base_fields::field_type))), target_node_size_too_large); // Test the assumption made in setting kNodeValueSpace. COMPILE_ASSERT(sizeof(base_fields) >= 2 * sizeof(void*), node_space_assumption_incorrect); }; //// // btree_node methods template inline void btree_node

::insert_value(int i, const value_type &x) { assert(i <= count()); value_init(count(), x); for (int j = count(); j > i; --j) { value_swap(j, this, j - 1); } set_count(count() + 1); if (!leaf()) { ++i; for (int j = count(); j > i; --j) { *mutable_child(j) = child(j - 1); child(j)->set_position(j); } *mutable_child(i) = NULL; } } template inline void btree_node

::remove_value(int i) { if (!leaf()) { assert(child(i + 1)->count() == 0); for (int j = i + 1; j < count(); ++j) { *mutable_child(j) = child(j + 1); child(j)->set_position(j); } *mutable_child(count()) = NULL; } set_count(count() - 1); for (; i < count(); ++i) { value_swap(i, this, i + 1); } value_destroy(i); } template void btree_node

::rebalance_right_to_left(btree_node *src, int to_move) { assert(parent() == src->parent()); assert(position() + 1 == src->position()); assert(src->count() >= count()); assert(to_move >= 1); assert(to_move <= src->count()); // Make room in the left node for the new values. for (int i = 0; i < to_move; ++i) { value_init(i + count()); } // Move the delimiting value to the left node and the new delimiting value // from the right node. value_swap(count(), parent(), position()); parent()->value_swap(position(), src, to_move - 1); // Move the values from the right to the left node. for (int i = 1; i < to_move; ++i) { value_swap(count() + i, src, i - 1); } // Shift the values in the right node to their correct position. for (int i = to_move; i < src->count(); ++i) { src->value_swap(i - to_move, src, i); } for (int i = 1; i <= to_move; ++i) { src->value_destroy(src->count() - i); } if (!leaf()) { // Move the child pointers from the right to the left node. for (int i = 0; i < to_move; ++i) { set_child(1 + count() + i, src->child(i)); } for (int i = 0; i <= src->count() - to_move; ++i) { assert(i + to_move <= src->max_count()); src->set_child(i, src->child(i + to_move)); *src->mutable_child(i + to_move) = NULL; } } // Fixup the counts on the src and dest nodes. set_count(count() + to_move); src->set_count(src->count() - to_move); } template void btree_node

::rebalance_left_to_right(btree_node *dest, int to_move) { assert(parent() == dest->parent()); assert(position() + 1 == dest->position()); assert(count() >= dest->count()); assert(to_move >= 1); assert(to_move <= count()); // Make room in the right node for the new values. for (int i = 0; i < to_move; ++i) { dest->value_init(i + dest->count()); } for (int i = dest->count() - 1; i >= 0; --i) { dest->value_swap(i, dest, i + to_move); } // Move the delimiting value to the right node and the new delimiting value // from the left node. dest->value_swap(to_move - 1, parent(), position()); parent()->value_swap(position(), this, count() - to_move); value_destroy(count() - to_move); // Move the values from the left to the right node. for (int i = 1; i < to_move; ++i) { value_swap(count() - to_move + i, dest, i - 1); value_destroy(count() - to_move + i); } if (!leaf()) { // Move the child pointers from the left to the right node. for (int i = dest->count(); i >= 0; --i) { dest->set_child(i + to_move, dest->child(i)); *dest->mutable_child(i) = NULL; } for (int i = 1; i <= to_move; ++i) { dest->set_child(i - 1, child(count() - to_move + i)); *mutable_child(count() - to_move + i) = NULL; } } // Fixup the counts on the src and dest nodes. set_count(count() - to_move); dest->set_count(dest->count() + to_move); } template void btree_node

::split(btree_node *dest, int insert_position) { assert(dest->count() == 0); // We bias the split based on the position being inserted. If we're // inserting at the beginning of the left node then bias the split to put // more values on the right node. If we're inserting at the end of the // right node then bias the split to put more values on the left node. if (insert_position == 0) { dest->set_count(count() - 1); } else if (insert_position == max_count()) { dest->set_count(0); } else { dest->set_count(count() / 2); } set_count(count() - dest->count()); assert(count() >= 1); // Move values from the left sibling to the right sibling. for (int i = 0; i < dest->count(); ++i) { dest->value_init(i); value_swap(count() + i, dest, i); value_destroy(count() + i); } // The split key is the largest value in the left sibling. set_count(count() - 1); parent()->insert_value(position(), value_type()); value_swap(count(), parent(), position()); value_destroy(count()); parent()->set_child(position() + 1, dest); if (!leaf()) { for (int i = 0; i <= dest->count(); ++i) { assert(child(count() + i + 1) != NULL); dest->set_child(i, child(count() + i + 1)); *mutable_child(count() + i + 1) = NULL; } } } template void btree_node

::merge(btree_node *src) { assert(parent() == src->parent()); assert(position() + 1 == src->position()); // Move the delimiting value to the left node. value_init(count()); value_swap(count(), parent(), position()); // Move the values from the right to the left node. for (int i = 0; i < src->count(); ++i) { value_init(1 + count() + i); value_swap(1 + count() + i, src, i); src->value_destroy(i); } if (!leaf()) { // Move the child pointers from the right to the left node. for (int i = 0; i <= src->count(); ++i) { set_child(1 + count() + i, src->child(i)); *src->mutable_child(i) = NULL; } } // Fixup the counts on the src and dest nodes. set_count(1 + count() + src->count()); src->set_count(0); // Remove the value on the parent node. parent()->remove_value(position()); } template void btree_node

::swap(btree_node *x) { assert(leaf() == x->leaf()); // Swap the values. for (int i = count(); i < x->count(); ++i) { value_init(i); } for (int i = x->count(); i < count(); ++i) { x->value_init(i); } int n = std::max(count(), x->count()); for (int i = 0; i < n; ++i) { value_swap(i, x, i); } for (int i = count(); i < x->count(); ++i) { x->value_destroy(i); } for (int i = x->count(); i < count(); ++i) { value_destroy(i); } if (!leaf()) { // Swap the child pointers. for (int i = 0; i <= n; ++i) { btree_swap_helper(*mutable_child(i), *x->mutable_child(i)); } for (int i = 0; i <= count(); ++i) { x->child(i)->fields_.parent = x; } for (int i = 0; i <= x->count(); ++i) { child(i)->fields_.parent = this; } } // Swap the counts. btree_swap_helper(fields_.count, x->fields_.count); } //// // btree_iterator methods template void btree_iterator::increment_slow() { if (node->leaf()) { assert(position >= node->count()); self_type save(*this); while (position == node->count() && !node->is_root()) { assert(node->parent()->child(node->position()) == node); position = node->position(); node = node->parent(); } if (position == node->count()) { *this = save; } } else { assert(position < node->count()); node = node->child(position + 1); while (!node->leaf()) { node = node->child(0); } position = 0; } } template void btree_iterator::increment_by(int count) { while (count > 0) { if (node->leaf()) { int rest = node->count() - position; position += std::min(rest, count); count = count - rest; if (position < node->count()) { return; } } else { --count; } increment_slow(); } } template void btree_iterator::decrement_slow() { if (node->leaf()) { assert(position <= -1); self_type save(*this); while (position < 0 && !node->is_root()) { assert(node->parent()->child(node->position()) == node); position = node->position() - 1; node = node->parent(); } if (position < 0) { *this = save; } } else { assert(position >= 0); node = node->child(position); while (!node->leaf()) { node = node->child(node->count()); } position = node->count() - 1; } } //// // btree methods template btree

::btree(const key_compare &comp, const allocator_type &alloc) : key_compare(comp), root_(alloc, NULL) { } template btree

::btree(const self_type &x) : key_compare(x.key_comp()), root_(x.internal_allocator(), NULL) { assign(x); } template template std::pair::iterator, bool> btree

::insert_unique(const key_type &key, ValuePointer value) { if (empty()) { *mutable_root() = new_leaf_root_node(1); } std::pair res = internal_locate(key, iterator(root(), 0)); iterator &iter = res.first; if (res.second == kExactMatch) { // The key already exists in the tree, do nothing. return std::make_pair(internal_last(iter), false); } else if (!res.second) { iterator last = internal_last(iter); if (last.node && !compare_keys(key, last.key())) { // The key already exists in the tree, do nothing. return std::make_pair(last, false); } } return std::make_pair(internal_insert(iter, *value), true); } template inline typename btree

::iterator btree

::insert_unique(iterator position, const value_type &v) { if (!empty()) { const key_type &key = params_type::key(v); if (position == end() || compare_keys(key, position.key())) { iterator prev = position; if (position == begin() || compare_keys((--prev).key(), key)) { // prev.key() < key < position.key() return internal_insert(position, v); } } else if (compare_keys(position.key(), key)) { iterator next = position; ++next; if (next == end() || compare_keys(key, next.key())) { // position.key() < key < next.key() return internal_insert(next, v); } } else { // position.key() == key return position; } } return insert_unique(v).first; } template template void btree

::insert_unique(InputIterator b, InputIterator e) { for (; b != e; ++b) { insert_unique(end(), *b); } } template template typename btree

::iterator btree

::insert_multi(const key_type &key, ValuePointer value) { if (empty()) { *mutable_root() = new_leaf_root_node(1); } iterator iter = internal_upper_bound(key, iterator(root(), 0)); if (!iter.node) { iter = end(); } return internal_insert(iter, *value); } template typename btree

::iterator btree

::insert_multi(iterator position, const value_type &v) { if (!empty()) { const key_type &key = params_type::key(v); if (position == end() || !compare_keys(position.key(), key)) { iterator prev = position; if (position == begin() || !compare_keys(key, (--prev).key())) { // prev.key() <= key <= position.key() return internal_insert(position, v); } } else { iterator next = position; ++next; if (next == end() || !compare_keys(next.key(), key)) { // position.key() < key <= next.key() return internal_insert(next, v); } } } return insert_multi(v); } template template void btree

::insert_multi(InputIterator b, InputIterator e) { for (; b != e; ++b) { insert_multi(end(), *b); } } template void btree

::assign(const self_type &x) { clear(); *mutable_key_comp() = x.key_comp(); *mutable_internal_allocator() = x.internal_allocator(); // Assignment can avoid key comparisons because we know the order of the // values is the same order we'll store them in. for (const_iterator iter = x.begin(); iter != x.end(); ++iter) { if (empty()) { insert_multi(*iter); } else { // If the btree is not empty, we can just insert the new value at the end // of the tree! internal_insert(end(), *iter); } } } template typename btree

::iterator btree

::erase(iterator iter) { bool internal_delete = false; if (!iter.node->leaf()) { // Deletion of a value on an internal node. Swap the key with the largest // value of our left child. This is easy, we just decrement iter. iterator tmp_iter(iter--); assert(iter.node->leaf()); assert(!compare_keys(tmp_iter.key(), iter.key())); iter.node->value_swap(iter.position, tmp_iter.node, tmp_iter.position); internal_delete = true; --*mutable_size(); } else if (!root()->leaf()) { --*mutable_size(); } // Delete the key from the leaf. iter.node->remove_value(iter.position); // We want to return the next value after the one we just erased. If we // erased from an internal node (internal_delete == true), then the next // value is ++(++iter). If we erased from a leaf node (internal_delete == // false) then the next value is ++iter. Note that ++iter may point to an // internal node and the value in the internal node may move to a leaf node // (iter.node) when rebalancing is performed at the leaf level. // Merge/rebalance as we walk back up the tree. iterator res(iter); for (;;) { if (iter.node == root()) { try_shrink(); if (empty()) { return end(); } break; } if (iter.node->count() >= kMinNodeValues) { break; } bool merged = try_merge_or_rebalance(&iter); if (iter.node->leaf()) { res = iter; } if (!merged) { break; } iter.node = iter.node->parent(); } // Adjust our return value. If we're pointing at the end of a node, advance // the iterator. if (res.position == res.node->count()) { res.position = res.node->count() - 1; ++res; } // If we erased from an internal node, advance the iterator. if (internal_delete) { ++res; } return res; } template int btree

::erase(iterator b, iterator e) { int count = distance(b, e); for (int i = 0; i < count; i++) { b = erase(b); } return count; } template int btree

::erase_unique(const key_type &key) { iterator iter = internal_find_unique(key, iterator(root(), 0)); if (!iter.node) { // The key doesn't exist in the tree, return nothing done. return 0; } erase(iter); return 1; } template int btree

::erase_multi(const key_type &key) { iterator b = internal_lower_bound(key, iterator(root(), 0)); if (!b.node) { // The key doesn't exist in the tree, return nothing done. return 0; } // Delete all of the keys between begin and upper_bound(key). iterator e = internal_end( internal_upper_bound(key, iterator(root(), 0))); return erase(b, e); } template void btree

::clear() { if (root() != NULL) { internal_clear(root()); } *mutable_root() = NULL; } template void btree

::swap(self_type &x) { std::swap(static_cast(*this), static_cast(x)); std::swap(root_, x.root_); } template void btree

::verify() const { if (root() != NULL) { assert(size() == internal_verify(root(), NULL, NULL)); assert(leftmost() == (++const_iterator(root(), -1)).node); assert(rightmost() == (--const_iterator(root(), root()->count())).node); assert(leftmost()->leaf()); assert(rightmost()->leaf()); } else { assert(size() == 0); assert(leftmost() == NULL); assert(rightmost() == NULL); } } template void btree

::rebalance_or_split(iterator *iter) { node_type *&node = iter->node; int &insert_position = iter->position; assert(node->count() == node->max_count()); // First try to make room on the node by rebalancing. node_type *parent = node->parent(); if (node != root()) { if (node->position() > 0) { // Try rebalancing with our left sibling. node_type *left = parent->child(node->position() - 1); if (left->count() < left->max_count()) { // We bias rebalancing based on the position being inserted. If we're // inserting at the end of the right node then we bias rebalancing to // fill up the left node. int to_move = (left->max_count() - left->count()) / (1 + (insert_position < left->max_count())); to_move = std::max(1, to_move); if (((insert_position - to_move) >= 0) || ((left->count() + to_move) < left->max_count())) { left->rebalance_right_to_left(node, to_move); assert(node->max_count() - node->count() == to_move); insert_position = insert_position - to_move; if (insert_position < 0) { insert_position = insert_position + left->count() + 1; node = left; } assert(node->count() < node->max_count()); return; } } } if (node->position() < parent->count()) { // Try rebalancing with our right sibling. node_type *right = parent->child(node->position() + 1); if (right->count() < right->max_count()) { // We bias rebalancing based on the position being inserted. If we're // inserting at the beginning of the left node then we bias rebalancing // to fill up the right node. int to_move = (right->max_count() - right->count()) / (1 + (insert_position > 0)); to_move = std::max(1, to_move); if ((insert_position <= (node->count() - to_move)) || ((right->count() + to_move) < right->max_count())) { node->rebalance_left_to_right(right, to_move); if (insert_position > node->count()) { insert_position = insert_position - node->count() - 1; node = right; } assert(node->count() < node->max_count()); return; } } } // Rebalancing failed, make sure there is room on the parent node for a new // value. if (parent->count() == parent->max_count()) { iterator parent_iter(node->parent(), node->position()); rebalance_or_split(&parent_iter); } } else { // Rebalancing not possible because this is the root node. if (root()->leaf()) { // The root node is currently a leaf node: create a new root node and set // the current root node as the child of the new root. parent = new_internal_root_node(); parent->set_child(0, root()); *mutable_root() = parent; assert(*mutable_rightmost() == parent->child(0)); } else { // The root node is an internal node. We do not want to create a new root // node because the root node is special and holds the size of the tree // and a pointer to the rightmost node. So we create a new internal node // and move all of the items on the current root into the new node. parent = new_internal_node(parent); parent->set_child(0, parent); parent->swap(root()); node = parent; } } // Split the node. node_type *split_node; if (node->leaf()) { split_node = new_leaf_node(parent); node->split(split_node, insert_position); if (rightmost() == node) { *mutable_rightmost() = split_node; } } else { split_node = new_internal_node(parent); node->split(split_node, insert_position); } if (insert_position > node->count()) { insert_position = insert_position - node->count() - 1; node = split_node; } } template void btree

::merge_nodes(node_type *left, node_type *right) { left->merge(right); if (right->leaf()) { if (rightmost() == right) { *mutable_rightmost() = left; } delete_leaf_node(right); } else { delete_internal_node(right); } } template bool btree

::try_merge_or_rebalance(iterator *iter) { node_type *parent = iter->node->parent(); if (iter->node->position() > 0) { // Try merging with our left sibling. node_type *left = parent->child(iter->node->position() - 1); if ((1 + left->count() + iter->node->count()) <= left->max_count()) { iter->position += 1 + left->count(); merge_nodes(left, iter->node); iter->node = left; return true; } } if (iter->node->position() < parent->count()) { // Try merging with our right sibling. node_type *right = parent->child(iter->node->position() + 1); if ((1 + iter->node->count() + right->count()) <= right->max_count()) { merge_nodes(iter->node, right); return true; } // Try rebalancing with our right sibling. We don't perform rebalancing if // we deleted the first element from iter->node and the node is not // empty. This is a small optimization for the common pattern of deleting // from the front of the tree. if ((right->count() > kMinNodeValues) && ((iter->node->count() == 0) || (iter->position > 0))) { int to_move = (right->count() - iter->node->count()) / 2; to_move = std::min(to_move, right->count() - 1); iter->node->rebalance_right_to_left(right, to_move); return false; } } if (iter->node->position() > 0) { // Try rebalancing with our left sibling. We don't perform rebalancing if // we deleted the last element from iter->node and the node is not // empty. This is a small optimization for the common pattern of deleting // from the back of the tree. node_type *left = parent->child(iter->node->position() - 1); if ((left->count() > kMinNodeValues) && ((iter->node->count() == 0) || (iter->position < iter->node->count()))) { int to_move = (left->count() - iter->node->count()) / 2; to_move = std::min(to_move, left->count() - 1); left->rebalance_left_to_right(iter->node, to_move); iter->position += to_move; return false; } } return false; } template void btree

::try_shrink() { if (root()->count() > 0) { return; } // Deleted the last item on the root node, shrink the height of the tree. if (root()->leaf()) { assert(size() == 0); delete_leaf_node(root()); *mutable_root() = NULL; } else { node_type *child = root()->child(0); if (child->leaf()) { // The child is a leaf node so simply make it the root node in the tree. child->make_root(); delete_internal_root_node(); *mutable_root() = child; } else { // The child is an internal node. We want to keep the existing root node // so we move all of the values from the child node into the existing // (empty) root node. child->swap(root()); delete_internal_node(child); } } } template template inline IterType btree

::internal_last(IterType iter) { while (iter.node && iter.position == iter.node->count()) { iter.position = iter.node->position(); iter.node = iter.node->parent(); if (iter.node->leaf()) { iter.node = NULL; } } return iter; } template inline typename btree

::iterator btree

::internal_insert(iterator iter, const value_type &v) { if (!iter.node->leaf()) { // We can't insert on an internal node. Instead, we'll insert after the // previous value which is guaranteed to be on a leaf node. --iter; ++iter.position; } if (iter.node->count() == iter.node->max_count()) { // Make room in the leaf for the new item. if (iter.node->max_count() < kNodeValues) { // Insertion into the root where the root is smaller that the full node // size. Simply grow the size of the root node. assert(iter.node == root()); iter.node = new_leaf_root_node( std::min(kNodeValues, 2 * iter.node->max_count())); iter.node->swap(root()); delete_leaf_node(root()); *mutable_root() = iter.node; } else { rebalance_or_split(&iter); ++*mutable_size(); } } else if (!root()->leaf()) { ++*mutable_size(); } iter.node->insert_value(iter.position, v); return iter; } template template inline std::pair btree

::internal_locate( const key_type &key, IterType iter) const { return internal_locate_type::dispatch(key, *this, iter); } template template inline std::pair btree

::internal_locate_plain_compare( const key_type &key, IterType iter) const { for (;;) { iter.position = iter.node->lower_bound(key, key_comp()); if (iter.node->leaf()) { break; } iter.node = iter.node->child(iter.position); } return std::make_pair(iter, 0); } template template inline std::pair btree

::internal_locate_compare_to( const key_type &key, IterType iter) const { for (;;) { int res = iter.node->lower_bound(key, key_comp()); iter.position = res & kMatchMask; if (res & kExactMatch) { return std::make_pair(iter, static_cast(kExactMatch)); } if (iter.node->leaf()) { break; } iter.node = iter.node->child(iter.position); } return std::make_pair(iter, -kExactMatch); } template template IterType btree

::internal_lower_bound( const key_type &key, IterType iter) const { if (iter.node) { for (;;) { iter.position = iter.node->lower_bound(key, key_comp()) & kMatchMask; if (iter.node->leaf()) { break; } iter.node = iter.node->child(iter.position); } iter = internal_last(iter); } return iter; } template template IterType btree

::internal_upper_bound( const key_type &key, IterType iter) const { if (iter.node) { for (;;) { iter.position = iter.node->upper_bound(key, key_comp()); if (iter.node->leaf()) { break; } iter.node = iter.node->child(iter.position); } iter = internal_last(iter); } return iter; } template template IterType btree

::internal_find_unique( const key_type &key, IterType iter) const { if (iter.node) { std::pair res = internal_locate(key, iter); if (res.second == kExactMatch) { return res.first; } if (!res.second) { iter = internal_last(res.first); if (iter.node && !compare_keys(key, iter.key())) { return iter; } } } return IterType(NULL, 0); } template template IterType btree

::internal_find_multi( const key_type &key, IterType iter) const { if (iter.node) { iter = internal_lower_bound(key, iter); if (iter.node) { iter = internal_last(iter); if (iter.node && !compare_keys(key, iter.key())) { return iter; } } } return IterType(NULL, 0); } template void btree

::internal_clear(node_type *node) { if (!node->leaf()) { for (int i = 0; i <= node->count(); ++i) { internal_clear(node->child(i)); } if (node == root()) { delete_internal_root_node(); } else { delete_internal_node(node); } } else { delete_leaf_node(node); } } template void btree

::internal_dump( std::ostream &os, const node_type *node, int level) const { for (int i = 0; i < node->count(); ++i) { if (!node->leaf()) { internal_dump(os, node->child(i), level + 1); } for (int j = 0; j < level; ++j) { os << " "; } os << node->key(i) << " [" << level << "]\n"; } if (!node->leaf()) { internal_dump(os, node->child(node->count()), level + 1); } } template int btree

::internal_verify( const node_type *node, const key_type *lo, const key_type *hi) const { assert(node->count() > 0); assert(node->count() <= node->max_count()); if (lo) { assert(!compare_keys(node->key(0), *lo)); } if (hi) { assert(!compare_keys(*hi, node->key(node->count() - 1))); } for (int i = 1; i < node->count(); ++i) { assert(!compare_keys(node->key(i), node->key(i - 1))); } int count = node->count(); if (!node->leaf()) { for (int i = 0; i <= node->count(); ++i) { assert(node->child(i) != NULL); assert(node->child(i)->parent() == node); assert(node->child(i)->position() == i); count += internal_verify( node->child(i), (i == 0) ? lo : &node->key(i - 1), (i == node->count()) ? hi : &node->key(i)); } } return count; } } // namespace btree #endif // UTIL_BTREE_BTREE_H__ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/btree_bench.cc ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include #include #include #include #include #include #include "gflags/gflags.h" #include "btree_map.h" #include "btree_set.h" #include "btree_test.h" DEFINE_int32(test_random_seed, 123456789, "Seed for srand()"); DEFINE_int32(benchmark_max_iters, 10000000, "Maximum test iterations"); DEFINE_int32(benchmark_min_iters, 100, "Minimum test iterations"); DEFINE_int32(benchmark_target_seconds, 1, "Attempt to benchmark for this many seconds"); using std::allocator; using std::less; using std::map; using std::max; using std::min; using std::multimap; using std::multiset; using std::set; using std::string; using std::vector; namespace btree { namespace { struct RandGen { typedef ptrdiff_t result_type; RandGen(result_type seed) { srand(seed); } result_type operator()(result_type l) { return rand() % l; } }; struct BenchmarkRun { BenchmarkRun(const char *name, void (*func)(int)); void Run(); void Stop(); void Start(); void Reset(); BenchmarkRun *next_benchmark; const char *benchmark_name; void (*benchmark_func)(int); int64_t accum_micros; int64_t last_started; }; BenchmarkRun *first_benchmark; BenchmarkRun *current_benchmark; int64_t get_micros () { timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000000 + tv.tv_usec; } BenchmarkRun::BenchmarkRun(const char *name, void (*func)(int)) : next_benchmark(first_benchmark), benchmark_name(name), benchmark_func(func), accum_micros(0), last_started(0) { first_benchmark = this; } #define BTREE_BENCHMARK(name) \ BTREE_BENCHMARK2(#name, name, __COUNTER__) #define BTREE_BENCHMARK2(name, func, counter) \ BTREE_BENCHMARK3(name, func, counter) #define BTREE_BENCHMARK3(name, func, counter) \ BenchmarkRun bench ## counter (name, func) void StopBenchmarkTiming() { current_benchmark->Stop(); } void StartBenchmarkTiming() { current_benchmark->Start(); } void RunBenchmarks() { for (BenchmarkRun *bench = first_benchmark; bench; bench = bench->next_benchmark) { bench->Run(); } } void BenchmarkRun::Start() { assert(!last_started); last_started = get_micros(); } void BenchmarkRun::Stop() { if (last_started == 0) { return; } accum_micros += get_micros() - last_started; last_started = 0; } void BenchmarkRun::Reset() { last_started = 0; accum_micros = 0; } void BenchmarkRun::Run() { assert(current_benchmark == NULL); current_benchmark = this; int iters = FLAGS_benchmark_min_iters; for (;;) { Reset(); Start(); benchmark_func(iters); Stop(); if (accum_micros > FLAGS_benchmark_target_seconds * 1000000 || iters >= FLAGS_benchmark_max_iters) { break; } else if (accum_micros == 0) { iters *= 100; } else { int64_t target_micros = FLAGS_benchmark_target_seconds * 1000000; iters = target_micros * iters / accum_micros; } iters = min(iters, FLAGS_benchmark_max_iters); } std::cout << benchmark_name << "\t" << accum_micros * 1000 / iters << "\t" << iters; current_benchmark = NULL; } // Used to avoid compiler optimizations for these benchmarks. template void sink(const T& t0) { volatile T t = t0; } // Benchmark insertion of values into a container. template void BM_Insert(int n) { typedef typename std::remove_const::type V; typename KeyOfValue::type key_of_value; // Disable timing while we perform some initialization. StopBenchmarkTiming(); T container; vector values = GenerateValues(FLAGS_benchmark_values); for (int i = 0; i < values.size(); i++) { container.insert(values[i]); } for (int i = 0; i < n; ) { // Remove and re-insert 10% of the keys int m = min(n - i, FLAGS_benchmark_values / 10); for (int j = i; j < i + m; j++) { int x = j % FLAGS_benchmark_values; container.erase(key_of_value(values[x])); } StartBenchmarkTiming(); for (int j = i; j < i + m; j++) { int x = j % FLAGS_benchmark_values; container.insert(values[x]); } StopBenchmarkTiming(); i += m; } } // Benchmark lookup of values in a container. template void BM_Lookup(int n) { typedef typename std::remove_const::type V; typename KeyOfValue::type key_of_value; // Disable timing while we perform some initialization. StopBenchmarkTiming(); T container; vector values = GenerateValues(FLAGS_benchmark_values); for (int i = 0; i < values.size(); i++) { container.insert(values[i]); } V r = V(); StartBenchmarkTiming(); for (int i = 0; i < n; i++) { int m = i % values.size(); r = *container.find(key_of_value(values[m])); } StopBenchmarkTiming(); sink(r); // Keep compiler from optimizing away r. } // Benchmark lookup of values in a full container, meaning that values // are inserted in-order to take advantage of biased insertion, which // yields a full tree. template void BM_FullLookup(int n) { typedef typename std::remove_const::type V; typename KeyOfValue::type key_of_value; // Disable timing while we perform some initialization. StopBenchmarkTiming(); T container; vector values = GenerateValues(FLAGS_benchmark_values); vector sorted(values); sort(sorted.begin(), sorted.end()); for (int i = 0; i < sorted.size(); i++) { container.insert(sorted[i]); } V r = V(); StartBenchmarkTiming(); for (int i = 0; i < n; i++) { int m = i % values.size(); r = *container.find(key_of_value(values[m])); } StopBenchmarkTiming(); sink(r); // Keep compiler from optimizing away r. } // Benchmark deletion of values from a container. template void BM_Delete(int n) { typedef typename std::remove_const::type V; typename KeyOfValue::type key_of_value; // Disable timing while we perform some initialization. StopBenchmarkTiming(); T container; vector values = GenerateValues(FLAGS_benchmark_values); for (int i = 0; i < values.size(); i++) { container.insert(values[i]); } for (int i = 0; i < n; ) { // Remove and re-insert 10% of the keys int m = min(n - i, FLAGS_benchmark_values / 10); StartBenchmarkTiming(); for (int j = i; j < i + m; j++) { int x = j % FLAGS_benchmark_values; container.erase(key_of_value(values[x])); } StopBenchmarkTiming(); for (int j = i; j < i + m; j++) { int x = j % FLAGS_benchmark_values; container.insert(values[x]); } i += m; } } // Benchmark steady-state insert (into first half of range) and remove // (from second second half of range), treating the container // approximately like a queue with log-time access for all elements. // This benchmark does not test the case where insertion and removal // happen in the same region of the tree. This benchmark counts two // value constructors. template void BM_QueueAddRem(int n) { typedef typename std::remove_const::type V; typename KeyOfValue::type key_of_value; // Disable timing while we perform some initialization. StopBenchmarkTiming(); assert(FLAGS_benchmark_values % 2 == 0); T container; const int half = FLAGS_benchmark_values / 2; vector remove_keys(half); vector add_keys(half); for (int i = 0; i < half; i++) { remove_keys[i] = i; add_keys[i] = i; } RandGen rand(FLAGS_test_random_seed); random_shuffle(remove_keys.begin(), remove_keys.end(), rand); random_shuffle(add_keys.begin(), add_keys.end(), rand); Generator g(FLAGS_benchmark_values + FLAGS_benchmark_max_iters); for (int i = 0; i < half; i++) { container.insert(g(add_keys[i])); container.insert(g(half + remove_keys[i])); } // There are three parts each of size "half": // 1 is being deleted from [offset - half, offset) // 2 is standing [offset, offset + half) // 3 is being inserted into [offset + half, offset + 2 * half) int offset = 0; StartBenchmarkTiming(); for (int i = 0; i < n; i++) { int idx = i % half; if (idx == 0) { StopBenchmarkTiming(); random_shuffle(remove_keys.begin(), remove_keys.end(), rand); random_shuffle(add_keys.begin(), add_keys.end(), rand); offset += half; StartBenchmarkTiming(); } int e = container.erase(key_of_value(g(offset - half + remove_keys[idx]))); assert(e == 1); container.insert(g(offset + half + add_keys[idx])); } StopBenchmarkTiming(); } // Mixed insertion and deletion in the same range using pre-constructed values. template void BM_MixedAddRem(int n) { typedef typename std::remove_const::type V; typename KeyOfValue::type key_of_value; // Disable timing while we perform some initialization. StopBenchmarkTiming(); assert(FLAGS_benchmark_values % 2 == 0); T container; RandGen rand(FLAGS_test_random_seed); vector values = GenerateValues(FLAGS_benchmark_values * 2); // Create two random shuffles vector remove_keys(FLAGS_benchmark_values); vector add_keys(FLAGS_benchmark_values); // Insert the first half of the values (already in random order) for (int i = 0; i < FLAGS_benchmark_values; i++) { container.insert(values[i]); // remove_keys and add_keys will be swapped before each round, // therefore fill add_keys here w/ the keys being inserted, so // they'll be the first to be removed. remove_keys[i] = i + FLAGS_benchmark_values; add_keys[i] = i; } StartBenchmarkTiming(); for (int i = 0; i < n; i++) { int idx = i % FLAGS_benchmark_values; if (idx == 0) { StopBenchmarkTiming(); remove_keys.swap(add_keys); random_shuffle(remove_keys.begin(), remove_keys.end(), rand); random_shuffle(add_keys.begin(), add_keys.end(), rand); StartBenchmarkTiming(); } int e = container.erase(key_of_value(values[remove_keys[idx]])); assert(e == 1); container.insert(values[add_keys[idx]]); } StopBenchmarkTiming(); } // Insertion at end, removal from the beginning. This benchmark // counts two value constructors. template void BM_Fifo(int n) { typedef typename std::remove_const::type V; // Disable timing while we perform some initialization. StopBenchmarkTiming(); T container; Generator g(FLAGS_benchmark_values + FLAGS_benchmark_max_iters); for (int i = 0; i < FLAGS_benchmark_values; i++) { container.insert(g(i)); } StartBenchmarkTiming(); for (int i = 0; i < n; i++) { container.erase(container.begin()); container.insert(container.end(), g(i + FLAGS_benchmark_values)); } StopBenchmarkTiming(); } // Iteration (forward) through the tree template void BM_FwdIter(int n) { typedef typename std::remove_const::type V; // Disable timing while we perform some initialization. StopBenchmarkTiming(); T container; vector values = GenerateValues(FLAGS_benchmark_values); for (int i = 0; i < FLAGS_benchmark_values; i++) { container.insert(values[i]); } typename T::iterator iter; V r = V(); StartBenchmarkTiming(); for (int i = 0; i < n; i++) { int idx = i % FLAGS_benchmark_values; if (idx == 0) { iter = container.begin(); } r = *iter; ++iter; } StopBenchmarkTiming(); sink(r); // Keep compiler from optimizing away r. } typedef set stl_set_int32; typedef set stl_set_int64; typedef set stl_set_string; typedef map stl_map_int32; typedef map stl_map_int64; typedef map stl_map_string; typedef multiset stl_multiset_int32; typedef multiset stl_multiset_int64; typedef multiset stl_multiset_string; typedef multimap stl_multimap_int32; typedef multimap stl_multimap_int64; typedef multimap stl_multimap_string; #define MY_BENCHMARK_TYPES2(value, name, size) \ typedef btree ## _set, allocator, size> \ btree ## _ ## size ## _set_ ## name; \ typedef btree ## _map, allocator, size> \ btree ## _ ## size ## _map_ ## name; \ typedef btree ## _multiset, allocator, size> \ btree ## _ ## size ## _multiset_ ## name; \ typedef btree ## _multimap, allocator, size> \ btree ## _ ## size ## _multimap_ ## name #define MY_BENCHMARK_TYPES(value, name) \ MY_BENCHMARK_TYPES2(value, name, 128); \ MY_BENCHMARK_TYPES2(value, name, 160); \ MY_BENCHMARK_TYPES2(value, name, 192); \ MY_BENCHMARK_TYPES2(value, name, 224); \ MY_BENCHMARK_TYPES2(value, name, 256); \ MY_BENCHMARK_TYPES2(value, name, 288); \ MY_BENCHMARK_TYPES2(value, name, 320); \ MY_BENCHMARK_TYPES2(value, name, 352); \ MY_BENCHMARK_TYPES2(value, name, 384); \ MY_BENCHMARK_TYPES2(value, name, 416); \ MY_BENCHMARK_TYPES2(value, name, 448); \ MY_BENCHMARK_TYPES2(value, name, 480); \ MY_BENCHMARK_TYPES2(value, name, 512); \ MY_BENCHMARK_TYPES2(value, name, 1024); \ MY_BENCHMARK_TYPES2(value, name, 1536); \ MY_BENCHMARK_TYPES2(value, name, 2048) MY_BENCHMARK_TYPES(int32_t, int32); MY_BENCHMARK_TYPES(int64_t, int64); MY_BENCHMARK_TYPES(string, string); #define MY_BENCHMARK4(type, name, func) \ void BM_ ## type ## _ ## name(int n) { BM_ ## func (n); } \ BTREE_BENCHMARK(BM_ ## type ## _ ## name) // Define NODESIZE_TESTING when running btree_perf.py. #ifdef NODESIZE_TESTING #define MY_BENCHMARK3(tree, type, name, func) \ MY_BENCHMARK4(tree ## _128_ ## type, name, func); \ MY_BENCHMARK4(tree ## _160_ ## type, name, func); \ MY_BENCHMARK4(tree ## _192_ ## type, name, func); \ MY_BENCHMARK4(tree ## _224_ ## type, name, func); \ MY_BENCHMARK4(tree ## _256_ ## type, name, func); \ MY_BENCHMARK4(tree ## _288_ ## type, name, func); \ MY_BENCHMARK4(tree ## _320_ ## type, name, func); \ MY_BENCHMARK4(tree ## _352_ ## type, name, func); \ MY_BENCHMARK4(tree ## _384_ ## type, name, func); \ MY_BENCHMARK4(tree ## _416_ ## type, name, func); \ MY_BENCHMARK4(tree ## _448_ ## type, name, func); \ MY_BENCHMARK4(tree ## _480_ ## type, name, func); \ MY_BENCHMARK4(tree ## _512_ ## type, name, func); \ MY_BENCHMARK4(tree ## _1024_ ## type, name, func); \ MY_BENCHMARK4(tree ## _1536_ ## type, name, func); \ MY_BENCHMARK4(tree ## _2048_ ## type, name, func) #else #define MY_BENCHMARK3(tree, type, name, func) \ MY_BENCHMARK4(tree ## _256_ ## type, name, func); \ MY_BENCHMARK4(tree ## _2048_ ## type, name, func) #endif #define MY_BENCHMARK2(type, name, func) \ MY_BENCHMARK4(stl_ ## type, name, func); \ MY_BENCHMARK3(btree, type, name, func) #define MY_BENCHMARK(type) \ MY_BENCHMARK2(type, insert, Insert); \ MY_BENCHMARK2(type, lookup, Lookup); \ MY_BENCHMARK2(type, fulllookup, FullLookup); \ MY_BENCHMARK2(type, delete, Delete); \ MY_BENCHMARK2(type, queueaddrem, QueueAddRem); \ MY_BENCHMARK2(type, mixedaddrem, MixedAddRem); \ MY_BENCHMARK2(type, fifo, Fifo); \ MY_BENCHMARK2(type, fwditer, FwdIter) MY_BENCHMARK(set_int32); MY_BENCHMARK(map_int32); MY_BENCHMARK(set_int64); MY_BENCHMARK(map_int64); MY_BENCHMARK(set_string); MY_BENCHMARK(map_string); MY_BENCHMARK(multiset_int32); MY_BENCHMARK(multimap_int32); MY_BENCHMARK(multiset_int64); MY_BENCHMARK(multimap_int64); MY_BENCHMARK(multiset_string); MY_BENCHMARK(multimap_string); } // namespace } // namespace btree int main(int argc, char **argv) { btree::RunBenchmarks(); return 0; } ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/btree_container.h ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef UTIL_BTREE_BTREE_CONTAINER_H__ #define UTIL_BTREE_BTREE_CONTAINER_H__ #include #include #include "btree.h" namespace btree { // A common base class for btree_set, btree_map, btree_multiset and // btree_multimap. template class btree_container { typedef btree_container self_type; public: typedef typename Tree::params_type params_type; typedef typename Tree::key_type key_type; typedef typename Tree::value_type value_type; typedef typename Tree::key_compare key_compare; typedef typename Tree::allocator_type allocator_type; typedef typename Tree::pointer pointer; typedef typename Tree::const_pointer const_pointer; typedef typename Tree::reference reference; typedef typename Tree::const_reference const_reference; typedef typename Tree::size_type size_type; typedef typename Tree::difference_type difference_type; typedef typename Tree::iterator iterator; typedef typename Tree::const_iterator const_iterator; typedef typename Tree::reverse_iterator reverse_iterator; typedef typename Tree::const_reverse_iterator const_reverse_iterator; public: // Default constructor. btree_container(const key_compare &comp, const allocator_type &alloc) : tree_(comp, alloc) { } // Copy constructor. btree_container(const self_type &x) : tree_(x.tree_) { } // Iterator routines. iterator begin() { return tree_.begin(); } const_iterator begin() const { return tree_.begin(); } iterator end() { return tree_.end(); } const_iterator end() const { return tree_.end(); } reverse_iterator rbegin() { return tree_.rbegin(); } const_reverse_iterator rbegin() const { return tree_.rbegin(); } reverse_iterator rend() { return tree_.rend(); } const_reverse_iterator rend() const { return tree_.rend(); } // Lookup routines. iterator lower_bound(const key_type &key) { return tree_.lower_bound(key); } const_iterator lower_bound(const key_type &key) const { return tree_.lower_bound(key); } iterator upper_bound(const key_type &key) { return tree_.upper_bound(key); } const_iterator upper_bound(const key_type &key) const { return tree_.upper_bound(key); } std::pair equal_range(const key_type &key) { return tree_.equal_range(key); } std::pair equal_range(const key_type &key) const { return tree_.equal_range(key); } // Utility routines. void clear() { tree_.clear(); } void swap(self_type &x) { tree_.swap(x.tree_); } void dump(std::ostream &os) const { tree_.dump(os); } void verify() const { tree_.verify(); } // Size routines. size_type size() const { return tree_.size(); } size_type max_size() const { return tree_.max_size(); } bool empty() const { return tree_.empty(); } size_type height() const { return tree_.height(); } size_type internal_nodes() const { return tree_.internal_nodes(); } size_type leaf_nodes() const { return tree_.leaf_nodes(); } size_type nodes() const { return tree_.nodes(); } size_type bytes_used() const { return tree_.bytes_used(); } static double average_bytes_per_value() { return Tree::average_bytes_per_value(); } double fullness() const { return tree_.fullness(); } double overhead() const { return tree_.overhead(); } bool operator==(const self_type& x) const { if (size() != x.size()) { return false; } for (const_iterator i = begin(), xi = x.begin(); i != end(); ++i, ++xi) { if (*i != *xi) { return false; } } return true; } bool operator!=(const self_type& other) const { return !operator==(other); } protected: Tree tree_; }; template inline std::ostream& operator<<(std::ostream &os, const btree_container &b) { b.dump(os); return os; } // A common base class for btree_set and safe_btree_set. template class btree_unique_container : public btree_container { typedef btree_unique_container self_type; typedef btree_container super_type; public: typedef typename Tree::key_type key_type; typedef typename Tree::value_type value_type; typedef typename Tree::size_type size_type; typedef typename Tree::key_compare key_compare; typedef typename Tree::allocator_type allocator_type; typedef typename Tree::iterator iterator; typedef typename Tree::const_iterator const_iterator; public: // Default constructor. btree_unique_container(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. btree_unique_container(const self_type &x) : super_type(x) { } // Range constructor. template btree_unique_container(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { insert(b, e); } // Lookup routines. iterator find(const key_type &key) { return this->tree_.find_unique(key); } const_iterator find(const key_type &key) const { return this->tree_.find_unique(key); } size_type count(const key_type &key) const { return this->tree_.count_unique(key); } // Insertion routines. std::pair insert(const value_type &x) { return this->tree_.insert_unique(x); } iterator insert(iterator position, const value_type &x) { return this->tree_.insert_unique(position, x); } template void insert(InputIterator b, InputIterator e) { this->tree_.insert_unique(b, e); } // Deletion routines. int erase(const key_type &key) { return this->tree_.erase_unique(key); } // Erase the specified iterator from the btree. The iterator must be valid // (i.e. not equal to end()). Return an iterator pointing to the node after // the one that was erased (or end() if none exists). iterator erase(const iterator &iter) { return this->tree_.erase(iter); } void erase(const iterator &first, const iterator &last) { this->tree_.erase(first, last); } }; // A common base class for btree_map and safe_btree_map. template class btree_map_container : public btree_unique_container { typedef btree_map_container self_type; typedef btree_unique_container super_type; public: typedef typename Tree::key_type key_type; typedef typename Tree::data_type data_type; typedef typename Tree::value_type value_type; typedef typename Tree::mapped_type mapped_type; typedef typename Tree::key_compare key_compare; typedef typename Tree::allocator_type allocator_type; private: // A pointer-like object which only generates its value when // dereferenced. Used by operator[] to avoid constructing an empty data_type // if the key already exists in the map. struct generate_value { generate_value(const key_type &k) : key(k) { } value_type operator*() const { return std::make_pair(key, data_type()); } const key_type &key; }; public: // Default constructor. btree_map_container(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. btree_map_container(const self_type &x) : super_type(x) { } // Range constructor. template btree_map_container(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(b, e, comp, alloc) { } // Insertion routines. data_type& operator[](const key_type &key) { return this->tree_.insert_unique(key, generate_value(key)).first->second; } }; // A common base class for btree_multiset and btree_multimap. template class btree_multi_container : public btree_container { typedef btree_multi_container self_type; typedef btree_container super_type; public: typedef typename Tree::key_type key_type; typedef typename Tree::value_type value_type; typedef typename Tree::size_type size_type; typedef typename Tree::key_compare key_compare; typedef typename Tree::allocator_type allocator_type; typedef typename Tree::iterator iterator; typedef typename Tree::const_iterator const_iterator; public: // Default constructor. btree_multi_container(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. btree_multi_container(const self_type &x) : super_type(x) { } // Range constructor. template btree_multi_container(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { insert(b, e); } // Lookup routines. iterator find(const key_type &key) { return this->tree_.find_multi(key); } const_iterator find(const key_type &key) const { return this->tree_.find_multi(key); } size_type count(const key_type &key) const { return this->tree_.count_multi(key); } // Insertion routines. iterator insert(const value_type &x) { return this->tree_.insert_multi(x); } iterator insert(iterator position, const value_type &x) { return this->tree_.insert_multi(position, x); } template void insert(InputIterator b, InputIterator e) { this->tree_.insert_multi(b, e); } // Deletion routines. int erase(const key_type &key) { return this->tree_.erase_multi(key); } // Erase the specified iterator from the btree. The iterator must be valid // (i.e. not equal to end()). Return an iterator pointing to the node after // the one that was erased (or end() if none exists). iterator erase(const iterator &iter) { return this->tree_.erase(iter); } void erase(const iterator &first, const iterator &last) { this->tree_.erase(first, last); } }; } // namespace btree #endif // UTIL_BTREE_BTREE_CONTAINER_H__ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/btree_map.h ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // A btree_map<> implements the STL unique sorted associative container // interface and the pair associative container interface (a.k.a map<>) using a // btree. A btree_multimap<> implements the STL multiple sorted associative // container interface and the pair associtive container interface (a.k.a // multimap<>) using a btree. See btree.h for details of the btree // implementation and caveats. #ifndef UTIL_BTREE_BTREE_MAP_H__ #define UTIL_BTREE_BTREE_MAP_H__ #include #include #include #include #include #include "btree.h" #include "btree_container.h" namespace btree { // The btree_map class is needed mainly for its constructors. template , typename Alloc = std::allocator >, int TargetNodeSize = 256> class btree_map : public btree_map_container< btree > > { typedef btree_map self_type; typedef btree_map_params< Key, Value, Compare, Alloc, TargetNodeSize> params_type; typedef btree btree_type; typedef btree_map_container super_type; public: typedef typename btree_type::key_compare key_compare; typedef typename btree_type::allocator_type allocator_type; public: // Default constructor. btree_map(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. btree_map(const self_type &x) : super_type(x) { } // Range constructor. template btree_map(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(b, e, comp, alloc) { } }; template inline void swap(btree_map &x, btree_map &y) { x.swap(y); } // The btree_multimap class is needed mainly for its constructors. template , typename Alloc = std::allocator >, int TargetNodeSize = 256> class btree_multimap : public btree_multi_container< btree > > { typedef btree_multimap self_type; typedef btree_map_params< Key, Value, Compare, Alloc, TargetNodeSize> params_type; typedef btree btree_type; typedef btree_multi_container super_type; public: typedef typename btree_type::key_compare key_compare; typedef typename btree_type::allocator_type allocator_type; typedef typename btree_type::data_type data_type; typedef typename btree_type::mapped_type mapped_type; public: // Default constructor. btree_multimap(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. btree_multimap(const self_type &x) : super_type(x) { } // Range constructor. template btree_multimap(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(b, e, comp, alloc) { } }; template inline void swap(btree_multimap &x, btree_multimap &y) { x.swap(y); } } // namespace btree #endif // UTIL_BTREE_BTREE_MAP_H__ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/btree_set.h ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // A btree_set<> implements the STL unique sorted associative container // interface (a.k.a set<>) using a btree. A btree_multiset<> implements the STL // multiple sorted associative container interface (a.k.a multiset<>) using a // btree. See btree.h for details of the btree implementation and caveats. #ifndef UTIL_BTREE_BTREE_SET_H__ #define UTIL_BTREE_BTREE_SET_H__ #include #include #include #include "btree.h" #include "btree_container.h" namespace btree { // The btree_set class is needed mainly for its constructors. template , typename Alloc = std::allocator, int TargetNodeSize = 256> class btree_set : public btree_unique_container< btree > > { typedef btree_set self_type; typedef btree_set_params params_type; typedef btree btree_type; typedef btree_unique_container super_type; public: typedef typename btree_type::key_compare key_compare; typedef typename btree_type::allocator_type allocator_type; public: // Default constructor. btree_set(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. btree_set(const self_type &x) : super_type(x) { } // Range constructor. template btree_set(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(b, e, comp, alloc) { } }; template inline void swap(btree_set &x, btree_set &y) { x.swap(y); } // The btree_multiset class is needed mainly for its constructors. template , typename Alloc = std::allocator, int TargetNodeSize = 256> class btree_multiset : public btree_multi_container< btree > > { typedef btree_multiset self_type; typedef btree_set_params params_type; typedef btree btree_type; typedef btree_multi_container super_type; public: typedef typename btree_type::key_compare key_compare; typedef typename btree_type::allocator_type allocator_type; public: // Default constructor. btree_multiset(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. btree_multiset(const self_type &x) : super_type(x) { } // Range constructor. template btree_multiset(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(b, e, comp, alloc) { } }; template inline void swap(btree_multiset &x, btree_multiset &y) { x.swap(y); } } // namespace btree #endif // UTIL_BTREE_BTREE_SET_H__ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/btree_test.cc ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "gtest/gtest.h" #include "btree_map.h" #include "btree_set.h" #include "btree_test.h" namespace btree { namespace { template void SetTest() { typedef TestAllocator TestAlloc; ASSERT_EQ(sizeof(btree_set), sizeof(void*)); BtreeTest, std::allocator, N>, std::set >(); BtreeAllocatorTest, TestAlloc, N> >(); } template void MapTest() { typedef TestAllocator TestAlloc; ASSERT_EQ(sizeof(btree_map), sizeof(void*)); BtreeTest, std::allocator, N>, std::map >(); BtreeAllocatorTest, TestAlloc, N> >(); BtreeMapTest, std::allocator, N> >(); } TEST(Btree, set_int32_32) { SetTest(); } TEST(Btree, set_int32_64) { SetTest(); } TEST(Btree, set_int32_128) { SetTest(); } TEST(Btree, set_int32_256) { SetTest(); } TEST(Btree, set_int64_256) { SetTest(); } TEST(Btree, set_string_256) { SetTest(); } TEST(Btree, set_pair_256) { SetTest, 256>(); } TEST(Btree, map_int32_256) { MapTest(); } TEST(Btree, map_int64_256) { MapTest(); } TEST(Btree, map_string_256) { MapTest(); } TEST(Btree, map_pair_256) { MapTest, 256>(); } // Large-node tests TEST(Btree, map_int32_1024) { MapTest(); } TEST(Btree, map_int32_1032) { MapTest(); } TEST(Btree, map_int32_1040) { MapTest(); } TEST(Btree, map_int32_1048) { MapTest(); } TEST(Btree, map_int32_1056) { MapTest(); } TEST(Btree, map_int32_2048) { MapTest(); } TEST(Btree, map_int32_4096) { MapTest(); } TEST(Btree, set_int32_1024) { SetTest(); } TEST(Btree, set_int32_2048) { SetTest(); } TEST(Btree, set_int32_4096) { SetTest(); } TEST(Btree, map_string_1024) { MapTest(); } TEST(Btree, map_string_2048) { MapTest(); } TEST(Btree, map_string_4096) { MapTest(); } TEST(Btree, set_string_1024) { SetTest(); } TEST(Btree, set_string_2048) { SetTest(); } TEST(Btree, set_string_4096) { SetTest(); } template void MultiSetTest() { typedef TestAllocator TestAlloc; ASSERT_EQ(sizeof(btree_multiset), sizeof(void*)); BtreeMultiTest, std::allocator, N>, std::multiset >(); BtreeAllocatorTest, TestAlloc, N> >(); } template void MultiMapTest() { typedef TestAllocator TestAlloc; ASSERT_EQ(sizeof(btree_multimap), sizeof(void*)); BtreeMultiTest, std::allocator, N>, std::multimap >(); BtreeMultiMapTest, std::allocator, N> >(); BtreeAllocatorTest, TestAlloc, N> >(); } TEST(Btree, multiset_int32_256) { MultiSetTest(); } TEST(Btree, multiset_int64_256) { MultiSetTest(); } TEST(Btree, multiset_string_256) { MultiSetTest(); } TEST(Btree, multiset_pair_256) { MultiSetTest, 256>(); } TEST(Btree, multimap_int32_256) { MultiMapTest(); } TEST(Btree, multimap_int64_256) { MultiMapTest(); } TEST(Btree, multimap_string_256) { MultiMapTest(); } TEST(Btree, multimap_pair_256) { MultiMapTest, 256>(); } // Large-node tests TEST(Btree, multimap_int32_1024) { MultiMapTest(); } TEST(Btree, multimap_int32_2048) { MultiMapTest(); } TEST(Btree, multimap_int32_4096) { MultiMapTest(); } TEST(Btree, multiset_int32_1024) { MultiSetTest(); } TEST(Btree, multiset_int32_2048) { MultiSetTest(); } TEST(Btree, multiset_int32_4096) { MultiSetTest(); } TEST(Btree, multimap_string_1024) { MultiMapTest(); } TEST(Btree, multimap_string_2048) { MultiMapTest(); } TEST(Btree, multimap_string_4096) { MultiMapTest(); } TEST(Btree, multiset_string_1024) { MultiSetTest(); } TEST(Btree, multiset_string_2048) { MultiSetTest(); } TEST(Btree, multiset_string_4096) { MultiSetTest(); } // Verify that swapping btrees swaps the key comparision functors. struct SubstringLess { SubstringLess() : n(2) {} SubstringLess(size_t length) : n(length) { } bool operator()(const std::string &a, const std::string &b) const { std::string as(a.data(), std::min(n, a.size())); std::string bs(b.data(), std::min(n, b.size())); return as < bs; } size_t n; }; TEST(Btree, SwapKeyCompare) { typedef btree_set SubstringSet; SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type()); SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type()); ASSERT_TRUE(s1.insert("a").second); ASSERT_FALSE(s1.insert("aa").second); ASSERT_TRUE(s2.insert("a").second); ASSERT_TRUE(s2.insert("aa").second); ASSERT_FALSE(s2.insert("aaa").second); swap(s1, s2); ASSERT_TRUE(s1.insert("b").second); ASSERT_TRUE(s1.insert("bb").second); ASSERT_FALSE(s1.insert("bbb").second); ASSERT_TRUE(s2.insert("b").second); ASSERT_FALSE(s2.insert("bb").second); } TEST(Btree, UpperBoundRegression) { // Regress a bug where upper_bound would default-construct a new key_compare // instead of copying the existing one. typedef btree_set SubstringSet; SubstringSet my_set(SubstringLess(3)); my_set.insert("aab"); my_set.insert("abb"); // We call upper_bound("aaa"). If this correctly uses the length 3 // comparator, aaa < aab < abb, so we should get aab as the result. // If it instead uses the default-constructed length 2 comparator, // aa == aa < ab, so we'll get abb as our result. SubstringSet::iterator it = my_set.upper_bound("aaa"); ASSERT_TRUE(it != my_set.end()); EXPECT_EQ("aab", *it); } TEST(Btree, IteratorIncrementBy) { // Test that increment_by returns the same position as increment. const int kSetSize = 2341; btree_set my_set; for (int i = 0; i < kSetSize; ++i) { my_set.insert(i); } { // Simple increment vs. increment by. btree_set::iterator a = my_set.begin(); btree_set::iterator b = my_set.begin(); a.increment(); b.increment_by(1); EXPECT_EQ(*a, *b); } btree_set::iterator a = my_set.begin(); for (int i = 1; i < kSetSize; ++i) { ++a; // increment_by btree_set::iterator b = my_set.begin(); b.increment_by(i); EXPECT_EQ(*a, *b) << ": i=" << i; } } TEST(Btree, Comparison) { const int kSetSize = 1201; btree_set my_set; for (int i = 0; i < kSetSize; ++i) { my_set.insert(i); } btree_set my_set_copy(my_set); EXPECT_TRUE(my_set_copy == my_set); EXPECT_TRUE(my_set == my_set_copy); EXPECT_FALSE(my_set_copy != my_set); EXPECT_FALSE(my_set != my_set_copy); my_set.insert(kSetSize); EXPECT_FALSE(my_set_copy == my_set); EXPECT_FALSE(my_set == my_set_copy); EXPECT_TRUE(my_set_copy != my_set); EXPECT_TRUE(my_set != my_set_copy); my_set.erase(kSetSize - 1); EXPECT_FALSE(my_set_copy == my_set); EXPECT_FALSE(my_set == my_set_copy); EXPECT_TRUE(my_set_copy != my_set); EXPECT_TRUE(my_set != my_set_copy); btree_map my_map; for (int i = 0; i < kSetSize; ++i) { my_map[std::string(i, 'a')] = i; } btree_map my_map_copy(my_map); EXPECT_TRUE(my_map_copy == my_map); EXPECT_TRUE(my_map == my_map_copy); EXPECT_FALSE(my_map_copy != my_map); EXPECT_FALSE(my_map != my_map_copy); ++my_map_copy[std::string(7, 'a')]; EXPECT_FALSE(my_map_copy == my_map); EXPECT_FALSE(my_map == my_map_copy); EXPECT_TRUE(my_map_copy != my_map); EXPECT_TRUE(my_map != my_map_copy); my_map_copy = my_map; my_map["hello"] = kSetSize; EXPECT_FALSE(my_map_copy == my_map); EXPECT_FALSE(my_map == my_map_copy); EXPECT_TRUE(my_map_copy != my_map); EXPECT_TRUE(my_map != my_map_copy); my_map.erase(std::string(kSetSize - 1, 'a')); EXPECT_FALSE(my_map_copy == my_map); EXPECT_FALSE(my_map == my_map_copy); EXPECT_TRUE(my_map_copy != my_map); EXPECT_TRUE(my_map != my_map_copy); } TEST(Btree, RangeCtorSanity) { typedef btree_set, std::allocator, 256> test_set; typedef btree_map, std::allocator, 256> test_map; typedef btree_multiset, std::allocator, 256> test_mset; typedef btree_multimap, std::allocator, 256> test_mmap; std::vector ivec; ivec.push_back(1); std::map imap; imap.insert(std::make_pair(1, 2)); test_mset tmset(ivec.begin(), ivec.end()); test_mmap tmmap(imap.begin(), imap.end()); test_set tset(ivec.begin(), ivec.end()); test_map tmap(imap.begin(), imap.end()); EXPECT_EQ(1, tmset.size()); EXPECT_EQ(1, tmmap.size()); EXPECT_EQ(1, tset.size()); EXPECT_EQ(1, tmap.size()); } } // namespace } // namespace btree ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/btree_test.h ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef UTIL_BTREE_BTREE_TEST_H__ #define UTIL_BTREE_BTREE_TEST_H__ #include #include #include #include #include #include #include #include #include #include #include #include "gtest/gtest.h" #include "gflags/gflags.h" #include "btree_container.h" DECLARE_int32(test_values); DECLARE_int32(benchmark_values); namespace std { // Provide operator<< support for std::pair. template ostream& operator<<(ostream &os, const std::pair &p) { os << "(" << p.first << "," << p.second << ")"; return os; } // Provide pair equality testing that works as long as x.first is comparable to // y.first and x.second is comparable to y.second. Needed in the test for // comparing std::pair to std::pair. template bool operator==(const std::pair &x, const std::pair &y) { return x.first == y.first && x.second == y.second; } // Partial specialization of remove_const that propagates the removal through // std::pair. template struct remove_const > { typedef pair::type, typename remove_const::type> type; }; } // namespace std namespace btree { // Select the first member of a pair. template struct select1st : public std::unary_function<_Pair, typename _Pair::first_type> { const typename _Pair::first_type& operator()(const _Pair& __x) const { return __x.first; } }; // Utility class to provide an accessor for a key given a value. The default // behavior is to treat the value as a pair and return the first element. template struct KeyOfValue { typedef select1st type; }; template struct identity { inline const T& operator()(const T& t) const { return t; } }; // Partial specialization of KeyOfValue class for when the key and value are // the same type such as in set<> and btree_set<>. template struct KeyOfValue { typedef identity type; }; // Counts the number of occurances of "c" in a buffer. inline ptrdiff_t strcount(const char* buf_begin, const char* buf_end, char c) { if (buf_begin == NULL) return 0; if (buf_end <= buf_begin) return 0; ptrdiff_t num = 0; for (const char* bp = buf_begin; bp != buf_end; bp++) { if (*bp == c) num++; } return num; } // for when the string is not null-terminated. inline ptrdiff_t strcount(const char* buf, size_t len, char c) { return strcount(buf, buf + len, c); } inline ptrdiff_t strcount(const std::string& buf, char c) { return strcount(buf.c_str(), buf.size(), c); } // The base class for a sorted associative container checker. TreeType is the // container type to check and CheckerType is the container type to check // against. TreeType is expected to be btree_{set,map,multiset,multimap} and // CheckerType is expected to be {set,map,multiset,multimap}. template class base_checker { typedef base_checker self_type; public: typedef typename TreeType::key_type key_type; typedef typename TreeType::value_type value_type; typedef typename TreeType::key_compare key_compare; typedef typename TreeType::pointer pointer; typedef typename TreeType::const_pointer const_pointer; typedef typename TreeType::reference reference; typedef typename TreeType::const_reference const_reference; typedef typename TreeType::size_type size_type; typedef typename TreeType::difference_type difference_type; typedef typename TreeType::iterator iterator; typedef typename TreeType::const_iterator const_iterator; typedef typename TreeType::reverse_iterator reverse_iterator; typedef typename TreeType::const_reverse_iterator const_reverse_iterator; public: // Default constructor. base_checker() : const_tree_(tree_) { } // Copy constructor. base_checker(const self_type &x) : tree_(x.tree_), const_tree_(tree_), checker_(x.checker_) { } // Range constructor. template base_checker(InputIterator b, InputIterator e) : tree_(b, e), const_tree_(tree_), checker_(b, e) { } // Iterator routines. iterator begin() { return tree_.begin(); } const_iterator begin() const { return tree_.begin(); } iterator end() { return tree_.end(); } const_iterator end() const { return tree_.end(); } reverse_iterator rbegin() { return tree_.rbegin(); } const_reverse_iterator rbegin() const { return tree_.rbegin(); } reverse_iterator rend() { return tree_.rend(); } const_reverse_iterator rend() const { return tree_.rend(); } // Helper routines. template IterType iter_check( IterType tree_iter, CheckerIterType checker_iter) const { if (tree_iter == tree_.end()) { EXPECT_EQ(checker_iter, checker_.end()); } else { EXPECT_EQ(*tree_iter, *checker_iter); } return tree_iter; } template IterType riter_check( IterType tree_iter, CheckerIterType checker_iter) const { if (tree_iter == tree_.rend()) { EXPECT_EQ(checker_iter, checker_.rend()); } else { EXPECT_EQ(*tree_iter, *checker_iter); } return tree_iter; } void value_check(const value_type &x) { typename KeyOfValue::type key_of_value; const key_type &key = key_of_value(x); EXPECT_EQ(*find(key), x); lower_bound(key); upper_bound(key); equal_range(key); count(key); } void erase_check(const key_type &key) { EXPECT_TRUE(tree_.find(key) == const_tree_.end()); EXPECT_TRUE(const_tree_.find(key) == tree_.end()); EXPECT_TRUE(tree_.equal_range(key).first == const_tree_.equal_range(key).second); } // Lookup routines. iterator lower_bound(const key_type &key) { return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); } const_iterator lower_bound(const key_type &key) const { return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); } iterator upper_bound(const key_type &key) { return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); } const_iterator upper_bound(const key_type &key) const { return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); } std::pair equal_range(const key_type &key) { std::pair checker_res = checker_.equal_range(key); std::pair tree_res = tree_.equal_range(key); iter_check(tree_res.first, checker_res.first); iter_check(tree_res.second, checker_res.second); return tree_res; } std::pair equal_range(const key_type &key) const { std::pair checker_res = checker_.equal_range(key); std::pair tree_res = tree_.equal_range(key); iter_check(tree_res.first, checker_res.first); iter_check(tree_res.second, checker_res.second); return tree_res; } iterator find(const key_type &key) { return iter_check(tree_.find(key), checker_.find(key)); } const_iterator find(const key_type &key) const { return iter_check(tree_.find(key), checker_.find(key)); } size_type count(const key_type &key) const { size_type res = checker_.count(key); EXPECT_EQ(res, tree_.count(key)); return res; } // Assignment operator. self_type& operator=(const self_type &x) { tree_ = x.tree_; checker_ = x.checker_; return *this; } // Deletion routines. int erase(const key_type &key) { int size = tree_.size(); int res = checker_.erase(key); EXPECT_EQ(res, tree_.count(key)); EXPECT_EQ(res, tree_.erase(key)); EXPECT_EQ(tree_.count(key), 0); EXPECT_EQ(tree_.size(), size - res); erase_check(key); return res; } iterator erase(iterator iter) { key_type key = iter.key(); int size = tree_.size(); int count = tree_.count(key); typename CheckerType::iterator checker_iter = checker_.find(key); for (iterator tmp(tree_.find(key)); tmp != iter; ++tmp) { ++checker_iter; } typename CheckerType::iterator checker_next = checker_iter; ++checker_next; checker_.erase(checker_iter); iter = tree_.erase(iter); EXPECT_EQ(tree_.size(), checker_.size()); EXPECT_EQ(tree_.size(), size - 1); EXPECT_EQ(tree_.count(key), count - 1); if (count == 1) { erase_check(key); } return iter_check(iter, checker_next); } void erase(iterator begin, iterator end) { int size = tree_.size(); int count = distance(begin, end); typename CheckerType::iterator checker_begin = checker_.find(begin.key()); for (iterator tmp(tree_.find(begin.key())); tmp != begin; ++tmp) { ++checker_begin; } typename CheckerType::iterator checker_end = end == tree_.end() ? checker_.end() : checker_.find(end.key()); if (end != tree_.end()) { for (iterator tmp(tree_.find(end.key())); tmp != end; ++tmp) { ++checker_end; } } checker_.erase(checker_begin, checker_end); tree_.erase(begin, end); EXPECT_EQ(tree_.size(), checker_.size()); EXPECT_EQ(tree_.size(), size - count); } // Utility routines. void clear() { tree_.clear(); checker_.clear(); } void swap(self_type &x) { tree_.swap(x.tree_); checker_.swap(x.checker_); } void verify() const { tree_.verify(); EXPECT_EQ(tree_.size(), checker_.size()); // Move through the forward iterators using increment. typename CheckerType::const_iterator checker_iter(checker_.begin()); const_iterator tree_iter(tree_.begin()); for (; tree_iter != tree_.end(); ++tree_iter, ++checker_iter) { EXPECT_EQ(*tree_iter, *checker_iter); } // Move through the forward iterators using decrement. for (int n = tree_.size() - 1; n >= 0; --n) { iter_check(tree_iter, checker_iter); --tree_iter; --checker_iter; } EXPECT_TRUE(tree_iter == tree_.begin()); EXPECT_TRUE(checker_iter == checker_.begin()); // Move through the reverse iterators using increment. typename CheckerType::const_reverse_iterator checker_riter(checker_.rbegin()); const_reverse_iterator tree_riter(tree_.rbegin()); for (; tree_riter != tree_.rend(); ++tree_riter, ++checker_riter) { EXPECT_EQ(*tree_riter, *checker_riter); } // Move through the reverse iterators using decrement. for (int n = tree_.size() - 1; n >= 0; --n) { riter_check(tree_riter, checker_riter); --tree_riter; --checker_riter; } EXPECT_EQ(tree_riter, tree_.rbegin()); EXPECT_EQ(checker_riter, checker_.rbegin()); } // Access to the underlying btree. const TreeType& tree() const { return tree_; } // Size routines. size_type size() const { EXPECT_EQ(tree_.size(), checker_.size()); return tree_.size(); } size_type max_size() const { return tree_.max_size(); } bool empty() const { EXPECT_EQ(tree_.empty(), checker_.empty()); return tree_.empty(); } size_type height() const { return tree_.height(); } size_type internal_nodes() const { return tree_.internal_nodes(); } size_type leaf_nodes() const { return tree_.leaf_nodes(); } size_type nodes() const { return tree_.nodes(); } size_type bytes_used() const { return tree_.bytes_used(); } double fullness() const { return tree_.fullness(); } double overhead() const { return tree_.overhead(); } protected: TreeType tree_; const TreeType &const_tree_; CheckerType checker_; }; // A checker for unique sorted associative containers. TreeType is expected to // be btree_{set,map} and CheckerType is expected to be {set,map}. template class unique_checker : public base_checker { typedef base_checker super_type; typedef unique_checker self_type; public: typedef typename super_type::iterator iterator; typedef typename super_type::value_type value_type; public: // Default constructor. unique_checker() : super_type() { } // Copy constructor. unique_checker(const self_type &x) : super_type(x) { } // Range constructor. template unique_checker(InputIterator b, InputIterator e) : super_type(b, e) { } // Insertion routines. std::pair insert(const value_type &x) { int size = this->tree_.size(); std::pair checker_res = this->checker_.insert(x); std::pair tree_res = this->tree_.insert(x); EXPECT_EQ(*tree_res.first, *checker_res.first); EXPECT_EQ(tree_res.second, checker_res.second); EXPECT_EQ(this->tree_.size(), this->checker_.size()); EXPECT_EQ(this->tree_.size(), size + tree_res.second); return tree_res; } iterator insert(iterator position, const value_type &x) { int size = this->tree_.size(); std::pair checker_res = this->checker_.insert(x); iterator tree_res = this->tree_.insert(position, x); EXPECT_EQ(*tree_res, *checker_res.first); EXPECT_EQ(this->tree_.size(), this->checker_.size()); EXPECT_EQ(this->tree_.size(), size + checker_res.second); return tree_res; } template void insert(InputIterator b, InputIterator e) { for (; b != e; ++b) { insert(*b); } } }; // A checker for multiple sorted associative containers. TreeType is expected // to be btree_{multiset,multimap} and CheckerType is expected to be // {multiset,multimap}. template class multi_checker : public base_checker { typedef base_checker super_type; typedef multi_checker self_type; public: typedef typename super_type::iterator iterator; typedef typename super_type::value_type value_type; public: // Default constructor. multi_checker() : super_type() { } // Copy constructor. multi_checker(const self_type &x) : super_type(x) { } // Range constructor. template multi_checker(InputIterator b, InputIterator e) : super_type(b, e) { } // Insertion routines. iterator insert(const value_type &x) { int size = this->tree_.size(); typename CheckerType::iterator checker_res = this->checker_.insert(x); iterator tree_res = this->tree_.insert(x); EXPECT_EQ(*tree_res, *checker_res); EXPECT_EQ(this->tree_.size(), this->checker_.size()); EXPECT_EQ(this->tree_.size(), size + 1); return tree_res; } iterator insert(iterator position, const value_type &x) { int size = this->tree_.size(); typename CheckerType::iterator checker_res = this->checker_.insert(x); iterator tree_res = this->tree_.insert(position, x); EXPECT_EQ(*tree_res, *checker_res); EXPECT_EQ(this->tree_.size(), this->checker_.size()); EXPECT_EQ(this->tree_.size(), size + 1); return tree_res; } template void insert(InputIterator b, InputIterator e) { for (; b != e; ++b) { insert(*b); } } }; char* GenerateDigits(char buf[16], int val, int maxval) { EXPECT_LE(val, maxval); int p = 15; buf[p--] = 0; while (maxval > 0) { buf[p--] = '0' + (val % 10); val /= 10; maxval /= 10; } return buf + p + 1; } template struct Generator { int maxval; Generator(int m) : maxval(m) { } K operator()(int i) const { EXPECT_LE(i, maxval); return i; } }; template <> struct Generator { int maxval; Generator(int m) : maxval(m) { } std::string operator()(int i) const { char buf[16]; return GenerateDigits(buf, i, maxval); } }; template struct Generator > { Generator::type> tgen; Generator::type> ugen; Generator(int m) : tgen(m), ugen(m) { } std::pair operator()(int i) const { return std::make_pair(tgen(i), ugen(i)); } }; // Generate values for our tests and benchmarks. Value range is [0, maxval]. const std::vector& GenerateNumbers(int n, int maxval) { static std::vector values; static std::set unique_values; if (values.size() < n) { for (int i = values.size(); i < n; i++) { int value; do { value = rand() % (maxval + 1); } while (unique_values.find(value) != unique_values.end()); values.push_back(value); unique_values.insert(value); } } return values; } // Generates values in the range // [0, 4 * min(FLAGS_benchmark_values, FLAGS_test_values)] template std::vector GenerateValues(int n) { int two_times_max = 2 * std::max(FLAGS_benchmark_values, FLAGS_test_values); int four_times_max = 2 * two_times_max; EXPECT_LE(n, two_times_max); const std::vector &nums = GenerateNumbers(n, four_times_max); Generator gen(four_times_max); std::vector vec; for (int i = 0; i < n; i++) { vec.push_back(gen(nums[i])); } return vec; } template void DoTest(const char *name, T *b, const std::vector &values) { typename KeyOfValue::type key_of_value; T &mutable_b = *b; const T &const_b = *b; // Test insert. for (int i = 0; i < values.size(); ++i) { mutable_b.insert(values[i]); mutable_b.value_check(values[i]); } assert(mutable_b.size() == values.size()); const_b.verify(); printf(" %s fullness=%0.2f overhead=%0.2f bytes-per-value=%0.2f\n", name, const_b.fullness(), const_b.overhead(), double(const_b.bytes_used()) / const_b.size()); // Test copy constructor. T b_copy(const_b); EXPECT_EQ(b_copy.size(), const_b.size()); EXPECT_LE(b_copy.height(), const_b.height()); EXPECT_LE(b_copy.internal_nodes(), const_b.internal_nodes()); EXPECT_LE(b_copy.leaf_nodes(), const_b.leaf_nodes()); for (int i = 0; i < values.size(); ++i) { EXPECT_EQ(*b_copy.find(key_of_value(values[i])), values[i]); } // Test range constructor. T b_range(const_b.begin(), const_b.end()); EXPECT_EQ(b_range.size(), const_b.size()); EXPECT_LE(b_range.height(), const_b.height()); EXPECT_LE(b_range.internal_nodes(), const_b.internal_nodes()); EXPECT_LE(b_range.leaf_nodes(), const_b.leaf_nodes()); for (int i = 0; i < values.size(); ++i) { EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]); } // Test range insertion for values that already exist. b_range.insert(b_copy.begin(), b_copy.end()); b_range.verify(); // Test range insertion for new values. b_range.clear(); b_range.insert(b_copy.begin(), b_copy.end()); EXPECT_EQ(b_range.size(), b_copy.size()); EXPECT_EQ(b_range.height(), b_copy.height()); EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes()); EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes()); for (int i = 0; i < values.size(); ++i) { EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]); } // Test assignment to self. Nothing should change. b_range.operator=(b_range); EXPECT_EQ(b_range.size(), b_copy.size()); EXPECT_EQ(b_range.height(), b_copy.height()); EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes()); EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes()); // Test assignment of new values. b_range.clear(); b_range = b_copy; EXPECT_EQ(b_range.size(), b_copy.size()); EXPECT_EQ(b_range.height(), b_copy.height()); EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes()); EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes()); // Test swap. b_range.clear(); b_range.swap(b_copy); EXPECT_EQ(b_copy.size(), 0); EXPECT_EQ(b_range.size(), const_b.size()); for (int i = 0; i < values.size(); ++i) { EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]); } b_range.swap(b_copy); // Test erase via values. for (int i = 0; i < values.size(); ++i) { mutable_b.erase(key_of_value(values[i])); // Erasing a non-existent key should have no effect. EXPECT_EQ(mutable_b.erase(key_of_value(values[i])), 0); } const_b.verify(); EXPECT_EQ(const_b.internal_nodes(), 0); EXPECT_EQ(const_b.leaf_nodes(), 0); EXPECT_EQ(const_b.size(), 0); // Test erase via iterators. mutable_b = b_copy; for (int i = 0; i < values.size(); ++i) { mutable_b.erase(mutable_b.find(key_of_value(values[i]))); } const_b.verify(); EXPECT_EQ(const_b.internal_nodes(), 0); EXPECT_EQ(const_b.leaf_nodes(), 0); EXPECT_EQ(const_b.size(), 0); // Test insert with hint. for (int i = 0; i < values.size(); i++) { mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]); } const_b.verify(); // Test dumping of the btree to an ostream. There should be 1 line for each // value. std::stringstream strm; strm << mutable_b.tree(); EXPECT_EQ(mutable_b.size(), strcount(strm.str(), '\n')); // Test range erase. mutable_b.erase(mutable_b.begin(), mutable_b.end()); EXPECT_EQ(mutable_b.size(), 0); const_b.verify(); // First half. mutable_b = b_copy; typename T::iterator mutable_iter_end = mutable_b.begin(); for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end; mutable_b.erase(mutable_b.begin(), mutable_iter_end); EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2); const_b.verify(); // Second half. mutable_b = b_copy; typename T::iterator mutable_iter_begin = mutable_b.begin(); for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin; mutable_b.erase(mutable_iter_begin, mutable_b.end()); EXPECT_EQ(mutable_b.size(), values.size() / 2); const_b.verify(); // Second quarter. mutable_b = b_copy; mutable_iter_begin = mutable_b.begin(); for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin; mutable_iter_end = mutable_iter_begin; for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end; mutable_b.erase(mutable_iter_begin, mutable_iter_end); EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4); const_b.verify(); mutable_b.clear(); } template void ConstTest() { typedef typename T::value_type value_type; typename KeyOfValue::type key_of_value; T mutable_b; const T &const_b = mutable_b; // Insert a single value into the container and test looking it up. value_type value = Generator(2)(2); mutable_b.insert(value); EXPECT_TRUE(mutable_b.find(key_of_value(value)) != const_b.end()); EXPECT_TRUE(const_b.find(key_of_value(value)) != mutable_b.end()); EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value); EXPECT_TRUE(const_b.upper_bound(key_of_value(value)) == const_b.end()); EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value); // We can only create a non-const iterator from a non-const container. typename T::iterator mutable_iter(mutable_b.begin()); EXPECT_TRUE(mutable_iter == const_b.begin()); EXPECT_TRUE(mutable_iter != const_b.end()); EXPECT_TRUE(const_b.begin() == mutable_iter); EXPECT_TRUE(const_b.end() != mutable_iter); typename T::reverse_iterator mutable_riter(mutable_b.rbegin()); EXPECT_TRUE(mutable_riter == const_b.rbegin()); EXPECT_TRUE(mutable_riter != const_b.rend()); EXPECT_TRUE(const_b.rbegin() == mutable_riter); EXPECT_TRUE(const_b.rend() != mutable_riter); // We can create a const iterator from a non-const iterator. typename T::const_iterator const_iter(mutable_iter); EXPECT_TRUE(const_iter == mutable_b.begin()); EXPECT_TRUE(const_iter != mutable_b.end()); EXPECT_TRUE(mutable_b.begin() == const_iter); EXPECT_TRUE(mutable_b.end() != const_iter); typename T::const_reverse_iterator const_riter(mutable_riter); EXPECT_EQ(const_riter, mutable_b.rbegin()); EXPECT_TRUE(const_riter != mutable_b.rend()); EXPECT_EQ(mutable_b.rbegin(), const_riter); EXPECT_TRUE(mutable_b.rend() != const_riter); // Make sure various methods can be invoked on a const container. const_b.verify(); EXPECT_FALSE(const_b.empty()); EXPECT_EQ(const_b.size(), 1); EXPECT_GT(const_b.max_size(), 0); EXPECT_EQ(const_b.height(), 1); EXPECT_EQ(const_b.count(key_of_value(value)), 1); EXPECT_EQ(const_b.internal_nodes(), 0); EXPECT_EQ(const_b.leaf_nodes(), 1); EXPECT_EQ(const_b.nodes(), 1); EXPECT_GT(const_b.bytes_used(), 0); EXPECT_GT(const_b.fullness(), 0); EXPECT_GT(const_b.overhead(), 0); } template void BtreeTest() { ConstTest(); typedef typename std::remove_const::type V; std::vector random_values = GenerateValues(FLAGS_test_values); unique_checker container; // Test key insertion/deletion in sorted order. std::vector sorted_values(random_values); sort(sorted_values.begin(), sorted_values.end()); DoTest("sorted: ", &container, sorted_values); // Test key insertion/deletion in reverse sorted order. reverse(sorted_values.begin(), sorted_values.end()); DoTest("rsorted: ", &container, sorted_values); // Test key insertion/deletion in random order. DoTest("random: ", &container, random_values); } template void BtreeMultiTest() { ConstTest(); typedef typename std::remove_const::type V; const std::vector& random_values = GenerateValues(FLAGS_test_values); multi_checker container; // Test keys in sorted order. std::vector sorted_values(random_values); sort(sorted_values.begin(), sorted_values.end()); DoTest("sorted: ", &container, sorted_values); // Test keys in reverse sorted order. reverse(sorted_values.begin(), sorted_values.end()); DoTest("rsorted: ", &container, sorted_values); // Test keys in random order. DoTest("random: ", &container, random_values); // Test keys in random order w/ duplicates. std::vector duplicate_values(random_values); duplicate_values.insert( duplicate_values.end(), random_values.begin(), random_values.end()); DoTest("duplicates:", &container, duplicate_values); // Test all identical keys. std::vector identical_values(100); fill(identical_values.begin(), identical_values.end(), Generator(2)(2)); DoTest("identical: ", &container, identical_values); } template > class TestAllocator : public Alloc { public: typedef typename Alloc::pointer pointer; typedef typename Alloc::size_type size_type; TestAllocator() : bytes_used_(NULL) { } TestAllocator(int64_t *bytes_used) : bytes_used_(bytes_used) { } // Constructor used for rebinding template TestAllocator(const TestAllocator& x) : Alloc(x), bytes_used_(x.bytes_used()) { } pointer allocate(size_type n, std::allocator::const_pointer hint = 0) { EXPECT_TRUE(bytes_used_ != NULL); *bytes_used_ += n * sizeof(T); return Alloc::allocate(n, hint); } void deallocate(pointer p, size_type n) { Alloc::deallocate(p, n); EXPECT_TRUE(bytes_used_ != NULL); *bytes_used_ -= n * sizeof(T); } // Rebind allows an allocator to be used for a different type template struct rebind { typedef TestAllocator::other> other; }; int64_t* bytes_used() const { return bytes_used_; } private: int64_t *bytes_used_; }; template void BtreeAllocatorTest() { typedef typename T::value_type value_type; int64_t alloc1 = 0; int64_t alloc2 = 0; T b1(typename T::key_compare(), &alloc1); T b2(typename T::key_compare(), &alloc2); // This should swap the allocators! swap(b1, b2); for (int i = 0; i < 1000; i++) { b1.insert(Generator(1000)(i)); } // We should have allocated out of alloc2! EXPECT_LE(b1.bytes_used(), alloc2 + sizeof(b1)); EXPECT_GT(alloc2, alloc1); } template void BtreeMapTest() { typedef typename T::value_type value_type; typedef typename T::mapped_type mapped_type; mapped_type m = Generator(0)(0); (void) m; T b; // Verify we can insert using operator[]. for (int i = 0; i < 1000; i++) { value_type v = Generator(1000)(i); b[v.first] = v.second; } EXPECT_EQ(b.size(), 1000); // Test whether we can use the "->" operator on iterators and // reverse_iterators. This stresses the btree_map_params::pair_pointer // mechanism. EXPECT_EQ(b.begin()->first, Generator(1000)(0).first); EXPECT_EQ(b.begin()->second, Generator(1000)(0).second); EXPECT_EQ(b.rbegin()->first, Generator(1000)(999).first); EXPECT_EQ(b.rbegin()->second, Generator(1000)(999).second); } template void BtreeMultiMapTest() { typedef typename T::mapped_type mapped_type; mapped_type m = Generator(0)(0); (void) m; } } // namespace btree #endif // UTIL_BTREE_BTREE_TEST_H__ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/btree_test_flags.cc ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "gflags/gflags.h" DEFINE_int32(test_values, 10000, "The number of values to use for tests."); DEFINE_int32(benchmark_values, 1000000, "The number of values to use for benchmarks."); ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/safe_btree.h ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // A safe_btree<> wraps around a btree<> and removes the caveat that insertion // and deletion invalidate iterators. A safe_btree<> maintains a generation // number that is incremented on every mutation. A safe_btree<>::iterator keeps // a pointer to the safe_btree<> it came from, the generation of the tree when // it was last validated and the key the underlying btree<>::iterator points // to. If an iterator is accessed and its generation differs from the tree // generation it is revalidated. // // References and pointers returned by safe_btree iterators are not safe. // // See the incorrect usage examples mentioned in safe_btree_set.h and // safe_btree_map.h. #ifndef UTIL_BTREE_SAFE_BTREE_H__ #define UTIL_BTREE_SAFE_BTREE_H__ #include #include #include #include "btree.h" namespace btree { template class safe_btree_iterator { public: typedef typename Iterator::key_type key_type; typedef typename Iterator::value_type value_type; typedef typename Iterator::size_type size_type; typedef typename Iterator::difference_type difference_type; typedef typename Iterator::pointer pointer; typedef typename Iterator::reference reference; typedef typename Iterator::const_pointer const_pointer; typedef typename Iterator::const_reference const_reference; typedef typename Iterator::iterator_category iterator_category; typedef typename Tree::iterator iterator; typedef typename Tree::const_iterator const_iterator; typedef safe_btree_iterator self_type; void update() const { if (iter_ != tree_->internal_btree()->end()) { // A positive generation indicates a valid key. generation_ = tree_->generation(); key_ = iter_.key(); } else { // Use a negative generation to indicate iter_ points to end(). generation_ = -tree_->generation(); } } public: safe_btree_iterator() : generation_(0), key_(), iter_(), tree_(NULL) { } safe_btree_iterator(const iterator &x) : generation_(x.generation()), key_(x.key()), iter_(x.iter()), tree_(x.tree()) { } safe_btree_iterator(Tree *tree, const Iterator &iter) : generation_(), key_(), iter_(iter), tree_(tree) { update(); } Tree* tree() const { return tree_; } int64_t generation() const { return generation_; } Iterator* mutable_iter() const { if (generation_ != tree_->generation()) { if (generation_ > 0) { // This does the wrong thing for a multi{set,map}. If my iter was // pointing to the 2nd of 2 values with the same key, then this will // reset it to point to the first. This is why we don't provide a // safe_btree_multi{set,map}. iter_ = tree_->internal_btree()->lower_bound(key_); update(); } else if (-generation_ != tree_->generation()) { iter_ = tree_->internal_btree()->end(); generation_ = -tree_->generation(); } } return &iter_; } const Iterator& iter() const { return *mutable_iter(); } // Equality/inequality operators. bool operator==(const const_iterator &x) const { return iter() == x.iter(); } bool operator!=(const const_iterator &x) const { return iter() != x.iter(); } // Accessors for the key/value the iterator is pointing at. const key_type& key() const { return key_; } // This reference value is potentially invalidated by any non-const // method on the tree; it is NOT safe. reference operator*() const { assert(generation_ > 0); return iter().operator*(); } // This pointer value is potentially invalidated by any non-const // method on the tree; it is NOT safe. pointer operator->() const { assert(generation_ > 0); return iter().operator->(); } // Increment/decrement operators. self_type& operator++() { ++(*mutable_iter()); update(); return *this; } self_type& operator--() { --(*mutable_iter()); update(); return *this; } self_type operator++(int) { self_type tmp = *this; ++*this; return tmp; } self_type operator--(int) { self_type tmp = *this; --*this; return tmp; } private: // The generation of the tree when "iter" was updated. mutable int64_t generation_; // The key the iterator points to. mutable key_type key_; // The underlying iterator. mutable Iterator iter_; // The tree the iterator is associated with. Tree *tree_; }; template class safe_btree { typedef safe_btree self_type; typedef btree btree_type; typedef typename btree_type::iterator tree_iterator; typedef typename btree_type::const_iterator tree_const_iterator; public: typedef typename btree_type::params_type params_type; typedef typename btree_type::key_type key_type; typedef typename btree_type::data_type data_type; typedef typename btree_type::mapped_type mapped_type; typedef typename btree_type::value_type value_type; typedef typename btree_type::key_compare key_compare; typedef typename btree_type::allocator_type allocator_type; typedef typename btree_type::pointer pointer; typedef typename btree_type::const_pointer const_pointer; typedef typename btree_type::reference reference; typedef typename btree_type::const_reference const_reference; typedef typename btree_type::size_type size_type; typedef typename btree_type::difference_type difference_type; typedef safe_btree_iterator iterator; typedef safe_btree_iterator< const self_type, tree_const_iterator> const_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef std::reverse_iterator reverse_iterator; public: // Default constructor. safe_btree(const key_compare &comp, const allocator_type &alloc) : tree_(comp, alloc), generation_(1) { } // Copy constructor. safe_btree(const self_type &x) : tree_(x.tree_), generation_(1) { } iterator begin() { return iterator(this, tree_.begin()); } const_iterator begin() const { return const_iterator(this, tree_.begin()); } iterator end() { return iterator(this, tree_.end()); } const_iterator end() const { return const_iterator(this, tree_.end()); } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } // Lookup routines. iterator lower_bound(const key_type &key) { return iterator(this, tree_.lower_bound(key)); } const_iterator lower_bound(const key_type &key) const { return const_iterator(this, tree_.lower_bound(key)); } iterator upper_bound(const key_type &key) { return iterator(this, tree_.upper_bound(key)); } const_iterator upper_bound(const key_type &key) const { return const_iterator(this, tree_.upper_bound(key)); } std::pair equal_range(const key_type &key) { std::pair p = tree_.equal_range(key); return std::make_pair(iterator(this, p.first), iterator(this, p.second)); } std::pair equal_range(const key_type &key) const { std::pair p = tree_.equal_range(key); return std::make_pair(const_iterator(this, p.first), const_iterator(this, p.second)); } iterator find_unique(const key_type &key) { return iterator(this, tree_.find_unique(key)); } const_iterator find_unique(const key_type &key) const { return const_iterator(this, tree_.find_unique(key)); } iterator find_multi(const key_type &key) { return iterator(this, tree_.find_multi(key)); } const_iterator find_multi(const key_type &key) const { return const_iterator(this, tree_.find_multi(key)); } size_type count_unique(const key_type &key) const { return tree_.count_unique(key); } size_type count_multi(const key_type &key) const { return tree_.count_multi(key); } // Insertion routines. template std::pair insert_unique(const key_type &key, ValuePointer value) { std::pair p = tree_.insert_unique(key, value); generation_ += p.second; return std::make_pair(iterator(this, p.first), p.second); } std::pair insert_unique(const value_type &v) { std::pair p = tree_.insert_unique(v); generation_ += p.second; return std::make_pair(iterator(this, p.first), p.second); } iterator insert_unique(iterator position, const value_type &v) { tree_iterator tree_pos = position.iter(); ++generation_; return iterator(this, tree_.insert_unique(tree_pos, v)); } template void insert_unique(InputIterator b, InputIterator e) { for (; b != e; ++b) { insert_unique(*b); } } iterator insert_multi(const value_type &v) { ++generation_; return iterator(this, tree_.insert_multi(v)); } iterator insert_multi(iterator position, const value_type &v) { tree_iterator tree_pos = position.iter(); ++generation_; return iterator(this, tree_.insert_multi(tree_pos, v)); } template void insert_multi(InputIterator b, InputIterator e) { for (; b != e; ++b) { insert_multi(*b); } } self_type& operator=(const self_type &x) { if (&x == this) { // Don't copy onto ourselves. return *this; } ++generation_; tree_ = x.tree_; return *this; } // Deletion routines. void erase(const iterator &begin, const iterator &end) { tree_.erase(begin.iter(), end.iter()); ++generation_; } // Erase the specified iterator from the btree. The iterator must be valid // (i.e. not equal to end()). Return an iterator pointing to the node after // the one that was erased (or end() if none exists). iterator erase(iterator iter) { tree_iterator res = tree_.erase(iter.iter()); ++generation_; return iterator(this, res); } int erase_unique(const key_type &key) { int res = tree_.erase_unique(key); generation_ += res; return res; } int erase_multi(const key_type &key) { int res = tree_.erase_multi(key); generation_ += res; return res; } // Access to the underlying btree. btree_type* internal_btree() { return &tree_; } const btree_type* internal_btree() const { return &tree_; } // Utility routines. void clear() { ++generation_; tree_.clear(); } void swap(self_type &x) { ++generation_; ++x.generation_; tree_.swap(x.tree_); } void dump(std::ostream &os) const { tree_.dump(os); } void verify() const { tree_.verify(); } int64_t generation() const { return generation_; } key_compare key_comp() const { return tree_.key_comp(); } // Size routines. size_type size() const { return tree_.size(); } size_type max_size() const { return tree_.max_size(); } bool empty() const { return tree_.empty(); } size_type height() const { return tree_.height(); } size_type internal_nodes() const { return tree_.internal_nodes(); } size_type leaf_nodes() const { return tree_.leaf_nodes(); } size_type nodes() const { return tree_.nodes(); } size_type bytes_used() const { return tree_.bytes_used(); } static double average_bytes_per_value() { return btree_type::average_bytes_per_value(); } double fullness() const { return tree_.fullness(); } double overhead() const { return tree_.overhead(); } private: btree_type tree_; int64_t generation_; }; } // namespace btree #endif // UTIL_BTREE_SAFE_BTREE_H__ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/safe_btree_map.h ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // The safe_btree_map<> is like btree_map<> except that it removes the caveat // about insertion and deletion invalidating existing iterators at a small cost // in making iterators larger and slower. // // Revalidation occurs whenever an iterator is accessed. References // and pointers returned by safe_btree_map<> iterators are not stable, // they are potentially invalidated by any non-const method on the map. // // BEGIN INCORRECT EXAMPLE // for (auto i = safe_map->begin(); i != safe_map->end(); ++i) { // const T *value = &i->second; // DO NOT DO THIS // [code that modifies safe_map and uses value]; // } // END INCORRECT EXAMPLE #ifndef UTIL_BTREE_SAFE_BTREE_MAP_H__ #define UTIL_BTREE_SAFE_BTREE_MAP_H__ #include #include #include #include "btree_container.h" #include "btree_map.h" #include "safe_btree.h" namespace btree { // The safe_btree_map class is needed mainly for its constructors. template , typename Alloc = std::allocator >, int TargetNodeSize = 256> class safe_btree_map : public btree_map_container< safe_btree > > { typedef safe_btree_map self_type; typedef btree_map_params< Key, Value, Compare, Alloc, TargetNodeSize> params_type; typedef safe_btree btree_type; typedef btree_map_container super_type; public: typedef typename btree_type::key_compare key_compare; typedef typename btree_type::allocator_type allocator_type; public: // Default constructor. safe_btree_map(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. safe_btree_map(const self_type &x) : super_type(x) { } // Range constructor. template safe_btree_map(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(b, e, comp, alloc) { } }; template inline void swap(safe_btree_map &x, safe_btree_map &y) { x.swap(y); } } // namespace btree #endif // UTIL_BTREE_SAFE_BTREE_MAP_H__ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/safe_btree_set.h ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // The safe_btree_set<> is like btree_set<> except that it removes the caveat // about insertion and deletion invalidating existing iterators at a small cost // in making iterators larger and slower. // // Revalidation occurs whenever an iterator is accessed. References // and pointers returned by safe_btree_map<> iterators are not stable, // they are potentially invalidated by any non-const method on the set. // // BEGIN INCORRECT EXAMPLE // for (auto i = safe_set->begin(); i != safe_set->end(); ++i) { // const T &value = *i; // DO NOT DO THIS // [code that modifies safe_set and uses value]; // } // END INCORRECT EXAMPLE #ifndef UTIL_BTREE_SAFE_BTREE_SET_H__ #define UTIL_BTREE_SAFE_BTREE_SET_H__ #include #include #include "btree_container.h" #include "btree_set.h" #include "safe_btree.h" namespace btree { // The safe_btree_set class is needed mainly for its constructors. template , typename Alloc = std::allocator, int TargetNodeSize = 256> class safe_btree_set : public btree_unique_container< safe_btree > > { typedef safe_btree_set self_type; typedef btree_set_params params_type; typedef safe_btree btree_type; typedef btree_unique_container super_type; public: typedef typename btree_type::key_compare key_compare; typedef typename btree_type::allocator_type allocator_type; public: // Default constructor. safe_btree_set(const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(comp, alloc) { } // Copy constructor. safe_btree_set(const self_type &x) : super_type(x) { } // Range constructor. template safe_btree_set(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : super_type(b, e, comp, alloc) { } }; template inline void swap(safe_btree_set &x, safe_btree_set &y) { x.swap(y); } } // namespace btree #endif // UTIL_BTREE_SAFE_BTREE_SET_H__ ================================================ FILE: source-code/dependencies/xdelta3/cpp-btree/safe_btree_test.cc ================================================ // Copyright 2013 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // TODO(pmattis): Add some tests that iterators are not invalidated by // insertion and deletion. #include #include #include #include #include #include "gtest/gtest.h" #include "btree_test.h" #include "safe_btree_map.h" #include "safe_btree_set.h" class UnsafeArena; namespace btree { namespace { template void SetTest() { typedef TestAllocator TestAlloc; BtreeTest, std::allocator, N>, std::set >(); BtreeAllocatorTest, TestAlloc, N> >(); } template void MapTest() { typedef TestAllocator TestAlloc; BtreeTest, std::allocator, N>, std::map >(); BtreeAllocatorTest, TestAlloc, N> >(); BtreeMapTest, std::allocator, N> >(); } TEST(SafeBtree, set_int32_32) { SetTest(); } TEST(SafeBtree, set_int32_64) { SetTest(); } TEST(SafeBtree, set_int32_128) { SetTest(); } TEST(SafeBtree, set_int32_256) { SetTest(); } TEST(SafeBtree, set_int64_256) { SetTest(); } TEST(SafeBtree, set_string_256) { SetTest(); } TEST(SafeBtree, set_pair_256) { SetTest, 256>(); } TEST(SafeBtree, map_int32_256) { MapTest(); } TEST(SafeBtree, map_int64_256) { MapTest(); } TEST(SafeBtree, map_string_256) { MapTest(); } TEST(SafeBtree, map_pair_256) { MapTest, 256>(); } TEST(SafeBtree, Comparison) { const int kSetSize = 1201; safe_btree_set my_set; for (int i = 0; i < kSetSize; ++i) { my_set.insert(i); } safe_btree_set my_set_copy(my_set); EXPECT_TRUE(my_set_copy == my_set); EXPECT_TRUE(my_set == my_set_copy); EXPECT_FALSE(my_set_copy != my_set); EXPECT_FALSE(my_set != my_set_copy); my_set.insert(kSetSize); EXPECT_FALSE(my_set_copy == my_set); EXPECT_FALSE(my_set == my_set_copy); EXPECT_TRUE(my_set_copy != my_set); EXPECT_TRUE(my_set != my_set_copy); my_set.erase(kSetSize - 1); EXPECT_FALSE(my_set_copy == my_set); EXPECT_FALSE(my_set == my_set_copy); EXPECT_TRUE(my_set_copy != my_set); EXPECT_TRUE(my_set != my_set_copy); safe_btree_map my_map; for (int i = 0; i < kSetSize; ++i) { my_map[std::string(i, 'a')] = i; } safe_btree_map my_map_copy(my_map); EXPECT_TRUE(my_map_copy == my_map); EXPECT_TRUE(my_map == my_map_copy); EXPECT_FALSE(my_map_copy != my_map); EXPECT_FALSE(my_map != my_map_copy); ++my_map_copy[std::string(7, 'a')]; EXPECT_FALSE(my_map_copy == my_map); EXPECT_FALSE(my_map == my_map_copy); EXPECT_TRUE(my_map_copy != my_map); EXPECT_TRUE(my_map != my_map_copy); my_map_copy = my_map; my_map["hello"] = kSetSize; EXPECT_FALSE(my_map_copy == my_map); EXPECT_FALSE(my_map == my_map_copy); EXPECT_TRUE(my_map_copy != my_map); EXPECT_TRUE(my_map != my_map_copy); my_map.erase(std::string(kSetSize - 1, 'a')); EXPECT_FALSE(my_map_copy == my_map); EXPECT_FALSE(my_map == my_map_copy); EXPECT_TRUE(my_map_copy != my_map); EXPECT_TRUE(my_map != my_map_copy); } } // namespace } // namespace btree ================================================ FILE: source-code/dependencies/xdelta3/draft-korn-vcdiff.txt ================================================ David G. Korn, AT&T Labs Joshua P. MacDonald, UC Berkeley Jeffrey C. Mogul, Compaq WRL Internet-Draft Kiem-Phong Vo, AT&T Labs Expires: 09 November 2002 09 November 2001 The VCDIFF Generic Differencing and Compression Data Format draft-korn-vcdiff-06.txt Status of this Memo This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet- Drafts as reference material or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at http://www.ietf.org/ietf/1id-abstracts.txt The list of Internet-Draft Shadow Directories can be accessed at http://www.ietf.org/shadow.html. Abstract This memo describes a general, efficient and portable data format suitable for encoding compressed and/or differencing data so that they can be easily transported among computers. Table of Contents: 1. EXECUTIVE SUMMARY ............................................ 2 2. CONVENTIONS .................................................. 3 3. DELTA INSTRUCTIONS ........................................... 4 4. DELTA FILE ORGANIZATION ...................................... 5 5. DELTA INSTRUCTION ENCODING ................................... 9 6. DECODING A TARGET WINDOW ..................................... 14 7. APPLICATION-DEFINED CODE TABLES .............................. 16 8. PERFORMANCE .................................................. 16 9. FURTHER ISSUES ............................................... 17 10. SUMMARY ...................................................... 18 11. ACKNOWLEDGEMENTS ............................................. 18 12. SECURITY CONSIDERATIONS ...................................... 18 13. SOURCE CODE AVAILABILITY ..................................... 18 14. INTELLECTUAL PROPERTY RIGHTS ................................. 18 15. IANA CONSIDERATIONS .......................................... 19 16. REFERENCES ................................................... 19 17. AUTHOR'S ADDRESS ............................................. 20 1. EXECUTIVE SUMMARY Compression and differencing techniques can greatly improve storage and transmission of files and file versions. Since files are often transported across machines with distinct architectures and performance characteristics, such data should be encoded in a form that is portable and can be decoded with little or no knowledge of the encoders. This document describes Vcdiff, a compact portable encoding format designed for these purposes. Data differencing is the process of computing a compact and invertible encoding of a "target file" given a "source file". Data compression is similar but without the use of source data. The UNIX utilities diff, compress, and gzip are well-known examples of data differencing and compression tools. For data differencing, the computed encoding is called a "delta file", and, for data compression, it is called a "compressed file". Delta and compressed files are good for storage and transmission as they are often smaller than the originals. Data differencing and data compression are traditionally treated as distinct types of data processing. However, as shown in the Vdelta technique by Korn and Vo [1], compression can be thought of as a special case of differencing in which the source data is empty. The basic idea is to unify the string parsing scheme used in the Lempel-Ziv'77 style compressors [2], and the block-move technique of Tichy [3]. Loosely speaking, this works as follows: a. Concatenate source and target data. b. Parse the data from left to right as in LZ'77 but make sure that a parsed segment starts the target data. c. Start to output when reaching target data. Parsing is based on string matching algorithms such as suffix trees [4] or hashing with different time and space performance characteristics. Vdelta uses a fast string matching algorithm that requires less memory than other techniques [5,6]. However, even with this algorithm, the memory requirement can still be prohibitive for large files. A common way to deal with memory limitation is to partition an input file into chunks called "windows" and process them separately. Here, except for unpublished work by Vo, little has been done on designing effective windowing schemes. Current techniques, including Vdelta, simply use source and target windows with corresponding addresses across source and target files. String matching and windowing algorithms have large influence on the compression rate of delta and compressed files. However, it is desirable to have a portable encoding format that is independent of such algorithms. This enables construction of client-server applications in which a server may serve clients with unknown computing characteristics. Unfortunately, all current differencing and compressing tools, including Vdelta, fall short in this respect. Their storage formats are closely intertwined with the implemented string matching and/or windowing algorithms. The encoding format Vcdiff proposed here addresses the above issues. Vcdiff achieves the below characteristics: Output compactness: The basic encoding format compactly represents compressed or delta files. Applications can further extend the basic encoding format with "secondary encoders" to achieve more compression. Data portability: The basic encoding format is free from machine byte order and word size issues. This allows data to be encoded on one machine and decoded on a different machine with different architecture. Algorithm genericity: The decoding algorithm is independent from string matching and windowing algorithms. This allows competition among implementations of the encoder while keeping the same decoder. Decoding efficiency: Except for secondary encoder issues, the decoding algorithm runs in time proportional to the size of the target file and uses space proportional to the maximal window size. Vcdiff differs from more conventional compressors in that it uses only byte-aligned data, thus avoiding bit-level operations, which improves decoding speed at the slight cost of compression efficiency. The Vcdiff data format and the algorithms for decoding data shall be described next. Since Vcdiff treats compression as a special case of differencing, we shall use the term "delta file" to indicate the compressed output for both cases. 2. CONVENTIONS The basic data unit is a byte. For portability, Vcdiff shall limit a byte to its lower eight bits even on machines with larger bytes. The bits in a byte are ordered from right to left so that the least significant bit (LSB) has value 1, and the most significant bit (MSB), has value 128. For purposes of exposition in this document, we adopt the convention that the LSB is numbered 0, and the MSB is numbered 7. Bit numbers never appear in the encoded format itself. Vcdiff encodes unsigned integer values using a portable variable-sized format (originally introduced in the Sfio library [7]). This encoding treats an integer as a number in base 128. Then, each digit in this representation is encoded in the lower seven bits of a byte. Except for the least significant byte, other bytes have their most significant bit turned on to indicate that there are still more digits in the encoding. The two key properties of this integer encoding that are beneficial to a data compression format are: a. The encoding is portable among systems using 8-bit bytes, and b. Small values are encoded compactly. For example, consider the value 123456789 which can be represented with four 7-bit digits whose values are 58, 111, 26, 21 in order from most to least significant. Below is the 8-bit byte encoding of these digits. Note that the MSBs of 58, 111 and 26 are on. +-------------------------------------------+ | 10111010 | 11101111 | 10011010 | 00010101 | +-------------------------------------------+ MSB+58 MSB+111 MSB+26 0+21 Henceforth, the terms "byte" and "integer" will refer to a byte and an unsigned integer as described. From time to time, algorithms are exhibited to clarify the descriptions of parts of the Vcdiff format. On such occasions, the C language will be used to make precise the algorithms. The C code shown in this document is meant for clarification only, and is not part of the actual specification of the Vcdiff format. In this specification, the key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" document are to be interpreted as described in RFC2119 [12]. 3. DELTA INSTRUCTIONS A large target file is partitioned into non-overlapping sections called "target windows". These target windows are processed separately and sequentially based on their order in the target file. A target window T of length t may be compared against some source data segment S of length s. By construction, this source data segment S comes either from the source file, if one is used, or from a part of the target file earlier than T. In this way, during decoding, S is completely known when T is being decoded. The choices of T, t, S and s are made by some window selection algorithm which can greatly affect the size of the encoding. However, as seen later, these choices are encoded so that no knowledge of the window selection algorithm is needed during decoding. Assume that S[j] represents the jth byte in S, and T[k] represents the kth byte in T. Then, for the delta instructions, we treat the data windows S and T as substrings of a superstring U formed by concatenating them like this: S[0]S[1]...S[s-1]T[0]T[1]...T[t-1] The "address" of a byte in S or T is referred to by its location in U. For example, the address of T[k] is s+k. The instructions to encode and direct the reconstruction of a target window are called delta instructions. There are three types: ADD: This instruction has two arguments, a size x and a sequence of x bytes to be copied. COPY: This instruction has two arguments, a size x and an address p in the string U. The arguments specify the substring of U that must be copied. We shall assert that such a substring must be entirely contained in either S or T. RUN: This instruction has two arguments, a size x and a byte b that will be repeated x times. Below are example source and target windows and the delta instructions that encode the target window in terms of the source window. a b c d e f g h i j k l m n o p a b c d w x y z e f g h e f g h e f g h e f g h z z z z COPY 4, 0 ADD 4, w x y z COPY 4, 4 COPY 12, 24 RUN 4, z Thus, the first letter 'a' in the target window is at location 16 in the superstring. Note that the fourth instruction, "COPY 12, 24", copies data from T itself since address 24 is position 8 in T. This instruction also shows that it is fine to overlap the data to be copied with the data being copied from as long as the latter starts earlier. This enables efficient encoding of periodic sequences, i.e., sequences with regularly repeated subsequences. The RUN instruction is a compact way to encode a sequence repeating the same byte even though such a sequence can be thought of as a periodic sequence with period 1. To reconstruct the target window, one simply processes one delta instruction at a time and copy the data either from the source window or the being reconstructed target window based on the type of the instruction and the associated address, if any. 4. DELTA FILE ORGANIZATION A Vcdiff delta file starts with a Header section followed by a sequence of Window sections. The Header section includes magic bytes to identify the file type, and information concerning data processing beyond the basic encoding format. The Window sections encode the target windows. Below is the overall organization of a delta file. The indented items refine the ones immediately above them. An item in square brackets may or may not be present in the file depending on the information encoded in the Indicator byte above it. Header Header1 - byte Header2 - byte Header3 - byte Header4 - byte Hdr_Indicator - byte [Secondary compressor ID] - byte [@@@ Why is compressor ID not an integer? ] [@@@ If we aren't defining any secondary compressors yet, then it seems that defining the [Secondary compressor ID] and the corresponding VCD_DECOMPRESS Hdr_Indicator bit in this draft has no real value. An implementation of this specification won't be able to decode a VCDIFF encoded with this option if it doesn't know about any secondary compressors. It seems that you should specify the bits related to secondary compressors once you have defined the first a secondary compressor. I can imagine a secondary-compressor might want to supply extra information, such as a dictionary of some kind, in which case this speculative treatment wouldn't go far enough.] [Length of code table data] - integer [Code table data] Size of near cache - byte Size of same cache - byte Compressed code table data Window1 Win_Indicator - byte [Source segment size] - integer [Source segment position] - integer The delta encoding of the target window Length of the delta encoding - integer The delta encoding Size of the target window - integer Delta_Indicator - byte Length of data for ADDs and RUNs - integer Length of instructions and sizes - integer Length of addresses for COPYs - integer Data section for ADDs and RUNs - array of bytes Instructions and sizes section - array of bytes Addresses section for COPYs - array of bytes Window2 ... 4.1 The Header Section Each delta file starts with a header section organized as below. Note the convention that square-brackets enclose optional items. Header1 - byte = 0xE6 Header2 - byte = 0xD3 Header3 - byte = 0xD4 HMMM 0xD6 0xC3 0xC4 Header4 - byte Hdr_Indicator - byte [Secondary compressor ID] - byte [Length of code table data] - integer [Code table data] The first three Header bytes are the ASCII characters 'V', 'C' and 'D' with their most significant bits turned on (in hexadecimal, the values are 0xE6, 0xD3, and 0xD4). The fourth Header byte is currently set to zero. In the future, it might be used to indicate the version of Vcdiff. The Hdr_Indicator byte shows if there are any initialization data required to aid in the reconstruction of data in the Window sections. This byte MAY have non-zero values for either, both, or neither of the two bits VCD_DECOMPRESS and VCD_CODETABLE below: 7 6 5 4 3 2 1 0 +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ ^ ^ | | | +-- VCD_DECOMPRESS +---- VCD_CODETABLE If bit 0 (VCD_DECOMPRESS) is non-zero, this indicates that a secondary compressor may have been used to further compress certain parts of the delta encoding data as described in Sections 4.3 and 6. In that case, the ID of the secondary compressor is given next. If this bit is zero, the compressor ID byte is not included. [@@@ If we aren't defining any secondary compressors yet, then it seems this bit has no real value yet..] If bit 1 (VCD_CODETABLE) is non-zero, this indicates that an application-defined code table is to be used for decoding the delta instructions. This table itself is compressed. The length of the data comprising this compressed code table and the data follow next. Section 7 discusses application-defined code tables. If this bit is zero, the code table data length and the code table data are not included. If both bits are set, then the compressor ID byte is included before the code table data length and the code table data. 4.2 The Format of a Window Section Each Window section is organized as follows: Win_Indicator - byte [Source segment length] - integer [Source segment position] - integer The delta encoding of the target window Below are the detail of the various items: [@@@ Here, I want to replace the Win_Indicator with a source-count, followed by source-count length/position pairs?] Win_Indicator: This byte is a set of bits, as shown: 7 6 5 4 3 2 1 0 +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ ^ ^ | | | +-- VCD_SOURCE +---- VCD_TARGET If bit 0 (VCD_SOURCE) is non-zero, this indicates that a segment of data from the "source" file was used as the corresponding source window of data to encode the target window. The decoder will use this same source data segment to decode the target window. If bit 1 (VCD_TARGET) is non-zero, this indicates that a segment of data from the "target" file was used as the corresponding source window of data to encode the target window. As above, this same source data segment is used to decode the target window. The Win_Indicator byte MUST NOT have more than one of the bits set (non-zero). It MAY have none of these bits set. If one of these bits is set, the byte is followed by two integers to indicate respectively the length and position of the source data segment in the relevant file. If the indicator byte is zero, the target window was compressed by itself without comparing against another data segment, and these two integers are not included. The delta encoding of the target window: This contains the delta encoding of the target window either in terms of the source data segment (i.e., VCD_SOURCE or VCD_TARGET was set) or by itself if no source window is specified. This data format is discussed next. 4.3 The Delta Encoding of a Target Window The delta encoding of a target window is organized as follows: Length of the delta encoding - integer The delta encoding Length of the target window - integer Delta_Indicator - byte Length of data for ADDs and RUNs - integer Length of instructions section - integer Length of addresses for COPYs - integer Data section for ADDs and RUNs - array of bytes Instructions and sizes section - array of bytes Addresses section for COPYs - array of bytes Length of the delta encoding: This integer gives the total number of remaining bytes that comprise data of the delta encoding for this target window. The delta encoding: This contains the data representing the delta encoding which is described next. Length of the target window: This integer indicates the actual size of the target window after decompression. A decoder can use this value to allocate memory to store the uncompressed data. Delta_Indicator: This byte is a set of bits, as shown: 7 6 5 4 3 2 1 0 +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ ^ ^ ^ | | | | | +-- VCD_DATACOMP | +---- VCD_INSTCOMP +------ VCD_ADDRCOMP VCD_DATACOMP: bit value 1. VCD_INSTCOMP: bit value 2. VCD_ADDRCOMP: bit value 4. As discussed, the delta encoding consists of COPY, ADD and RUN instructions. The ADD and RUN instructions have accompanying unmatched data (that is, data that does not specifically match any data in the source window or in some earlier part of the target window) and the COPY instructions have addresses of where the matches occur. OPTIONALLY, these types of data MAY be further compressed using a secondary compressor. Thus, Vcdiff separates the encoding of the delta instructions into three parts: a. The unmatched data in the ADD and RUN instructions, b. The delta instructions and accompanying sizes, and c. The addresses of the COPY instructions. If the bit VCD_DECOMPRESS (Section 4.1) was on, each of these sections may have been compressed using the specified secondary compressor. The bit positions 0 (VCD_DATACOMP), 1 (VCD_INSTCOMP), and 2 (VCD_ADDRCOMP) respectively indicate, if non-zero, that the corresponding parts are compressed. Then, these parts MUST be decompressed before decoding the delta instructions. Length of data for ADDs and RUNs: This is the length (in bytes) of the section of data storing the unmatched data accompanying the ADD and RUN instructions. Length of instructions section: This is the length (in bytes) of the delta instructions and accompanying sizes. Length of addresses for COPYs: This is the length (in bytes) of the section storing the addresses of the COPY instructions. Data section for ADDs and RUNs: This sequence of bytes encodes the unmatched data for the ADD and RUN instructions. Instructions and sizes section: This sequence of bytes encodes the instructions and their sizes. Addresses section for COPYs: This sequence of bytes encodes the addresses of the COPY instructions. 5. DELTA INSTRUCTION ENCODING The delta instructions described in Section 3 represent the results of string matching. For many data differencing applications in which the changes between source and target data are small, any straightforward representation of these instructions would be adequate. However, for applications including data compression, it is important to encode these instructions well to achieve good compression rates. From our experience, the following observations can be made: a. The addresses in COPY instructions are locations of matches and often occur close by or even exactly equal to one another. This is because data in local regions are often replicated with minor changes. In turn, this means that coding a newly matched address against some set of recently matched addresses can be beneficial. b. The matches are often short in length and separated by small amounts of unmatched data. That is, the lengths of COPY and ADD instructions are often small. This is particularly true of binary data such as executable files or structured data such as HTML or XML. In such cases, compression can be improved by combining the encoding of the sizes and the instruction types as well as combining the encoding of adjacent delta instructions with sufficiently small data sizes. The below subsections discuss how the Vcdiff data format provides mechanisms enabling encoders to use the above observations to improve compression rates. 5.1 Address Encoding Modes of COPY Instructions As mentioned earlier, addresses of COPY instructions often occur close to one another or are exactly equal. To take advantage of this phenomenon and encode addresses of COPY instructions more efficiently, the Vcdiff data format supports the use of two different types of address caches. Both the encoder and decoder maintain these caches, so that decoder's caches remain synchronized with the encoder's caches. a. A "near" cache is an array with "s_near" slots, each containing an address used for encoding addresses nearby to previously encoded addresses (in the positive direction only). The near cache also maintains a "next_slot" index to the near cache. New entries to the near cache are always inserted in the next_slot index, which maintains a circular buffer of the s_near most recent addresses. b. A "same" cache is an array with "s_same" multiple of 256 slots, each containing an address. The same cache maintains a hash table of recent addresses used for repeated encoding of the exact same address. By default, the parameters s_near and s_same are respectively set to 4 and 3. An encoder MAY modify these values, but then it MUST encode the new values in the encoding itself, as discussed in Section 7, so that the decoder can properly set up its own caches. At the start of processing a target window, an implementation (encoder or decoder) initializes all of the slots in both caches to zero. The next_slot pointer of the near cache is set to point to slot zero. Each time a COPY instruction is processed by the encoder or decoder, the implementation's caches are updated as follows, where "addr" is the address in the COPY instruction. a. The slot in the near cache referenced by the next_slot index is set to addr. The next_slot index is then incremented modulo s_near. b. The slot in the same cache whose index is addr%(s_same*256) is set to addr. [We use the C notations of % for modulo and * for multiplication.] 5.2 Example code for maintaining caches To make clear the above description, below are example cache data structures and algorithms to initialize and update them: typedef struct _cache_s { int* near; /* array of size s_near */ int s_near; int next_slot; /* the circular index for near */ int* same; /* array of size s_same*256 */ int s_same; } Cache_t; cache_init(Cache_t* ka) { int i; ka->next_slot = 0; for(i = 0; i < ka->s_near; ++i) ka->near[i] = 0; for(i = 0; i < ka->s_same*256; ++i) ka->same[i] = 0; } cache_update(Cache_t* ka, int addr) { if(ka->s_near > 0) { ka->near[ka->next_slot] = addr; ka->next_slot = (ka->next_slot + 1) % ka->s_near; } if(ka->s_same > 0) ka->same[addr % (ka->s_same*256)] = addr; } 5.3 Encoding of COPY instruction addresses The address of a COPY instruction is encoded using different modes depending on the type of cached address used, if any. Let "addr" be the address of a COPY instruction to be decoded and "here" be the current location in the target data (i.e., the start of the data about to be encoded or decoded). Let near[j] be the jth element in the near cache, and same[k] be the kth element in the same cache. Below are the possible address modes: VCD_SELF: This mode has value 0. The address was encoded by itself as an integer. VCD_HERE: This mode has value 1. The address was encoded as the integer value "here - addr". Near modes: The "near modes" are in the range [2,s_near+1]. Let m be the mode of the address encoding. The address was encoded as the integer value "addr - near[m-2]". Same modes: The "same modes" are in the range [s_near+2,s_near+s_same+1]. Let m be the mode of the encoding. The address was encoded as a single byte b such that "addr == same[(m - (s_near+2))*256 + b]". 5.3 Example code for encoding and decoding of COPY instruction addresses We show example algorithms below to demonstrate use of address modes more clearly. The encoder has freedom to choose address modes, the sample addr_encode() algorithm merely shows one way of picking the address mode. The decoding algorithm addr_decode() will uniquely decode addresses regardless of the encoder's algorithm choice. Note that the address caches are updated immediately after an address is encoded or decoded. In this way, the decoder is always synchronized with the encoder. int addr_encode(Cache_t* ka, int addr, int here, int* mode) { int i, d, bestd, bestm; /* Attempt to find the address mode that yields the * smallest integer value for "d", the encoded address * value, thereby minimizing the encoded size of the * address. */ bestd = addr; bestm = VCD_SELF; /* VCD_SELF == 0 */ if((d = here-addr) < bestd) { bestd = d; bestm = VCD_HERE; } /* VCD_HERE == 1 */ for(i = 0; i < ka->s_near; ++i) if((d = addr - ka->near[i]) >= 0 && d < bestd) { bestd = d; bestm = i+2; } if(ka->s_same > 0 && ka->same[d = addr%(ka->s_same*256)] == addr) { bestd = d%256; bestm = ka->s_near + 2 + d/256; } cache_update(ka,addr); *mode = bestm; /* this returns the address encoding mode */ return bestd; /* this returns the encoded address */ } Note that the addr_encode() algorithm chooses the best address mode using a local optimization, but that may not lead to the best encoding efficiency because different modes lead to different instruction encodings, as described below. The functions addrint() and addrbyte() used in addr_decode() obtain from the "Addresses section for COPYs" (Section 4.3) an integer or a byte, respectively. These utilities will not be described here. We simply recall that an integer is represented as a compact variable-sized string of bytes as described in Section 2 (i.e., base 128). int addr_decode(Cache_t* ka, int here, int mode) { int addr, m; if(mode == VCD_SELF) addr = addrint(); else if(mode == VCD_HERE) addr = here - addrint(); else if((m = mode - 2) >= 0 && m < ka->s_near) /* near cache */ addr = ka->near[m] + addrint(); else /* same cache */ { m = mode - (2 + ka->s_near); addr = ka->same[m*256 + addrbyte()]; } cache_update(ka, addr); return addr; } 5.4 Instruction Codes As noted, the data sizes associated with delta instructions are often small. Thus, compression efficiency can be improved by combining the sizes and instruction types in a single encoding, as well by combining certain pairs of adjacent delta instructions. Effective choices of when to perform such combinations depend on many factors including the data being processed and the string matching algorithm in use. For example, if many COPY instructions have the same data sizes, it may be worth to encode these instructions more compactly than others. The Vcdiff data format is designed so that a decoder does not need to be aware of the choices made in encoding algorithms. This is achieved with the notion of an "instruction code table" containing 256 entries. Each entry defines either a single delta instruction or a pair of instructions that have been combined. Note that the code table itself only exists in main memory, not in the delta file (unless using an application-defined code table, described in Section 7). The encoded data simply includes the index of each instruction and, since there are only 256 indices, each index can be represented as a single byte. Each instruction code entry contains six fields, each of which is a single byte with unsigned value: +-----------------------------------------------+ | inst1 | size1 | mode1 | inst2 | size2 | mode2 | +-----------------------------------------------+ @@@ could be more compact Each triple (inst,size,mode) defines a delta instruction. The meanings of these fields are as follows: inst: An "inst" field can have one of the four values: NOOP (0), ADD (1), RUN (2) or COPY (3) to indicate the instruction types. NOOP means that no instruction is specified. In this case, both the corresponding size and mode fields will be zero. size: A "size" field is zero or positive. A value zero means that the size associated with the instruction is encoded separately as an integer in the "Instructions and sizes section" (Section 6). A positive value for "size" defines the actual data size. Note that since the size is restricted to a byte, the maximum value for any instruction with size implicitly defined in the code table is 255. mode: A "mode" field is significant only when the associated delta instruction is a COPY. It defines the mode used to encode the associated addresses. For other instructions, this is always zero. 5.5 The Code Table Following the discussions on address modes and instruction code tables, we define a "Code Table" to have the data below: s_near: the size of the near cache, s_same: the size of the same cache, i_code: the 256-entry instruction code table. Vcdiff itself defines a "default code table" in which s_near is 4 and s_same is 3. Thus, there are 9 address modes for a COPY instruction. The first two are VCD_SELF (0) and VCD_HERE (1). Modes 2, 3, 4 and 5 are for addresses coded against the near cache. And, modes 6, 7 and 8 are for addresses coded against the same cache. The default instruction code table is depicted below, in a compact representation that we use only for descriptive purposes. See section 7 for the specification of how an instruction code table is represented in the Vcdiff encoding format. In the depiction, a zero value for size indicates that the size is separately coded. The mode of non-COPY instructions is represented as 0 even though they are not used. TYPE SIZE MODE TYPE SIZE MODE INDEX --------------------------------------------------------------- 1. RUN 0 0 NOOP 0 0 0 2. ADD 0, [1,17] 0 NOOP 0 0 [1,18] 3. COPY 0, [4,18] 0 NOOP 0 0 [19,34] 4. COPY 0, [4,18] 1 NOOP 0 0 [35,50] 5. COPY 0, [4,18] 2 NOOP 0 0 [51,66] 6. COPY 0, [4,18] 3 NOOP 0 0 [67,82] 7. COPY 0, [4,18] 4 NOOP 0 0 [83,98] 8. COPY 0, [4,18] 5 NOOP 0 0 [99,114] 9. COPY 0, [4,18] 6 NOOP 0 0 [115,130] 10. COPY 0, [4,18] 7 NOOP 0 0 [131,146] 11. COPY 0, [4,18] 8 NOOP 0 0 [147,162] 12. ADD [1,4] 0 COPY [4,6] 0 [163,174] 13. ADD [1,4] 0 COPY [4,6] 1 [175,186] 14. ADD [1,4] 0 COPY [4,6] 2 [187,198] 15. ADD [1,4] 0 COPY [4,6] 3 [199,210] 16. ADD [1,4] 0 COPY [4,6] 4 [211,222] 17. ADD [1,4] 0 COPY [4,6] 5 [223,234] 18. ADD [1,4] 0 COPY 4 6 [235,238] 19. ADD [1,4] 0 COPY 4 7 [239,242] 20. ADD [1,4] 0 COPY 4 8 [243,246] 21. COPY 4 [0,8] ADD 1 0 [247,255] --------------------------------------------------------------- In the above depiction, each numbered line represents one or more entries in the actual instruction code table (recall that an entry in the instruction code table may represent up to two combined delta instructions.) The last column ("INDEX") shows which index value or range of index values of the entries covered by that line. The notation [i,j] means values from i through j, inclusive. The first 6 columns of a line in the depiction describe the pairs of instructions used for the corresponding index value(s). If a line in the depiction includes a column entry using the [i,j] notation, this means that the line is instantiated for each value in the range from i to j, inclusive. The notation "0, [i,j]" means that the line is instantiated for the value 0 and for each value in the range from i to j, inclusive. If a line in the depiction includes more than one entry using the [i,j] notation, implying a "nested loop" to convert the line to a range of table entries, the first such [i,j] range specifies the outer loop, and the second specifies the inner loop. The below examples should make clear the above description: Line 1 shows the single RUN instruction with index 0. As the size field is 0, this RUN instruction always has its actual size encoded separately. Line 2 shows the 18 single ADD instructions. The ADD instruction with size field 0 (i.e., the actual size is coded separately) has index 1. ADD instructions with sizes from 1 to 17 use code indices 2 to 18 and their sizes are as given (so they will not be separately encoded.) Following the single ADD instructions are the single COPY instructions ordered by their address encoding modes. For example, line 11 shows the COPY instructions with mode 8, i.e., the last of the same cache. In this case, the COPY instruction with size field 0 has index 147. Again, the actual size of this instruction will be coded separately. Lines 12 to 21 show the pairs of instructions that are combined together. For example, line 12 depicts the 12 entries in which an ADD instruction is combined with an immediately following COPY instruction. The entries with indices 163, 164, 165 represent the pairs in which the ADD instructions all have size 1 while the COPY instructions has mode 0 (VCD_SELF) and sizes 4, 5 and 6 respectively. The last line, line 21, shows the eight instruction pairs where the first instruction is a COPY and the second is an ADD. In this case, all COPY instructions have size 4 with mode ranging from 0 to 8 and all the ADD instructions have size 1. Thus, the entry with largest index 255 combines a COPY instruction of size 4 and mode 8 with an ADD instruction of size 1. The choice of the minimum size 4 for COPY instructions in the default code table was made from experiments that showed that excluding small matches (less then 4 bytes long) improved the compression rates. 6. DECODING A TARGET WINDOW Section 4.3 discusses that the delta instructions and associated data are encoded in three arrays of bytes: Data section for ADDs and RUNs, Instructions and sizes section, and Addresses section for COPYs. Further, these data sections may have been further compressed by some secondary compressor. Assuming that any such compressed data has been decompressed so that we now have three arrays: inst: bytes coding the instructions and sizes. data: unmatched data associated with ADDs and RUNs. addr: bytes coding the addresses of COPYs. These arrays are organized as follows: inst: a sequence of (index, [size1], [size2]) tuples, where "index" is an index into the instruction code table, and size1 and size2 are integers that MAY or MAY NOT be included in the tuple as follows. The entry with the given "index" in the instruction code table potentially defines two delta instructions. If the first delta instruction is not a VCD_NOOP and its size is zero, then size1 MUST be present. Otherwise, size1 MUST be omitted and the size of the instruction (if it is not VCD_NOOP) is as defined in the table. The presence or absence of size2 is defined similarly with respect to the second delta instruction. data: a sequence of data values, encoded as bytes. addr: a sequence of address values. Addresses are normally encoded as integers as described in Section 2 (i.e., base 128). Since the same cache emits addresses in the range [0,255], however, same cache addresses are always encoded as a single byte. To summarize, each tuple in the "inst" array includes an index to some entry in the instruction code table that determines: a. Whether one or two instructions were encoded and their types. b. If the instructions have their sizes encoded separately, these sizes will follow, in order, in the tuple. c. If the instructions have accompanying data, i.e., ADDs or RUNs, their data will be in the array "data". d. Similarly, if the instructions are COPYs, the coded addresses are found in the array "addr". The decoding procedure simply processes the arrays by reading one code index at a time, looking up the corresponding instruction code entry, then consuming the respective sizes, data and addresses following the directions in this entry. In other words, the decoder maintains an implicit next-element pointer for each array; "consuming" an instruction tuple, data, or address value implies incrementing the associated pointer. For example, if during the processing of the target window, the next unconsumed tuple in the inst array has index value 19, then the first instruction is a COPY, whose size is found as the immediately following integer in the inst array. Since the mode of this COPY instruction is VCD_SELF, the corresponding address is found by consuming the next integer in the addr array. The data array is left intact. As the second instruction for code index 19 is a NOOP, this tuple is finished. 7. APPLICATION-DEFINED CODE TABLES Although the default code table used in Vcdiff is good for general purpose encoders, there are times when other code tables may perform better. For example, to code a file with many identical segments of data, it may be advantageous to have a COPY instruction with the specific size of these data segments so that the instruction can be encoded in a single byte. Such a special code table MUST then be encoded in the delta file so that the decoder can reconstruct it before decoding the data. Vcdiff allows an application-defined code table to be specified in a delta file with the following data: Size of near cache - byte Size of same cache - byte Compressed code table data The "compressed code table data" encodes the delta between the default code table (source) and the new code table (target) in the same manner as described in Section 4.3 for encoding a target window in terms of a source window. This delta is computed using the following steps: a. Convert the new instruction code table into a string, "code", of 1536 bytes using the below steps in order: i. Add in order the 256 bytes representing the types of the first instructions in the instruction pairs. ii. Add in order the 256 bytes representing the types of the second instructions in the instruction pairs. iii. Add in order the 256 bytes representing the sizes of the first instructions in the instruction pairs. iv. Add in order the 256 bytes representing the sizes of the second instructions in the instruction pairs. v. Add in order the 256 bytes representing the modes of the first instructions in the instruction pairs. vi. Add in order the 256 bytes representing the modes of the second instructions in the instruction pairs. b. Similarly, convert the default instruction code table into a string "dflt". c. Treat the string "code" as a target window and "dflt" as the corresponding source data and apply an encoding algorithm to compute the delta encoding of "code" in terms of "dflt". This computation MUST use the default code table for encoding the delta instructions. The decoder can then reverse the above steps to decode the compressed table data using the method of Section 6, employing the default code table, to generate the new code table. Note that the decoder does not need to know anything about the details of the encoding algorithm used in step (c). The decoder is still able to decode the new code table because the Vcdiff format is independent from the choice of encoding algorithm, and because the encoder in step (c) uses the known, default code table. 8. PERFORMANCE The encoding format is compact. For compression only, using the LZ-77 string parsing strategy and without any secondary compressors, the typical compression rate is better than Unix compress and close to gzip. For differencing, the data format is better than all known methods in terms of its stated goal, which is primarily decoding speed and encoding efficiency. We compare the performance of compress, gzip and Vcdiff using the archives of three versions of the Gnu C compiler, gcc-2.95.1.tar, gcc-2.95.2.tar and gcc-2.95.3.tar. The experiments were done on an SGI-MIPS3, 400MHZ. Gzip was used at its default compression level. Vcdiff timings were done using the Vcodex/Vcdiff software (Section 13). As string and window matching typically dominates the computation during compression, the Vcdiff compression times were directly due to the algorithms used in the Vcodex/Vcdiff software. However, the decompression times should be generic and representative of any good implementation of the Vcdiff data format. Timing was done by running each program three times and taking the average of the total cpu+system times. Below are the different Vcdiff runs: Vcdiff: vcdiff is used as compressor only. Vcdiff-d: vcdiff is used as a differencer only. That is, it only compares target data against source data. Since the files involved are large, they are broken into windows. In this case, each target window starting at some file offset in the target file is compared against a source window with the same file offset (in the source file). The source window is also slightly larger than the target window to increase matching opportunities. The -d option also gives a hint to the string matching algorithm of Vcdiff that the two files are very similar with long stretches of matches. The algorithm takes advantage of this to minimize its processing of source data and save time. Vcdiff-dc: This is similar to Vcdiff-d but vcdiff can also compare target data against target data as applicable. Thus, vcdiff both computes differences and compresses data. The windowing algorithm is the same as above. However, the above hint is recinded in this case. Vcdiff-dcs: This is similar to Vcdiff-dc but the windowing algorithm uses a content-based heuristic to select source data segments that are more likely to match with a given target window. Thus, the source data segment selected for a target window often will not be aligned with the file offsets of this target window. gcc-2.95.1 gcc-2.95.2 compression decompression raw size 55746560 55797760 compress - 19939390 13.85s 7.09s gzip - 12973443 42.99s 5.35s Vcdiff - 15358786 20.04s 4.65s Vcdiff-d - 100971 10.93s 1.92s Vcdiff-dc - 97246 20.03s 1.84s Vcdiff-dcs - 256445 44.81s 1.84s TABLE 1. Compressing gcc-2.95.2.tar given gcc-2.95.1 TABLE 1 shows the raw sizes of gcc-2.95.1.tar and gcc-2.95.2.tar and the sizes of the compressed results. As a pure compressor, the compression rate for Vcdiff is worse than gzip and better than compress. The last three rows shows that when two file versions are very similar, differencing can have dramatically good compression rates. Vcdiff-d and Vcdiff-dc use the same simple window selection method but Vcdiff-dc also does compression so its output is slightly smaller. Vcdiff-dcs uses a heuristic based on data content to search for source data that likely will match a given target window. Although it does a good job, the heuristic did not always find the best matches which are given by the simple algorithm of Vcdiff-d. As a result, the output size is slightly larger. Note also that there is a large cost in computing matching windows this way. Finally, the compression times of Vcdiff-d is nearly half of that of Vcdiff-dc. It is tempting to conclude that the compression feature causes the additional time in Vcdiff-dc relative to Vcdiff-d. However, this is not the case. The hint given to the Vcdiff string matching algorithm that the two files are likely to have very long stretches of matches helps the algorithm to minimize processing of the "source data", thus saving half the time. However, as we shall see below when this hint is wrong, the result is even longer time. gcc-2.95.2 gcc-2.95.3 compression decompression raw size 55797760 55787520 compress - 19939453 13.54s 7.00s gzip - 12998097 42.63s 5.62s Vcdiff - 15371737 20.09s 4.74s Vcdiff-d - 26383849 71.41s 6.41s Vcdiff-dc - 14461203 42.48s 4.82s Vcdiff-dcs - 1248543 61.18s 1.99s TABLE 2. Compressing gcc-2.95.3.tar given gcc-2.95.2 TABLE 2 shows the raw sizes of gcc-2.95.2.tar and gcc-2.95.3.tar and the sizes of the compressed results. In this case, the tar file of gcc-2.95.3 is rearranged in a way that makes the straightforward method of matching file offsets for source and target windows fail. As a result, Vcdiff-d performs rather dismally both in time and output size. The large time for Vcdiff-d is directly due to fact that the string matching algorithm has to work much harder to find matches when the hint that two files have long matching stretches fails to hold. On the other hand, Vcdiff-dc does both differencing and compression resulting in good output size. Finally, the window searching heuristic used in Vcdiff-dcs is effective in finding the right matching source windows for target windows resulting a small output size. This shows why the data format needs to have a way to specify matching windows to gain performance. Finally, we note that the decoding times are always good regardless of how the string matching or window searching algorithms perform. 9. FURTHER ISSUES This document does not address a few issues: Secondary compressors: As discussed in Section 4.3, certain sections in the delta encoding of a window may be further compressed by a secondary compressor. In our experience, the basic Vcdiff format is adequate for most purposes so that secondary compressors are seldom needed. In particular, for normal use of data differencing where the files to be compared have long stretches of matches, much of the gain in compression rate is already achieved by normal string matching. Thus, the use of secondary compressors is seldom needed in this case. However, for applications beyond differencing of such nearly identical files, secondary compressors may be needed to achieve maximal compressed results. Therefore, we recommend to leave the Vcdiff data format defined as in this document so that the use of secondary compressors can be implemented when they become needed in the future. The formats of the compressed data via such compressors or any compressors that may be defined in the future are left open to their implementations. These could include Huffman encoding, arithmetic encoding, and splay tree encoding [8,9]. Large file system vs. small file system: As discussed in Section 4, a target window in a large file may be compared against some source window in another file or in the same file (from some earlier part). In that case, the file offset of the source window is specified as a variable-sized integer in the delta encoding. There is a possibility that the encoding was computed on a system supporting much larger files than in a system where the data may be decoded (e.g., 64-bit file systems vs. 32-bit file systems). In that case, some target data may not be recoverable. This problem could afflict any compression format, and ought to be resolved with a generic negotiation mechanism in the appropriate protocol(s). 10. SUMMARY We have described Vcdiff, a general and portable encoding format for compression and differencing. The format is good in that it allows implementing a decoder without knowledge of the encoders. Further, ignoring the use of secondary compressors not defined within the format, the decoding algorithms runs in linear time and requires working space proportional to window sizes. 11. ACKNOWLEDGEMENTS Thanks are due to Balachander Krishnamurthy, Jeff Mogul and Arthur Van Hoff who provided much encouragement to publicize Vcdiff. In particular, Jeff helped clarifying the description of the data format presented here. 12. SECURITY CONSIDERATIONS Vcdiff only provides a format to encode compressed and differenced data. It does not address any issues concerning how such data are, in fact, stored in a given file system or the run-time memory of a computer system. Therefore, we do not anticipate any security issues with respect to Vcdiff. 13. SOURCE CODE AVAILABILITY Vcdiff is implemented as a data transforming method in Phong Vo's Vcodex library. AT&T Corp. has made the source code for Vcodex available for anyone to use to transmit data via HTTP/1.1 Delta Encoding [10,11]. The source code and according license is accessible at the below URL: http://www.research.att.com/sw/tools 14. INTELLECTUAL PROPERTY RIGHTS The IETF has been notified of intellectual property rights claimed in regard to some or all of the specification contained in this document. For more information consult the online list of claimed rights, at . The IETF takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on the IETF's procedures with respect to rights in standards-track and standards-related documentation can be found in BCP-11. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification can be obtained from the IETF Secretariat. 15. IANA CONSIDERATIONS The Internet Assigned Numbers Authority (IANA) administers the number space for Secondary Compressor ID values. Values and their meaning must be documented in an RFC or other peer-reviewed, permanent, and readily available reference, in sufficient detail so that interoperability between independent implementations is possible. Subject to these constraints, name assignments are First Come, First Served - see RFC2434 [13]. Legal ID values are in the range 1..255. This document does not define any values in this number space. 16. REFERENCES [1] D.G. Korn and K.P. Vo, Vdelta: Differencing and Compression, Practical Reusable Unix Software, Editor B. Krishnamurthy, John Wiley & Sons, Inc., 1995. [2] J. Ziv and A. Lempel, A Universal Algorithm for Sequential Data Compression, IEEE Trans. on Information Theory, 23(3):337-343, 1977. [3] W. Tichy, The String-to-String Correction Problem with Block Moves, ACM Transactions on Computer Systems, 2(4):309-321, November 1984. [4] E.M. McCreight, A Space-Economical Suffix Tree Construction Algorithm, Journal of the ACM, 23:262-272, 1976. [5] J.J. Hunt, K.P. Vo, W. Tichy, An Empirical Study of Delta Algorithms, IEEE Software Configuration and Maintenance Workshop, 1996. [6] J.J. Hunt, K.P. Vo, W. Tichy, Delta Algorithms: An Empirical Analysis, ACM Trans. on Software Engineering and Methodology, 7:192-214, 1998. [7] D.G. Korn, K.P. Vo, Sfio: A buffered I/O Library, Proc. of the Summer '91 Usenix Conference, 1991. [8] D. W. Jones, Application of Splay Trees to Data Compression, CACM, 31(8):996:1007. [9] M. Nelson, J. Gailly, The Data Compression Book, ISBN 1-55851-434-1, M&T Books, New York, NY, 1995. [10] J.C. Mogul, F. Douglis, A. Feldmann, and B. Krishnamurthy, Potential benefits of delta encoding and data compression for HTTP, SIGCOMM '97, Cannes, France, 1997. [11] J.C. Mogul, B. Krishnamurthy, F. Douglis, A. Feldmann, Y. Goland, and A. Van Hoff, Delta Encoding in HTTP, IETF, draft-mogul-http-delta-10, 2001. [12] S. Bradner, Key words for use in RFCs to Indicate Requirement Levels, RFC 2119, March 1997. [13] T. Narten, H. Alvestrand, Guidelines for Writing an IANA Considerations Section in RFCs, RFC2434, October 1998. 17. AUTHOR'S ADDRESS Kiem-Phong Vo (main contact) AT&T Labs, Room D223 180 Park Avenue Florham Park, NJ 07932 Email: kpv@research.att.com Phone: 1 973 360 8630 David G. Korn AT&T Labs, Room D237 180 Park Avenue Florham Park, NJ 07932 Email: dgk@research.att.com Phone: 1 973 360 8602 Jeffrey C. Mogul Western Research Laboratory Compaq Computer Corporation 250 University Avenue Palo Alto, California, 94305, U.S.A. Email: JeffMogul@acm.org Phone: 1 650 617 3304 (email preferred) Joshua P. MacDonald Computer Science Division University of California, Berkeley 345 Soda Hall Berkeley, CA 94720 Email: jmacd@cs.berkeley.edu ================================================ FILE: source-code/dependencies/xdelta3/examples/Makefile ================================================ CFLAGS = -g -Wall -I.. -DXD3_DEBUG=1 -DNDEBUG=0 -DSIZEOF_SIZE_T=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 #CFLAGS = -O3 -Wall -I.. -DXD3_DEBUG=0 -fno-builtin -DNDEBUG=1 # -pg SOURCES = small_page_test.c encode_decode_test.c speed_test.c DEPS = ../*.h ../*.c *.h TARGETS = small_page_test encode_decode_test speed_test32 speed_test64 compare_test checksum_test all: $(TARGETS) small_page_test: small_page_test.c $(DEPS) $(CC) $(CFLAGS) small_page_test.c -o small_page_test -DXD3_USE_LARGEFILE64=0 -DSECONDARY_DJW=1 encode_decode_test: encode_decode_test.c $(DEPS) $(CC) $(CFLAGS) encode_decode_test.c -o encode_decode_test speed_test32: speed_test.c $(DEPS) $(CC) $(CFLAGS) -DXD3_USE_LARGEFILE64=0 speed_test.c -o speed_test32 speed_test64: speed_test.c $(DEPS) $(CC) $(CFLAGS) -DXD3_USE_LARGEFILE64=1 speed_test.c -o speed_test64 compare_test: compare_test.c $(CC) $(CFLAGS) compare_test.c -o compare_test checksum_test: checksum_test.cc $(CXX) $(CFLAGS) checksum_test.cc -o checksum_test clean: rm -r -f *.exe *.stackdump $(TARGETS) *.dSYM *~ ================================================ FILE: source-code/dependencies/xdelta3/examples/README.md ================================================ Files in this directory demonstrate how to use the Xdelta3 API. Copyrights are held by the respective authors. small_page_test.c -- how to use xdelta3 in an environment such as the kernel for small pages with little memory encode_decode_test.c -- how to use xdelta3 to process (encode/decode) data in multiple windows with the non-blocking API ================================================ FILE: source-code/dependencies/xdelta3/examples/compare_test.c ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include #include #include #include #include #include "xdelta3.h" #define NUM (1<<20) #define ITERS 100 /* From wikipedia on RDTSC */ inline uint64_t rdtsc() { uint32_t lo, hi; asm volatile ("rdtsc" : "=a" (lo), "=d" (hi)); return (uint64_t)hi << 32 | lo; } typedef int (*test_func)(const char *s1, const char *s2, int n); void run_test(const char *buf1, const char *buf2, const char *name, test_func func) { uint64_t start, end; uint64_t accum = 0; int i, x; for (i = 0; i < ITERS; i++) { start = rdtsc(); x = func(buf1, buf2, NUM); end = rdtsc(); accum += end - start; assert(x == NUM - 1); } accum /= ITERS; printf("%s : %qu cycles\n", name, accum); } /* Build w/ -fno-builtin for this to be fast, this assumes that there * is a difference at s1[n-1] */ int memcmp_fake(const char *s1, const char *s2, int n) { int x = memcmp(s1, s2, n); return x < 0 ? n - 1 : n + 1; } #define UNALIGNED_OK 1 static inline int test2(const char *s1c, const char *s2c, int n) { int i = 0; #if UNALIGNED_OK int nint = n / sizeof(int); if (nint >> 3) { int j = 0; const int *s1 = (const int*)s1c; const int *s2 = (const int*)s2c; int nint_8 = nint - 8; while (i <= nint_8 && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++]) { } i = (i - 1) * sizeof(int); } #endif while (i < n && s1c[i] == s2c[i]) { i++; } return i; } static inline int test1(const char *s1c, const char *s2c, int n) { int i = 0; while (i < n && s1c[i] == s2c[i]) { i++; } return i; } int main(/*int argc, char **argv*/) { char *buf1 = malloc(NUM+1); char *buf2 = malloc(NUM+1); int i; for (i = 0; i < NUM; i++) { buf1[i] = buf2[i] = rand(); } buf2[NUM-1]++; printf ("ALIGNED\n"); run_test(buf1, buf2, "memcmp", &memcmp_fake); run_test(buf1, buf2, "test1", &test1); run_test(buf1, buf2, "test2", &test2); for (i = 0; i < NUM; i++) { buf1[i] = buf2[i+1] = rand(); } buf2[NUM]++; printf ("UNALIGNED\n"); run_test(buf1, buf2+1, "memcmp", &memcmp_fake); run_test(buf1, buf2+1, "test1", &test1); run_test(buf1, buf2+1, "test2", &test2); return 0; } ================================================ FILE: source-code/dependencies/xdelta3/examples/encode_decode_test.c ================================================ // Permission to distribute this example by // Copyright (C) 2007 Ralf Junker // Ralf Junker // http://www.yunqa.de/delphi/ //--------------------------------------------------------------------------- #include #include #include "xdelta3.h" #include "xdelta3.c" //--------------------------------------------------------------------------- int code ( int encode, FILE* InFile, FILE* SrcFile , FILE* OutFile, int BufSize ) { int r, ret; struct stat statbuf; xd3_stream stream; xd3_config config; xd3_source source; void* Input_Buf; int Input_Buf_Read; if (BufSize < XD3_ALLOCSIZE) BufSize = XD3_ALLOCSIZE; memset (&stream, 0, sizeof (stream)); memset (&source, 0, sizeof (source)); xd3_init_config(&config, XD3_ADLER32); config.winsize = BufSize; xd3_config_stream(&stream, &config); if (SrcFile) { r = fstat(fileno(SrcFile), &statbuf); if (r) return r; source.blksize = BufSize; source.curblk = malloc(source.blksize); /* Load 1st block of stream. */ r = fseek(SrcFile, 0, SEEK_SET); if (r) return r; source.onblk = fread((void*)source.curblk, 1, source.blksize, SrcFile); source.curblkno = 0; /* Set the stream. */ xd3_set_source(&stream, &source); } Input_Buf = malloc(BufSize); fseek(InFile, 0, SEEK_SET); do { Input_Buf_Read = fread(Input_Buf, 1, BufSize, InFile); if (Input_Buf_Read < BufSize) { xd3_set_flags(&stream, XD3_FLUSH | stream.flags); } xd3_avail_input(&stream, Input_Buf, Input_Buf_Read); process: if (encode) ret = xd3_encode_input(&stream); else ret = xd3_decode_input(&stream); switch (ret) { case XD3_INPUT: { fprintf (stderr,"XD3_INPUT\n"); continue; } case XD3_OUTPUT: { fprintf (stderr,"XD3_OUTPUT\n"); r = fwrite(stream.next_out, 1, stream.avail_out, OutFile); if (r != (int)stream.avail_out) return r; xd3_consume_output(&stream); goto process; } case XD3_GETSRCBLK: { fprintf (stderr,"XD3_GETSRCBLK %qd\n", source.getblkno); if (SrcFile) { r = fseek(SrcFile, source.blksize * source.getblkno, SEEK_SET); if (r) return r; source.onblk = fread((void*)source.curblk, 1, source.blksize, SrcFile); source.curblkno = source.getblkno; } goto process; } case XD3_GOTHEADER: { fprintf (stderr,"XD3_GOTHEADER\n"); goto process; } case XD3_WINSTART: { fprintf (stderr,"XD3_WINSTART\n"); goto process; } case XD3_WINFINISH: { fprintf (stderr,"XD3_WINFINISH\n"); goto process; } default: { fprintf (stderr,"!!! INVALID %s %d !!!\n", stream.msg, ret); return ret; } } } while (Input_Buf_Read == BufSize); free(Input_Buf); free((void*)source.curblk); xd3_close_stream(&stream); xd3_free_stream(&stream); return 0; }; int main(int argc, char* argv[]) { FILE* InFile; FILE* SrcFile; FILE* OutFile; int r; if (argc != 3) { fprintf (stderr, "usage: %s source input\n", argv[0]); return 1; } char *input = argv[2]; char *source = argv[1]; const char *output = "encoded.testdata"; const char *decoded = "decoded.testdata"; /* Encode */ InFile = fopen(input, "rb"); SrcFile = fopen(source, "rb"); OutFile = fopen(output, "wb"); r = code (1, InFile, SrcFile, OutFile, 0x1000); fclose(OutFile); fclose(SrcFile); fclose(InFile); if (r) { fprintf (stderr, "Encode error: %d\n", r); return r; } /* Decode */ InFile = fopen(output, "rb"); SrcFile = fopen(source, "rb"); OutFile = fopen(decoded, "wb"); r = code (0, InFile, SrcFile, OutFile, 0x1000); fclose(OutFile); fclose(SrcFile); fclose(InFile); if (r) { fprintf (stderr, "Decode error: %d\n", r); return r; } return 0; } ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSAppDelegate.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: objc *-* Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #import @interface Xd3iOSAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSAppDelegate.m ================================================ /* xdelta3 - delta compression tools and library -*- Mode: objc *-* Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #import "Xd3iOSAppDelegate.h" @implementation Xd3iOSAppDelegate @synthesize window = _window; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { /* Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. */ } - (void)applicationDidEnterBackground:(UIApplication *)application { /* Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. */ } - (void)applicationWillEnterForeground:(UIApplication *)application { /* Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. */ } - (void)applicationDidBecomeActive:(UIApplication *)application { /* Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. */ } - (void)applicationWillTerminate:(UIApplication *)application { /* Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. */ } @end ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSViewController.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: objc *-* Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #import @interface Xd3iOSViewController : UIViewController { NSString *inputSeed; } - (IBAction)startTest:(id)sender; @property (weak, nonatomic) IBOutlet UITextField *theSeed; @property (weak, nonatomic) IBOutlet UITextView *theView; @property (atomic, retain) NSMutableString *theOutput; @property (nonatomic) BOOL inTest; @end ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/Xd3iOSViewController.m ================================================ /* xdelta3 - delta compression tools and library -*- Mode: objc *-* Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #import "Xd3iOSViewController.h" #include "xdelta3.h" #include "dispatch/queue.h" #include "Foundation/NSBundle.h" extern void (*xprintf_message_func)(const char* msg); void print_to_view(const char* buf); int xd3_main_cmdline(int argc, char **argv); void do_localfile_test(void); int compare_files(const char* file1, const char* file2); Xd3iOSViewController *static_ptr; @implementation Xd3iOSViewController @synthesize theSeed = _theSeed; @synthesize theView = _theView; @synthesize theOutput = _theOutput; @synthesize inTest = _inTest; - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewDidUnload { [self setTheSeed:nil]; [self setTheView:nil]; [self setTheView:nil]; [super viewDidUnload]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { switch (interfaceOrientation) { case UIInterfaceOrientationPortrait: case UIInterfaceOrientationPortraitUpsideDown: return YES; default: break; } return NO; } - (BOOL)textFieldShouldReturn:(UITextField*)theTextField { if (theTextField == self.theSeed) { [theTextField resignFirstResponder]; } return YES; } - (IBAction)startTest:(id)sender { if (self.inTest) { return; } self.inTest = YES; NSString *seedString = self.theSeed.text; if ([seedString length] == 0) { seedString = @"RFC3284"; } static_ptr = self; xprintf_message_func = &print_to_view; self.theOutput = [[NSMutableString alloc] initWithFormat:@"Starting test (seed=%@)\n", seedString]; self.theView.text = self.theOutput; dispatch_queue_t mq = dispatch_get_main_queue(); dispatch_queue_t dq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(dq, ^{ do_localfile_test(); char *argv[] = { "xdelta3", "test", NULL }; xd3_main_cmdline(2, argv); print_to_view("Finished unittest: success"); dispatch_async(mq, ^{ self.inTest = NO; }); }); } void printns_to_view(NSString* ns); void printns_to_view(NSString* ns) { dispatch_queue_t mq = dispatch_get_main_queue(); dispatch_async(mq, ^{ if ([static_ptr.theOutput length] < 25000) { [static_ptr.theOutput appendString:ns]; } else { static_ptr.theOutput = [[NSMutableString alloc] initWithString:ns]; } static_ptr.theView.text = static_ptr.theOutput; CGSize size = static_ptr.theView.contentSize; [static_ptr.theView scrollRectToVisible:CGRectMake(0, size.height - 1, 1, 1) animated:NO]; }); } void print_to_view(const char* buf) { NSString *ns = [NSString stringWithCString:buf encoding:NSASCIIStringEncoding]; printns_to_view(ns); } void do_localfile_test(void) { NSBundle *bundle; bundle = [NSBundle mainBundle]; NSString *localfile1 = [bundle pathForResource:@"file_v1" ofType:@"bin"]; NSString *localfile2 = [bundle pathForResource:@"file_v2" ofType:@"bin"]; NSString *localfiled = [bundle pathForResource:@"file_v1_to_v2" ofType:@"bin"]; printns_to_view([localfile1 stringByAppendingString:@"\n"]); printns_to_view([localfile2 stringByAppendingString:@"\n"]); printns_to_view([localfiled stringByAppendingString:@"\n"]); NSString *tmpdir = NSTemporaryDirectory(); NSString *tmpfile = [tmpdir stringByAppendingPathComponent:@"delta.tmp"]; printns_to_view([tmpfile stringByAppendingString:@"\n"]); char *argv[] = { "xdelta3", "-dfvv", "-s", (char*)[localfile1 UTF8String], (char*)[localfiled UTF8String], (char*)[tmpfile UTF8String] }; xd3_main_cmdline(6, argv); NSFileManager *filemgr; filemgr = [NSFileManager defaultManager]; if ([filemgr contentsEqualAtPath: localfile2 andPath: tmpfile] == YES) { printns_to_view(@"File contents match\n"); } else { NSError *err1 = NULL; NSDictionary *d1 = [filemgr attributesOfItemAtPath: tmpfile error: &err1]; if (err1 != NULL) { printns_to_view([@"File localfile2 could not stat %s\n" stringByAppendingString: tmpfile]); } else { printns_to_view([@"File contents do not match!!!! tmpfile size=" stringByAppendingString: [[NSMutableString alloc] initWithFormat:@"%llu\n", [d1 fileSize]]]); } compare_files([localfile2 UTF8String], [tmpfile UTF8String]); } print_to_view("Finished localfile test.\n"); } @end ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/InfoPlist.strings ================================================ /* Localized versions of Info.plist keys */ ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/MainStoryboard_iPad.storyboard ================================================ ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/en.lproj/MainStoryboard_iPhone.storyboard ================================================ ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/main.m ================================================ /* xdelta3 - delta compression tools and library -*- Mode: objc *-* Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #import #import "Xd3iOSAppDelegate.h" int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([Xd3iOSAppDelegate class])); } } ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test/xdelta3-ios-test-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleDisplayName ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFiles CFBundleIdentifier Joshua-MacDonald.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 LSRequiresIPhoneOS UIMainStoryboardFile MainStoryboard_iPhone UIMainStoryboardFile~ipad MainStoryboard_iPad UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: source-code/dependencies/xdelta3/examples/iOS/xdelta3-ios-test/xdelta3-ios-test.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ B9001B65158D008900B9E855 /* xdelta3.c in Sources */ = {isa = PBXBuildFile; fileRef = B9001B63158D008900B9E855 /* xdelta3.c */; }; B9313C3C158D11BA001C1F28 /* file_v1_to_v2.bin in Resources */ = {isa = PBXBuildFile; fileRef = B9313C39158D11BA001C1F28 /* file_v1_to_v2.bin */; }; B9313C3D158D11BA001C1F28 /* file_v1.bin in Resources */ = {isa = PBXBuildFile; fileRef = B9313C3A158D11BA001C1F28 /* file_v1.bin */; }; B9313C3E158D11BA001C1F28 /* file_v2.bin in Resources */ = {isa = PBXBuildFile; fileRef = B9313C3B158D11BA001C1F28 /* file_v2.bin */; }; B9ADC6BF158CFD36007EF999 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9ADC6BE158CFD36007EF999 /* UIKit.framework */; }; B9ADC6C1158CFD36007EF999 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9ADC6C0158CFD36007EF999 /* Foundation.framework */; }; B9ADC6C3158CFD36007EF999 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9ADC6C2158CFD36007EF999 /* CoreGraphics.framework */; }; B9ADC6C9158CFD36007EF999 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B9ADC6C7158CFD36007EF999 /* InfoPlist.strings */; }; B9ADC6CB158CFD36007EF999 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B9ADC6CA158CFD36007EF999 /* main.m */; }; B9ADC6CF158CFD36007EF999 /* Xd3iOSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B9ADC6CE158CFD36007EF999 /* Xd3iOSAppDelegate.m */; }; B9ADC6D2158CFD36007EF999 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9ADC6D0158CFD36007EF999 /* MainStoryboard_iPhone.storyboard */; }; B9ADC6D5158CFD36007EF999 /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9ADC6D3158CFD36007EF999 /* MainStoryboard_iPad.storyboard */; }; B9ADC6D8158CFD36007EF999 /* Xd3iOSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B9ADC6D7158CFD36007EF999 /* Xd3iOSViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ B9001B56158D008900B9E855 /* xdelta3-blkcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-blkcache.h"; path = "../../../../xdelta3-blkcache.h"; sourceTree = ""; }; B9001B57158D008900B9E855 /* xdelta3-cfgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-cfgs.h"; path = "../../../../xdelta3-cfgs.h"; sourceTree = ""; }; B9001B58158D008900B9E855 /* xdelta3-decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-decode.h"; path = "../../../../xdelta3-decode.h"; sourceTree = ""; }; B9001B59158D008900B9E855 /* xdelta3-djw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-djw.h"; path = "../../../../xdelta3-djw.h"; sourceTree = ""; }; B9001B5A158D008900B9E855 /* xdelta3-fgk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-fgk.h"; path = "../../../../xdelta3-fgk.h"; sourceTree = ""; }; B9001B5B158D008900B9E855 /* xdelta3-hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-hash.h"; path = "../../../../xdelta3-hash.h"; sourceTree = ""; }; B9001B5C158D008900B9E855 /* xdelta3-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-internal.h"; path = "../../../../xdelta3-internal.h"; sourceTree = ""; }; B9001B5D158D008900B9E855 /* xdelta3-list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-list.h"; path = "../../../../xdelta3-list.h"; sourceTree = ""; }; B9001B5E158D008900B9E855 /* xdelta3-main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-main.h"; path = "../../../../xdelta3-main.h"; sourceTree = ""; }; B9001B5F158D008900B9E855 /* xdelta3-merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-merge.h"; path = "../../../../xdelta3-merge.h"; sourceTree = ""; }; B9001B60158D008900B9E855 /* xdelta3-python.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-python.h"; path = "../../../../xdelta3-python.h"; sourceTree = ""; }; B9001B61158D008900B9E855 /* xdelta3-second.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-second.h"; path = "../../../../xdelta3-second.h"; sourceTree = ""; }; B9001B62158D008900B9E855 /* xdelta3-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "xdelta3-test.h"; path = "../../../../xdelta3-test.h"; sourceTree = ""; }; B9001B63158D008900B9E855 /* xdelta3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xdelta3.c; path = ../../../../xdelta3.c; sourceTree = ""; }; B9001B64158D008900B9E855 /* xdelta3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xdelta3.h; path = ../../../../xdelta3.h; sourceTree = ""; }; B9313C39158D11BA001C1F28 /* file_v1_to_v2.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = file_v1_to_v2.bin; sourceTree = ""; }; B9313C3A158D11BA001C1F28 /* file_v1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = file_v1.bin; sourceTree = ""; }; B9313C3B158D11BA001C1F28 /* file_v2.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = file_v2.bin; sourceTree = ""; }; B9ADC6BA158CFD36007EF999 /* xdelta3-ios-test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "xdelta3-ios-test.app"; sourceTree = BUILT_PRODUCTS_DIR; }; B9ADC6BE158CFD36007EF999 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; B9ADC6C0158CFD36007EF999 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; B9ADC6C2158CFD36007EF999 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; B9ADC6C6158CFD36007EF999 /* xdelta3-ios-test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "xdelta3-ios-test-Info.plist"; sourceTree = ""; }; B9ADC6C8158CFD36007EF999 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; B9ADC6CA158CFD36007EF999 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; B9ADC6CC158CFD36007EF999 /* xdelta3-ios-test-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "xdelta3-ios-test-Prefix.pch"; sourceTree = ""; }; B9ADC6CD158CFD36007EF999 /* Xd3iOSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Xd3iOSAppDelegate.h; sourceTree = ""; }; B9ADC6CE158CFD36007EF999 /* Xd3iOSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Xd3iOSAppDelegate.m; sourceTree = ""; }; B9ADC6D1158CFD36007EF999 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = ""; }; B9ADC6D4158CFD36007EF999 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; }; B9ADC6D6158CFD36007EF999 /* Xd3iOSViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Xd3iOSViewController.h; sourceTree = ""; }; B9ADC6D7158CFD36007EF999 /* Xd3iOSViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Xd3iOSViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ B9ADC6B7158CFD36007EF999 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( B9ADC6BF158CFD36007EF999 /* UIKit.framework in Frameworks */, B9ADC6C1158CFD36007EF999 /* Foundation.framework in Frameworks */, B9ADC6C3158CFD36007EF999 /* CoreGraphics.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ B9ADC6AF158CFD36007EF999 = { isa = PBXGroup; children = ( B9ADC6C4158CFD36007EF999 /* xdelta3-ios-test */, B9ADC6BD158CFD36007EF999 /* Frameworks */, B9ADC6BB158CFD36007EF999 /* Products */, ); sourceTree = ""; }; B9ADC6BB158CFD36007EF999 /* Products */ = { isa = PBXGroup; children = ( B9ADC6BA158CFD36007EF999 /* xdelta3-ios-test.app */, ); name = Products; sourceTree = ""; }; B9ADC6BD158CFD36007EF999 /* Frameworks */ = { isa = PBXGroup; children = ( B9ADC6BE158CFD36007EF999 /* UIKit.framework */, B9ADC6C0158CFD36007EF999 /* Foundation.framework */, B9ADC6C2158CFD36007EF999 /* CoreGraphics.framework */, ); name = Frameworks; sourceTree = ""; }; B9ADC6C4158CFD36007EF999 /* xdelta3-ios-test */ = { isa = PBXGroup; children = ( B9001B56158D008900B9E855 /* xdelta3-blkcache.h */, B9001B57158D008900B9E855 /* xdelta3-cfgs.h */, B9001B58158D008900B9E855 /* xdelta3-decode.h */, B9001B59158D008900B9E855 /* xdelta3-djw.h */, B9001B5A158D008900B9E855 /* xdelta3-fgk.h */, B9001B5B158D008900B9E855 /* xdelta3-hash.h */, B9001B5C158D008900B9E855 /* xdelta3-internal.h */, B9001B5D158D008900B9E855 /* xdelta3-list.h */, B9001B5E158D008900B9E855 /* xdelta3-main.h */, B9001B5F158D008900B9E855 /* xdelta3-merge.h */, B9001B60158D008900B9E855 /* xdelta3-python.h */, B9001B61158D008900B9E855 /* xdelta3-second.h */, B9001B62158D008900B9E855 /* xdelta3-test.h */, B9001B63158D008900B9E855 /* xdelta3.c */, B9001B64158D008900B9E855 /* xdelta3.h */, B9ADC6CD158CFD36007EF999 /* Xd3iOSAppDelegate.h */, B9ADC6CE158CFD36007EF999 /* Xd3iOSAppDelegate.m */, B9ADC6D0158CFD36007EF999 /* MainStoryboard_iPhone.storyboard */, B9ADC6D3158CFD36007EF999 /* MainStoryboard_iPad.storyboard */, B9ADC6D6158CFD36007EF999 /* Xd3iOSViewController.h */, B9ADC6D7158CFD36007EF999 /* Xd3iOSViewController.m */, B9ADC6C5158CFD36007EF999 /* Supporting Files */, ); path = "xdelta3-ios-test"; sourceTree = ""; }; B9ADC6C5158CFD36007EF999 /* Supporting Files */ = { isa = PBXGroup; children = ( B9313C39158D11BA001C1F28 /* file_v1_to_v2.bin */, B9313C3A158D11BA001C1F28 /* file_v1.bin */, B9313C3B158D11BA001C1F28 /* file_v2.bin */, B9ADC6C6158CFD36007EF999 /* xdelta3-ios-test-Info.plist */, B9ADC6C7158CFD36007EF999 /* InfoPlist.strings */, B9ADC6CA158CFD36007EF999 /* main.m */, B9ADC6CC158CFD36007EF999 /* xdelta3-ios-test-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ B9ADC6B9158CFD36007EF999 /* xdelta3-ios-test */ = { isa = PBXNativeTarget; buildConfigurationList = B9ADC6DB158CFD36007EF999 /* Build configuration list for PBXNativeTarget "xdelta3-ios-test" */; buildPhases = ( B9ADC6B6158CFD36007EF999 /* Sources */, B9ADC6B7158CFD36007EF999 /* Frameworks */, B9ADC6B8158CFD36007EF999 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "xdelta3-ios-test"; productName = "xdelta3-ios-test"; productReference = B9ADC6BA158CFD36007EF999 /* xdelta3-ios-test.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ B9ADC6B1158CFD36007EF999 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0420; }; buildConfigurationList = B9ADC6B4158CFD36007EF999 /* Build configuration list for PBXProject "xdelta3-ios-test" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = B9ADC6AF158CFD36007EF999; productRefGroup = B9ADC6BB158CFD36007EF999 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( B9ADC6B9158CFD36007EF999 /* xdelta3-ios-test */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ B9ADC6B8158CFD36007EF999 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( B9ADC6C9158CFD36007EF999 /* InfoPlist.strings in Resources */, B9ADC6D2158CFD36007EF999 /* MainStoryboard_iPhone.storyboard in Resources */, B9ADC6D5158CFD36007EF999 /* MainStoryboard_iPad.storyboard in Resources */, B9313C3C158D11BA001C1F28 /* file_v1_to_v2.bin in Resources */, B9313C3D158D11BA001C1F28 /* file_v1.bin in Resources */, B9313C3E158D11BA001C1F28 /* file_v2.bin in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ B9ADC6B6158CFD36007EF999 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B9ADC6CB158CFD36007EF999 /* main.m in Sources */, B9ADC6CF158CFD36007EF999 /* Xd3iOSAppDelegate.m in Sources */, B9ADC6D8158CFD36007EF999 /* Xd3iOSViewController.m in Sources */, B9001B65158D008900B9E855 /* xdelta3.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ B9ADC6C7158CFD36007EF999 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( B9ADC6C8158CFD36007EF999 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; B9ADC6D0158CFD36007EF999 /* MainStoryboard_iPhone.storyboard */ = { isa = PBXVariantGroup; children = ( B9ADC6D1158CFD36007EF999 /* en */, ); name = MainStoryboard_iPhone.storyboard; sourceTree = ""; }; B9ADC6D3158CFD36007EF999 /* MainStoryboard_iPad.storyboard */ = { isa = PBXVariantGroup; children = ( B9ADC6D4158CFD36007EF999 /* en */, ); name = MainStoryboard_iPad.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ B9ADC6D9158CFD36007EF999 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_INPUT_FILETYPE = sourcecode.c.objc; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "XD3_USE_LARGEFILE64=0", "XD3_POSIX=1", "EXTERNAL_COMPRESSION=0", "NOT_MAIN=1", "XD3_MAIN=1", "SECONDARY_DJW=1", "XD3_DEBUG=1", "REGRESSION_TEST=1", "SHELL_TESTS=0", "SECONDARY_FGK=1", "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.0; OTHER_CFLAGS = ( "-DXD3_USE_LARGEFILE64=0", "-DXD3_POSIX=1", "-DEXTERNAL_COMPRESSION=0", "-DNOT_MAIN=1", "-DXD3_MAIN=1", "-DSECONDARY_DJW=1", "-DXD3_DEBUG=1", "-DREGRESSION_TEST=1", "-DSHELL_TESTS=0", "-DSECONDARY_FGK=1", ); SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; B9ADC6DA158CFD36007EF999 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_INPUT_FILETYPE = sourcecode.c.objc; GCC_PREPROCESSOR_DEFINITIONS = ( "XD3_USE_LARGEFILE64=0", "XD3_POSIX=1", "EXTERNAL_COMPRESSION=0", "NOT_MAIN=1", "XD3_MAIN=1", "SECONDARY_DJW=1", "XD3_DEBUG=1", "REGRESSION_TEST=1", "SHELL_TESTS=0", "SECONDARY_FGK=1", ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.0; OTHER_CFLAGS = ( "-DXD3_USE_LARGEFILE64=0", "-DXD3_POSIX=1", "-DEXTERNAL_COMPRESSION=0", "-DNOT_MAIN=1", "-DXD3_MAIN=1", "-DSECONDARY_DJW=1", "-DXD3_DEBUG=1", "-DREGRESSION_TEST=1", "-DSHELL_TESTS=0", "-DSECONDARY_FGK=1", ); SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; B9ADC6DC158CFD36007EF999 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "xdelta3-ios-test/xdelta3-ios-test-Prefix.pch"; INFOPLIST_FILE = "xdelta3-ios-test/xdelta3-ios-test-Info.plist"; OTHER_CFLAGS = ""; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; name = Debug; }; B9ADC6DD158CFD36007EF999 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "xdelta3-ios-test/xdelta3-ios-test-Prefix.pch"; INFOPLIST_FILE = "xdelta3-ios-test/xdelta3-ios-test-Info.plist"; OTHER_CFLAGS = ""; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ B9ADC6B4158CFD36007EF999 /* Build configuration list for PBXProject "xdelta3-ios-test" */ = { isa = XCConfigurationList; buildConfigurations = ( B9ADC6D9158CFD36007EF999 /* Debug */, B9ADC6DA158CFD36007EF999 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; B9ADC6DB158CFD36007EF999 /* Build configuration list for PBXNativeTarget "xdelta3-ios-test" */ = { isa = XCConfigurationList; buildConfigurations = ( B9ADC6DC158CFD36007EF999 /* Debug */, B9ADC6DD158CFD36007EF999 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = B9ADC6B1158CFD36007EF999 /* Project object */; } ================================================ FILE: source-code/dependencies/xdelta3/examples/small_page_test.c ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include #define PAGE_SIZE 4096 #define SPACE_MAX 131072 // how much memory per process #define OUTPUT_MAX 1024 // max size for output #define XD3_ALLOCSIZE 256 // internal size for various buffers #define IOPT_SIZE 128 // instruction buffer // SPACE_MAX of 32K is sufficient for most inputs with XD3_COMPLEVEL_1 // XD3_COMPLEVEL_9 requires about 4x more space than XD3_COMPLEVEL_1 #include "xdelta3.h" #include "xdelta3.c" typedef struct _context { uint8_t *buffer; int allocated; } context_t; static int max_allocated = 0; void* process_alloc (void* opaque, usize_t items, usize_t size) { context_t *ctx = (context_t*) opaque; usize_t t = items * size; void *ret; if (ctx->allocated + t > SPACE_MAX) { return NULL; } ret = ctx->buffer + ctx->allocated; ctx->allocated += t; return ret; } void process_free (void* opaque, void *ptr) { } int process_page (int is_encode, int (*func) (xd3_stream *), const uint8_t *input, usize_t input_size, const uint8_t *source, uint8_t *output, usize_t *output_size, usize_t output_size_max, int flags) { /* On my x86 this is 1072 of objects on the stack */ xd3_stream stream; xd3_config config; xd3_source src; context_t *ctx = calloc(SPACE_MAX, 1); int ret; memset (&config, 0, sizeof(config)); if (ctx == NULL) { printf("calloc failed\n"); return -1; } ctx->buffer = (uint8_t*)ctx; ctx->allocated = sizeof(*ctx); config.flags = flags; config.winsize = PAGE_SIZE; config.sprevsz = PAGE_SIZE; config.srcwin_maxsz = PAGE_SIZE; config.iopt_size = IOPT_SIZE; config.alloc = &process_alloc; config.freef = &process_free; config.opaque = (void*) ctx; src.blksize = PAGE_SIZE; src.onblk = PAGE_SIZE; src.curblk = source; src.curblkno = 0; if ((ret = xd3_config_stream (&stream, &config)) != 0 || (ret = xd3_set_source_and_size (&stream, &src, PAGE_SIZE)) != 0 || (ret = xd3_process_stream (is_encode, &stream, func, 1, input, input_size, output, output_size, output_size_max)) != 0) { if (stream.msg != NULL) { fprintf(stderr, "stream message: %s\n", stream.msg); } } xd3_free_stream (&stream); if (max_allocated < ctx->allocated) { max_allocated = ctx->allocated; fprintf(stderr, "max allocated %d\n", max_allocated); } free(ctx); return ret; } int test(int stride, int encode_flags) { uint8_t frompg[PAGE_SIZE]; uint8_t topg[PAGE_SIZE]; uint8_t output[OUTPUT_MAX]; uint8_t reout[PAGE_SIZE]; usize_t output_size; usize_t re_size; int i, j, ret; for (i = 0; i < PAGE_SIZE; i++) { topg[i] = frompg[i] = (rand() >> 3 ^ rand() >> 6 ^ rand() >> 9); } // change 1 byte every stride if (stride > 0) { for (j = stride; j <= PAGE_SIZE; j += stride) { topg[j - 1] ^= 0xff; } } if ((ret = process_page (1, xd3_encode_input, topg, PAGE_SIZE, frompg, output, &output_size, OUTPUT_MAX, encode_flags)) != 0) { fprintf (stderr, "encode failed: stride %u flags 0x%x\n", stride, encode_flags); return ret; } if ((ret = process_page (0, xd3_decode_input, output, output_size, frompg, reout, &re_size, PAGE_SIZE, 0)) != 0) { fprintf (stderr, "decode failed: stride %u output_size %u flags 0x%x\n", stride, output_size, encode_flags); return ret; } if (output_size > OUTPUT_MAX || re_size != PAGE_SIZE) { fprintf (stderr, "internal error: %u != %u\n", output_size, re_size); return -1; } for (i = 0; i < PAGE_SIZE; i++) { if (reout[i] != topg[i]) { fprintf (stderr, "encode-decode error: position %d\n", i); return -1; } } fprintf(stderr, "stride %d flags 0x%x size %u ", stride, encode_flags, output_size); fprintf(stderr, "%s\n", (ret == 0) ? "OK" : "FAIL"); return 0; } int main() { int stride; int level; for (level = 1; level < 10; level = (level == 1 ? 3 : level + 3)) { int lflag = level << XD3_COMPLEVEL_SHIFT; for (stride = 2; stride <= PAGE_SIZE; stride += 2) { test(stride, lflag); test(stride, lflag | XD3_SEC_DJW); } } return 0; } ================================================ FILE: source-code/dependencies/xdelta3/examples/speed_test.c ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "test.h" usize_t bench_speed(const uint8_t *from_buf, const size_t from_len, const uint8_t *to_buf, const size_t to_len, uint8_t *delta_buf, const size_t delta_alloc, int flags) { usize_t delta_size; int ret = xd3_encode_memory(to_buf, to_len, from_buf, from_len, delta_buf, &delta_size, delta_alloc, flags); if (ret != 0) { fprintf(stderr, "encode failure: %d: %s\n", ret, xd3_strerror(ret)); abort(); } return delta_size; } int main(int argc, char **argv) { int repeat, level; char *from, *to; uint8_t *from_buf = NULL, *to_buf = NULL, *delta_buf = NULL; size_t from_len = 0, to_len, delta_alloc, delta_size = 0; long start, finish; int i, ret; int flags; if (argc != 5) { fprintf(stderr, "usage: speed_test LEVEL COUNT FROM TO\n"); return 1; } level = atoi(argv[1]); repeat = atoi(argv[2]); from = argv[3]; to = argv[4]; flags = (level << XD3_COMPLEVEL_SHIFT) & XD3_COMPLEVEL_MASK; if ((strcmp(from, "null") != 0 && (ret = read_whole_file(from, &from_buf, &from_len))) || (ret = read_whole_file(to, &to_buf, &to_len))) { fprintf(stderr, "read_whole_file error\n"); goto exit; } delta_alloc = to_len * 11 / 10; delta_buf = main_malloc(delta_alloc); start = get_millisecs_now(); for (i = 0; i < repeat; ++i) { delta_size = bench_speed(from_buf, from_len, to_buf, to_len, delta_buf, delta_alloc, flags); } finish = get_millisecs_now(); fprintf(stderr, "STAT: encode %3.2f ms from %s to %s repeat %d %zdbit delta %zd\n", (double)(finish - start) / repeat, from, to, repeat, sizeof (xoff_t) * 8, delta_size); ret = 0; if (0) { exit: ret = 1; } main_free(to_buf); main_free(from_buf); main_free(delta_buf); return ret; } ================================================ FILE: source-code/dependencies/xdelta3/examples/test.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #define NOT_MAIN 1 #include "xdelta3.h" #include "xdelta3.c" static int read_whole_file(const char *name, uint8_t **buf_ptr, size_t *buf_len) { main_file file; int ret; xoff_t len; usize_t nread; main_file_init(&file); file.filename = name; ret = main_file_open(&file, name, XO_READ); if (ret != 0) { fprintf(stderr, "open failed\n"); goto exit; } ret = main_file_stat(&file, &len); if (ret != 0) { fprintf(stderr, "stat failed\n"); goto exit; } (*buf_len) = (size_t)len; (*buf_ptr) = (uint8_t*) main_malloc(*buf_len); ret = main_file_read(&file, *buf_ptr, *buf_len, &nread, "read failed"); if (ret == 0 && *buf_len == nread) { ret = 0; } else { fprintf(stderr, "invalid read\n"); ret = XD3_INTERNAL; } exit: main_file_cleanup(&file); return ret; } ================================================ FILE: source-code/dependencies/xdelta3/generate_build_files.sh ================================================ #!/bin/sh aclocal && autoreconf --install && libtoolize && autoconf && automake --add-missing && automake ================================================ FILE: source-code/dependencies/xdelta3/go/src/regtest.go ================================================ package main import ( "fmt" "io" "path" "os" "sort" "time" "xdelta" ) const ( xdataset = "/volume/home/jmacd/src/testdata" xcompare = "/volume/home/jmacd/src/xdelta-devel/xdelta3/build/x86_64-pc-linux-gnu-m64/xoff64/xdelta3" xdelta3 = "/volume/home/jmacd/src/xdelta-64bithash/xdelta3/build/x86_64-pc-linux-gnu-m64/usize64/xoff64/xdelta3" seed = 1422253499919909358 ) type Config struct { srcbuf_size int64 window_size int64 blocksize int } func NewC() Config { // TODO make these (and above) flags return Config{1<<26, 1<<22, 1<<16} } func (c Config) smokeTest(t *xdelta.TestGroup, p xdelta.Program) { target := "Hello world!" source := "Hello world, nice to meet you!" enc, err := t.Exec("encode", p, true, []string{"-e"}) if err != nil { t.Panic(err) } dec, err := t.Exec("decode", p, true, []string{"-d"}) if err != nil { t.Panic(err) } encodeout := t.Drain(enc.Stdout, "encode.stdout") decodeout := t.Drain(dec.Stdout, "decode.stdout") t.Empty(enc.Stderr, "encode") t.Empty(dec.Stderr, "decode") t.TestWrite("encode.stdin", enc.Stdin, []byte(target)) t.TestWrite("encode.srcin", enc.Srcin, []byte(source)) t.TestWrite("decode.stdin", dec.Stdin, <-encodeout) t.TestWrite("decode.srcin", dec.Srcin, []byte(source)) if do := string(<-decodeout); do != target { t.Panic(fmt.Errorf("It's not working! %s\n!=\n%s\n", do, target)) } t.Wait(enc, dec) } type PairTest struct { // Input Config program xdelta.Program source, target string // Output TestOutput } type TestOutput struct { encoded int64 encDuration time.Duration decDuration time.Duration encSysDuration time.Duration decSysDuration time.Duration } func (to *TestOutput) Add(a TestOutput) { to.encoded += a.encoded to.encDuration += a.encDuration to.decDuration += a.decDuration to.encSysDuration += a.encSysDuration to.decSysDuration += a.decSysDuration } func (to *TestOutput) String() string { return fmt.Sprintf("SIZE: %v\tT: %v\tTSYS: %v\tDT: %v\tDTSYS: %v", to.encoded, to.encDuration, to.encSysDuration, to.decDuration, to.encSysDuration) } // P is the test program, Q is the reference version. func (cfg Config) datasetTest(t *xdelta.TestGroup, p, q xdelta.Program) { dir, err := os.Open(xdataset) if err != nil { t.Panic(err) } dents, err := dir.Readdir(-1) if err != nil { t.Panic(err) } paths := make([]string, len(dents)) var total int64 for i, d := range dents { if !d.Mode().IsRegular() { continue } paths[i] = fmt.Sprint(xdataset, "/", d.Name()) total += d.Size() } meansize := total / int64(len(dents)) largest := uint(20) for ; largest <= 31 && 1< (1.05 * float64(expect)) { t.Fail("encoded size should be ~=", expect, ", actual ", encoded_size) } } func main() { r, err := xdelta.NewRunner() if err != nil { panic(err) } defer r.Cleanup() cfg := NewC() prog := xdelta.Program{xdelta3} r.RunTest("smoketest", func(t *xdelta.TestGroup) { cfg.smokeTest(t, prog) }) for i := uint(29); i <= 33; i += 1 { // The arguments to offsetTest are offset, source // window size, and file size. The source window size // is (2 << i) and (in the 3.0x release branch) is // limited to 2^31, so the the greatest value of i is // 30. cfg.srcbuf_size = 2 << i r.RunTest(fmt.Sprint("offset", i), func(t *xdelta.TestGroup) { cfg.offsetTest(t, prog, 1 << i, 3 << i) }) } comp := xdelta.Program{xcompare} r.RunTest("dataset", func(t *xdelta.TestGroup) { cfg.datasetTest(t, prog, comp) }) } ================================================ FILE: source-code/dependencies/xdelta3/go/src/xdelta/rstream.go ================================================ package xdelta import ( "io" "math/rand" ) const ( blocksize = 1<<17 ) func (t *TestGroup) WriteRstreams(desc string, seed, offset, len int64, src, tgt io.WriteCloser) { t.Go("src-write:"+desc, func (g *Goroutine) { writeOne(g, seed, 0, len, tgt, false) }) t.Go("tgt-write:"+desc, func (g *Goroutine) { writeOne(g, seed, offset, len, src, true) }) } func writeOne(g *Goroutine, seed, offset, len int64, stream io.WriteCloser, readall bool) { if !readall { // Allow the source-read to fail or block until the process terminates. // This behavior is reserved for the decoder, which is not required to // read the entire source. g.OK() } if offset != 0 { // Fill with other random data until the offset if err := writeRand(g, rand.New(rand.NewSource(^seed)), offset, stream); err != nil { g.Panic(err) } } if err := writeRand(g, rand.New(rand.NewSource(seed)), len - offset, stream); err != nil { g.Panic(err) } if err := stream.Close(); err != nil { g.Panic(err) } g.OK() } func writeRand(g *Goroutine, r *rand.Rand, len int64, s io.Writer) error { blk := make([]byte, blocksize) for len > 0 { fillRand(r, blk) c := blocksize if len < blocksize { c = int(len) } if _, err := s.Write(blk[0:c]); err != nil { return err } len -= int64(c) } return nil } func fillRand(r *rand.Rand, blk []byte) { for p := 0; p < len(blk); { v := r.Int63() for i := 7; i != 0 && p < len(blk); i-- { blk[p] = byte(v) p++ v >>= 8 } } } ================================================ FILE: source-code/dependencies/xdelta3/go/src/xdelta/run.go ================================================ package xdelta import ( "fmt" "io" "io/ioutil" "os" "os/exec" ) type Program struct { Path string } type Run struct { Cmd exec.Cmd Srcfile string Stdin io.WriteCloser Srcin io.WriteCloser Stdout io.ReadCloser Stderr io.ReadCloser } type Runner struct { Testdir string } func (r *Run) Wait() error { return r.Cmd.Wait() } func NewRunner() (*Runner, error) { if dir, err := ioutil.TempDir(tmpDir, "xrt"); err != nil { return nil, err } else { return &Runner{dir}, nil } } func (r *Runner) newTestGroup(name string) (*TestGroup) { tg := &TestGroup{Runner: r} tg.WaitGroup.Add(1) g0 := &Goroutine{tg, name, false} tg.running = append(tg.running, g0) tg.main = g0 return tg } func (r *Runner) Cleanup() { os.RemoveAll(r.Testdir) } func (r *Runner) RunTest(name string, f func (t *TestGroup)) { t := r.newTestGroup(name) c := make(chan interface{}) go func() { defer func() { rec := recover() c <- rec }() fmt.Println("Testing", name, "...") f(t) c <- nil }() rec := <- c if t.errors == nil && rec == nil { fmt.Println("Success:", name) } else { fmt.Println("FAILED:", name, t.errors, rec) } } ================================================ FILE: source-code/dependencies/xdelta3/go/src/xdelta/test.go ================================================ package xdelta import ( "bufio" "bytes" "errors" "fmt" "io" "io/ioutil" "os" "path" "sync/atomic" "golang.org/x/sys/unix" ) var ( tmpDir = "/tmp" srcSeq int64 ) func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte { c := make(chan []byte) t.Go(desc, func(g *Goroutine) { if b, err := ioutil.ReadAll(f); err != nil { g.Panic(err) } else { c <- b } g.OK() }) return c } func (t *TestGroup) Empty(f io.ReadCloser, desc string) *Goroutine { return t.Go("empty:"+desc, func (g *Goroutine) { s := bufio.NewScanner(f) for s.Scan() { os.Stderr.Write([]byte(fmt.Sprint(desc, ": ", s.Text(), "\n"))) } err := s.Err() f.Close() if err != nil { g.Panic(err) } g.OK() }) } func (t *TestGroup) TestWrite(what string, f io.WriteCloser, b []byte) *Goroutine { return t.Go("write", func(g *Goroutine) { if _, err := f.Write(b); err != nil { g.Panic(err) } if err := f.Close(); err != nil { g.Panic(err) } g.OK() }) } func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser, written *int64) *Goroutine { return t.Go("copy", func(g *Goroutine) { nwrite, err := io.Copy(w, r) if err != nil { g.Panic(err) } err = r.Close() if err != nil { g.Panic(err) } err = w.Close() if err != nil { g.Panic(err) } g.OK() *written = nwrite }) } func (t *TestGroup) CompareStreams(r1 io.ReadCloser, r2 io.ReadCloser, length int64) *Goroutine { return t.Go("compare", func(g *Goroutine) { b1 := make([]byte, blocksize) b2 := make([]byte, blocksize) var idx int64 for length > 0 { c := blocksize if length < blocksize { c = int(length) } if _, err := io.ReadFull(r1, b1[0:c]); err != nil { g.Panic(err) } if _, err := io.ReadFull(r2, b2[0:c]); err != nil { g.Panic(err) } if bytes.Compare(b1[0:c], b2[0:c]) != 0 { fmt.Println("B1 is", string(b1[0:c])) fmt.Println("B2 is", string(b2[0:c])) g.Panic(errors.New(fmt.Sprint("Bytes do not compare at ", idx))) } length -= int64(c) idx += int64(c) } g.OK() }) } func (t *TestGroup) Exec(desc string, p Program, srcfifo bool, flags []string) (*Run, error) { var err error run := &Run{} args := []string{p.Path} if srcfifo { num := atomic.AddInt64(&srcSeq, 1) run.Srcfile = path.Join(t.Runner.Testdir, fmt.Sprint("source", num)) if err = unix.Mkfifo(run.Srcfile, 0600); err != nil { return nil, err } read, write := io.Pipe() t.writeFifo(run.Srcfile, read) run.Srcin = write args = append(args, "-s") args = append(args, run.Srcfile) } if run.Stdin, err = run.Cmd.StdinPipe(); err != nil { return nil, err } if run.Stdout, err = run.Cmd.StdoutPipe(); err != nil { return nil, err } if run.Stderr, err = run.Cmd.StderrPipe(); err != nil { return nil, err } run.Cmd.Path = p.Path run.Cmd.Args = append(args, flags...) run.Cmd.Dir = t.Runner.Testdir if serr := run.Cmd.Start(); serr != nil { return nil, serr } return run, nil } func (t *TestGroup) Fail(v ...interface{}) { panic(fmt.Sprintln(v...)) } func (t *TestGroup) writeFifo(srcfile string, read io.Reader) *Goroutine { return t.Go("compare", func(g *Goroutine) { fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600) if err != nil { fifo.Close() g.Panic(err) } if _, err := io.Copy(fifo, read); err != nil { fifo.Close() g.Panic(err) } if err := fifo.Close(); err != nil { g.Panic(err) } g.OK() }) } ================================================ FILE: source-code/dependencies/xdelta3/go/src/xdelta/tgroup.go ================================================ package xdelta import ( "fmt" "runtime" "sync" ) type TestGroup struct { *Runner main *Goroutine sync.Mutex sync.WaitGroup running []*Goroutine errors []error nonerrors []error // For tolerated / expected conditions } type Goroutine struct { *TestGroup name string done bool } func (g *Goroutine) String() string { return fmt.Sprint("[", g.name, "]") } func (g *Goroutine) finish(err error) { wait := false tg := g.TestGroup sbuf := make([]byte, 4096) sbuf = sbuf[0:runtime.Stack(sbuf, false)] if err != nil { err = fmt.Errorf("%v:%v:%v", g.name, err, string(sbuf)) } tg.Lock() if g.done { if err != nil { tg.nonerrors = append(tg.nonerrors, err) } } else { wait = true g.done = true if err != nil { tg.errors = append(tg.errors, err) } } tg.Unlock() if wait { tg.WaitGroup.Done() } } func (g *Goroutine) OK() { g.finish(nil) } func (g *Goroutine) Panic(err error) { g.finish(err) if g != g.TestGroup.main { runtime.Goexit() } } func (t *TestGroup) Main() *Goroutine { return t.main } func (t *TestGroup) Panic(err error) { t.Main().Panic(err) } func (t *TestGroup) Go(name string, f func(*Goroutine)) *Goroutine { g := &Goroutine{t, name, false} t.Lock() t.WaitGroup.Add(1) t.running = append(t.running, g) t.Unlock() go f(g) return g } func (t *TestGroup) Wait(procs... *Run) { t.Main().OK() t.WaitGroup.Wait() for _, p := range procs { if err := p.Wait(); err != nil { t.errors = append(t.errors, err) } } for _, err := range t.errors { fmt.Println(":ERROR:", err) } for _, err := range t.nonerrors { fmt.Println("(ERROR)", err) } if len(t.errors) != 0 { t.Fail("Test failed with", len(t.errors), "errors") } } ================================================ FILE: source-code/dependencies/xdelta3/linkxd3lib.c ================================================ #include "xdelta3.h" extern int VVV; int VVV; void use(int r) { VVV = r; } int main() { xd3_config config; xd3_stream stream; xd3_source source; xd3_init_config (& config, 0); use (xd3_config_stream (&stream, &config)); use (xd3_close_stream (&stream)); xd3_abort_stream (&stream); xd3_free_stream (&stream); xd3_avail_input (& stream, NULL, 0); xd3_consume_output (& stream); use (xd3_set_source (& stream, & source)); xd3_set_flags (& stream, 0); use (xd3_decode_stream (& stream, NULL, 0, NULL, NULL, 0)); use (xd3_decode_input (&stream)); use (xd3_get_appheader (& stream, NULL, NULL)); #if XD3_ENCODER use (xd3_encode_input (&stream)); use (xd3_encode_stream (& stream, NULL, 0, NULL, NULL, 0)); use (xd3_set_appheader (& stream)); use (xd3_encoder_used_source (& stream)); use (xd3_encoder_srcbase (& stream)); use (xd3_encoder_srclen (& stream)); #endif return 0; } ================================================ FILE: source-code/dependencies/xdelta3/m4/ax_check_aligned_access_required.m4 ================================================ # ==================================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_aligned_access_required.html # ==================================================================================== # # SYNOPSIS # # AC_CHECK_ALIGNED_ACCESS_REQUIRED # # DESCRIPTION # # While the x86 CPUs allow access to memory objects to be unaligned it # happens that most of the modern designs require objects to be aligned - # or they will fail with a buserror. That mode is quite known by # big-endian machines (sparc, etc) however the alpha cpu is little- # endian. # # The following function will test for aligned access to be required and # set a config.h define HAVE_ALIGNED_ACCESS_REQUIRED (name derived by # standard usage). Structures loaded from a file (or mmapped to memory) # should be accessed per-byte in that case to avoid segfault type errors. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 7 AC_DEFUN([AX_CHECK_ALIGNED_ACCESS_REQUIRED], [AC_CACHE_CHECK([if pointers to integers require aligned access], [ax_cv_have_aligned_access_required], [AC_TRY_RUN([ #include #include int main() { char* string = malloc(40); int i; for (i=0; i < 40; i++) string[[i]] = i; { void* s = string; int* p = s+1; int* q = s+2; if (*p == *q) { return 1; } } return 0; } ], [ax_cv_have_aligned_access_required=yes], [ax_cv_have_aligned_access_required=no], [ax_cv_have_aligned_access_required=no]) ]) if test "$ax_cv_have_aligned_access_required" = yes ; then AC_DEFINE([HAVE_ALIGNED_ACCESS_REQUIRED], [1], [Define if pointers to integers require aligned access]) fi ]) ================================================ FILE: source-code/dependencies/xdelta3/m4/ax_pkg_swig.m4 ================================================ # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html # =========================================================================== # # SYNOPSIS # # AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found]) # # DESCRIPTION # # This macro searches for a SWIG installation on your system. If found, # then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is # found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd. # # You can use the optional first argument to check if the version of the # available SWIG is greater than or equal to the value of the argument. It # should have the format: N[.N[.N]] (N is a number between 0 and 999. Only # the first N is mandatory.) If the version argument is given (e.g. # 1.3.17), AX_PKG_SWIG checks that the swig package is this version number # or higher. # # As usual, action-if-found is executed if SWIG is found, otherwise # action-if-not-found is executed. # # In configure.in, use as: # # AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ]) # AX_SWIG_ENABLE_CXX # AX_SWIG_MULTI_MODULE_SUPPORT # AX_SWIG_PYTHON # # LICENSE # # Copyright (c) 2008 Sebastian Huber # Copyright (c) 2008 Alan W. Irwin # Copyright (c) 2008 Rafael Laboissiere # Copyright (c) 2008 Andrew Collier # Copyright (c) 2011 Murray Cumming # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 8 AC_DEFUN([AX_PKG_SWIG],[ # Ubuntu has swig 2.0 as /usr/bin/swig2.0 AC_PATH_PROGS([SWIG],[swig swig2.0]) if test -z "$SWIG" ; then m4_ifval([$3],[$3],[:]) elif test -n "$1" ; then AC_MSG_CHECKING([SWIG version]) [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`] AC_MSG_RESULT([$swig_version]) if test -n "$swig_version" ; then # Calculate the required version number components [required=$1] [required_major=`echo $required | sed 's/[^0-9].*//'`] if test -z "$required_major" ; then [required_major=0] fi [required=`echo $required | sed 's/[0-9]*[^0-9]//'`] [required_minor=`echo $required | sed 's/[^0-9].*//'`] if test -z "$required_minor" ; then [required_minor=0] fi [required=`echo $required | sed 's/[0-9]*[^0-9]//'`] [required_patch=`echo $required | sed 's/[^0-9].*//'`] if test -z "$required_patch" ; then [required_patch=0] fi # Calculate the available version number components [available=$swig_version] [available_major=`echo $available | sed 's/[^0-9].*//'`] if test -z "$available_major" ; then [available_major=0] fi [available=`echo $available | sed 's/[0-9]*[^0-9]//'`] [available_minor=`echo $available | sed 's/[^0-9].*//'`] if test -z "$available_minor" ; then [available_minor=0] fi [available=`echo $available | sed 's/[0-9]*[^0-9]//'`] [available_patch=`echo $available | sed 's/[^0-9].*//'`] if test -z "$available_patch" ; then [available_patch=0] fi # Convert the version tuple into a single number for easier comparison. # Using base 100 should be safe since SWIG internally uses BCD values # to encode its version number. required_swig_vernum=`expr $required_major \* 10000 \ \+ $required_minor \* 100 \+ $required_patch` available_swig_vernum=`expr $available_major \* 10000 \ \+ $available_minor \* 100 \+ $available_patch` if test $available_swig_vernum -lt $required_swig_vernum; then AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.]) SWIG='' m4_ifval([$3],[$3],[]) else AC_MSG_CHECKING([for SWIG library]) SWIG_LIB=`$SWIG -swiglib` AC_MSG_RESULT([$SWIG_LIB]) m4_ifval([$2],[$2],[]) fi else AC_MSG_WARN([cannot determine SWIG version]) SWIG='' m4_ifval([$3],[$3],[]) fi fi AC_SUBST([SWIG_LIB]) ]) ================================================ FILE: source-code/dependencies/xdelta3/m4/ax_python_devel.m4 ================================================ # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_python_devel.html # =========================================================================== # # SYNOPSIS # # AX_PYTHON_DEVEL([version]) # # DESCRIPTION # # Note: Defines as a precious variable "PYTHON_VERSION". Don't override it # in your configure.ac. # # This macro checks for Python and tries to get the include path to # 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS) # output variables. It also exports $(PYTHON_EXTRA_LIBS) and # $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code. # # You can search for some particular version of Python by passing a # parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please # note that you *have* to pass also an operator along with the version to # match, and pay special attention to the single quotes surrounding the # version number. Don't use "PYTHON_VERSION" for this: that environment # variable is declared as precious and thus reserved for the end-user. # # This macro should work for all versions of Python >= 2.1.0. As an end # user, you can disable the check for the python version by setting the # PYTHON_NOVERSIONCHECK environment variable to something else than the # empty string. # # If you need to use this macro for an older Python version, please # contact the authors. We're always open for feedback. # # LICENSE # # Copyright (c) 2009 Sebastian Huber # Copyright (c) 2009 Alan W. Irwin # Copyright (c) 2009 Rafael Laboissiere # Copyright (c) 2009 Andrew Collier # Copyright (c) 2009 Matteo Settenvini # Copyright (c) 2009 Horst Knorr # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 8 AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL]) AC_DEFUN([AX_PYTHON_DEVEL],[ # # Allow the use of a (user set) custom python version # AC_ARG_VAR([PYTHON_VERSION],[The installed Python version to use, for example '2.3'. This string will be appended to the Python interpreter canonical name.]) AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]]) if test -z "$PYTHON"; then AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path]) PYTHON_VERSION="" fi # # Check for a version of Python >= 2.1.0 # AC_MSG_CHECKING([for a version of Python >= '2.1.0']) ac_supports_python_ver=`$PYTHON -c "import sys; \ ver = sys.version.split ()[[0]]; \ print (ver >= '2.1.0')"` if test "$ac_supports_python_ver" != "True"; then if test -z "$PYTHON_NOVERSIONCHECK"; then AC_MSG_RESULT([no]) AC_MSG_FAILURE([ This version of the AC@&t@_PYTHON_DEVEL macro doesn't work properly with versions of Python before 2.1.0. You may need to re-run configure, setting the variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG, PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand. Moreover, to disable this check, set PYTHON_NOVERSIONCHECK to something else than an empty string. ]) else AC_MSG_RESULT([skip at user request]) fi else AC_MSG_RESULT([yes]) fi # # if the macro parameter ``version'' is set, honour it # if test -n "$1"; then AC_MSG_CHECKING([for a version of Python $1]) ac_supports_python_ver=`$PYTHON -c "import sys; \ ver = sys.version.split ()[[0]]; \ print (ver $1)"` if test "$ac_supports_python_ver" = "True"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) AC_MSG_ERROR([this package requires Python $1. If you have it installed, but it isn't the default Python interpreter in your system path, please pass the PYTHON_VERSION variable to configure. See ``configure --help'' for reference. ]) PYTHON_VERSION="" fi fi # # Check if you have distutils, else fail # AC_MSG_CHECKING([for the distutils Python package]) ac_distutils_result=`$PYTHON -c "import distutils" 2>&1` if test -z "$ac_distutils_result"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) AC_MSG_ERROR([cannot import Python module "distutils". Please check your Python installation. The error was: $ac_distutils_result]) PYTHON_VERSION="" fi # # Check for Python include path # AC_MSG_CHECKING([for Python include path]) if test -z "$PYTHON_CPPFLAGS"; then python_path=`$PYTHON -c "import distutils.sysconfig; \ print (distutils.sysconfig.get_python_inc ());"` if test -n "${python_path}"; then python_path="-I$python_path" fi PYTHON_CPPFLAGS=$python_path fi AC_MSG_RESULT([$PYTHON_CPPFLAGS]) AC_SUBST([PYTHON_CPPFLAGS]) # # Check for Python library path # AC_MSG_CHECKING([for Python library path]) if test -z "$PYTHON_LDFLAGS"; then # (makes two attempts to ensure we've got a version number # from the interpreter) ac_python_version=`cat<]], [[Py_Initialize();]]) ],[pythonexists=yes],[pythonexists=no]) AC_LANG_POP([C]) # turn back to default flags CPPFLAGS="$ac_save_CPPFLAGS" LIBS="$ac_save_LIBS" AC_MSG_RESULT([$pythonexists]) if test ! "x$pythonexists" = "xyes"; then AC_MSG_FAILURE([ Could not link test program to Python. Maybe the main Python library has been installed in some non-standard library path. If so, pass it to configure, via the LDFLAGS environment variable. Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib" ============================================================================ ERROR! You probably have to install the development version of the Python package for your distribution. The exact name of this package varies among them. ============================================================================ ]) PYTHON_VERSION="" fi # # all done! # ]) ================================================ FILE: source-code/dependencies/xdelta3/m4/ax_swig_python.m4 ================================================ # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_swig_python.html # =========================================================================== # # SYNOPSIS # # AX_SWIG_PYTHON([use-shadow-classes = {no, yes}]) # # DESCRIPTION # # Checks for Python and provides the $(AX_SWIG_PYTHON_CPPFLAGS), and # $(AX_SWIG_PYTHON_OPT) output variables. # # $(AX_SWIG_PYTHON_OPT) contains all necessary SWIG options to generate # code for Python. Shadow classes are enabled unless the value of the # optional first argument is exactly 'no'. If you need multi module # support (provided by the AX_SWIG_MULTI_MODULE_SUPPORT macro) use # $(AX_SWIG_PYTHON_LIBS) to link against the appropriate library. It # contains the SWIG Python runtime library that is needed by the type # check system for example. # # LICENSE # # Copyright (c) 2008 Sebastian Huber # Copyright (c) 2008 Alan W. Irwin # Copyright (c) 2008 Rafael Laboissiere # Copyright (c) 2008 Andrew Collier # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 7 AU_ALIAS([SWIG_PYTHON], [AX_SWIG_PYTHON]) AC_DEFUN([AX_SWIG_PYTHON],[ AC_REQUIRE([AX_PKG_SWIG]) AC_REQUIRE([AX_PYTHON_DEVEL]) test "x$1" != "xno" || swig_shadow=" -noproxy" AC_SUBST([AX_SWIG_PYTHON_OPT],[-python$swig_shadow]) AC_SUBST([AX_SWIG_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS]) ]) ================================================ FILE: source-code/dependencies/xdelta3/plot.sh ================================================ #!/bin/sh G=/usr/bin/gnuplot D=./output_dir I=$1 O=$D/$2 $G > $O < #include #include #include #include #include #include #include #include #include #include #undef BUFSIZE #define BUFSIZE (1<<14) char *tmp_file_1; gboolean tmp_file_1_free = TRUE; char *tmp_file_2; gboolean tmp_file_2_free = TRUE; int skip_count; int small_count; int large_count; int process_count; extern time_t str2time (char const *, time_t, long); static guint8 readbuf[BUFSIZE]; static const char* rcswalk_input_dir = NULL; static const char* config_output_base = NULL; static const char* config_output_dir = NULL; static const char* rcswalk_experiment = NULL; static ConfigOption rcswalk_options[] = { { "rcswalk_experiment", "ex", CS_Use, CO_Required, CD_String, & rcswalk_experiment }, { "rcs_input_dir", "id", CS_UseAsFile, CO_Required, CD_String, & rcswalk_input_dir } }; static ConfigOption config_options[] = { { "config_output_base", "ob", CS_Ignore, CO_Required, CD_String, & config_output_base } }; void rcswalk_free_segment (RcsVersion *v) { if (v->segment) g_free (v->segment); if (v->filename == tmp_file_1) tmp_file_1_free = TRUE; else if (v->filename == tmp_file_2) tmp_file_2_free = TRUE; else if (v->filename) g_free (v->filename); v->segment = NULL; v->filename = NULL; } int rcswalk_checkout (RcsFile* rcs, RcsWalker* walker, RcsVersion *v) { FILE* out; char cmdbuf[1024]; int nread; int alloc = BUFSIZE; int pos = 0; sprintf (cmdbuf, "co -ko -p%s %s 2>/dev/null\n", v->vname, rcs->filename); g_assert (! v->segment); v->segment = g_malloc (alloc); if (! (out = popen (cmdbuf, "r"))) { g_warning ("popen failed: %s: %s", cmdbuf, g_strerror (errno)); return errno; } for (;;) { nread = fread (readbuf, 1, BUFSIZE, out); if (nread == 0) break; if (nread < 0) { g_warning ("fread failed: %s", g_strerror (errno)); return errno; } if (pos + nread > alloc) { alloc *= 2; v->segment = g_realloc (v->segment, alloc); } memcpy (v->segment + pos, readbuf, nread); pos += nread; } if (pclose (out) < 0) { g_warning ("pclose failed"); return errno; } v->size = pos; if (walker->write_files) { char* file = NULL; if (! file && tmp_file_1_free) { file = tmp_file_1; tmp_file_1_free = FALSE; } if (! file && tmp_file_2_free) { file = tmp_file_2; tmp_file_2_free = FALSE; } g_assert (file); v->filename = file; if (! (out = fopen (file, "w"))) { g_warning ("fopen failed: %s\n", file); return errno; } if (fwrite (v->segment, v->size, 1, out) != 1) { g_warning ("fwrite failed: %s\n", file); return errno; } if (fclose (out) < 0) { g_warning ("fclose failed: %s\n", file); return errno; } } return 0; } int rcswalk_delta_date (RcsFile* rcs, RcsWalker* walker, void* data) { int i; int ret; RcsVersion *vf = NULL; RcsVersion *vt = NULL; for (i = 0; i < (rcs->version_count-1); i += 1) { vf = rcs->versions_date[i+1]; vt = rcs->versions_date[i]; if (! vt->segment && (ret = rcswalk_checkout (rcs, walker, vt))) { return ret; } if ((ret = rcswalk_checkout (rcs, walker, vf))) { return ret; } if ((ret = walker->delta_date (rcs, vf, vt, data))) { return ret; } rcswalk_free_segment (vt); } if (vf) rcswalk_free_segment (vf); if (vt) rcswalk_free_segment (vt); return 0; } int rcswalk_delta_orig (RcsFile* rcs, RcsWalker* walker, RcsVersion* version, int *count, void* data) { int ret; GSList *c; RcsVersion *child; for (c = version->children; c; c = c->next) { gboolean reverse; child = c->data; if (! version->segment) { if ((ret = rcswalk_checkout (rcs, walker, version))) { return ret; } } if ((ret = rcswalk_checkout (rcs, walker, child))) { return ret; } reverse = version->on_trunk && child->on_trunk; (* count) += 1; if ((ret = walker->delta_orig (rcs, reverse ? child : version, reverse ? version : child, data))) { return ret; } rcswalk_free_segment (version); if ((ret = rcswalk_delta_orig (rcs, walker, child, count, data))) { return ret; } } rcswalk_free_segment (version); return 0; } int rcswalk_dateorder (RcsFile* rcs, RcsWalker *walker, RcsStats *stats, void* data) { int i, ret; for (i = 0; i < rcs->version_count; i += 1) { RcsVersion *v = rcs->versions_date[i]; if ((ret = rcswalk_checkout (rcs, walker, v))) { return ret; } stat_bincount_add_item (stats->avg_version_size, i, v->size); if ((ret = walker->dateorder (rcs, v, data))) { return ret; } rcswalk_free_segment (v); } return 0; } gboolean rcswalk_match (char** line_p, char* str) { int len = strlen (str); if (strncmp (*line_p, str, len) == 0) { (*line_p) += len; return TRUE; } return FALSE; } void rcswalk_find_parent (RcsFile *rcs, GHashTable* hash, RcsVersion *v) { char *lastdot; char mbuf[1024]; int lastn; RcsVersion *p; strcpy (mbuf, v->vname); if (! (lastdot = strchr (mbuf, '.'))) abort (); if (! (lastdot = strchr (lastdot+1, '.'))) v->on_trunk = TRUE; lastdot = strrchr (mbuf, '.'); lastn = atoi (lastdot + 1); do { if (lastn == 1) { (*lastdot) = 0; if (strcmp (mbuf, "1") == 0) { /* Assuming the first version is always "1.1". */ rcs->root_version = v; return; } else if (! (lastdot = strrchr (mbuf, '.'))) { int i = 1; int br = atoi (mbuf) - 1; RcsVersion *p2 = NULL; /* Now we have something like "2.1" and need to * search for the highest "1.x" version. */ do { sprintf (mbuf, "%d.%d", br, i++); p = p2; } while ((p2 = g_hash_table_lookup (hash, mbuf))); if (p == NULL) { rcs->root_version = v; return; } break; } else { /* 1.2.3.1 => 1.2 */ (*lastdot) = 0; lastdot = strrchr (mbuf, '.'); lastn = atoi (lastdot + 1); } } else { lastn -= 1; sprintf (lastdot, ".%d", lastn); } } while (! (p = g_hash_table_lookup (hash, mbuf))); g_assert (p); v->parent = p; p->children = g_slist_prepend (p->children, v); } int rcswalk_traverse_graph (RcsFile* rcs, RcsVersion* version, RcsVersion *parent) { GSList *c; int distance = -1; version->cc = g_slist_length (version->children); if (version->cc > 1) rcs->branch_count += (version->cc - 1); if (parent) { /* Insure that there is proper date ordering. */ if (version->date <= parent->date) version->date = parent->date + 1; if (parent->on_trunk && version->on_trunk) rcs->reverse_count += 1; else rcs->forward_count += 1; } for (c = version->children; c; c = c->next) { int c_dist = rcswalk_traverse_graph (rcs, c->data, version); distance = MAX (distance, c_dist); } if (version == rcs->head_version) distance = 0; if (distance >= 0) { version->chain_length = distance; return distance + 1; } return -1; } void rcswalk_compute_chain_length (RcsFile* rcs, RcsVersion* version, RcsVersion *parent) { GSList *c; if (! parent) { g_assert (version->chain_length >= 0); } else if (version->chain_length < 0) { version->chain_length = parent->chain_length + 1; } for (c = version->children; c; c = c->next) { rcswalk_compute_chain_length (rcs, c->data, version); } } int rcswalk_date_compare (const void* a, const void* b) { RcsVersion **ra = (void*) a; RcsVersion **rb = (void*) b; return (*ra)->date - (*rb)->date; } int rcswalk_build_graph (RcsFile* rcs) { GHashTable* hash = g_hash_table_new (g_str_hash, g_str_equal); int i; for (i = 0; i < rcs->version_count; i += 1) g_hash_table_insert (hash, rcs->versions[i].vname, rcs->versions + i); for (i = 0; i < rcs->version_count; i += 1) { RcsVersion *v = rcs->versions + i; v->chain_length = -1; v->rcs = rcs; rcswalk_find_parent (rcs, hash, v); } rcs->head_version = g_hash_table_lookup (hash, rcs->headname); rcswalk_traverse_graph (rcs, rcs->root_version, NULL); rcswalk_compute_chain_length (rcs, rcs->root_version, NULL); for (i = 0; i < rcs->version_count; i += 1) rcs->versions_date[i] = rcs->versions + i; qsort (rcs->versions_date, rcs->version_count, sizeof (RcsVersion*), & rcswalk_date_compare); for (i = 0; i < rcs->version_count; i += 1) { RcsVersion *v = rcs->versions_date[i]; v->dateseq = i; } g_hash_table_destroy (hash); return 0; } #define HEAD_STATE 0 #define BAR_STATE 1 #define REV_STATE 2 #define DATE_STATE 3 int rcswalk_load (RcsFile *rcs, gboolean *skip) { FILE* rlog; char cmdbuf[1024]; char oneline[1024], *oneline_p; char rbuf[1024]; int version_i = 0, ret; int read_state = HEAD_STATE; sprintf (cmdbuf, "rlog %s", rcs->filename); if (! (rlog = popen (cmdbuf, "r"))) { g_warning ("popen failed: %s", cmdbuf); return errno; } rcs->headname = NULL; while (fgets (oneline, 1024, rlog)) { oneline_p = oneline; if (read_state == HEAD_STATE && rcswalk_match (& oneline_p, "total revisions: ")) { if (sscanf (oneline_p, "%d", & rcs->version_count) != 1) goto badscan; rcs->versions = g_new0 (RcsVersion, rcs->version_count); rcs->versions_date = g_new (RcsVersion*, rcs->version_count); read_state = BAR_STATE; } else if (read_state == HEAD_STATE && rcswalk_match (& oneline_p, "head: ")) { if (sscanf (oneline_p, "%s", rbuf) != 1) goto badscan; rcs->headname = g_strdup (rbuf); read_state = HEAD_STATE; /* no change */ } else if (read_state == BAR_STATE && rcswalk_match (& oneline_p, "----------------------------")) { read_state = REV_STATE; } else if (read_state == REV_STATE && rcswalk_match (& oneline_p, "revision ")) { if (version_i >= rcs->version_count) { /* jkh likes to insert the rlog of one RCS file into the log * message of another, and this can confuse things. Why, oh why, * doesn't rlog have an option to not print the log? */ fprintf (stderr, "rcswalk: too many versions: skipping file %s\n", rcs->filename); *skip = TRUE; skip_count += 1; pclose (rlog); return 0; } if (sscanf (oneline_p, "%s", rbuf) != 1) goto badscan; rcs->versions[version_i].vname = g_strdup (rbuf); read_state = DATE_STATE; g_assert (rcs->versions[version_i].vname); } else if (read_state == DATE_STATE && rcswalk_match (& oneline_p, "date: ")) { char* semi = strchr (oneline_p, ';'); if (! semi) goto badscan; strncpy (rbuf, oneline_p, semi - oneline_p); rbuf[semi - oneline_p] = 0; rcs->versions[version_i].date = str2time (rbuf, 0, 0); version_i += 1; read_state = BAR_STATE; } } if (! rcs->headname) { fprintf (stderr, "rcswalk: no head version: skipping file %s\n", rcs->filename); *skip = TRUE; skip_count += 1; pclose (rlog); return 0; } if (pclose (rlog) < 0) { g_warning ("pclose failed: %s", cmdbuf); return errno; } if ((ret = rcswalk_build_graph (rcs))) { return ret; } return 0; badscan: pclose (rlog); g_warning ("rlog syntax error"); return -1; } void rcswalk_free (RcsFile* rcs) { int i; for (i = 0; i < rcs->version_count; i += 1) { g_free (rcs->versions[i].vname); g_slist_free (rcs->versions[i].children); } g_free (rcs->filename); g_free (rcs->headname); g_free (rcs->versions); g_free (rcs->versions_date); g_free (rcs); } int rcswalk_one (char* rcsfile, char* copyfile, RcsWalker* walker, RcsStats* stats, void* data) { RcsFile* rcs; int i, ret; long long maxsize = 0; gboolean skip = FALSE; rcs = g_new0 (RcsFile, 1); rcs->filename = g_strdup (rcsfile); rcs->copyname = copyfile; if ((ret = rcswalk_load (rcs, & skip))) { return ret; } if (walker->min_versions > rcs->version_count) { small_count += 1; skip = TRUE; } if (walker->max_versions < rcs->version_count) { large_count += 1; skip = TRUE; } if (! skip) { process_count += 1; if (walker->dateorder && (ret = rcswalk_dateorder (rcs, walker, stats, data))) { return ret; } if (walker->delta_orig) { int count = 0; if ((ret = rcswalk_delta_orig (rcs, walker, rcs->root_version, & count, data))) { return ret; } g_assert (count == (rcs->version_count - 1)); } if (walker->delta_date && (ret = rcswalk_delta_date (rcs, walker, data))) { return ret; } for (i = 0; i < rcs->version_count; i += 1) { rcs->total_size += rcs->versions[i].size; maxsize = MAX (rcs->versions[i].size, maxsize); } stat_int_add_item (stats->version_stat, rcs->version_count); stat_int_add_item (stats->forward_stat, rcs->forward_count); stat_int_add_item (stats->reverse_stat, rcs->reverse_count); stat_int_add_item (stats->branch_stat, rcs->branch_count); stat_int_add_item (stats->unencoded_stat, rcs->total_size); stat_int_add_item (stats->literal_stat, maxsize); if (walker->onefile && (ret = walker->onefile (rcs, stats, data))) { return ret; } } rcswalk_free (rcs); return 0; } int rcswalk_dir (const char* dir, RcsWalker* walker, RcsStats* stats, void* data, const char* copy_dir) { int ret; DIR* thisdir; struct dirent* ent; if (copy_dir && (ret = config_create_dir (copy_dir))) { return ret; } if (! (thisdir = opendir (dir))) { g_warning ("opendir failed: %s", dir); return errno; } while ((ent = readdir (thisdir))) { char* name = ent->d_name; int len; struct stat buf; char* fullname; char* copyname = NULL; if (strcmp (name, ".") == 0) continue; if (strcmp (name, "..") == 0) continue; len = strlen (name); fullname = g_strdup_printf ("%s/%s", dir, name); if (copy_dir) copyname = g_strdup_printf ("%s/%s", copy_dir, name); if (len > 2 && strcmp (name + len - 2, ",v") == 0) { if ((ret = rcswalk_one (fullname, copyname, walker, stats, data))) { goto abort; } } else { if (stat (fullname, & buf) < 0) { g_warning ("stat failed: %s\n", fullname); goto abort; } if (S_ISDIR (buf.st_mode)) { if ((ret = rcswalk_dir (fullname, walker, stats, data, copyname))) { goto abort; } } } g_free (fullname); if (copyname) g_free (copyname); } if (closedir (thisdir) < 0) { g_warning ("closedir failed: %s", dir); return errno; } return 0; abort: if (thisdir) closedir (thisdir); return -1; } void rcswalk_init (void) { config_register (rcswalk_options, ARRAY_SIZE (rcswalk_options)); } int rcswalk (RcsWalker *walker, const char* copy_base) { void* data = NULL; RcsStats stats; int ret; skip_count = 0; small_count = 0; process_count = 0; large_count = 0; memset (& stats, 0, sizeof (stats)); stats.avg_version_size = stat_bincount_new ("AvgVersionSize"); /* @@@ leak */ stats.version_stat = stat_int_new ("Version"); /* @@@ leak */ stats.forward_stat = stat_int_new ("Forward"); /* @@@ leak */ stats.reverse_stat = stat_int_new ("Reverse"); /* @@@ leak */ stats.branch_stat = stat_int_new ("Branch"); /* @@@ leak */ stats.unencoded_stat = stat_int_new ("Unencoded"); /* @@@ leak */ stats.literal_stat = stat_int_new ("Literal"); /* @@@ leak */ tmp_file_1 = g_strdup_printf ("%s/rcs1.%d", g_get_tmp_dir (), (int) getpid ()); tmp_file_2 = g_strdup_printf ("%s/rcs2.%d", g_get_tmp_dir (), (int) getpid ()); if (walker->initialize) data = walker->initialize (); if ((ret = rcswalk_dir (rcswalk_input_dir, walker, & stats, data, copy_base))) { return ret; } if (walker->finalize) { if ((ret = walker->finalize (& stats, data))) { return ret; } } unlink (tmp_file_1); unlink (tmp_file_2); fprintf (stderr, "rcswalk: processed %d files: too small %d; too large: %d; damaged: %d\n", process_count, small_count, large_count, skip_count); return 0; } /* Statistics */ void rcswalk_report (RcsStats* set) { stat_bincount_report (set->avg_version_size); stat_int_report (set->version_stat); stat_int_report (set->forward_stat); stat_int_report (set->reverse_stat); stat_int_report (set->branch_stat); stat_int_report (set->unencoded_stat); stat_int_report (set->literal_stat); } /* Int stat */ IntStat* stat_int_new (const char* name) { IntStat* s = g_new0 (IntStat, 1); s->name = name; s->values = g_array_new (FALSE, FALSE, sizeof (long long)); return s; } void stat_int_add_item (IntStat* stat, long long v) { if (! stat->count) stat->min = v; stat->count += 1; stat->min = MIN (v, stat->min); stat->max = MAX (v, stat->max); stat->sum += v; g_array_append_val (stat->values, v); } double stat_int_stddev (IntStat *stat) { double f = 0; double m = (double) stat->sum / (double) stat->count; double v; int i; for (i = 0; i < stat->count; i += 1) { long long x = g_array_index (stat->values, long long, i); f += (m - (double) x) * (m - (double) x); } v = f / (double) stat->count; return sqrt (v); } int ll_comp (const void* a, const void* b) { const long long* lla = a; const long long* llb = b; return (*lla) - (*llb); } void stat_int_histogram (IntStat *stat) { int i, consec; long long cum = 0; FILE* p_out; FILE* s_out; if (! (p_out = config_output ("%s.pop.hist", stat->name))) abort (); if (! (s_out = config_output ("%s.sum.hist", stat->name))) abort (); qsort (stat->values->data, stat->count, sizeof (long long), ll_comp); for (i = 0; i < stat->count; i += consec) { long long ix = g_array_index (stat->values, long long, i); for (consec = 1; (i+consec) < stat->count; consec += 1) { long long jx = g_array_index (stat->values, long long, i+consec); if (ix != jx) break; } cum += consec * g_array_index (stat->values, long long, i); fprintf (p_out, "%qd, %0.3f\n", g_array_index (stat->values, long long, i), (double) (i+consec) / (double) stat->count); fprintf (s_out, "%qd, %0.3f\n", g_array_index (stat->values, long long, i), (double) cum / (double) stat->sum); } if (fclose (p_out) < 0 || fclose (s_out) < 0) { g_error ("fclose failed\n"); } } void stat_int_report (IntStat* stat) { FILE* out; if (! (out = config_output ("%s.stat", stat->name))) abort (); fprintf (out, "Name: %s\n", stat->name); fprintf (out, "Count: %d\n", stat->count); fprintf (out, "Min: %qd\n", stat->min); fprintf (out, "Max: %qd\n", stat->max); fprintf (out, "Sum: %qd\n", stat->sum); fprintf (out, "Mean: %0.2f\n", (double) stat->sum / (double) stat->count); fprintf (out, "Stddev: %0.2f\n", stat_int_stddev (stat)); if (fclose (out) < 0) g_error ("fclose failed"); stat_int_histogram (stat); } /* Dbl stat */ DblStat* stat_dbl_new (const char* name) { DblStat* s = g_new0 (DblStat, 1); s->name = name; s->values = g_array_new (FALSE, FALSE, sizeof (double)); return s; } void stat_dbl_add_item (DblStat* stat, double v) { if (! stat->count) stat->min = v; stat->count += 1; stat->min = MIN (v, stat->min); stat->max = MAX (v, stat->max); stat->sum += v; g_array_append_val (stat->values, v); } double stat_dbl_stddev (DblStat *stat) { double f = 0; double m = stat->sum / stat->count; double v; int i; for (i = 0; i < stat->count; i += 1) { double x = g_array_index (stat->values, double, i); f += (m - x) * (m - x); } v = f / stat->count; return sqrt (v); } int dbl_comp (const void* a, const void* b) { const double* da = a; const double* db = b; double diff = (*da) - (*db); if (diff > 0.0) return 1; else if (diff < 0.0) return -1; else return 0; } void stat_dbl_histogram (DblStat *stat) { int i, consec; double cum = 0.0; FILE* p_out; FILE* s_out; if (! (p_out = config_output ("%s.pop.hist", stat->name))) abort (); if (! (s_out = config_output ("%s.sum.hist", stat->name))) abort (); qsort (stat->values->data, stat->count, sizeof (double), dbl_comp); for (i = 0; i < stat->count; i += consec) { double ix = g_array_index (stat->values, double, i); for (consec = 1; (i+consec) < stat->count; consec += 1) { double jx = g_array_index (stat->values, double, i+consec); if (ix != jx) break; } cum += ((double) consec) * g_array_index (stat->values, double, i); fprintf (p_out, "%0.6f, %0.3f\n", g_array_index (stat->values, double, i), (double) (i+consec) / (double) stat->count); fprintf (s_out, "%0.6f, %0.3f\n", g_array_index (stat->values, double, i), cum / stat->sum); } if (fclose (p_out) < 0 || fclose (s_out) < 0) { g_error ("fclose failed\n"); } } void stat_dbl_report (DblStat* stat) { FILE* out; if (! (out = config_output ("%s.stat", stat->name))) abort (); fprintf (out, "Name: %s\n", stat->name); fprintf (out, "Count: %d\n", stat->count); fprintf (out, "Min: %0.6f\n", stat->min); fprintf (out, "Max: %0.6f\n", stat->max); fprintf (out, "Sum: %0.6f\n", stat->sum); fprintf (out, "Mean: %0.6f\n", stat->sum / stat->count); fprintf (out, "Stddev: %0.6f\n", stat_dbl_stddev (stat)); if (fclose (out) < 0) g_error ("fclose failed"); stat_dbl_histogram (stat); } /* Bincount */ BinCounter* stat_bincount_new (const char* name) { BinCounter* bc = g_new0 (BinCounter, 1); bc->name = name; bc->bins = g_ptr_array_new (); return bc; } void stat_bincount_add_item (BinCounter* bc, int bin, double val) { GArray* one; int last; if (bin >= bc->bins->len) { g_ptr_array_set_size (bc->bins, bin+1); } if (! (one = bc->bins->pdata[bin])) { one = bc->bins->pdata[bin] = g_array_new (FALSE, TRUE, sizeof (double)); } g_assert (one); last = one->len; g_array_set_size (one, last + 1); g_array_index (one, double, last) = val; } void stat_bincount_report (BinCounter* bc) { FILE *avg_out; FILE *raw_out; int i; if (! (avg_out = config_output ("%s.avg", bc->name))) abort (); if (! (raw_out = config_output ("%s.raw", bc->name))) abort (); for (i = 0; i < bc->bins->len; i += 1) { GArray* one = bc->bins->pdata[i]; double sum = 0.0; int j; for (j = 0; j < one->len; j += 1) { double d = g_array_index (one, double, j); sum += d; fprintf (raw_out, "%e ", d); } fprintf (raw_out, "\n"); fprintf (avg_out, "%e %d\n", sum / one->len, one->len); } if (fclose (avg_out) < 0) g_error ("fclose failed"); if (fclose (raw_out) < 0) g_error ("fclose failed"); } /* Config stuff */ int config_create_dir (const char* dirname) { struct stat buf; if (stat (dirname, & buf) < 0) { if (mkdir (dirname, 0777) < 0) { fprintf (stderr, "mkdir failed: %s\n", dirname); return errno; } } else { if (! S_ISDIR (buf.st_mode)) { fprintf (stderr, "not a directory: %s\n", dirname); return errno; } } return 0; } int config_clear_dir (const char* dir) { char buf[1024]; if (dir) { sprintf (buf, "rm -rf %s", dir); system (buf); } return 0; } static ConfigOption all_options[64]; static int option_count; void config_init () { static gboolean once = FALSE; if (! once) { once = TRUE; config_register (config_options, ARRAY_SIZE (config_options)); } } void config_register (ConfigOption *opts, int nopts) { int i; config_init (); for (i = 0; i < nopts; i += 1) { all_options[option_count++] = opts[i]; } } void config_set_string (const char* var, const char* val) { int i; for (i = 0; i < option_count; i += 1) { ConfigOption *opt = all_options + i; if (strcmp (opt->name, var) == 0) { (* (const char**) opt->value) = val; opt->found = TRUE; return; } } } int config_parse (const char* config_file) { FILE *in; char oname[1024], value[1024]; int i; if (! (in = fopen (config_file, "r"))) { fprintf (stderr, "fopen failed: %s\n", config_file); return errno; } for (;;) { ConfigOption *opt = NULL; if (fscanf (in, "%s", oname) != 1) break; for (i = 0; i < option_count; i += 1) { if (strcmp (oname, all_options[i].name) == 0) { opt = all_options + i; break; } } if (opt && opt->arg == CO_None) { (* (gboolean*) opt->value) = TRUE; opt->found = TRUE; continue; } if (fscanf (in, "%s", value) != 1) { fprintf (stderr, "no value for option: %s; file: %s\n", oname, config_file); goto abort; } if (! opt) { /*fprintf (stderr, "unrecognized option: %s\n", oname);*/ continue; } switch (opt->type) { case CD_Bool: if (strcasecmp (value, "yes") == 0 || strcasecmp (value, "true") == 0 || strcmp (value, "1") == 0 || strcasecmp (value, "on") == 0) { ((gboolean*) opt->value) = TRUE; } else { ((gboolean*) opt->value) = FALSE; } break; case CD_Int32: if (sscanf (value, "%d", (gint32*) opt->value) != 1) { fprintf (stderr, "parse error for option: %s; file: %s\n", oname, config_file); goto abort; } break; case CD_Double: if (sscanf (value, "%lf", (double*) opt->value) != 1) { fprintf (stderr, "parse error for option: %s; file: %s\n", oname, config_file); goto abort; } break; case CD_String: (* (const char**) opt->value) = g_strdup (value); break; } opt->found = TRUE; } fclose (in); return 0; abort: fclose (in); return -1; } int config_compute_output_dir () { char tmp[1024]; char buf[1024]; int i; gboolean last = FALSE; buf[0] = 0; for (i = 0; i < option_count; i += 1) { ConfigOption *opt = all_options + i; if (opt->style == CS_Ignore) continue; if (! opt->found) continue; if (last) strcat (buf, ","); last = TRUE; strcat (buf, opt->abbrev); strcat (buf, "="); switch (opt->type) { case CD_Bool: if (* (gboolean*) opt->value) strcat (buf, "true"); else strcat (buf, "false"); break; case CD_Int32: sprintf (tmp, "%d", (* (gint32*) opt->value)); strcat (buf, tmp); break; case CD_Double: sprintf (tmp, "%0.2f", (* (double*) opt->value)); strcat (buf, tmp); break; case CD_String: if (opt->style == CS_UseAsFile) { const char* str = (* (const char**) opt->value); const char* ls = strrchr (str, '/'); strcat (buf, ls ? (ls + 1) : str); } else { strcat (buf, (* (const char**) opt->value)); } break; } } config_output_dir = g_strdup_printf ("%s/%s", config_output_base, buf); return 0; } int config_done (void) { int i, ret; FILE *out; for (i = 0; i < option_count; i += 1) { ConfigOption *opt = all_options + i; if (! opt->found && opt->arg == CO_Required) { fprintf (stderr, "required option not found: %s\n", all_options[i].name); return -1; } } if ((ret = config_compute_output_dir ())) { return ret; } if ((ret = config_clear_dir (config_output_dir))) { return ret; } if ((ret = config_create_dir (config_output_dir))) { return ret; } if (! (out = config_output ("Options"))) abort (); for (i = 0; i < option_count; i += 1) { ConfigOption *opt = all_options + i; fprintf (out, "option: %s; value: ", all_options[i].name); switch (opt->type) { case CD_Bool: fprintf (out, "%s", (* (gboolean*) opt->value) ? "TRUE" : "FALSE"); break; case CD_Int32: fprintf (out, "%d", (* (gint32*) opt->value)); break; case CD_Double: fprintf (out, "%0.2f", (* (double*) opt->value)); break; case CD_String: fprintf (out, "%s", (* (const char**) opt->value)); break; } fprintf (out, "\n"); } if (fclose (out)) { fprintf (stderr, "fclose failed\n"); return errno; } return 0; } const char* config_help_arg (ConfigOption *opt) { switch (opt->arg) { case CO_Required: return "required"; case CO_Optional: return "optional"; case CO_None: return "no value"; } return "unknown"; } const char* config_help_type (ConfigOption *opt) { switch (opt->arg) { case CO_None: return "boolean"; default: break; } switch (opt->type) { case CD_Bool: return "boolean"; case CD_Int32: return "int"; case CD_Double: return "double"; case CD_String: return "string"; } return "unknown"; } void config_help (void) { int i; fprintf (stderr, "Expecting the following options in one or more config files on the command line:\n"); for (i = 0; i < option_count; i += 1) { ConfigOption *opt = all_options + i; fprintf (stderr, "%s: %s %s\n", opt->name, config_help_arg (opt), config_help_type (opt)); } } FILE* config_output (const char* format, ...) { gchar *buffer; gchar *file; va_list args; FILE *f; va_start (args, format); buffer = g_strdup_vprintf (format, args); va_end (args); file = g_strdup_printf ("%s/%s", config_output_dir, buffer); if (! (f = fopen (file, "w"))) g_error ("fopen failed: %s\n", buffer); g_free (file); g_free (buffer); return f; } #include #include #include #include "xdfs.h" /* Warning: very cheesy! */ #ifdef DEBUG_EXTRACT FileHandle *fh2 = handle_read_file (filename); guint8* debug_buf = g_malloc (buflen); if (! handle_read (fh2, debug_buf, buflen)) g_error ("read failed"); #endif gboolean rcs_count (const char* filename, guint *encoded_size) { char *readbuf0, *readbuf; gboolean in_string = FALSE; gboolean in_text = FALSE; guint string_start = 0; guint string_end = 0; guint current_pos = 0; /*char *current_delta = NULL;*/ FileHandle *fh = handle_read_file (filename); guint buflen = handle_length (fh); (* encoded_size) = 0; readbuf0 = g_new (guint8, buflen); for (;;) { int c = handle_gets (fh, readbuf0, buflen); readbuf = readbuf0; if (c < 0) break; if (strncmp (readbuf, "text", 4) == 0) in_text = TRUE; if (! in_string && readbuf[0] == '@') { string_start = current_pos + 1; in_string = TRUE; readbuf += 1; } current_pos += c; if (in_string) { while ((readbuf = strchr (readbuf, '@'))) { if (readbuf[1] == '@') { string_start += 1; /* @@@ bogus, just counting. */ readbuf += 2; continue; } in_string = FALSE; break; } string_end = current_pos - 2; if (in_text && ! in_string) { in_text = FALSE; /*g_free (current_delta); current_delta = NULL;*/ (* encoded_size) += (string_end - string_start); } continue; } if (isdigit (readbuf[0])) { #if 0 (* strchr (readbuf, '\n')) = 0; if (current_delta) g_free (current_delta); current_delta = g_strdup (readbuf); #endif } } handle_close (fh); g_free (readbuf0); #if 0 if (current_delta) g_free (current_delta); #endif return TRUE; } #if 0 int main (int argc, char** argv) { guint size; if (argc != 2) g_error ("usage: %s RCS_file\n", argv[0]); if (! rcs_count (argv[1], &size)) g_error ("rcs_parse failed"); return 0; } #endif ================================================ FILE: source-code/dependencies/xdelta3/run_release.sh ================================================ #!/bin/bash # Run from the source dir. SRCDIR=${PWD} # TODO replace w/ wget LZMA="xz-5.2.1" LZMA_FILE="${SRCDIR}/../${LZMA}.tar.gz" MAKEFLAGS="-j 10" BUILDDIR=${SRCDIR}/build LZMASRC=${BUILDDIR}/${LZMA} NONWIN_CFLAGS="" MINGW_CFLAGS="-DEXTERNAL_COMPRESSION=0 -DXD3_WIN32=1 -DSHELL_TESTS=0" MYOS=`uname` DATE=`date` CLEAN="" LINUXTGTS="" LINUXTEST1="" LINUXTEST2="" WINTGTS="" WINTEST1="" WINTEST2="" OSXTGTS="" OSXTEST1="" OSXTEST2="" XTMP="/tmp" if [ "${TMP}" != "" ]; then XTMP="${TMP}" fi if [ "${TMPDIR}" != "" ]; then XTMP="${TMPDIR}" fi BUILDFILES=`ls -A ${BUILDDIR} 2> /dev/null` if [ -d "${BUILDDIR}" ]; then if [ -n "${BUILDFILES}" ]; then echo "Directory ${BUILDDIR} should be empty" exit 1 fi else mkdir "${BUILDDIR}" fi function setup { libtoolize || glibtoolize automake --add-missing aclocal -I m4 autoheader automake autoconf } function try { local w=$1 shift local dir=$1 shift echo -n " ${w} ... " (cd "${dir}" && "$@" >${w}.stdout 2>${w}.stderr) local s=$? if [ ${s} -eq 0 ]; then echo " success" else echo " failed!" echo "Error $1 in ${dir}" >&2 fi return ${s} } function buildlzma { host=$1 march=$2 local target="${BUILDDIR}/lib-${host}${march}" echo " ... liblzma" mkdir -p ${target} try configure-lzma ${target} ${LZMASRC}/configure \ --host=${host} \ --prefix=${target} \ --disable-shared \ "CC=${CC}" \ "CXX=${CXX}" \ "CFLAGS=${march}" \ "CXXFLAGS=${march}" \ "LDFLAGS=${march}" if [ $? -ne 0 ]; then return fi try build-lzma ${target} make ${MAKEFLAGS} if [ $? -ne 0 ]; then return fi try install-lzma ${target} make install if [ $? -ne 0 ]; then return fi } function buildit { local host=$1 local march=$2 local usizebits=$3 local offsetbits=$4 local cargs=$5 local afl=$6 local BM="${host}${march}" local USECC="${CC}" local USECXX="${CXX}" local LIBBM="${BM}" if [ "${afl}" = "1" ]; then USECC="afl-gcc" USECXX="afl-g++" BM="${BM}-afl" fi local D="build/${BM}/usize${usizebits}/xoff${offsetbits}" local BMD="${BM}-${usizebits}-${offsetbits}" local FULLD="${SRCDIR}/${D}" local CFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include" local CXXFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include" local CPPFLAGS="-I${SRCDIR}/build/lib-${LIBBM}/include" local LDFLAGS="${march} -L${SRCDIR}/build/lib-${LIBBM}/lib" local EXEC_PREAMBLE="" local EXEC_SUFFIX="" case ${host} in *mingw*) EXEC_PREAMBLE="wine" EXEC_SUFFIX=".exe" ;; esac mkdir -p ${D} echo " ... ${BMD}" cat >> Makefile.test < \${TMP}/regtest.${BMD}.stdout 2> \${TMP}/regtest.${BMD}.stderr) .PHONY: selftest-${BMD} selftest-${BMD}: (cd ${D} && ${EXEC_PREAMBLE} ./bin/xdelta3${EXEC_SUFFIX} test 1> \${TMP}/selftest.${BMD}.stdout 2> \${TMP}/selftest.${BMD}.stderr) EOF case ${host} in *linux*) LINUXTGTS="${LINUXTGTS} build-${BMD}" LINUXTEST1="${LINUXTEST1} selftest-${BMD}" LINUXTEST2="${LINUXTEST2} regtest-${BMD}" ;; *mingw*) WINTGTS="${WINTGTS} build-${BMD}" WINTEST1="${WINTEST1} selftest-${BMD}" WINTEST2="${WINTEST2} regtest-${BMD}" ;; *apple*) OSXTGTS="${OSXTGTS} build-${BMD}" OSXTEST1="${OSXTEST1} selftest-${BMD}" OSXTEST2="${OSXTEST2} regtest-${BMD}" ;; esac CLEAN="${CLEAN} clean-${BMD}" try configure-xdelta ${FULLD} ${SRCDIR}/configure \ --host=${host} \ --prefix=${FULLD} \ --enable-static \ --disable-shared \ --enable-debug-symbols \ "CFLAGS=${CFLAGS}" \ "CXXFLAGS=${CXXFLAGS}" \ "CPPFLAGS=${CPPFLAGS}" \ "LDFLAGS=${LDFLAGS}" \ "CC=${USECC}" \ "CXX=${USECXX}" if [ $? -ne 0 ]; then return fi # try build-xdelta ${FULLD} make ${MAKEFLAGS} all # if [ $? -ne 0 ]; then # return # fi # try install-xdelta ${FULLD} make install } function buildall { echo "" echo "Host $1$2 afl=$4" echo "" buildlzma "$1" "$2" buildit "$1" "$2" 32 32 "-DXD3_USE_LARGESIZET=0 -DXD3_USE_LARGEFILE64=0 $3" "$4" buildit "$1" "$2" 32 64 "-DXD3_USE_LARGESIZET=0 -DXD3_USE_LARGEFILE64=1 $3" "$4" buildit "$1" "$2" 64 64 "-DXD3_USE_LARGESIZET=1 -DXD3_USE_LARGEFILE64=1 $3" "$4" } setup try untar-lzma ${BUILDDIR} tar -xvf "${LZMA_FILE}" if [ $? -ne 0 ]; then exit $? fi cat > Makefile.test <> Makefile.test < #include #include #include #include "../cpp-btree/btree_map.h" extern "C" { uint32_t xd3_large32_cksum_old (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look); uint32_t xd3_large32_cksum_update_old (xd3_hash_cfg *cfg, uint32_t cksum, const uint8_t *base, const usize_t look); uint64_t xd3_large64_cksum_old (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look); uint64_t xd3_large64_cksum_update_old (xd3_hash_cfg *cfg, uint64_t cksum, const uint8_t *base, const usize_t look); } using btree::btree_map; using std::list; using std::vector; // MLCG parameters // a, a* uint32_t good_32bit_values[] = { 1597334677U, // ... 741103597U, 887987685U, }; // a, a* uint64_t good_64bit_values[] = { 1181783497276652981ULL, 4292484099903637661ULL, 7664345821815920749ULL, // ... }; void print_header() { static int hdr_cnt = 0; if (hdr_cnt++ % 20 == 0) { printf("%-32sConf\t\tCount\tUniq\tFull\tCover\tColls" "\tMB/s\tIters\t#Colls\n", "Name"); } } struct true_type { }; struct false_type { }; template usize_t bitsof(); template<> usize_t bitsof() { return sizeof(unsigned int) * 8; } template<> usize_t bitsof() { return sizeof(unsigned long) * 8; } template<> usize_t bitsof() { return sizeof(unsigned long long) * 8; } template struct hhash { // shift "s" bits leaving the high bits as a hash value for // this checksum, which are the most "distant" in terms of the // spectral test for the rabin_karp MLCG. For short windows, // the high bits aren't enough, XOR "mask" worth of these in. Word operator()(const Word t, const Word s, const Word mask) { return (t >> s) ^ (t & mask); } }; template Word good_word(); template<> uint32_t good_word() { return good_32bit_values[0]; } template<> uint64_t good_word() { return good_64bit_values[0]; } // CLASSES #define SELF Word, CksumSize, CksumSkip, Hash, Compaction #define MEMBER template MEMBER struct cksum_params { typedef Word word_type; typedef Hash hash_type; static const int cksum_size = CksumSize; static const int cksum_skip = CksumSkip; static const int compaction = Compaction; }; MEMBER struct rabin_karp : public cksum_params { // (a^cksum_size-1 c_0) + (a^cksum_size-2 c_1) ... rabin_karp() : powers(make_powers()), product(powers[0] * good_word()), incr_state(0) { } static Word* make_powers() { Word *p = new Word[CksumSize]; p[CksumSize - 1] = 1; for (int i = CksumSize - 2; i >= 0; i--) { p[i] = p[i + 1] * good_word(); } return p; } ~rabin_karp() { delete [] powers; } Word step(const uint8_t *ptr) { Word h = 0; for (int i = 0; i < CksumSize; i++) { h += (ptr[i]) * powers[i]; } return h; } Word state0(const uint8_t *ptr) { incr_state = step(ptr); return incr_state; } Word incr(const uint8_t *ptr) { incr_state = good_word() * incr_state - product * (ptr[-1]) + (ptr[CksumSize - 1]); return incr_state; } const Word *const powers; const Word product; Word incr_state; }; MEMBER struct with_stream : public cksum_params { xd3_stream stream; with_stream() { xd3_config cfg; memset (&stream, 0, sizeof (stream)); xd3_init_config (&cfg, 0); cfg.smatch_cfg = XD3_SMATCH_SOFT; cfg.smatcher_soft.large_look = CksumSize; cfg.smatcher_soft.large_step = CksumSkip; cfg.smatcher_soft.small_look = 4; cfg.smatcher_soft.small_chain = 4; cfg.smatcher_soft.small_lchain = 4; cfg.smatcher_soft.max_lazy = 4; cfg.smatcher_soft.long_enough = 4; CHECK_EQ(0, xd3_config_stream (&stream, &cfg)); CHECK_EQ(0, xd3_size_hashtable (&stream, 1<<10 /* ignored */, stream.smatcher.large_look, & stream.large_hash)); } ~with_stream() { xd3_free_stream (&stream); } }; MEMBER struct large_cksum : public with_stream { Word step(const uint8_t *ptr) { return xd3_large_cksum (&this->stream.large_hash, ptr, CksumSize); } Word state0(const uint8_t *ptr) { incr_state = step(ptr); return incr_state; } Word incr(const uint8_t *ptr) { incr_state = xd3_large_cksum_update (&this->stream.large_hash, incr_state, ptr - 1, CksumSize); return incr_state; } Word incr_state; }; #if SIZEOF_USIZE_T == 4 #define xd3_large_cksum_old xd3_large32_cksum_old #define xd3_large_cksum_update_old xd3_large32_cksum_update_old #elif SIZEOF_USIZE_T == 8 #define xd3_large_cksum_old xd3_large64_cksum_old #define xd3_large_cksum_update_old xd3_large64_cksum_update_old #endif MEMBER struct large_cksum_old : public with_stream { Word step(const uint8_t *ptr) { return xd3_large_cksum_old (&this->stream.large_hash, ptr, CksumSize); } Word state0(const uint8_t *ptr) { incr_state = step(ptr); return incr_state; } Word incr(const uint8_t *ptr) { incr_state = xd3_large_cksum_update_old (&this->stream.large_hash, incr_state, ptr - 1, CksumSize); return incr_state; } Word incr_state; }; // TESTS template struct file_stats { typedef const uint8_t* ptr_type; typedef Word word_type; typedef btree::btree_multimap table_type; typedef typename table_type::iterator table_iterator; usize_t cksum_size; usize_t cksum_skip; usize_t unique; usize_t unique_values; usize_t count; table_type table; file_stats(usize_t size, usize_t skip) : cksum_size(size), cksum_skip(skip), unique(0), unique_values(0), count(0) { } void reset() { unique = 0; unique_values = 0; count = 0; table.clear(); } void update(word_type word, ptr_type ptr) { table_iterator t_i = table.find(word); count++; if (t_i != table.end()) { int collisions = 0; for (table_iterator p_i = t_i; p_i != table.end() && p_i->first == word; ++p_i) { if (memcmp(p_i->second, ptr, cksum_size) == 0) { return; } collisions++; } if (collisions >= 1000) { fprintf(stderr, "Something is not right, lots of collisions=%d\n", collisions); abort(); } } else { unique_values++; } unique++; table.insert(std::make_pair(word, ptr)); return; } void freeze() { table.clear(); } }; struct test_result_base; static vector all_tests; struct test_result_base { virtual ~test_result_base() { } virtual void reset() = 0; virtual void print() = 0; virtual void get(const uint8_t* buf, const size_t buf_size, usize_t iters) = 0; virtual void stat() = 0; virtual usize_t count() = 0; virtual usize_t dups() = 0; virtual double uniqueness() = 0; virtual double fullness() = 0; virtual double collisions() = 0; virtual double coverage() = 0; virtual double compression() = 0; virtual double time() = 0; virtual double total_time() = 0; virtual usize_t total_count() = 0; virtual usize_t total_dups() = 0; }; template struct test_result : public test_result_base { Checksum cksum; const char *test_name; file_stats fstats; usize_t test_size; usize_t n_steps; usize_t n_incrs; typename Checksum::word_type s_bits; typename Checksum::word_type s_mask; usize_t t_entries; usize_t h_bits; usize_t h_buckets_full; char *hash_table; long accum_millis; usize_t accum_iters; // These are not reset double accum_time; usize_t accum_count; usize_t accum_dups; usize_t accum_colls; size_t accum_size; test_result(const char *name) : test_name(name), fstats(Checksum::cksum_size, Checksum::cksum_skip), hash_table(NULL), accum_millis(0), accum_iters(0), accum_time(0.0), accum_count(0), accum_dups(0), accum_colls(0), accum_size(0) { all_tests.push_back(this); } ~test_result() { reset(); } void reset() { // size of file test_size = 0; // count n_steps = 0; n_incrs = 0; // four values used by new_table()/summarize_table() s_bits = 0; s_mask = 0; t_entries = 0; h_bits = 0; h_buckets_full = 0; accum_millis = 0; accum_iters = 0; fstats.reset(); // temporary if (hash_table) { delete(hash_table); hash_table = NULL; } } usize_t count() { if (Checksum::cksum_skip == 1) { return n_incrs; } else { return n_steps; } } usize_t dups() { return fstats.count - fstats.unique; } /* Fraction of distinct strings of length cksum_size which are not * represented in the hash table. */ double collisions() { return (fstats.unique - fstats.unique_values) / (double) fstats.unique; } usize_t colls() { return (fstats.unique - fstats.unique_values); } double uniqueness() { return 1.0 - (double) dups() / count(); } double fullness() { return (double) h_buckets_full / (1 << h_bits); } double coverage() { return (double) h_buckets_full / uniqueness() / count(); } double compression() { return 1.0 - coverage(); } double time() { return (double) accum_millis / accum_iters; } double total_time() { return accum_time; } usize_t total_count() { return accum_count; } usize_t total_dups() { return accum_dups; } usize_t total_colls() { return accum_dups; } void stat() { accum_time += time(); accum_count += count(); accum_dups += dups(); accum_colls += colls(); accum_size += test_size; } void print() { if (fstats.count != count()) { fprintf(stderr, "internal error: %" W "d != %" W "d\n", fstats.count, count()); abort(); } print_header(); printf("%-32s%d/%d 2^%" W "u\t%" W "u\t%0.4f\t%.4f\t%.4f\t%.1e\t%.2f\t" "%" W "u\t%" W "u\n", test_name, Checksum::cksum_size, Checksum::cksum_skip, h_bits, count(), uniqueness(), fullness(), coverage(), collisions(), 0.001 * accum_iters * test_size / accum_millis, accum_iters, colls()); } usize_t size_log2 (usize_t slots) { usize_t bits = bitsof() - 1; usize_t i; for (i = 3; i <= bits; i += 1) { if (slots <= (1U << i)) { return i - Checksum::compaction; } } return bits; } void new_table(usize_t entries) { t_entries = entries; h_bits = size_log2(entries); usize_t n = 1 << h_bits; s_bits = bitsof() - h_bits; s_mask = n - 1U; hash_table = new char[n / 8]; memset(hash_table, 0, n / 8); } int get_table_bit(usize_t i) { return hash_table[i/8] & (1 << i%8); } int set_table_bit(usize_t i) { return hash_table[i/8] |= (1 << i%8); } void summarize_table() { usize_t n = 1 << h_bits; usize_t f = 0; for (usize_t i = 0; i < n; i++) { if (get_table_bit(i)) { f++; } } h_buckets_full = f; } void get(const uint8_t* buf, const size_t buf_size, usize_t test_iters) { typename Checksum::hash_type hash; const uint8_t *ptr; const uint8_t *end; usize_t periods; int64_t last_offset; int64_t stop; test_size = buf_size; last_offset = buf_size - Checksum::cksum_size; if (last_offset < 0) { periods = 0; n_steps = 0; n_incrs = 0; stop = -Checksum::cksum_size; } else { periods = last_offset / Checksum::cksum_skip; n_steps = periods + 1; n_incrs = last_offset + 1; stop = last_offset - (periods + 1) * Checksum::cksum_skip; } // Compute file stats once. if (fstats.unique_values == 0) { if (Checksum::cksum_skip == 1) { for (size_t i = 0; i <= buf_size - Checksum::cksum_size; i++) { fstats.update(hash(cksum.step(buf + i), s_bits, s_mask), buf + i); } } else { ptr = buf + last_offset; end = buf + stop; for (; ptr != end; ptr -= Checksum::cksum_skip) { fstats.update(hash(cksum.step(ptr), s_bits, s_mask), ptr); } } fstats.freeze(); } long start_test = get_millisecs_now(); if (Checksum::cksum_skip != 1) { new_table(n_steps); for (usize_t i = 0; i < test_iters; i++) { ptr = buf + last_offset; end = buf + stop; for (; ptr != end; ptr -= Checksum::cksum_skip) { set_table_bit(hash(cksum.step(ptr), s_bits, s_mask)); } } summarize_table(); } stop = buf_size - Checksum::cksum_size + 1; if (stop < 0) { stop = 0; } if (Checksum::cksum_skip == 1) { new_table(n_incrs); for (usize_t i = 0; i < test_iters; i++) { ptr = buf; end = buf + stop; if (ptr != end) { set_table_bit(hash(cksum.state0(ptr++), s_bits, s_mask)); } for (; ptr != end; ptr++) { typename Checksum::word_type w = cksum.incr(ptr); CHECK_EQ(w, cksum.step(ptr)); set_table_bit(hash(w, s_bits, s_mask)); } } summarize_table(); } accum_iters += test_iters; accum_millis += get_millisecs_now() - start_test; } }; static int read_whole_file(const char *name, uint8_t **buf_ptr, size_t *buf_len) { main_file file; int ret; xoff_t len; size_t nread; main_file_init(&file); file.filename = name; ret = main_file_open(&file, name, XO_READ); if (ret != 0) { fprintf(stderr, "open failed\n"); goto exit; } ret = main_file_stat(&file, &len); if (ret != 0) { fprintf(stderr, "stat failed\n"); goto exit; } (*buf_len) = (size_t)len; (*buf_ptr) = (uint8_t*) main_malloc(*buf_len); ret = main_file_read(&file, *buf_ptr, *buf_len, &nread, "read failed"); if (ret == 0 && *buf_len == nread) { ret = 0; } else { fprintf(stderr, "invalid read\n"); ret = XD3_INTERNAL; } exit: main_file_cleanup(&file); return ret; } int main(int argc, char** argv) { int i; uint8_t *buf = NULL; size_t buf_len = 0; int ret; if (argc <= 1) { fprintf(stderr, "usage: %s file ...\n", argv[0]); return 1; } // TODO: The xdelta3-hash.h code is identical now; add sameness test. // using rabin_karp<> template. #define TEST(T,Z,S,C) \ test_result,C>> \ _xck_ ## T ## _ ## Z ## _ ## S ## _ ## C \ ("xck_" #T "_" #Z "_" #S "_" #C); \ test_result,C>> \ _old_ ## T ## _ ## Z ## _ ## S ## _ ## C \ ("old_" #T "_" #Z "_" #S "_" #C) #define TESTS(SIZE, SKIP) \ TEST(usize_t, SIZE, SKIP, 1); \ TEST(usize_t, SIZE, SKIP, 2) TESTS(5, 1); TESTS(6, 1); TESTS(7, 1); TESTS(8, 1); TESTS(9, 1); TESTS(10, 1); TESTS(11, 1); TESTS(12, 1); TESTS(13, 1); TESTS(14, 1); TESTS(15, 1); TESTS(16, 1); TESTS(17, 1); TESTS(18, 1); TESTS(19, 1); TESTS(20, 1); TESTS(21, 1); TESTS(22, 1); TESTS(23, 1); TESTS(24, 1); TESTS(25, 1); TESTS(26, 1); TESTS(27, 1); TESTS(28, 1); TESTS(29, 1); TESTS(30, 1); TESTS(31, 1); TESTS(32, 1); TESTS(33, 1); TESTS(34, 1); TESTS(35, 1); TESTS(36, 1); TESTS(37, 1); TESTS(38, 1); TESTS(39, 1); for (i = 1; i < argc; i++) { if ((ret = read_whole_file(argv[i], & buf, & buf_len))) { return 1; } fprintf(stderr, "file %s is %zu bytes\n", argv[i], buf_len); double min_time = -1.0; double min_compression = 0.0; for (vector::iterator iter = all_tests.begin(); iter != all_tests.end(); ++iter) { test_result_base *test = *iter; test->reset(); usize_t iters = 1; long start_test = get_millisecs_now(); do { test->get(buf, buf_len, iters); iters *= 3; iters /= 2; } while (get_millisecs_now() - start_test < 2000); test->stat(); if (min_time < 0.0) { min_compression = test->compression(); min_time = test->time(); } if (min_time > test->time()) { min_time = test->time(); } if (min_compression > test->compression()) { min_compression = test->compression(); } test->print(); } main_free(buf); buf = NULL; } return 0; } ================================================ FILE: source-code/dependencies/xdelta3/testing/checksum_test_c.c ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "../xdelta3.c" // OLD CHECKSUM CODE #define PERMUTE32(x) (__single_hash32[x]) #define PERMUTE64(x) (__single_hash64[x]) const uint16_t __single_hash32[256] = { /* This hashes the input alphabet (Scheme SLIB pseudo-random). */ 0xbcd1, 0xbb65, 0x42c2, 0xdffe, 0x9666, 0x431b, 0x8504, 0xeb46, 0x6379, 0xd460, 0xcf14, 0x53cf, 0xdb51, 0xdb08, 0x12c8, 0xf602, 0xe766, 0x2394, 0x250d, 0xdcbb, 0xa678, 0x02af, 0xa5c6, 0x7ea6, 0xb645, 0xcb4d, 0xc44b, 0xe5dc, 0x9fe6, 0x5b5c, 0x35f5, 0x701a, 0x220f, 0x6c38, 0x1a56, 0x4ca3, 0xffc6, 0xb152, 0x8d61, 0x7a58, 0x9025, 0x8b3d, 0xbf0f, 0x95a3, 0xe5f4, 0xc127, 0x3bed, 0x320b, 0xb7f3, 0x6054, 0x333c, 0xd383, 0x8154, 0x5242, 0x4e0d, 0x0a94, 0x7028, 0x8689, 0x3a22, 0x0980, 0x1847, 0xb0f1, 0x9b5c, 0x4176, 0xb858, 0xd542, 0x1f6c, 0x2497, 0x6a5a, 0x9fa9, 0x8c5a, 0x7743, 0xa8a9, 0x9a02, 0x4918, 0x438c, 0xc388, 0x9e2b, 0x4cad, 0x01b6, 0xab19, 0xf777, 0x365f, 0x1eb2, 0x091e, 0x7bf8, 0x7a8e, 0x5227, 0xeab1, 0x2074, 0x4523, 0xe781, 0x01a3, 0x163d, 0x3b2e, 0x287d, 0x5e7f, 0xa063, 0xb134, 0x8fae, 0x5e8e, 0xb7b7, 0x4548, 0x1f5a, 0xfa56, 0x7a24, 0x900f, 0x42dc, 0xcc69, 0x02a0, 0x0b22, 0xdb31, 0x71fe, 0x0c7d, 0x1732, 0x1159, 0xcb09, 0xe1d2, 0x1351, 0x52e9, 0xf536, 0x5a4f, 0xc316, 0x6bf9, 0x8994, 0xb774, 0x5f3e, 0xf6d6, 0x3a61, 0xf82c, 0xcc22, 0x9d06, 0x299c, 0x09e5, 0x1eec, 0x514f, 0x8d53, 0xa650, 0x5c6e, 0xc577, 0x7958, 0x71ac, 0x8916, 0x9b4f, 0x2c09, 0x5211, 0xf6d8, 0xcaaa, 0xf7ef, 0x287f, 0x7a94, 0xab49, 0xfa2c, 0x7222, 0xe457, 0xd71a, 0x00c3, 0x1a76, 0xe98c, 0xc037, 0x8208, 0x5c2d, 0xdfda, 0xe5f5, 0x0b45, 0x15ce, 0x8a7e, 0xfcad, 0xaa2d, 0x4b5c, 0xd42e, 0xb251, 0x907e, 0x9a47, 0xc9a6, 0xd93f, 0x085e, 0x35ce, 0xa153, 0x7e7b, 0x9f0b, 0x25aa, 0x5d9f, 0xc04d, 0x8a0e, 0x2875, 0x4a1c, 0x295f, 0x1393, 0xf760, 0x9178, 0x0f5b, 0xfa7d, 0x83b4, 0x2082, 0x721d, 0x6462, 0x0368, 0x67e2, 0x8624, 0x194d, 0x22f6, 0x78fb, 0x6791, 0xb238, 0xb332, 0x7276, 0xf272, 0x47ec, 0x4504, 0xa961, 0x9fc8, 0x3fdc, 0xb413, 0x007a, 0x0806, 0x7458, 0x95c6, 0xccaa, 0x18d6, 0xe2ae, 0x1b06, 0xf3f6, 0x5050, 0xc8e8, 0xf4ac, 0xc04c, 0xf41c, 0x992f, 0xae44, 0x5f1b, 0x1113, 0x1738, 0xd9a8, 0x19ea, 0x2d33, 0x9698, 0x2fe9, 0x323f, 0xcde2, 0x6d71, 0xe37d, 0xb697, 0x2c4f, 0x4373, 0x9102, 0x075d, 0x8e25, 0x1672, 0xec28, 0x6acb, 0x86cc, 0x186e, 0x9414, 0xd674, 0xd1a5 }; const uint32_t __single_hash64[256] = { /* http://random.org 2014.10.24 */ 0xd25e9f0a, 0xb1af9d5e, 0xb753dfa2, 0x157050f7, /* 0 */ 0xc84b072c, 0xdd14fe7c, 0xf92208c3, 0xdf08a0c0, 0x63a5c118, 0x76f5d90f, 0xa2f8b93e, 0xb6c12d22, 0xaf074957, 0x966fb7d9, 0x62f7b785, 0xb40e8a09, 0x0a811d5d, 0x323a6daa, 0xb62f7c5b, 0xfdcb9a53, 0xf25a9067, 0x4506bc7a, 0xff58a74b, 0x5ae62817, 0x74097675, 0x722c0fd9, 0x116a2a66, 0x65f76728, 0x72c79651, 0xe043cf9d, 0x64b867c7, 0x6604834f, 0xcdca58a6, 0x0f164e2d, 0x24515f05, 0x632cdbf8, 0x18091d4a, 0x3eff4128, 0x673d1c33, 0xd8e10c71, 0x1a3edf11, 0xba52892f, 0xa56949e0, 0xf3e1dd77, /* 10 */ 0x86fcbe3e, 0x138d66d0, 0x4fc98359, 0xc22e5dd6, 0xc59f2267, 0x6c6dd739, 0xe03da190, 0x07e8469c, 0xadcfb02c, 0x00d3b0d9, 0xa1f44918, 0x8bd84d87, 0x08ec9ec1, 0xbbcd156f, 0xb57718e3, 0x3177e752, 0xf52a4d70, 0xde7aaad9, 0x075f1da0, 0x21ba00c6, 0xb9469a5c, 0xcf08d5ba, 0x91ac9edc, 0xc6167b63, 0xc1974919, 0xc8c8d195, 0x4b1996dd, 0xeff8991c, 0xf7f66c6b, 0x25b012e2, 0x59d12a98, 0xea40d3cc, 0x41f9970b, 0xec48101a, 0xa3bdcf90, 0x99f16905, 0x27af6c97, 0xc849af37, 0x49cad89b, 0xf48c2278, /* 20 */ 0x5529c3d8, 0x9e7d6dce, 0x16feb52d, 0xf1b0aca1, 0xaf28fccb, 0x48e4ce3c, 0xc4436617, 0x64524e3e, 0x61806681, 0x6384f2d7, 0x1172880f, 0x34a5ef5f, 0xcc8cc0a8, 0x66e8f100, 0x2866085f, 0xba9b1b2d, 0x51285949, 0x2be4b574, 0x889b1ef5, 0x3dbe920d, 0x9277a62f, 0x0584a9f6, 0x085d8fc4, 0x4b5d403d, 0x4e46ca78, 0x3294c2f9, 0x29313e70, 0xe4f09b24, 0xe73b331c, 0x072f5552, 0x2e390b78, 0xea0021ca, 0xd8f40320, 0xed0e16fd, 0x7de9cf7a, 0xf17e3d6c, 0x8df1bd85, 0x052cae67, 0x3486e512, 0x3a1c09b8, /* 30 */ 0x6c2a7b4e, 0x83455753, 0xbc0353ac, 0x0ffe20b6, 0x5fdcef85, 0x010f506c, 0x595ce972, 0xe28680d0, 0xa7e216b2, 0xa392ee0f, 0x25b73faa, 0x2b1f4983, 0xeeaefe98, 0x1d3d9cbc, 0x6aebe97b, 0x8b7b3584, 0x9e6a9a07, 0xd37f1e99, 0x4ac2a441, 0x8ae9a213, 0x7d0e27d7, 0x5de54b9a, 0x8621de1f, 0xf0f2f866, 0xcb08d275, 0x49c3f87e, 0xd5ee68c1, 0x9802fc77, 0x68be6c5e, 0x65aa8c27, 0xf423d5f7, 0x10ec5502, 0x9909bce1, 0x509cdf1b, 0x338fea72, 0x2733e9bf, 0xf92f4fd7, 0x87738ea2, 0x931a8bbc, 0x0a5c9155, /* 40 */ 0xbe5edd9b, 0xadbf5838, 0x0338f8d2, 0x290da210, 0x390c37d8, 0xe7cffae8, 0x20617ebe, 0x464322dd, 0x7b3c4e78, 0xac142dcb, 0x2d5cef76, 0xd8fe49fc, 0x60f4e9a9, 0x7473816f, 0x0dc35f39, 0x5eed80c1, 0x0cb55ab6, 0x1d3ac541, 0x13c7f529, 0x7bffdf4a, 0xe334785b, 0x85263ec1, 0xd132ae56, 0x7c868b9e, 0x47f60638, 0x1012b979, 0x81c31dd3, 0x1af868c8, 0x0c5d0742, 0xd1b3e1a2, 0x5873200a, 0xf848465c, 0x0fc4d596, 0x609c18af, 0xc9f5a480, 0xd1a94a84, 0xa1431a3f, 0x7de8bb1a, 0x25f1256b, 0x1dcc732c, /* 50 */ 0x6aa1549a, 0xa2367281, 0x32f2a77e, 0x82e62a0f, 0x045cbb56, 0x74b2027c, 0xd71a32d9, 0x022e7cb5, 0xe99be177, 0x60222fdf, 0xd69681ca, 0x9008ee2c, 0x32923db4, 0xcf82bf97, 0x38960a5b, 0xb3503d5b, 0x9bd4c7f2, 0x33c029c8, 0x1ef504a3, 0xdb249d3b, 0x91e89676, 0x4ca43b36, 0x9191433c, 0x465d5dc4, 0xf4dcb118, 0x9d11dd00, 0xb592f058, 0xdbe5ce30, 0x74790d92, 0x779850a8, 0x7180d25b, 0xfa951d99, 0x5990935a, 0x921cb022, 0x3b7c39bc, 0x6a38a7c7, 0xdc22703b, 0x142bab3b, 0x4e3d9479, 0x44bb8482, /* 60 */ 0x8043abce, 0xfebe832a, 0x8e6a2f98, 0x4d43c4fe, 0xd192a70a, 0x802f3c3a, 0x5d11bbab, 0x2665d241, 0xb3f3a680, 0x3a8d223f, 0xcf82cdb4, 0x4ed28743, }; uint64_t xd3_large64_cksum_old (xd3_hash_cfg *ignore, const uint8_t *base, const usize_t look) { static const uint64_t kBits = 32; static const uint64_t kMask = 0xffffffff; usize_t i = 0; uint64_t low = 0; uint64_t high = 0; for (; i < look; i += 1) { low += PERMUTE64(*base++); high += low; } return ((high & kMask) << kBits) | (low & kMask); } uint64_t xd3_large64_cksum_update_old (xd3_hash_cfg *ignore, const uint64_t cksum, const uint8_t *base, const usize_t look) { static const uint64_t kBits = 32; static const uint64_t kMask = 0xffffffff; uint64_t old_c = PERMUTE64(base[0]); uint64_t new_c = PERMUTE64(base[look]); uint64_t low = ((cksum & kMask) - old_c + new_c) & kMask; uint64_t high = ((cksum >> kBits) - (old_c * look) + low) & kMask; return (high << kBits) | low; } uint32_t xd3_large32_cksum_old (xd3_hash_cfg *ignore, const uint8_t *base, const usize_t look) { static const uint32_t kBits = 16; static const uint32_t kMask = 0xffff; usize_t i = 0; uint32_t low = 0; uint32_t high = 0; for (; i < look; i += 1) { low += PERMUTE32(*base++); high += low; } return ((high & kMask) << kBits) | (low & kMask); } uint32_t xd3_large32_cksum_update_old (xd3_hash_cfg *ignore, const uint32_t cksum, const uint8_t *base, const usize_t look) { static const uint32_t kBits = 16; static const uint32_t kMask = 0xffff; uint32_t old_c = PERMUTE32(base[0]); uint32_t new_c = PERMUTE32(base[look]); uint32_t low = ((cksum & kMask) - old_c + new_c) & kMask; uint32_t high = ((cksum >> kBits) - (old_c * look) + low) & kMask; return (high << kBits) | low; } ================================================ FILE: source-code/dependencies/xdelta3/testing/cmp.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ static size_t CmpDifferentBlockBytes(const Block &a, const Block &b) { size_t total = 0; size_t i = 0; size_t m = min(a.Size(), b.Size()); for (; i < m; i++) { if (a[i] != b[i]) { total++; } } total += a.Size() - i; total += b.Size() - i; return total; } static xoff_t CmpDifferentBytes(const FileSpec &a, const FileSpec &b) { Block block_a, block_b; xoff_t total = 0; typename FileSpec::iterator a_i(a), b_i(b); for (; !a_i.Done() && !b_i.Done(); a_i.Next(), b_i.Next()) { a_i.Get(&block_a); b_i.Get(&block_b); total += CmpDifferentBlockBytes(block_a, block_b); } for (; !a_i.Done(); a_i.Next()) { total += a_i.BytesOnBlock(); } for (; !b_i.Done(); b_i.Next()) { total += b_i.BytesOnBlock(); } return total; } static size_t CmpDifferentBlockBytesAtOffset(const Block &a, const FileSpec &b_spec, xoff_t offset) { Block b; size_t size = a.Size(); CHECK_LE(offset, b_spec.Size()); if (b_spec.Size() < offset + size) { size = b_spec.Size() - offset; } b_spec.Get(&b, offset, size); return CmpDifferentBlockBytes(a, b); } ================================================ FILE: source-code/dependencies/xdelta3/testing/delta.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ class Delta { public: Delta(const Block &block) { int ret; xd3_config config; memset(&stream_, 0, sizeof (stream_)); memset(&config, 0, sizeof (config)); xd3_init_config(&config, XD3_SKIP_EMIT | XD3_ADLER32_NOVER); CHECK_EQ(0, xd3_config_stream (&stream_, &config)); xd3_avail_input (&stream_, block.Data(), block.Size()); bool done = false; while (!done) { ret = xd3_decode_input(&stream_); switch (ret) { case XD3_INPUT: done = true; break; case XD3_OUTPUT: CHECK_EQ(0, xd3_whole_append_window (&stream_)); break; case XD3_GOTHEADER: case XD3_WINSTART: case XD3_WINFINISH: break; default: cerr << "decode: " << done; abort(); } } } ~Delta() { xd3_free_stream(&stream_); } xoff_t AddedBytes() const { return stream_.whole_target.addslen; } xoff_t Windows() const { return stream_.whole_target.wininfolen; } // Note: This does not benefit from -Wformat= checking, due to the // enclosing template. Further, it was not used. // void Print() const { // for (size_t i = 0; i < stream_.whole_target.instlen; i++) { // xd3_winst &winst = stream_.whole_target.inst[i]; // switch (winst.type) { // case XD3_RUN: // DP(RINT, "%" Q "u run %" W "u\n", winst.position, winst.size); // break; // case XD3_ADD: // DP(RINT "%" Q "u add %" W "u\n", winst.position, winst.size); // break; // default: // DP(RINT "%" Q "u copy %" W "u @ %" Q "u (mode %u)\n", // winst.position, winst.size, winst.addr, winst.mode); // break; // } // } // } private: xd3_stream stream_; }; ================================================ FILE: source-code/dependencies/xdelta3/testing/file.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ class Block; class BlockIterator; class TmpFile; class Block { public: Block() : data_(NULL), data_size_(0), size_(0) { } ~Block() { if (data_) { delete [] data_; } } size_t Size() const { return size_; } uint8_t operator[](size_t i) const { CHECK_LT(i, size_); return data_[i]; } uint8_t* Data() const { if (data_ == NULL) { CHECK_EQ(0, size_); data_size_ = 1; data_ = new uint8_t[1]; } return data_; } // For writing to blocks void Append(const uint8_t *data, size_t size) { if (data_ == NULL) { CHECK_EQ(0, size_); CHECK_EQ(0, data_size_); data_ = new uint8_t[Constants::BLOCK_SIZE]; data_size_ = Constants::BLOCK_SIZE; } if (size_ + size > data_size_) { uint8_t *tmp = data_; while (size_ + size > data_size_) { data_size_ *= 2; } data_ = new uint8_t[data_size_]; memcpy(data_, tmp, size_); delete [] tmp; } memcpy(data_ + size_, data, size); size_ += size; } // For cleaing a block void Reset() { size_ = 0; } // Note: This does not benefit from -Wformat= checking, due to the // enclosing template. Further, it was not used. // void Print() const { // xoff_t pos = 0; // for (size_t i = 0; i < Size(); i++) { // if (pos % 16 == 0) { // DP(RINT "%5" Q "x: ", pos); // } // DP(RINT "%02x ", (*this)[i]); // if (pos % 16 == 15) { // DP(RINT "\n"); // } // pos++; // } // DP(RINT "\n"); // } void WriteTmpFile(TmpFile *f) const { f->Append(this); } void SetSize(size_t size) { uint8_t *t = NULL; if (data_size_ < size) { if (data_) { t = data_; } data_ = new uint8_t[size]; data_size_ = size; } if (t && size < size_) { memcpy(data_, t, size); } delete [] t; size_ = size; } private: friend class BlockIterator; mutable uint8_t *data_; mutable size_t data_size_; size_t size_; }; class FileSpec { public: FileSpec(MTRandom *rand) : rand_(rand) { } // Generates a file with a known size void GenerateFixedSize(xoff_t size) { Reset(); for (xoff_t p = 0; p < size; ) { xoff_t t = min(Constants::BLOCK_SIZE, size - p); table_.insert(make_pair(p, Segment(t, rand_))); p += t; } } // Generates a file with exponential-random distributed size void GenerateRandomSize(xoff_t mean) { GenerateFixedSize(rand_->ExpRand(mean)); } // Returns the size of the file xoff_t Size() const { if (table_.empty()) { return 0; } ConstSegmentMapIterator i = --table_.end(); return i->first + i->second.Size(); } // Returns the number of blocks xoff_t Blocks(size_t blksize = Constants::BLOCK_SIZE) const { if (table_.empty()) { return 0; } return ((Size() - 1) / blksize) + 1; } // Returns the number of segments xoff_t Segments() const { return table_.size(); } // Create a mutation according to "what". void ModifyTo(const Mutator &mutator, FileSpec *modify) const { modify->Reset(); mutator.Mutate(&modify->table_, &table_, rand_); modify->CheckSegments(); } void CheckSegments() const { for (ConstSegmentMapIterator iter(table_.begin()); iter != table_.end(); ) { ConstSegmentMapIterator iter0(iter++); if (iter == table_.end()) { break; } CHECK_EQ(iter0->first + iter0->second.Size(), iter->first); } } void Reset() { table_.clear(); } void Print() const { for (ConstSegmentMapIterator iter(table_.begin()); iter != table_.end(); ++iter) { const Segment &seg = iter->second; cerr << "Segment at " << iter->first << " (" << seg.ToString() << ")" << endl; } } void PrintData() const { Block block; for (BlockIterator iter(*this); !iter.Done(); iter.Next()) { iter.Get(&block); block.Print(); } } void WriteTmpFile(TmpFile *f) const { Block block; for (BlockIterator iter(*this); !iter.Done(); iter.Next()) { iter.Get(&block); f->Append(&block); } } void Get(Block *block, xoff_t offset, size_t size) const { size_t got = 0; block->SetSize(size); ConstSegmentMapIterator pos = table_.upper_bound(offset); if (pos == table_.begin()) { CHECK_EQ(0, Size()); return; } --pos; while (got < size) { CHECK(pos != table_.end()); CHECK_GE(offset, pos->first); const Segment &seg = pos->second; // The position of this segment may start before this block starts, // and then the position of the data may be offset from the seeding // position. size_t seg_offset = offset - pos->first; size_t advance = min(seg.Size() - seg_offset, size - got); seg.Fill(seg_offset, advance, block->Data() + got); got += advance; offset += advance; ++pos; } } typedef BlockIterator iterator; private: friend class BlockIterator; MTRandom *rand_; SegmentMap table_; }; class BlockIterator { public: explicit BlockIterator(const FileSpec& spec) : spec_(spec), blkno_(0), blksize_(Constants::BLOCK_SIZE) { } BlockIterator(const FileSpec& spec, size_t blksize) : spec_(spec), blkno_(0), blksize_(blksize) { } bool Done() const { return blkno_ >= spec_.Blocks(blksize_); } void Next() { blkno_++; } xoff_t Blkno() const { return blkno_; } xoff_t Blocks() const { return spec_.Blocks(blksize_); } xoff_t Offset() const { return blkno_ * blksize_; } void SetBlock(xoff_t blkno) { CHECK_LE(blkno, Blocks()); blkno_ = blkno; } void Get(Block *block) const { spec_.Get(block, blkno_ * blksize_, BytesOnBlock()); } size_t BytesOnBlock() const { xoff_t blocks = spec_.Blocks(blksize_); xoff_t size = spec_.Size(); DCHECK((blkno_ < blocks) || (blkno_ == blocks && size % blksize_ == 0)); if (blkno_ == blocks) { return 0; } if (blkno_ + 1 == blocks) { return ((size - 1) % blksize_) + 1; } return blksize_; } size_t BlockSize() const { return blksize_; } private: const FileSpec& spec_; xoff_t blkno_; size_t blksize_; }; class ExtFile { public: ExtFile() { static int static_counter = 0; pid_t pid = getpid(); char buf[64]; xoff_t xpid = pid; snprintf(buf, 64, "/tmp/regtest.%" Q "u.%d", xpid, static_counter++); filename_.append(buf); unlink(filename_.c_str()); } ~ExtFile() { unlink(filename_.c_str()); } const char* Name() const { return filename_.c_str(); } // Check whether a real file matches a file spec. bool EqualsSpec(const FileSpec &spec) const { main_file t; main_file_init(&t); CHECK_EQ(0, main_file_open(&t, Name(), XO_READ)); Block tblock; Block sblock; for (BlockIterator iter(spec); !iter.Done(); iter.Next()) { iter.Get(&sblock); tblock.SetSize(sblock.Size()); size_t tread; CHECK_EQ(0, main_file_read(&t, tblock.Data(), tblock.Size(), &tread, "read failed")); CHECK_EQ(0, CmpDifferentBlockBytes(tblock, sblock)); } CHECK_EQ(0, main_file_close(&t)); main_file_cleanup(&t); return true; } protected: string filename_; }; class TmpFile : public ExtFile { public: TmpFile() { main_file_init(&file_); CHECK_EQ(0, main_file_open(&file_, Name(), XO_WRITE)); } ~TmpFile() { main_file_cleanup(&file_); } void Append(const Block *block) { CHECK_EQ(0, main_file_write(&file_, block->Data(), block->Size(), "tmpfile write failed")); } const char* Name() const { if (main_file_isopen(&file_)) { CHECK_EQ(0, main_file_close(&file_)); } return ExtFile::Name(); } private: mutable main_file file_; }; ================================================ FILE: source-code/dependencies/xdelta3/testing/modify.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ class Mutator { public: virtual ~Mutator() { } virtual void Mutate(SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) const = 0; }; class Change { public: enum Kind { MODIFY = 1, // Mutate a certain range w/ random or supplied data ADD = 2, // Insert random or supplied data DELRANGE = 3, // Delete a specified range of data COPY = 4, // Copy from one region, inserting elsewhere MOVE = 5, // Copy then delete copied-from range COPYOVER = 6 // Copy then delete copied-to range // ADD, DELRANGE, and COPY change the file size // MODIFY, MOVE, COPYOVER preserve the file size }; // Constructor for modify, add, delete. Change(Kind kind0, xoff_t size0, xoff_t addr1_0) : kind(kind0), size(size0), addr1(addr1_0), addr2(0), insert(NULL) { CHECK(kind != MOVE && kind != COPY && kind != COPYOVER); } // Constructor for modify, add w/ provided data. Change(Kind kind0, xoff_t size0, xoff_t addr1_0, Segment *insert0) : kind(kind0), size(size0), addr1(addr1_0), addr2(0), insert(insert0) { CHECK(kind != MOVE && kind != COPY && kind != COPYOVER); } // Constructor for move, copy, overwrite Change(Kind kind0, xoff_t size0, xoff_t addr1_0, xoff_t addr2_0) : kind(kind0), size(size0), addr1(addr1_0), addr2(addr2_0), insert(NULL) { CHECK(kind == MOVE || kind == COPY || kind == COPYOVER); } Kind kind; xoff_t size; xoff_t addr1; xoff_t addr2; Segment *insert; // For modify and/or add }; typedef list ChangeList; typedef typename ChangeList::const_iterator ConstChangeListIterator; typedef typename ChangeList::iterator ChangeListIterator; class ChangeListMutator : public Mutator { public: ChangeListMutator(const ChangeList &cl) : cl_(cl) { } ChangeListMutator() { } void Mutate(SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) const { // The speed of processing gigabytes of data is so slow compared with // these table-copy operations, no attempt to make this fast. SegmentMap tmp; for (ConstChangeListIterator iter(cl_.begin()); iter != cl_.end(); ++iter) { const Change &ch = *iter; tmp.clear(); Mutate(ch, &tmp, source_table, rand); tmp.swap(*table); source_table = table; } } static void Mutate(const Change &ch, SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) { switch (ch.kind) { case Change::ADD: AddChange(ch, table, source_table, rand); break; case Change::MODIFY: ModifyChange(ch, table, source_table, rand); break; case Change::DELRANGE: DeleteChange(ch, table, source_table, rand); break; case Change::COPY: CopyChange(ch, table, source_table, rand); break; case Change::MOVE: MoveChange(ch, table, source_table, rand); break; case Change::COPYOVER: OverwriteChange(ch, table, source_table, rand); break; } } static void ModifyChange(const Change &ch, SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) { xoff_t m_start = ch.addr1; xoff_t m_end = m_start + ch.size; xoff_t i_start = 0; xoff_t i_end = 0; for (ConstSegmentMapIterator iter(source_table->begin()); iter != source_table->end(); ++iter) { const Segment &seg = iter->second; i_start = iter->first; i_end = i_start + seg.Size(); if (i_end <= m_start || i_start >= m_end) { table->insert(table->end(), make_pair(i_start, seg)); continue; } if (i_start < m_start) { table->insert(table->end(), make_pair(i_start, seg.Subseg(0, m_start - i_start))); } // Insert the entire segment, even though it may extend into later // segments. This condition avoids inserting it during later // segments. if (m_start >= i_start) { if (ch.insert != NULL) { table->insert(table->end(), make_pair(m_start, *ch.insert)); } else { Segment part(m_end - m_start, rand); table->insert(table->end(), make_pair(m_start, part)); } } if (i_end > m_end) { table->insert(table->end(), make_pair(m_end, seg.Subseg(m_end - i_start, i_end - m_end))); } } // This check verifies that the modify does not extend past the // source_table EOF. CHECK_LE(m_end, i_end); } static void AddChange(const Change &ch, SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) { xoff_t m_start = ch.addr1; xoff_t i_start = 0; xoff_t i_end = 0; for (ConstSegmentMapIterator iter(source_table->begin()); iter != source_table->end(); ++iter) { const Segment &seg = iter->second; i_start = iter->first; i_end = i_start + seg.Size(); if (i_end <= m_start) { table->insert(table->end(), make_pair(i_start, seg)); continue; } if (i_start > m_start) { table->insert(table->end(), make_pair(i_start + ch.size, seg)); continue; } if (i_start < m_start) { table->insert(table->end(), make_pair(i_start, seg.Subseg(0, m_start - i_start))); } if (ch.insert != NULL) { table->insert(table->end(), make_pair(m_start, *ch.insert)); } else { Segment addseg(ch.size, rand); table->insert(table->end(), make_pair(m_start, addseg)); } if (m_start < i_end) { table->insert(table->end(), make_pair(m_start + ch.size, seg.Subseg(m_start - i_start, i_end - m_start))); } } CHECK_LE(m_start, i_end); // Special case for add at end-of-input. if (m_start == i_end) { Segment addseg(ch.size, rand); table->insert(table->end(), make_pair(m_start, addseg)); } } static void DeleteChange(const Change &ch, SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) { xoff_t m_start = ch.addr1; xoff_t m_end = m_start + ch.size; xoff_t i_start = 0; xoff_t i_end = 0; for (ConstSegmentMapIterator iter(source_table->begin()); iter != source_table->end(); ++iter) { const Segment &seg = iter->second; i_start = iter->first; i_end = i_start + seg.Size(); if (i_end <= m_start) { table->insert(table->end(), make_pair(i_start, seg)); continue; } if (i_start >= m_end) { table->insert(table->end(), make_pair(i_start - ch.size, seg)); continue; } if (i_start < m_start) { table->insert(table->end(), make_pair(i_start, seg.Subseg(0, m_start - i_start))); } if (i_end > m_end) { table->insert(table->end(), make_pair(m_end - ch.size, seg.Subseg(m_end - i_start, i_end - m_end))); } } CHECK_LT(m_start, i_end); CHECK_LE(m_end, i_end); } // A move is a copy followed by delete of the copied-from range. static void MoveChange(const Change &ch, SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) { SegmentMap tmp; CHECK_NE(ch.addr1, ch.addr2); CopyChange(ch, &tmp, source_table, rand); Change d(Change::DELRANGE, ch.size, ch.addr1 < ch.addr2 ? ch.addr1 : ch.addr1 + ch.size); DeleteChange(d, table, &tmp, rand); } // An overwrite is a copy followed by a delete of the copied-to range. static void OverwriteChange(const Change &ch, SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) { SegmentMap tmp; CHECK_NE(ch.addr1, ch.addr2); CopyChange(ch, &tmp, source_table, rand); Change d(Change::DELRANGE, ch.size, ch.addr2 + ch.size); DeleteChange(d, table, &tmp, rand); } static void CopyChange(const Change &ch, SegmentMap *table, const SegmentMap *source_table, MTRandom *ignore) { xoff_t m_start = ch.addr2; xoff_t c_start = ch.addr1; xoff_t i_start = 0; xoff_t i_end = 0; // Like AddChange() with AppendCopy instead of a random segment. for (ConstSegmentMapIterator iter(source_table->begin()); iter != source_table->end(); ++iter) { const Segment &seg = iter->second; i_start = iter->first; i_end = i_start + seg.Size(); if (i_end <= m_start) { table->insert(table->end(), make_pair(i_start, seg)); continue; } if (i_start > m_start) { table->insert(table->end(), make_pair(i_start + ch.size, seg)); continue; } if (i_start < m_start) { table->insert(table->end(), make_pair(i_start, seg.Subseg(0, m_start - i_start))); } AppendCopy(table, source_table, c_start, m_start, ch.size); if (m_start < i_end) { table->insert(table->end(), make_pair(m_start + ch.size, seg.Subseg(m_start - i_start, i_end - m_start))); } } CHECK_LE(m_start, i_end); // Special case for copy to end-of-input. if (m_start == i_end) { AppendCopy(table, source_table, c_start, m_start, ch.size); } } static void AppendCopy(SegmentMap *table, const SegmentMap *source_table, xoff_t copy_offset, xoff_t append_offset, xoff_t length) { ConstSegmentMapIterator pos(source_table->upper_bound(copy_offset)); --pos; xoff_t got = 0; while (got < length) { size_t seg_offset = copy_offset - pos->first; size_t advance = min(pos->second.Size() - seg_offset, (size_t)(length - got)); table->insert(table->end(), make_pair(append_offset, pos->second.Subseg(seg_offset, advance))); got += advance; copy_offset += advance; append_offset += advance; ++pos; } } ChangeList* Changes() { return &cl_; } const ChangeList* Changes() const { return &cl_; } private: ChangeList cl_; }; class Modify1stByte : public Mutator { public: void Mutate(SegmentMap *table, const SegmentMap *source_table, MTRandom *rand) const { ChangeListMutator::Mutate(Change(Change::MODIFY, 1, 0), table, source_table, rand); } }; ================================================ FILE: source-code/dependencies/xdelta3/testing/random.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #undef MT_LEN #undef MT_IA class MTRandom { public: enum Constants { MT_LEN = 624, MT_IA = 397 }; static const uint32_t TEST_SEED1; static const uint32_t UPPER_MASK; static const uint32_t LOWER_MASK; static const uint32_t MATRIX_A; MTRandom() { Init(TEST_SEED1); } explicit MTRandom(uint32_t seed) { Init(seed); } /* This Mersenne Twister code is attributed to Michael Brundage. Thanks! * http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation.html */ uint32_t Rand32 () { uint32_t y; static unsigned long mag01[2] = { 0 , MATRIX_A }; if (mt_index_ >= MT_LEN) { int kk; for (kk = 0; kk < MT_LEN - MT_IA; kk++) { y = (mt_buffer_[kk] & UPPER_MASK) | (mt_buffer_[kk + 1] & LOWER_MASK); mt_buffer_[kk] = mt_buffer_[kk + MT_IA] ^ (y >> 1) ^ mag01[y & 0x1UL]; } for (;kk < MT_LEN - 1; kk++) { y = (mt_buffer_[kk] & UPPER_MASK) | (mt_buffer_[kk + 1] & LOWER_MASK); mt_buffer_[kk] = mt_buffer_[kk + (MT_IA - MT_LEN)] ^ (y >> 1) ^ mag01[y & 0x1UL]; } y = (mt_buffer_[MT_LEN - 1] & UPPER_MASK) | (mt_buffer_[0] & LOWER_MASK); mt_buffer_[MT_LEN - 1] = mt_buffer_[MT_IA - 1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mt_index_ = 0; } y = mt_buffer_[mt_index_++]; y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } uint32_t ExpRand32(uint32_t mean) { double mean_d = mean; double erand = log (1.0 / (Rand32() / (double)UINT32_MAX)); uint32_t x = (uint32_t) (mean_d * erand + 0.5); return x; } uint64_t Rand64() { return ((uint64_t)Rand32() << 32) | Rand32(); } uint64_t ExpRand64(uint64_t mean) { double mean_d = mean; double erand = log (1.0 / (Rand64() / (double)UINT32_MAX)); uint64_t x = (uint64_t) (mean_d * erand + 0.5); return x; } template T Rand() { switch (sizeof(T)) { case sizeof(uint32_t): return Rand32(); case sizeof(uint64_t): return Rand64(); default: cerr << "Invalid sizeof T" << endl; abort(); } } template T ExpRand(T mean) { switch (sizeof(T)) { case sizeof(uint32_t): return ExpRand32(mean); case sizeof(uint64_t): return ExpRand64(mean); default: cerr << "Invalid sizeof T" << endl; abort(); } } private: void Init(uint32_t seed) { mt_buffer_[0] = seed; mt_index_ = MT_LEN; for (int i = 1; i < MT_LEN; i++) { /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ /* 2002/01/09 modified by Makoto Matsumoto */ mt_buffer_[i] = (1812433253UL * (mt_buffer_[i-1] ^ (mt_buffer_[i-1] >> 30)) + i); } } int mt_index_; uint32_t mt_buffer_[MT_LEN]; }; const uint32_t MTRandom::TEST_SEED1 = 5489UL; const uint32_t MTRandom::UPPER_MASK = 0x80000000; const uint32_t MTRandom::LOWER_MASK = 0x7FFFFFFF; const uint32_t MTRandom::MATRIX_A = 0x9908B0DF; class MTRandom8 { public: MTRandom8(MTRandom *rand) : rand_(rand) { } uint8_t Rand8() { uint32_t r = rand_->Rand32(); // TODO: make this use a single byte at a time? return (r & 0xff) ^ (r >> 7) ^ (r >> 15) ^ (r >> 21); } private: MTRandom *rand_; }; ================================================ FILE: source-code/dependencies/xdelta3/testing/regtest.cc ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "test.h" #include "random.h" #include "sizes.h" template class Regtest { public: typedef typename Constants::Sizes Sizes; struct Options { Options() : encode_srcwin_maxsz(1<<20), block_size(Constants::BLOCK_SIZE), window_size(Constants::WINDOW_SIZE), size_known(false), iopt_size(XD3_DEFAULT_IOPT_SIZE), smatch_cfg(XD3_SMATCH_DEFAULT) { } xoff_t encode_srcwin_maxsz; size_t block_size; xoff_t window_size; bool size_known; usize_t iopt_size; xd3_smatch_cfg smatch_cfg; }; #include "segment.h" #include "modify.h" #include "file.h" #include "cmp.h" #include "delta.h" void InMemoryEncodeDecode(const FileSpec &source_file, const FileSpec &target_file, Block *coded_data, const Options &options) { xd3_stream encode_stream; xd3_config encode_config; xd3_source encode_source; xd3_stream decode_stream; xd3_config decode_config; xd3_source decode_source; xoff_t verified_bytes = 0; xoff_t encoded_bytes = 0; if (coded_data) { coded_data->Reset(); } memset(&encode_stream, 0, sizeof (encode_stream)); memset(&encode_source, 0, sizeof (encode_source)); memset(&decode_stream, 0, sizeof (decode_stream)); memset(&decode_source, 0, sizeof (decode_source)); xd3_init_config(&encode_config, XD3_ADLER32); xd3_init_config(&decode_config, XD3_ADLER32); encode_config.winsize = options.window_size; encode_config.iopt_size = options.iopt_size; encode_config.smatch_cfg = options.smatch_cfg; CHECK_EQ(0, xd3_config_stream (&encode_stream, &encode_config)); CHECK_EQ(0, xd3_config_stream (&decode_stream, &decode_config)); encode_source.blksize = options.block_size; decode_source.blksize = options.block_size; encode_source.max_winsize = options.encode_srcwin_maxsz; decode_source.max_winsize = options.encode_srcwin_maxsz; if (!options.size_known) { xd3_set_source (&encode_stream, &encode_source); xd3_set_source (&decode_stream, &decode_source); } else { xd3_set_source_and_size (&encode_stream, &encode_source, source_file.Size()); xd3_set_source_and_size (&decode_stream, &decode_source, source_file.Size()); } BlockIterator source_iterator(source_file, options.block_size); BlockIterator target_iterator(target_file, Constants::WINDOW_SIZE); Block encode_source_block, decode_source_block; Block decoded_block, target_block; bool encoding = true; bool done = false; bool done_after_input = false; IF_DEBUG1 (XPR(NTR "source %" Q "u[%" Z "u] target %" Q "u winsize %" Z "u\n", source_file.Size(), options.block_size, target_file.Size(), Constants::WINDOW_SIZE)); while (!done) { target_iterator.Get(&target_block); xoff_t blks = target_iterator.Blocks(); IF_DEBUG2(XPR(NTR "target in %s: %" Q "u[%" Z "u] %" Q "u(%" Q "u) " "verified %" Q "u\n", encoding ? "encoding" : "decoding", target_iterator.Offset(), target_block.Size(), target_iterator.Blkno(), blks, verified_bytes)); if (blks == 0 || target_iterator.Blkno() == (blks - 1)) { xd3_set_flags(&encode_stream, XD3_FLUSH | encode_stream.flags); } xd3_avail_input(&encode_stream, target_block.Data(), target_block.Size()); encoded_bytes += target_block.Size(); process: int ret; const char *msg; if (encoding) { ret = xd3_encode_input(&encode_stream); msg = encode_stream.msg; } else { ret = xd3_decode_input(&decode_stream); msg = decode_stream.msg; } (void) msg; switch (ret) { case XD3_OUTPUT: if (encoding) { if (coded_data != NULL) { // Optional encoded-output to the caller coded_data->Append(encode_stream.next_out, encode_stream.avail_out); } // Feed this data to the decoder. xd3_avail_input(&decode_stream, encode_stream.next_out, encode_stream.avail_out); xd3_consume_output(&encode_stream); encoding = false; } else { decoded_block.Append(decode_stream.next_out, decode_stream.avail_out); xd3_consume_output(&decode_stream); } goto process; case XD3_GETSRCBLK: { xd3_source *src = (encoding ? &encode_source : &decode_source); Block *block = (encoding ? &encode_source_block : &decode_source_block); if (encoding) { IF_DEBUG2(XPR(NTR "[srcblock] %" Q "u last srcpos %" Q "u " "encodepos %" Q "u\n", encode_source.getblkno, encode_stream.match_last_srcpos, encode_stream.input_position + encode_stream.total_in)); } source_iterator.SetBlock(src->getblkno); source_iterator.Get(block); src->curblkno = src->getblkno; src->onblk = block->Size(); src->curblk = block->Data(); goto process; } case XD3_INPUT: if (!encoding) { encoding = true; goto process; } else { if (done_after_input) { done = true; continue; } if (target_block.Size() < target_iterator.BlockSize()) { encoding = false; } else { target_iterator.Next(); } continue; } case XD3_WINFINISH: if (encoding) { if (encode_stream.flags & XD3_FLUSH) { done_after_input = true; } encoding = false; } else { CHECK_EQ(0, CmpDifferentBlockBytesAtOffset(decoded_block, target_file, verified_bytes)); verified_bytes += decoded_block.Size(); decoded_block.Reset(); encoding = true; } goto process; case XD3_WINSTART: case XD3_GOTHEADER: goto process; default: XPR(NTR "%s = %s %s\n", encoding ? "E " : " D", xd3_strerror(ret), msg == NULL ? "" : msg); CHECK_EQ(0, ret); CHECK_EQ(-1, ret); } } CHECK_EQ(target_file.Size(), encoded_bytes); CHECK_EQ(target_file.Size(), verified_bytes); CHECK_EQ(0, xd3_close_stream(&decode_stream)); CHECK_EQ(0, xd3_close_stream(&encode_stream)); xd3_free_stream(&encode_stream); xd3_free_stream(&decode_stream); } void MainEncodeDecode(const TmpFile &source_file, const TmpFile &target_file, ExtFile *coded_data, const Options &options) { vector ecmd; char bbuf[16]; snprintf(bbuf, sizeof(bbuf), "-B%" Q "u", options.encode_srcwin_maxsz); ecmd.push_back("xdelta3"); ecmd.push_back(bbuf); ecmd.push_back("-s"); ecmd.push_back(source_file.Name()); ecmd.push_back(target_file.Name()); ecmd.push_back(coded_data->Name()); ecmd.push_back(NULL); CHECK_EQ(0, xd3_main_cmdline(ecmd.size() - 1, const_cast(&ecmd[0]))); vector dcmd; ExtFile recon_file; dcmd.push_back("xdelta3"); ecmd.push_back(bbuf); dcmd.push_back("-d"); dcmd.push_back("-s"); dcmd.push_back(source_file.Name()); dcmd.push_back(coded_data->Name()); dcmd.push_back(recon_file.Name()); dcmd.push_back(NULL); CHECK_EQ(0, xd3_main_cmdline(dcmd.size() - 1, const_cast(&dcmd[0]))); CHECK_EQ(0, test_compare_files(recon_file.Name(), target_file.Name())); } // Similar to xd3_process_memory, with support for test Options. // Exercises xd3_process_stream. int TestProcessMemory (int is_encode, int (*func) (xd3_stream *), const uint8_t *input, usize_t input_size, const uint8_t *source, usize_t source_size, uint8_t *output, usize_t *output_size, usize_t output_size_max, const Options &options) { xd3_stream stream; xd3_config config; xd3_source src; int ret; memset (& stream, 0, sizeof (stream)); memset (& config, 0, sizeof (config)); if (is_encode) { config.winsize = input_size; config.iopt_size = options.iopt_size; config.sprevsz = xd3_pow2_roundup (config.winsize); } if ((ret = xd3_config_stream (&stream, &config)) != 0) { goto exit; } if (source != NULL) { memset (& src, 0, sizeof (src)); src.blksize = source_size; src.onblk = source_size; src.curblk = source; src.curblkno = 0; src.max_winsize = source_size; if ((ret = xd3_set_source_and_size (&stream, &src, source_size)) != 0) { goto exit; } } if ((ret = xd3_process_stream (is_encode, & stream, func, 1, input, input_size, output, output_size, output_size_max)) != 0) { goto exit; } exit: if (ret != 0) { IF_DEBUG2 (DP(RINT "test_process_memory: %d: %s\n", ret, stream.msg)); } xd3_free_stream(&stream); return ret; } void EncodeDecodeAPI(const FileSpec &spec0, const FileSpec &spec1, Block *delta, const Options &options) { Block from; Block to; spec0.Get(&from, 0, spec0.Size()); spec1.Get(&to, 0, spec1.Size()); delta->SetSize(to.Size() * 1.5); usize_t out_size; int enc_ret = TestProcessMemory(true, &xd3_encode_input, to.Data(), to.Size(), from.Data(), from.Size(), delta->Data(), &out_size, delta->Size(), options); CHECK_EQ(0, enc_ret); delta->SetSize(out_size); Block recon; recon.SetSize(to.Size()); usize_t recon_size; int dec_ret = xd3_decode_memory(delta->Data(), delta->Size(), from.Data(), from.Size(), recon.Data(), &recon_size, recon.Size(), 0); CHECK_EQ(0, dec_ret); CHECK_EQ(0, CmpDifferentBlockBytes(to, recon)); } ////////////////////////////////////////////////////////////////////// void TestPrintf() { char buf[64]; xoff_t x = XOFF_T_MAX; snprintf_func (buf, sizeof(buf), "%" Q "u", x); const char *expect = XD3_USE_LARGEFILE64 ? "18446744073709551615" : "4294967295"; XD3_ASSERT(strcmp (buf, expect) == 0); } void TestRandomNumbers() { MTRandom rand; int rounds = 1<<20; uint64_t usum = 0; uint64_t esum = 0; for (int i = 0; i < rounds; i++) { usum += rand.Rand32(); esum += rand.ExpRand32(1024); } double allowed_error = 0.01; uint32_t umean = usum / rounds; uint32_t emean = esum / rounds; uint32_t uexpect = UINT32_MAX / 2; uint32_t eexpect = 1024; if (umean < uexpect * (1.0 - allowed_error) || umean > uexpect * (1.0 + allowed_error)) { XPR(NT "uniform mean error: %u != %u\n", umean, uexpect); abort(); } if (emean < eexpect * (1.0 - allowed_error) || emean > eexpect * (1.0 + allowed_error)) { XPR(NT "exponential mean error: %u != %u\n", emean, eexpect); abort(); } } void TestRandomFile() { MTRandom rand1; FileSpec spec1(&rand1); BlockIterator bi(spec1); spec1.GenerateFixedSize(0); CHECK_EQ(0, spec1.Size()); CHECK_EQ(0, spec1.Segments()); CHECK_EQ(0, spec1.Blocks()); bi.SetBlock(0); CHECK_EQ(0, bi.BytesOnBlock()); spec1.GenerateFixedSize(1); CHECK_EQ(1, spec1.Size()); CHECK_EQ(1, spec1.Segments()); CHECK_EQ(1, spec1.Blocks()); bi.SetBlock(0); CHECK_EQ(1, bi.BytesOnBlock()); spec1.GenerateFixedSize(Constants::BLOCK_SIZE); CHECK_EQ(Constants::BLOCK_SIZE, spec1.Size()); CHECK_EQ(1, spec1.Segments()); CHECK_EQ(1, spec1.Blocks()); bi.SetBlock(0); CHECK_EQ(Constants::BLOCK_SIZE, bi.BytesOnBlock()); bi.SetBlock(1); CHECK_EQ(0, bi.BytesOnBlock()); spec1.GenerateFixedSize(Constants::BLOCK_SIZE + 1); CHECK_EQ(Constants::BLOCK_SIZE + 1, spec1.Size()); CHECK_EQ(2, spec1.Segments()); CHECK_EQ(2, spec1.Blocks()); bi.SetBlock(0); CHECK_EQ(Constants::BLOCK_SIZE, bi.BytesOnBlock()); bi.SetBlock(1); CHECK_EQ(1, bi.BytesOnBlock()); spec1.GenerateFixedSize(Constants::BLOCK_SIZE * 2); CHECK_EQ(Constants::BLOCK_SIZE * 2, spec1.Size()); CHECK_EQ(2, spec1.Segments()); CHECK_EQ(2, spec1.Blocks()); bi.SetBlock(0); CHECK_EQ(Constants::BLOCK_SIZE, bi.BytesOnBlock()); bi.SetBlock(1); CHECK_EQ(Constants::BLOCK_SIZE, bi.BytesOnBlock()); } void TestFirstByte() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); spec0.GenerateFixedSize(0); spec1.GenerateFixedSize(1); CHECK_EQ(0, CmpDifferentBytes(spec0, spec0)); CHECK_EQ(0, CmpDifferentBytes(spec1, spec1)); CHECK_EQ(1, CmpDifferentBytes(spec0, spec1)); CHECK_EQ(1, CmpDifferentBytes(spec1, spec0)); spec0.GenerateFixedSize(1); spec0.ModifyTo(Modify1stByte(), &spec1); CHECK_EQ(1, CmpDifferentBytes(spec0, spec1)); spec0.GenerateFixedSize(Constants::BLOCK_SIZE + 1); spec0.ModifyTo(Modify1stByte(), &spec1); CHECK_EQ(1, CmpDifferentBytes(spec0, spec1)); SizeIterator si(&rand, Constants::TEST_ROUNDS); for (; !si.Done(); si.Next()) { size_t size = si.Get(); if (size == 0) { continue; } spec0.GenerateFixedSize(size); spec0.ModifyTo(Modify1stByte(), &spec1); InMemoryEncodeDecode(spec0, spec1, NULL, Options()); } } void TestModifyMutator() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 3); struct { size_t size; size_t addr; } test_cases[] = { { Constants::BLOCK_SIZE, 0 }, { Constants::BLOCK_SIZE / 2, 1 }, { Constants::BLOCK_SIZE, 1 }, { Constants::BLOCK_SIZE * 2, 1 }, }; for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { ChangeList cl1; cl1.push_back(Change(Change::MODIFY, test_cases[i].size, test_cases[i].addr)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size(), spec1.Size()); size_t diff = CmpDifferentBytes(spec0, spec1); CHECK_LE(diff, test_cases[i].size); // There is a 1/256 probability of the changed byte matching the // original value. The following allows double the probability to // pass. CHECK_GE(diff, test_cases[i].size - (2 * test_cases[i].size / 256)); InMemoryEncodeDecode(spec0, spec1, NULL, Options()); } } void TestAddMutator() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 2); // TODO: fix this test (for all block sizes)! it's broken because // the same byte could be added? struct { size_t size; size_t addr; size_t expected_adds; } test_cases[] = { { 1, 0, 2 /* 1st byte, last byte (short block) */ }, { 1, 1, 3 /* 1st 2 bytes, last byte */ }, { 1, Constants::BLOCK_SIZE - 1, 2 /* changed, last */ }, { 1, Constants::BLOCK_SIZE, 2 /* changed, last */ }, { 1, Constants::BLOCK_SIZE + 1, 3 /* changed + 1st of 2nd block, last */ }, { 1, 2 * Constants::BLOCK_SIZE, 1 /* last byte */ }, }; for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { ChangeList cl1; cl1.push_back(Change(Change::ADD, test_cases[i].size, test_cases[i].addr)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size() + test_cases[i].size, spec1.Size()); Block coded; InMemoryEncodeDecode(spec0, spec1, &coded, Options()); Delta delta(coded); CHECK_EQ(test_cases[i].expected_adds, delta.AddedBytes()); } } void TestDeleteMutator() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 4); struct { size_t size; size_t addr; } test_cases[] = { // Note: an entry { Constants::BLOCK_SIZE, 0 }, // does not work because the xd3_srcwin_move_point logic won't // find a copy if it occurs >= double its size into the file. { Constants::BLOCK_SIZE / 2, 0 }, { Constants::BLOCK_SIZE / 2, Constants::BLOCK_SIZE / 2 }, { Constants::BLOCK_SIZE, Constants::BLOCK_SIZE / 2 }, { Constants::BLOCK_SIZE * 2, Constants::BLOCK_SIZE * 3 / 2 }, { Constants::BLOCK_SIZE, Constants::BLOCK_SIZE * 2 }, }; for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { ChangeList cl1; cl1.push_back(Change(Change::DELRANGE, test_cases[i].size, test_cases[i].addr)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size() - test_cases[i].size, spec1.Size()); Block coded; InMemoryEncodeDecode(spec0, spec1, &coded, Options()); Delta delta(coded); CHECK_EQ(0, delta.AddedBytes()); } } void TestCopyMutator() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 3); struct { size_t size; size_t from; size_t to; } test_cases[] = { // Copy is difficult to write tests for because where Xdelta finds // copies, it does not enter checksums. So these tests copy data from // later to earlier so that checksumming will start. { Constants::BLOCK_SIZE / 2, Constants::BLOCK_SIZE / 2, 0 }, { Constants::BLOCK_SIZE, 2 * Constants::BLOCK_SIZE, Constants::BLOCK_SIZE, }, }; for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { ChangeList cl1; cl1.push_back(Change(Change::COPY, test_cases[i].size, test_cases[i].from, test_cases[i].to)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size() + test_cases[i].size, spec1.Size()); Block coded; InMemoryEncodeDecode(spec0, spec1, &coded, Options()); Delta delta(coded); CHECK_EQ(0, delta.AddedBytes()); } } void TestMoveMutator() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 3); struct { size_t size; size_t from; size_t to; } test_cases[] = { // This is easier to test than Copy but has the same trouble as Delete. { Constants::BLOCK_SIZE / 2, Constants::BLOCK_SIZE / 2, 0 }, { Constants::BLOCK_SIZE / 2, 0, Constants::BLOCK_SIZE / 2 }, { Constants::BLOCK_SIZE, Constants::BLOCK_SIZE, 2 * Constants::BLOCK_SIZE }, { Constants::BLOCK_SIZE, 2 * Constants::BLOCK_SIZE, Constants::BLOCK_SIZE }, { Constants::BLOCK_SIZE * 3 / 2, Constants::BLOCK_SIZE, Constants::BLOCK_SIZE * 3 / 2 }, // This is a no-op { Constants::BLOCK_SIZE, Constants::BLOCK_SIZE * 2, 3 * Constants::BLOCK_SIZE }, }; for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { ChangeList cl1; cl1.push_back(Change(Change::MOVE, test_cases[i].size, test_cases[i].from, test_cases[i].to)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size(), spec1.Size()); Block coded; InMemoryEncodeDecode(spec0, spec1, &coded, Options()); Delta delta(coded); CHECK_EQ(0, delta.AddedBytes()); } } void TestOverwriteMutator() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); spec0.GenerateFixedSize(Constants::BLOCK_SIZE); ChangeList cl1; cl1.push_back(Change(Change::COPYOVER, 10, 0, 20)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size(), spec1.Size()); Block b0, b1; BlockIterator(spec0).Get(&b0); BlockIterator(spec1).Get(&b1); CHECK(memcmp(b0.Data(), b1.Data() + 20, 10) == 0); CHECK(memcmp(b0.Data(), b1.Data(), 20) == 0); CHECK(memcmp(b0.Data() + 30, b1.Data() + 30, Constants::BLOCK_SIZE - 30) == 0); xoff_t zero = 0; cl1.clear(); cl1.push_back(Change(Change::COPYOVER, 10, 20, zero)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size(), spec1.Size()); BlockIterator(spec0).Get(&b0); BlockIterator(spec1).Get(&b1); CHECK(memcmp(b0.Data() + 20, b1.Data(), 10) == 0); CHECK(memcmp(b0.Data() + 10, b1.Data() + 10, Constants::BLOCK_SIZE - 10) == 0); } // Note: this test is written to expose a problem, but the problem was // only exposed with BLOCK_SIZE = 128. void TestNonBlocking() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); FileSpec spec2(&rand); spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 3); // This is a lazy target match Change ct(Change::COPYOVER, 22, Constants::BLOCK_SIZE + 50, Constants::BLOCK_SIZE + 20); // This is a source match just after the block boundary, shorter // than the lazy target match. Change cs1(Change::COPYOVER, 16, Constants::BLOCK_SIZE + 51, Constants::BLOCK_SIZE - 1); // This overwrites the original source bytes. Change cs2(Change::MODIFY, 108, Constants::BLOCK_SIZE + 20); // This changes the first blocks Change c1st(Change::MODIFY, Constants::BLOCK_SIZE - 2, 0); ChangeList csl; csl.push_back(cs1); csl.push_back(cs2); csl.push_back(c1st); spec0.ModifyTo(ChangeListMutator(csl), &spec1); ChangeList ctl; ctl.push_back(ct); ctl.push_back(c1st); spec0.ModifyTo(ChangeListMutator(ctl), &spec2); InMemoryEncodeDecode(spec1, spec2, NULL, Options()); } void TestEmptyInMemory() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); Block block; spec0.GenerateFixedSize(0); spec1.GenerateFixedSize(0); InMemoryEncodeDecode(spec0, spec1, &block, Options()); Delta delta(block); CHECK_LT(0, block.Size()); CHECK_EQ(1, delta.Windows()); } void TestBlockInMemory() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); Block block; spec0.GenerateFixedSize(Constants::BLOCK_SIZE); spec1.GenerateFixedSize(Constants::BLOCK_SIZE); InMemoryEncodeDecode(spec0, spec1, &block, Options()); Delta delta(block); CHECK_EQ(spec1.Blocks(Constants::WINDOW_SIZE), delta.Windows()); } void TestSmallStride() { MTRandom rand; FileSpec spec0(&rand); usize_t size = Constants::BLOCK_SIZE * 4; spec0.GenerateFixedSize(size); // Note: Not very good performance due to hash collisions, note 3x // multiplier below. for (int s = 15; s < 101; s++) { usize_t changes = 0; ChangeList cl; for (usize_t j = s; j < size; j += s, ++changes) { cl.push_back(Change(Change::MODIFY, 1, j)); } FileSpec spec1(&rand); spec0.ModifyTo(ChangeListMutator(cl), &spec1); Options options; options.encode_srcwin_maxsz = size; options.iopt_size = 128; options.smatch_cfg = XD3_SMATCH_SLOW; options.size_known = false; Block block; InMemoryEncodeDecode(spec0, spec1, &block, options); Delta delta(block); IF_DEBUG1(DP(RINT "[stride=%d] changes=%" W "u adds=%" Q "u\n", s, changes, delta.AddedBytes())); double allowance = Constants::BLOCK_SIZE < 8192 || s < 30 ? 3.0 : 1.1; CHECK_GE(allowance * changes, (double)delta.AddedBytes()); } } void TestCopyWindow() { // Construct an input that has many copies, to fill the IOPT buffer // and force a source window decision. "srclen" may be set to a // value that goes beyond the end-of-source. const int clen = 16; const int size = 4096; const int nmov = size / clen; const int iters = 16; uint32_t added_01 = 0; uint32_t added_10 = 0; for (int i = 1; i <= iters; i++) { MTRandom rand(MTRandom::TEST_SEED1 * i); FileSpec spec0(&rand); ChangeList cl; spec0.GenerateFixedSize(size); for (int j = 0; j < nmov; j += 2) { cl.push_back(Change(Change::MOVE, clen, (j + 1) * clen, j * clen)); } FileSpec spec1(&rand); spec0.ModifyTo(ChangeListMutator(cl), &spec1); Options options; options.encode_srcwin_maxsz = size; options.iopt_size = 128; options.smatch_cfg = XD3_SMATCH_SLOW; Block block1; InMemoryEncodeDecode(spec0, spec1, &block1, options); Delta delta1(block1); // Allow one missed window (e.g., hash collisions) added_01 += delta1.AddedBytes(); Block block2; InMemoryEncodeDecode(spec1, spec0, &block2, options); Delta delta2(block2); // Allow one missed window (e.g., hash collisions) added_10 += delta2.AddedBytes(); Block block3; Block block4; EncodeDecodeAPI(spec0, spec1, &block3, options); EncodeDecodeAPI(spec1, spec0, &block4, options); } // Average less than 0.5 misses (of length clen) per iteration. CHECK_GE(clen * iters / 2, added_01); CHECK_GE(clen * iters / 2, added_10); } void TestCopyFromEnd() { // Copies from the end of the source buffer, which reach a block // boundary end-of-file. const int size = 4096; const int clen = 16; const int nmov = (size / 2) / clen; const int iters = 16; uint32_t added_01 = 0; uint32_t added_10 = 0; for (int i = 1; i <= iters; i++) { MTRandom rand(MTRandom::TEST_SEED1 * i); FileSpec spec0(&rand); ChangeList cl; spec0.GenerateFixedSize(size); cl.push_back(Change(Change::MODIFY, 2012, 2048)); for (int j = 0; j < nmov; j += 2) { cl.push_back(Change(Change::MOVE, clen, (j + 1) * clen, j * clen)); } cl.push_back(Change(Change::COPYOVER, 28, 4068, 3000)); cl.push_back(Change(Change::COPYOVER, 30, 4066, 3100)); cl.push_back(Change(Change::COPYOVER, 32, 4064, 3200)); FileSpec spec1(&rand); spec0.ModifyTo(ChangeListMutator(cl), &spec1); Options options; options.encode_srcwin_maxsz = size; options.iopt_size = 128; options.smatch_cfg = XD3_SMATCH_SLOW; Block block1; InMemoryEncodeDecode(spec0, spec1, &block1, options); Delta delta1(block1); added_01 += delta1.AddedBytes(); Block block2; InMemoryEncodeDecode(spec1, spec0, &block2, options); Delta delta2(block2); added_10 += delta2.AddedBytes(); Block block3; Block block4; EncodeDecodeAPI(spec0, spec1, &block3, options); EncodeDecodeAPI(spec1, spec0, &block4, options); } CHECK_GE(2000 * iters, added_01); CHECK_LE(2000 * iters, added_10); } void TestHalfBlockCopy() { // Create a half-block copy, 7.5 blocks apart, in a pair of files: // 0 1 ... 6 7 // spec0 [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb][ccccc][bbbb_] // spec1 [aaaaa][ccccc][aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_] // where stage= // 0: the final block is full // a. (source)spec1->(target)spec0 copies block C: reads 8 source // blocks during target block 0. // b. (source)spec0->(target)spec1 does not copy block C b/c attempt // to read past EOF empties block 0 from (virtual) block cache // 1: the final block is less than full. // a. (same) copies block C // b. (same) copies block C, unlike 0a, no attempt to read past EOF // // "virtual" above refers to XD3_TOOFARBACK, since there is no caching // in the API, there is simply a promise not to request blocks that are // beyond source->max_winsize from the last known source file position. for (int stage = 0; stage < 2; stage++) { IF_DEBUG1 (DP(RINT "half_block_copy stage %d\n", stage)); MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 8 - stage); ChangeList cl1; cl1.push_back(Change(Change::MODIFY, Constants::BLOCK_SIZE / 2, // size 0)); cl1.push_back(Change(Change::COPYOVER, Constants::BLOCK_SIZE / 2, // size Constants::BLOCK_SIZE * 7, // offset Constants::BLOCK_SIZE / 2)); cl1.push_back(Change(Change::MODIFY, Constants::BLOCK_SIZE * 7, Constants::BLOCK_SIZE - stage)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); Options options; options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 8; Block block0; Block block1; InMemoryEncodeDecode(spec0, spec1, &block0, options); InMemoryEncodeDecode(spec1, spec0, &block1, options); Delta delta0(block0); Delta delta1(block1); const int yes = Constants::BLOCK_SIZE * 8 - Constants::BLOCK_SIZE / 2; const int no = Constants::BLOCK_SIZE * 8 - Constants::BLOCK_SIZE / 2; if (stage == 0) { CHECK_EQ(yes, delta0.AddedBytes()); CHECK_EQ(no, delta1.AddedBytes()); } else { CHECK_EQ(yes, delta0.AddedBytes()); CHECK_EQ(yes, delta1.AddedBytes()); } } } void FourWayMergeTest(const FileSpec &spec0, const FileSpec &spec1, const FileSpec &spec2, const FileSpec &spec3) { TmpFile f0, f1, f2, f3; ExtFile d01, d12, d23; Options options; options.encode_srcwin_maxsz = std::max(spec0.Size(), options.encode_srcwin_maxsz); spec0.WriteTmpFile(&f0); spec1.WriteTmpFile(&f1); spec2.WriteTmpFile(&f2); spec3.WriteTmpFile(&f3); MainEncodeDecode(f0, f1, &d01, options); MainEncodeDecode(f1, f2, &d12, options); MainEncodeDecode(f2, f3, &d23, options); // Merge 2 ExtFile out; vector mcmd; mcmd.push_back("xdelta3"); mcmd.push_back("merge"); mcmd.push_back("-m"); mcmd.push_back(d01.Name()); mcmd.push_back(d12.Name()); mcmd.push_back(out.Name()); mcmd.push_back(NULL); // XPR(NTR "Running one merge: %s\n", CommandToString(mcmd).c_str()); CHECK_EQ(0, xd3_main_cmdline(mcmd.size() - 1, const_cast(&mcmd[0]))); ExtFile recon; vector tcmd; tcmd.push_back("xdelta3"); tcmd.push_back("-d"); tcmd.push_back("-s"); tcmd.push_back(f0.Name()); tcmd.push_back(out.Name()); tcmd.push_back(recon.Name()); tcmd.push_back(NULL); // XPR(NTR "Running one recon! %s\n", CommandToString(tcmd).c_str()); CHECK_EQ(0, xd3_main_cmdline(tcmd.size() - 1, const_cast(&tcmd[0]))); // XPR(NTR "Should equal! %s\n", f2.Name()); CHECK(recon.EqualsSpec(spec2)); // Merge 3 ExtFile out3; vector mcmd3; mcmd3.push_back("xdelta3"); mcmd3.push_back("merge"); mcmd3.push_back("-m"); mcmd3.push_back(d01.Name()); mcmd3.push_back("-m"); mcmd3.push_back(d12.Name()); mcmd3.push_back(d23.Name()); mcmd3.push_back(out3.Name()); mcmd3.push_back(NULL); // XPR(NTR "Running one 3-merge: %s\n", CommandToString(mcmd3).c_str()); CHECK_EQ(0, xd3_main_cmdline(mcmd3.size() - 1, const_cast(&mcmd3[0]))); ExtFile recon3; vector tcmd3; tcmd3.push_back("xdelta3"); tcmd3.push_back("-d"); tcmd3.push_back("-s"); tcmd3.push_back(f0.Name()); tcmd3.push_back(out3.Name()); tcmd3.push_back(recon3.Name()); tcmd3.push_back(NULL); // XPR(NTR "Running one 3-recon %s\n", CommandToString(tcmd3).c_str()); CHECK_EQ(0, xd3_main_cmdline(tcmd3.size() - 1, const_cast(&tcmd3[0]))); // XPR(NTR "Should equal %s\n", f3.Name()); CHECK(recon3.EqualsSpec(spec3)); } void TestMergeCommand1() { /* Repeat random-input testing for a number of iterations. * Test 2, 3, and 4-file scenarios (i.e., 1, 2, and 3-delta merges). */ MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); FileSpec spec2(&rand); FileSpec spec3(&rand); SizeIterator si0(&rand, 10); for (; !si0.Done(); si0.Next()) { size_t size0 = si0.Get(); SizeIterator si1(&rand, 10); for (; !si1.Done(); si1.Next()) { size_t change1 = si1.Get(); if (change1 == 0) { continue; } // XPR(NTR "S0 = %lu\n", size0); // XPR(NTR "C1 = %lu\n", change1); // XPR(NTR "."); size_t add1_pos = size0 ? rand.Rand32() % size0 : 0; size_t del2_pos = size0 ? rand.Rand32() % size0 : 0; spec0.GenerateFixedSize(size0); ChangeList cl1, cl2, cl3; size_t change3 = change1; size_t change3_pos; if (change3 >= size0) { change3 = size0; change3_pos = 0; } else { change3_pos = rand.Rand32() % (size0 - change3); } cl1.push_back(Change(Change::ADD, change1, add1_pos)); cl2.push_back(Change(Change::DELRANGE, change1, del2_pos)); cl3.push_back(Change(Change::MODIFY, change3, change3_pos)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); spec1.ModifyTo(ChangeListMutator(cl2), &spec2); spec2.ModifyTo(ChangeListMutator(cl3), &spec3); FourWayMergeTest(spec0, spec1, spec2, spec3); FourWayMergeTest(spec3, spec2, spec1, spec0); } } } void TestMergeCommand2() { /* Same as above, different mutation pattern. */ /* TODO: run this with large sizes too */ /* TODO: run this with small sizes too */ MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); FileSpec spec2(&rand); FileSpec spec3(&rand); SizeIterator si0(&rand, 10); for (; !si0.Done(); si0.Next()) { size_t size0 = si0.Get(); SizeIterator si1(&rand, 10); for (; !si1.Done(); si1.Next()) { size_t size1 = si1.Get(); SizeIterator si2(&rand, 10); for (; !si2.Done(); si2.Next()) { size_t size2 = si2.Get(); SizeIterator si3(&rand, 10); for (; !si3.Done(); si3.Next()) { size_t size3 = si3.Get(); // We're only interested in three sizes, strictly decreasing. */ if (size3 >= size2 || size2 >= size1 || size1 >= size0) { continue; } // XPR(NTR "S0 = %lu\n", size0); // XPR(NTR "S1 = %lu\n", size1); // XPR(NTR "S2 = %lu\n", size2); // XPR(NTR "S3 = %lu\n", size3); // XPR(NTR "."); spec0.GenerateFixedSize(size0); ChangeList cl1, cl2, cl3; cl1.push_back(Change(Change::DELRANGE, size0 - size1, 0)); cl2.push_back(Change(Change::DELRANGE, size0 - size2, 0)); cl3.push_back(Change(Change::DELRANGE, size0 - size3, 0)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); spec0.ModifyTo(ChangeListMutator(cl2), &spec2); spec0.ModifyTo(ChangeListMutator(cl3), &spec3); FourWayMergeTest(spec0, spec1, spec2, spec3); FourWayMergeTest(spec3, spec2, spec1, spec0); } } } } } void TestLastFrontierBlock() { // This test constructs an input that can expose // https://github.com/jmacd/xdelta/issues/188 // when run through the command-line with source via a FIFO. // That is not tested here, but the test stays. if (Constants::WINDOW_SIZE < XD3_ALLOCSIZE) { return; } MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); const xoff_t size = XD3_ALLOCSIZE * 64; // == XD3_MINSRCWINSZ * 2 const xoff_t edit = XD3_ALLOCSIZE; Options options; options.encode_srcwin_maxsz = XD3_MINSRCWINSZ; options.block_size = XD3_ALLOCSIZE; options.window_size = XD3_MINSRCWINSZ; options.size_known = false; spec0.GenerateFixedSize(size); ChangeList cl; // Modify the 0th byte in order to induce indexing of subsequent // bytes, but allow copying most of the file to keep the test fast. cl.push_back(Change(Change::MODIFY, 1, edit * 31)); cl.push_back(Change(Change::COPYOVER, edit, edit * 31, edit * 63)); spec0.ModifyTo(ChangeListMutator(cl), &spec1); Block noblock; InMemoryEncodeDecode(spec0, spec1, &noblock, options); InMemoryEncodeDecode(spec1, spec0, &noblock, options); } }; // class Regtest #define TEST(x) XPR(NTR #x "...\n"); regtest.x() // These tests are primarily tests of the testing framework itself. template void UnitTest() { Regtest regtest; TEST(TestPrintf); TEST(TestRandomNumbers); TEST(TestRandomFile); TEST(TestFirstByte); TEST(TestModifyMutator); TEST(TestAddMutator); TEST(TestDeleteMutator); TEST(TestCopyMutator); TEST(TestMoveMutator); TEST(TestOverwriteMutator); } // These are Xdelta tests. template void MainTest() { XPR(NT "Blocksize %" Q "u windowsize %" Z "u\n", T::BLOCK_SIZE, T::WINDOW_SIZE); Regtest regtest; TEST(TestEmptyInMemory); TEST(TestBlockInMemory); TEST(TestSmallStride); TEST(TestCopyWindow); TEST(TestCopyFromEnd); TEST(TestNonBlocking); TEST(TestHalfBlockCopy); TEST(TestLastFrontierBlock); TEST(TestMergeCommand1); TEST(TestMergeCommand2); } #undef TEST int main(int argc, char **argv) { vector mcmd; string pn; const char *sp = strrchr(argv[0], '/'); if (sp != NULL) { pn.append(argv[0], sp - argv[0] + 1); } pn.append("xdelta3"); mcmd.push_back(pn.c_str()); mcmd.push_back("test"); mcmd.push_back(NULL); UnitTest(); MainTest(); MainTest(); MainTest(); MainTest(); CHECK_EQ(0, xd3_main_cmdline(mcmd.size() - 1, const_cast(&mcmd[0]))); return 0; } ================================================ FILE: source-code/dependencies/xdelta3/testing/regtest_c.c ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "../xdelta3.c" ================================================ FILE: source-code/dependencies/xdelta3/testing/run_release.sh ================================================ #!/bin/sh (cd .. && ./run_release.sh) ================================================ FILE: source-code/dependencies/xdelta3/testing/segment.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ class Segment { public: Segment(size_t size, MTRandom *rand) : size_(size), seed_(rand->Rand32()), seed_offset_(0), data_(NULL) { CHECK_GT(size_, 0); } Segment(size_t size, uint32_t seed) : size_(size), seed_(seed), seed_offset_(0), data_(NULL) { CHECK_GT(size_, 0); } Segment(size_t size, uint8_t *data) : size_(size), seed_(0), seed_offset_(0), data_(data) { CHECK_GT(size_, 0); } size_t Size() const { return size_; } Segment Subseg(size_t start, size_t size) const { CHECK_LE(start + size, size_); if (data_) { return Segment(size, data_ + start); } else { return Segment(size, seed_, seed_offset_ + start); } } void Fill(size_t seg_offset, size_t size, uint8_t *data) const { CHECK_LE(seg_offset + size, size_); if (data_) { memcpy(data, data_ + seg_offset, size); } else { size_t skip = seg_offset + seed_offset_; MTRandom gen(seed_); MTRandom8 gen8(&gen); while (skip--) { gen8.Rand8(); } for (size_t i = 0; i < size; i++) { data[i] = gen8.Rand8(); } } } string ToString() const { string r; if (data_) { for (size_t i = 0; i < size_; i++) { char buf[10]; sprintf(buf, "%02x ", data_[i]); r.append(buf); } } else { char buf[256]; sprintf(buf, "size=%ld,seed=%ud,skip=%ld", size_, seed_, seed_offset_); r.append(buf); } return r; } private: // Used by Subseg() Segment(size_t size, uint32_t seed, size_t seed_offset) : size_(size), seed_(seed), seed_offset_(seed_offset), data_(NULL) { CHECK_GT(size_, 0); } size_t size_; // Size of this segment // For random segments uint32_t seed_; // Seed used for generating byte sequence size_t seed_offset_; // Seed positions the sequence this many bytes // before its beginning. // For literal segments (data is not owned) uint8_t *data_; }; typedef map SegmentMap; typedef typename SegmentMap::const_iterator ConstSegmentMapIterator; typedef typename SegmentMap::iterator SegmentMapIterator; ================================================ FILE: source-code/dependencies/xdelta3/testing/sizes.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ template class SizeIterator { public: SizeIterator(MTRandom *rand, size_t howmany) : rand_(rand), count_(0), fixed_(U::sizes), fixed_size_(SIZEOF_ARRAY(U::sizes)), howmany_(howmany) { } T Get() { if (count_ < fixed_size_) { return fixed_[count_]; } return rand_->Rand() % U::max_value; } bool Done() { return count_ >= fixed_size_ && count_ >= howmany_; } void Next() { count_++; } private: MTRandom *rand_; size_t count_; T* fixed_; size_t fixed_size_; size_t howmany_; }; // Small sizes class SmallSizes { public: static size_t sizes[]; static size_t max_value; }; size_t SmallSizes::sizes[] = { 0, 1, 128 / 4, 3333, 128 - (128 / 3), 128, 128 + (128 / 3), 2 * 128 - (128 / 3), 2 * 128, 2 * 128 + (128 / 3), }; size_t SmallSizes::max_value = 128 * 3; // Large sizes class LargeSizes { public: static size_t sizes[]; static size_t max_value; }; size_t LargeSizes::sizes[] = { 1 << 20, 1 << 18, 1 << 16, }; size_t LargeSizes::max_value = 1<<20; // Base constants struct BaseConstants { static const size_t TEST_ROUNDS; }; const size_t BaseConstants::TEST_ROUNDS = 10; // Regtest<> arguments struct SmallBlock : public BaseConstants { static const xoff_t BLOCK_SIZE; static const size_t WINDOW_SIZE; typedef SmallSizes Sizes; }; const xoff_t SmallBlock::BLOCK_SIZE = 1<<7; const size_t SmallBlock::WINDOW_SIZE = 1<<7; struct LargeBlock : public BaseConstants { static const xoff_t BLOCK_SIZE; static const size_t WINDOW_SIZE; typedef LargeSizes Sizes; }; const xoff_t LargeBlock::BLOCK_SIZE = (1 << 13); const size_t LargeBlock::WINDOW_SIZE = (1 << 13); struct MixedBlock : public BaseConstants { static const xoff_t BLOCK_SIZE; static const size_t WINDOW_SIZE; typedef SmallSizes Sizes; }; const xoff_t MixedBlock::BLOCK_SIZE = 1<<7; const size_t MixedBlock::WINDOW_SIZE = 1<<8; struct OversizeBlock : public BaseConstants { static const xoff_t BLOCK_SIZE; static const size_t WINDOW_SIZE; typedef SmallSizes Sizes; }; const xoff_t OversizeBlock::BLOCK_SIZE = 1<<8; const size_t OversizeBlock::WINDOW_SIZE = 1<<7; ================================================ FILE: source-code/dependencies/xdelta3/testing/test.h ================================================ /* xdelta3 - delta compression tools and library -*- Mode: C++ -*- Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ extern "C" { #include "../xdelta3.h" #include "../xdelta3-internal.h" } #include #include #include #define CHECK_EQ(x,y) CHECK_OP(x,y,==) #define CHECK_NE(x,y) CHECK_OP(x,y,!=) #define CHECK_LT(x,y) CHECK_OP(x,y,<) #define CHECK_GT(x,y) CHECK_OP(x,y,>) #define CHECK_LE(x,y) CHECK_OP(x,y,<=) #define CHECK_GE(x,y) CHECK_OP(x,y,>=) #define CHECK_OP(x,y,OP) \ do { \ __typeof__(x) _x(x); \ __typeof__(x) _y(y); \ if (!(_x OP _y)) { \ cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x " " #OP " " #y << endl; \ cerr << __FILE__ << ":" << __LINE__ << " {0} " << _x << endl; \ cerr << __FILE__ << ":" << __LINE__ << " {1} " << _y << endl; \ abort(); \ } } while (false) #undef CHECK #define CHECK(x) \ do {if (!(x)) { \ cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x << endl; \ abort(); \ } } while (false) #define DCHECK(x) using std::string; #include using std::vector; inline string CommandToString(const vector &v) { string s(v[0]); for (size_t i = 1; i < v.size() && v[i] != NULL; i++) { s.append(" "); s.append(v[i]); } return s; } #include using std::cerr; using std::endl; using std::ostream; #include using std::map; using std::pair; #include using std::list; template pair make_pair(const T& t, const U& u) { return pair(t, u); } using std::min; using std::max; ================================================ FILE: source-code/dependencies/xdelta3/testing/xdelta3-regtest.py ================================================ #!/usr/bin/python2.7 # xdelta3 - delta compression tools and library -*- Mode: C++ -*- # Copyright 2016 Joshua MacDonald # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # TODO This code is no longer maintained :( import os, sys, math, re, time, types, array, random import xdelta3 RCSDIR = '/tmp/rcs' SAMPLEDIR = "/tmp/diff" # MIN_SIZE = 0 TIME_TOO_SHORT = 0.050 SKIP_TRIALS = 2 MIN_TRIALS = 3 MAX_TRIALS = 15 # 10 = fast 1.5 = slow MIN_STDDEV_PCT = 1.5 # How many results per round MAX_RESULTS = 500 TEST_ROUNDS = 10 KEEP_P = (0.5) # For RCS testing, what percent to select FILE_P = (0.50) # For run-speed tests MIN_RUN = 1000 * 1000 * 1 MAX_RUN = 1000 * 1000 * 10 # Testwide defaults ALL_ARGS = [ '-q' # '-vv' ] # The first 7 args go to -C SOFT_CONFIG_CNT = 7 CONFIG_ORDER = [ 'large_look', 'large_step', 'small_look', 'small_chain', 'small_lchain', 'max_lazy', 'long_enough', # > SOFT_CONFIG_CNT 'nocompress', 'winsize', 'srcwinsize', 'sprevsz', 'iopt', 'djw', 'altcode', ] CONFIG_ARGMAP = { 'winsize' : '-W', 'srcwinsize' : '-B', 'sprevsz' : '-P', 'iopt' : '-I', 'nocompress' : '-N', 'djw' : '-Sdjw', 'altcode' : '-T', } def INPUT_SPEC(rand): return { # Time/space costs: # -C 1,2,3,4,5,6,7 'large_look' : lambda d: rand.choice([9, 10, 11, 12]), 'large_step' : lambda d: rand.choice([25, 26, 27, 28, 29, 30]), 'small_look' : lambda d: rand.choice([4]), 'small_chain' : lambda d: rand.choice([1]), 'small_lchain' : lambda d: rand.choice([1]), 'max_lazy' : lambda d: rand.choice([4, 5, 6, 7, 8, 9, 10 ]), # Note: long_enough only refers to small matching and has no effect if # small_chain == 1. 'long_enough' : lambda d: rand.choice([4]), # -N 'nocompress' : lambda d: rand.choice(['false']), # -T 'altcode' : lambda d: rand.choice(['false']), # -S djw 'djw' : lambda d: rand.choice(['false']), # Memory costs: # -W 'winsize' : lambda d: 8 * (1<<20), # -B 'srcwinsize' : lambda d: 64 * (1<<20), # -I 0 is unlimited 'iopt' : lambda d: 0, # -P only powers of two 'sprevsz' : lambda d: rand.choice([x * (1<<16) for x in [4]]), } #end # TMPDIR = '/tmp/xd3regtest.%d' % os.getpid() RUNFILE = os.path.join(TMPDIR, 'run') DFILE = os.path.join(TMPDIR, 'output') RFILE = os.path.join(TMPDIR, 'recon') CMPTMP1 = os.path.join(TMPDIR, 'cmptmp1') CMPTMP2 = os.path.join(TMPDIR, 'cmptmp2') HEAD_STATE = 0 BAR_STATE = 1 REV_STATE = 2 DATE_STATE = 3 # IGNORE_FILENAME = re.compile('.*\\.(gif|jpg).*') # rcs output RE_TOTREV = re.compile('total revisions: (\\d+)') RE_BAR = re.compile('----------------------------') RE_REV = re.compile('revision (.+)') RE_DATE = re.compile('date: ([^;]+);.*') # xdelta output RE_HDRSZ = re.compile('VCDIFF header size: +(\\d+)') RE_EXTCOMP = re.compile('XDELTA ext comp.*') def c2str(c): return ' '.join(['%s' % x for x in c]) #end def SumList(l): return reduce(lambda x,y: x+y, l) #end # returns (total, mean, stddev, q2 (median), # (q3-q1)/2 ("semi-interquartile range"), max-min (spread)) class StatList: def __init__(self,l,desc): cnt = len(l) assert(cnt > 1) l.sort() self.cnt = cnt self.l = l self.total = SumList(l) self.mean = self.total / float(self.cnt) self.s = math.sqrt(SumList([(x-self.mean) * (x - self.mean) for x in l]) / float(self.cnt-1)) self.q0 = l[0] self.q1 = l[int(self.cnt/4.0+0.5)] self.q2 = l[int(self.cnt/2.0+0.5)] self.q3 = l[min(self.cnt-1,int((3.0*self.cnt)/4.0+0.5))] self.q4 = l[self.cnt-1] self.siqr = (self.q3-self.q1)/2.0; self.spread = (self.q4-self.q0) if len(l) == 1: self.str = '%s %s' % (desc, l[0]) else: self.str = '%s mean %.1f: 25%-ile %d %d %d %d %d' % \ (desc, self.mean, self.q0, self.q1, self.q2, self.q3, self.q4) #end #end def RunCommand(args, ok = [0]): #print 'run command %s' % (' '.join(args)) p = os.spawnvp(os.P_WAIT, args[0], args) if p not in ok: raise CommandError(args, 'exited %d' % p) #end #end def RunCommandIO(args,infn,outfn): p = os.fork() if p == 0: os.dup2(os.open(infn,os.O_RDONLY),0) os.dup2(os.open(outfn,os.O_CREAT|os.O_TRUNC|os.O_WRONLY),1) os.execvp(args[0], args) else: s = os.waitpid(p,0) o = os.WEXITSTATUS(s[1]) if not os.WIFEXITED(s[1]) or o != 0: raise CommandError(args, 'exited %d' % o) #end #end #end class TimedTest: def __init__(self, target, source, runnable, skip_trials = SKIP_TRIALS, min_trials = MIN_TRIALS, max_trials = MAX_TRIALS, min_stddev_pct = MIN_STDDEV_PCT): self.target = target self.source = source self.runnable = runnable self.skip_trials = skip_trials self.min_trials = min(min_trials, max_trials) self.max_trials = max_trials self.min_stddev_pct = min_stddev_pct self.encode_time = self.DoTest(DFILE, lambda x: x.Encode(self.target, self.source, DFILE)) self.encode_size = runnable.EncodeSize(DFILE) self.decode_time = self.DoTest(RFILE, lambda x: x.Decode(DFILE, self.source, RFILE), ) runnable.Verify(self.target, RFILE) #end def DoTest(self, fname, func): trials = 0 measured = [] while 1: try: os.remove(fname) except OSError: pass start_time = time.time() start_clock = time.clock() func(self.runnable) total_clock = (time.clock() - start_clock) total_time = (time.time() - start_time) elap_time = max(total_time, 0.0000001) elap_clock = max(total_clock, 0.0000001) trials = trials + 1 # skip some of the first trials if trials > self.skip_trials: measured.append((elap_clock, elap_time)) #print 'measurement total: %.1f ms' % (total_time * 1000.0) # at least so many if trials < (self.skip_trials + self.min_trials): #print 'continue: need more trials: %d' % trials continue # compute %variance done = 0 if self.skip_trials + self.min_trials <= 2: measured = measured + measured; done = 1 #end time_stat = StatList([x[1] for x in measured], 'elap time') sp = float(time_stat.s) / float(time_stat.mean) # what if MAX_TRIALS is exceeded? too_many = (trials - self.skip_trials) >= self.max_trials good = (100.0 * sp) < self.min_stddev_pct if done or too_many or good: trials = trials - self.skip_trials if not done and not good: #print 'too many trials: %d' % trials pass #clock = StatList([x[0] for x in measured], 'elap clock') return time_stat #end #end #end #end def Decimals(start, end): l = [] step = start while 1: r = range(step, step * 10, step) l = l + r if step * 10 >= end: l.append(step * 10) break step = step * 10 return l #end # This tests the raw speed of 0-byte inputs def RunSpeedTest(): for L in Decimals(MIN_RUN, MAX_RUN): SetFileSize(RUNFILE, L) trx = TimedTest(RUNFILE, None, Xdelta3Runner(['-W', str(1<<20)])) ReportSpeed(L, trx, '1MB ') trx = TimedTest(RUNFILE, None, Xdelta3Runner(['-W', str(1<<19)])) ReportSpeed(L, trx, '512k') trx = TimedTest(RUNFILE, None, Xdelta3Runner(['-W', str(1<<18)])) ReportSpeed(L, trx, '256k') trm = TimedTest(RUNFILE, None, Xdelta3Mod1(RUNFILE)) ReportSpeed(L, trm, 'swig') trg = TimedTest(RUNFILE, None, GzipRun1()) ReportSpeed(L,trg,'gzip') #end #end def SetFileSize(F,L): fd = os.open(F, os.O_CREAT | os.O_WRONLY) os.ftruncate(fd,L) assert os.fstat(fd).st_size == L os.close(fd) #end def ReportSpeed(L,tr,desc): print '%s run length %u: size %u: time %.3f ms: decode %.3f ms' % \ (desc, L, tr.encode_size, tr.encode_time.mean * 1000.0, tr.decode_time.mean * 1000.0) #end class Xdelta3RunClass: def __init__(self, extra): self.extra = extra #end def __str__(self): return ' '.join(self.extra) #end def New(self): return Xdelta3Runner(self.extra) #end #end class Xdelta3Runner: # Use "forkexec" to get special command-line only features like # external compression support. def __init__(self, extra, forkexec=False): self.forkexec = forkexec self.extra = extra #end def Encode(self, target, source, output): args = (ALL_ARGS + self.extra + ['-e']) if source: args.append('-s') args.append(source) #end args = args + [target, output] self.Main(args) #end def Decode(self, input, source, output): args = (ALL_ARGS + ['-d']) if source: args.append('-s') args.append(source) #end args = args + [input, output] self.Main(args) #end def Verify(self, target, recon): if target[-3:] == ".gz": RunCommandIO(('gzip', '-dc'), target, CMPTMP1) RunCommandIO(('gzip', '-dc'), recon, CMPTMP2) RunCommand(('cmp', CMPTMP1, CMPTMP2)) else: RunCommand(('cmp', target, recon)) #end def EncodeSize(self, output): return os.stat(output).st_size #end def Main(self, args): try: if self.forkexec: RunCommand(['../xdelta3'] + args) else: xdelta3.xd3_main_cmdline(args) except Exception, e: raise CommandError(args, "xdelta3.main exception: %s" % e) #end #end #end class Xdelta3Mod1: def __init__(self, file): self.target_data = open(file, 'r').read() #end def Encode(self, ignore1, ignore2, ignore3): r1, encoded = xdelta3.xd3_encode_memory(self.target_data, None, 1000000, 1<<10) if r1 != 0: raise CommandError('memory', 'encode failed: %s' % r1) #end self.encoded = encoded #end def Decode(self, ignore1, ignore2, ignore3): r2, data1 = xdelta3.xd3_decode_memory(self.encoded, None, len(self.target_data)) if r2 != 0: raise CommandError('memory', 'decode failed: %s' % r1) #end self.decoded = data1 #end def Verify(self, ignore1, ignore2): if self.target_data != self.decoded: raise CommandError('memory', 'bad decode') #end #end def EncodeSize(self, ignore1): return len(self.encoded) #end #end class GzipRun1: def Encode(self, target, source, output): assert source == None RunCommandIO(['gzip', '-cf'], target, output) #end def Decode(self, input, source, output): assert source == None RunCommandIO(['gzip', '-dcf'], input, output) #end def Verify(self, target, recon): RunCommand(('cmp', target, recon)) #end def EncodeSize(self, output): return os.stat(output).st_size #end #end class Xdelta1RunClass: def __str__(self): return 'xdelta1' #end def New(self): return Xdelta1Runner() #end #end class Xdelta1Runner: def Encode(self, target, source, output): assert source != None args = ['xdelta1', 'delta', '-q', source, target, output] RunCommand(args, [0, 1]) #end def Decode(self, input, source, output): assert source != None args = ['xdelta1', 'patch', '-q', input, source, output] # Note: for dumb historical reasons, xdelta1 returns 1 or 0 RunCommand(args) #end def Verify(self, target, recon): RunCommand(('cmp', target, recon)) #end def EncodeSize(self, output): return os.stat(output).st_size #end #end # exceptions class SkipRcsException: def __init__(self,reason): self.reason = reason #end #end class NotEnoughVersions: def __init__(self): pass #end #end class CommandError: def __init__(self,cmd,str): if type(cmd) is types.TupleType or \ type(cmd) is types.ListType: cmd = reduce(lambda x,y: '%s %s' % (x,y),cmd) #end print 'command was: ',cmd print 'command failed: ',str print 'have fun debugging' #end #end class RcsVersion: def __init__(self,vstr): self.vstr = vstr #end def __cmp__(self,other): return cmp(self.date, other.date) #end def __str__(self): return str(self.vstr) #end #end class RcsFile: def __init__(self, fname): self.fname = fname self.versions = [] self.state = HEAD_STATE #end def SetTotRev(self,s): self.totrev = int(s) #end def Rev(self,s): self.rev = RcsVersion(s) if len(self.versions) >= self.totrev: raise SkipRcsException('too many versions (in log messages)') #end self.versions.append(self.rev) #end def Date(self,s): self.rev.date = s #end def Match(self, line, state, rx, gp, newstate, f): if state == self.state: m = rx.match(line) if m: if f: f(m.group(gp)) #end self.state = newstate return 1 #end #end return None #end def Sum1Rlog(self): f = os.popen('rlog '+self.fname, "r") l = f.readline() while l: if self.Match(l, HEAD_STATE, RE_TOTREV, 1, BAR_STATE, self.SetTotRev): pass elif self.Match(l, BAR_STATE, RE_BAR, 1, REV_STATE, None): pass elif self.Match(l, REV_STATE, RE_REV, 1, DATE_STATE, self.Rev): pass elif self.Match(l, DATE_STATE, RE_DATE, 1, BAR_STATE, self.Date): pass #end l = f.readline() #end c = f.close() if c != None: raise c #end #end def Sum1(self): st = os.stat(self.fname) self.rcssize = st.st_size self.Sum1Rlog() if self.totrev != len(self.versions): raise SkipRcsException('wrong version count') #end self.versions.sort() #end def Checkout(self,n): v = self.versions[n] out = open(self.Verf(n), "w") cmd = 'co -ko -p%s %s' % (v.vstr, self.fname) total = 0 (inf, stream, err) = os.popen3(cmd, "r") inf.close() buf = stream.read() while buf: total = total + len(buf) out.write(buf) buf = stream.read() #end v.vsize = total estr = '' buf = err.read() while buf: estr = estr + buf buf = err.read() #end if stream.close(): raise CommandError(cmd, 'checkout failed: %s\n%s\n%s' % (v.vstr, self.fname, estr)) #end out.close() err.close() #end def Vdate(self,n): return self.versions[n].date #end def Vstr(self,n): return self.versions[n].vstr #end def Verf(self,n): return os.path.join(TMPDIR, 'input.%d' % n) #end def FilePairsByDate(self, runclass): if self.totrev < 2: raise NotEnoughVersions() #end self.Checkout(0) ntrials = [] if self.totrev < 2: return vtrials #end for v in range(0,self.totrev-1): if v > 1: os.remove(self.Verf(v-1)) #end self.Checkout(v+1) if os.stat(self.Verf(v)).st_size < MIN_SIZE or \ os.stat(self.Verf(v+1)).st_size < MIN_SIZE: continue #end result = TimedTest(self.Verf(v+1), self.Verf(v), runclass.New()) target_size = os.stat(self.Verf(v+1)).st_size ntrials.append(result) #end os.remove(self.Verf(self.totrev-1)) os.remove(self.Verf(self.totrev-2)) return ntrials #end def AppendVersion(self, f, n): self.Checkout(n) rf = open(self.Verf(n), "r") data = rf.read() f.write(data) rf.close() return len(data) #end class RcsFinder: def __init__(self): self.subdirs = [] self.rcsfiles = [] self.others = [] self.skipped = [] self.biground = 0 #end def Scan1(self,dir): dents = os.listdir(dir) subdirs = [] rcsfiles = [] others = [] for dent in dents: full = os.path.join(dir, dent) if os.path.isdir(full): subdirs.append(full) elif dent[len(dent)-2:] == ",v": rcsfiles.append(RcsFile(full)) else: others.append(full) #end #end self.subdirs = self.subdirs + subdirs self.rcsfiles = self.rcsfiles + rcsfiles self.others = self.others + others return subdirs #end def Crawl(self, dir): subdirs = [dir] while subdirs: s1 = self.Scan1(subdirs[0]) subdirs = subdirs[1:] + s1 #end #end def Summarize(self): good = [] for rf in self.rcsfiles: try: rf.Sum1() if rf.totrev < 2: raise SkipRcsException('too few versions (< 2)') #end except SkipRcsException, e: #print 'skipping file %s: %s' % (rf.fname, e.reason) self.skipped.append(rf) else: good.append(rf) #end self.rcsfiles = good #end def AllPairsByDate(self, runclass): results = [] good = [] for rf in self.rcsfiles: try: results = results + rf.FilePairsByDate(runclass) except SkipRcsException: print 'file %s has compressed versions: skipping' % (rf.fname) except NotEnoughVersions: print 'testing %s on %s: not enough versions' % (runclass, rf.fname) else: good.append(rf) #end self.rcsfiles = good self.ReportPairs(runclass, results) return results #end def ReportPairs(self, name, results): encode_time = 0 decode_time = 0 encode_size = 0 for r in results: encode_time += r.encode_time.mean decode_time += r.decode_time.mean encode_size += r.encode_size #end print '%s rcs: encode %.2f s: decode %.2f s: size %d' % \ (name, encode_time, decode_time, encode_size) #end def MakeBigFiles(self, rand): f1 = open(TMPDIR + "/big.1", "w") f2 = open(TMPDIR + "/big.2", "w") population = [] for file in self.rcsfiles: if len(file.versions) < 2: continue population.append(file) #end f1sz = 0 f2sz = 0 fcount = int(len(population) * FILE_P) assert fcount > 0 for file in rand.sample(population, fcount): m = IGNORE_FILENAME.match(file.fname) if m != None: continue #end r1, r2 = rand.sample(xrange(0, len(file.versions)), 2) f1sz += file.AppendVersion(f1, r1) f2sz += file.AppendVersion(f2, r2) #m.update('%s,%s,%s ' % (file.fname[len(RCSDIR):], #file.Vstr(r1), file.Vstr(r2))) #end testkey = 'rcs%d' % self.biground self.biground = self.biground + 1 print '%s; source %u bytes; target %u bytes' % (testkey, f1sz, f2sz) f1.close() f2.close() return (TMPDIR + "/big.1", TMPDIR + "/big.2", testkey) #end def Generator(self): return lambda rand: self.MakeBigFiles(rand) #end #end # find a set of RCS files for testing def GetTestRcsFiles(): rcsf = RcsFinder() rcsf.Crawl(RCSDIR) if len(rcsf.rcsfiles) == 0: raise CommandError('', 'no RCS files') #end rcsf.Summarize() print "rcsfiles: rcsfiles %d; subdirs %d; others %d; skipped %d" % ( len(rcsf.rcsfiles), len(rcsf.subdirs), len(rcsf.others), len(rcsf.skipped)) print StatList([x.rcssize for x in rcsf.rcsfiles], "rcssize").str print StatList([x.totrev for x in rcsf.rcsfiles], "totrev").str return rcsf #end class SampleDataTest: def __init__(self, dirs): dirs_in = dirs self.pairs = [] while dirs: d = dirs[0] dirs = dirs[1:] l = os.listdir(d) files = [] for e in l: p = os.path.join(d, e) if os.path.isdir(p): dirs.append(p) else: files.append(p) #end #end if len(files) > 1: files.sort() for x in xrange(len(files)): for y in xrange(len(files)): self.pairs.append((files[x], files[y], '%s-%s' % (files[x], files[y]))) #end #end #end #end print "Sample data test using %d file pairs in %s" % ( len(self.pairs), dirs_in) #end def Generator(self): return lambda rand: rand.choice(self.pairs) #end #end # configs are represented as a list of values, # program takes a list of strings: def ConfigToArgs(config): args = [ '-C', ','.join([str(x) for x in config[0:SOFT_CONFIG_CNT]])] for i in range(SOFT_CONFIG_CNT, len(CONFIG_ORDER)): key = CONFIG_ARGMAP[CONFIG_ORDER[i]] val = config[i] if val == 'true' or val == 'false': if val == 'true': args.append('%s' % key) #end else: args.append('%s=%s' % (key, val)) #end #end return args #end # class RandomTest: def __init__(self, tnum, tinput, config, syntuple = None): self.mytinput = tinput[2] self.myconfig = config self.tnum = tnum if syntuple != None: self.runtime = syntuple[0] self.compsize = syntuple[1] self.decodetime = None else: args = ConfigToArgs(config) result = TimedTest(tinput[1], tinput[0], Xdelta3Runner(args)) self.runtime = result.encode_time.mean self.compsize = result.encode_size self.decodetime = result.decode_time.mean #end self.score = None self.time_pos = None self.size_pos = None self.score_pos = None #end def __str__(self): decodestr = ' %s' % self.decodetime return 'time %.6f%s size %d%s << %s >>%s' % ( self.time(), ((self.time_pos != None) and (" (%s)" % self.time_pos) or ""), self.size(), ((self.size_pos != None) and (" (%s)" % self.size_pos) or ""), c2str(self.config()), decodestr) #end def time(self): return self.runtime #end def size(self): return self.compsize #end def config(self): return self.myconfig #end def score(self): return self.score #end def tinput(self): return self.mytinput #end #end def PosInAlist(l, e): for i in range(0, len(l)): if l[i][1] == e: return i; #end #end return -1 #end # Generates a set of num_results test configurations, given the list of # retest-configs. def RandomTestConfigs(rand, input_configs, num_results): outputs = input_configs[:] have_set = dict([(c,c) for c in input_configs]) # Compute a random configuration def RandomConfig(): config = [] cmap = {} for key in CONFIG_ORDER: val = cmap[key] = (INPUT_SPEC(rand)[key])(cmap) config.append(val) #end return tuple(config) #end while len(outputs) < num_results: newc = None for i in xrange(100): c = RandomConfig() if have_set.has_key(c): continue #end have_set[c] = c newc = c break if newc is None: print 'stopped looking for configs at %d' % len(outputs) break #end outputs.append(c) #end outputs.sort() return outputs #end def RunOptimizationLoop(rand, generator, rounds): configs = [] for rnum in xrange(rounds): configs = RandomTestConfigs(rand, configs, MAX_RESULTS) tinput = generator(rand) tests = [] for x in xrange(len(configs)): t = RandomTest(x, tinput, configs[x]) print 'Round %d test %d: %s' % (rnum, x, t) tests.append(t) #end results = ScoreTests(tests) for r in results: c = r.config() if not test_all_config_results.has_key(c): test_all_config_results[c] = [r] else: test_all_config_results[c].append(r) #end #end #GraphResults('expt%d' % rnum, results) #GraphSummary('sum%d' % rnum, results) # re-test some fraction configs = [r.config() for r in results[0:int(MAX_RESULTS * KEEP_P)]] #end #end # TODO: cleanup test_all_config_results = {} def ScoreTests(results): scored = [] timed = [] sized = [] t_min = float(min([test.time() for test in results])) #t_max = float(max([test.time() for test in results])) s_min = float(min([test.size() for test in results])) #s_max = float(max([test.size() for test in results])) for test in results: # Hyperbolic function. Smaller scores still better red = 0.999 # minimum factors for each dimension are 1/1000 test.score = ((test.size() - s_min * red) * (test.time() - t_min * red)) scored.append((test.score, test)) timed.append((test.time(), test)) sized.append((test.size(), test)) #end scored.sort() timed.sort() sized.sort() best_by_size = [] best_by_time = [] pos = 0 for (score, test) in scored: pos += 1 test.score_pos = pos #end scored = [x[1] for x in scored] for test in scored: test.size_pos = PosInAlist(sized, test) test.time_pos = PosInAlist(timed, test) #end for test in scored: c = test.config() s = 0.0 print 'H-Score: %0.9f %s' % (test.score, test) #end return scored #end def GraphResults(desc, results): f = open("data-%s.csv" % desc, "w") for r in results: f.write("%0.9f\t%d\t# %s\n" % (r.time(), r.size(), r)) #end f.close() os.system("./plot.sh data-%s.csv plot-%s.jpg" % (desc, desc)) #end def GraphSummary(desc, results_ignore): test_population = 0 config_ordered = [] # drops duplicate test/config pairs (TODO: don't retest them) for config, cresults in test_all_config_results.items(): input_config_map = {} uniq = [] for test in cresults: assert test.config() == config test_population += 1 key = test.tinput() if not input_config_map.has_key(key): input_config_map[key] = {} #end if input_config_map[key].has_key(config): print 'skipping repeat test %s vs. %s' % (input_config_map[key][config], test) continue #end input_config_map[key][config] = test uniq.append(test) #end config_ordered.append(uniq) #end # sort configs descending by number of tests config_ordered.sort(lambda x, y: len(y) - len(x)) print 'population %d: %d configs %d results' % \ (test_population, len(config_ordered), len(config_ordered[0])) if config_ordered[0] == 1: return #end # a map from test-key to test-list w/ various configs input_set = {} osize = len(config_ordered) for i in xrange(len(config_ordered)): config = config_ordered[i][0].config() config_tests = config_ordered[i] #print '%s has %d tested inputs' % (config, len(config_tests)) if len(input_set) == 0: input_set = dict([(t.tinput(), [t]) for t in config_tests]) continue #end # a map from test-key to test-list w/ various configs update_set = {} for r in config_tests: t = r.tinput() if input_set.has_key(t): update_set[t] = input_set[t] + [r] else: #print 'config %s does not have test %s' % (config, t) pass #end #end if len(update_set) <= 1: break #end input_set = update_set # continue if there are more w/ the same number of inputs if i < (len(config_ordered) - 1) and \ len(config_ordered[i + 1]) == len(config_tests): continue #end # synthesize results for multi-test inputs config_num = None # map of config to sum(various test-keys) smap = {} for (key, tests) in input_set.items(): if config_num == None: # config_num should be the same in all elements config_num = len(tests) smap = dict([(r.config(), (r.time(), r.size())) for r in tests]) else: # compuate the per-config sum of time/size assert config_num == len(tests) smap = dict([(r.config(), (smap[r.config()][0] + r.time(), smap[r.config()][1] + r.size())) for r in tests]) #end #end if config_num == 1: continue #end if len(input_set) == osize: break #end summary = '%s-%d' % (desc, len(input_set)) osize = len(input_set) print 'generate %s w/ %d configs' % (summary, config_num) syn = [RandomTest(0, (None, None, summary), config, syntuple = (smap[config][0], smap[config][1])) for config in smap.keys()] syn = ScoreTests(syn) #print 'smap is %s' % (smap,) #print 'syn is %s' % (' and '.join([str(x) for x in syn])) #GraphResults(summary, syn) #end #end def RunRegressionTest(pairs, rounds): for args in [ [], ['-S=djw'], ['-B=412907520'], ['-B 412907520', ], ]: print "Args %s" % (args) for (file1, file2, testkey) in pairs: ttest = TimedTest(file1, file2, Xdelta3Runner(args, forkexec=True), skip_trials = 0, min_trials = 1, max_trials = 1) print "Source %s\nTarget %s\nEncode %s\nDecode %s\nSize %s\n\n" % ( file1, file2, ttest.encode_time.str, ttest.decode_time.str, ttest.encode_size) #end #end if __name__ == "__main__": try: RunCommand(['rm', '-rf', TMPDIR]) os.mkdir(TMPDIR) #rcsf = GetTestRcsFiles() #generator = rcsf.Generator() sample = SampleDataTest([SAMPLEDIR]) generator = sample.Generator() rand = random.Random(135135135135135) RunRegressionTest(sample.pairs, TEST_ROUNDS) #RunSpeedTest() # the idea below is to add the default configurations and # xdelta1 to the optimization loop: #x3r = rcsf.AllPairsByDate(Xdelta3RunClass(['-1', '-3', '-6'])) #x3r = rcsf.AllPairsByDate(Xdelta3RunClass(['-9'])) #x3r = rcsf.AllPairsByDate(Xdelta3RunClass(['-9', '-S', 'djw'])) #x3r = rcsf.AllPairsByDate(Xdelta3RunClass(['-1', '-S', 'djw'])) #x3r = rcsf.AllPairsByDate(Xdelta3RunClass(['-9', '-T'])) #x1r = rcsf.AllPairsByDate(Xdelta1RunClass()) except CommandError: pass else: RunCommand(['rm', '-rf', TMPDIR]) pass #end #end ================================================ FILE: source-code/dependencies/xdelta3/testing/xdelta3-test.py ================================================ #!/usr/bin/python2.7 # xdelta3 - delta compression tools and library -*- Mode: C++ -*- # Copyright 2016 Joshua MacDonald # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import xdelta3 # the test data section is expected to be len('target') source = 'source source input0 source source' target = 'source source target source source' # # print 'encode: basic ...' result, patch = xdelta3.xd3_encode_memory(target, source, 50) assert result == 0 assert len(patch) < len(source) print 'encode: adler32 ...' result, patch_adler32 = xdelta3.xd3_encode_memory(target, source, 50, xdelta3.XD3_ADLER32) assert result == 0 assert len(patch_adler32) < len(source) assert len(patch_adler32) > len(patch) print 'encode: secondary ...' result, patch_djw = xdelta3.xd3_encode_memory(target, source, 50, xdelta3.XD3_SEC_DJW) assert result == 0 # secondary compression doesn't help assert len(patch_djw) > len(patch) print 'encode: exact ...' result, ignore = xdelta3.xd3_encode_memory(target, source, len(patch)) assert result == 0 assert len(ignore) < len(source) print 'encode: out of space ...' result, ignore = xdelta3.xd3_encode_memory(target, source, len(patch) - 1) assert result == 28 assert ignore == None print 'encode: zero space ...' result, ignore = xdelta3.xd3_encode_memory(target, source, 0) assert result == 28 assert ignore == None print 'encode: no source ...' result, zdata = xdelta3.xd3_encode_memory(target, None, 50) assert result == 0 assert len(zdata) > len(patch) print 'encode: no input ...' result, ignore = xdelta3.xd3_encode_memory(None, None, 50) assert result != 0 print 'decode: basic ...' result, target1 = xdelta3.xd3_decode_memory(patch, source, len(target)) assert result == 0 assert len(target1) == len(target) assert target1 == target print 'decode: out of space ...' result, ignore = xdelta3.xd3_decode_memory(patch, source, len(target) - 1) assert result == 28 assert ignore == None print 'decode: zero space ...' result, ignore = xdelta3.xd3_decode_memory(patch, source, 0) assert result == 28 assert ignore == None print 'decode: single byte error ...' # a few expected single-byte errors, e.g., unused address cache bits, see # xdelta3-test.h's single-bit error tests extra_count = 4 noverify_count = 0 for corrupt_pos in range(len(patch_adler32)): input = ''.join([j == corrupt_pos and '\xff' or patch_adler32[j] for j in range(len(patch_adler32))]) result, ignore = xdelta3.xd3_decode_memory(input, source, len(target), 0) assert result == -17712 assert ignore == None # without adler32 verification, the error may be in the data section which # in this case is 6 bytes 'target' result, corrupt = xdelta3.xd3_decode_memory(input, source, len(target), xdelta3.XD3_ADLER32_NOVER) if result == 0: noverify_count = noverify_count + 1 #print "got %s" % corrupt #end #end assert noverify_count == len('target') + extra_count print 'decode: no source ...' result, target2 = xdelta3.xd3_decode_memory(zdata, None, len(target)) assert result == 0 assert target == target2 # Test compression level setting via flags. assumes a 9 byte checksum # and that level 9 steps 2, level 1 steps 15: # 01234567890123456789012345678901 # level 1 only indexes 2 checksums "abcdefghi" and "ABCDEFGHI" # outputs 43 vs. 23 bytes print 'encode: compression level ...' source = '_la_la_abcdefghi_la_la_ABCDEFGHI' target = 'la_la_ABCDEFGH__la_la_abcdefgh__' result1, level1 = xdelta3.xd3_encode_memory(target, source, 50, xdelta3.XD3_COMPLEVEL_1) result9, level9 = xdelta3.xd3_encode_memory(target, source, 50, xdelta3.XD3_COMPLEVEL_9) assert result1 == 0 and result9 == 0 assert len(level1) > len(level9) # # Issue 65 print 'encode: 65 ...' source = 'Hello World' target = 'Hello everyone' result, patch = xdelta3.xd3_encode_memory(target, source, len(target)) assert result != 0 result, patch = xdelta3.xd3_encode_memory(target, source, 2 * len(target)) assert result == 0 print 'PASS' ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-blkcache.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "xdelta3-internal.h" typedef struct _main_blklru main_blklru; typedef struct _main_blklru_list main_blklru_list; #define XD3_INVALID_OFFSET XOFF_T_MAX struct _main_blklru_list { main_blklru_list *next; main_blklru_list *prev; }; struct _main_blklru { uint8_t *blk; xoff_t blkno; usize_t size; main_blklru_list link; }; XD3_MAKELIST(main_blklru_list,main_blklru,link); static usize_t lru_size = 0; static main_blklru *lru = NULL; /* array of lru_size elts */ static main_blklru_list lru_list; static int do_src_fifo = 0; /* set to avoid lru */ static int lru_hits = 0; static int lru_misses = 0; static int lru_filled = 0; static void main_lru_reset (void) { lru_size = 0; lru = NULL; do_src_fifo = 0; lru_hits = 0; lru_misses = 0; lru_filled = 0; } static void main_lru_cleanup (void) { if (lru != NULL) { main_buffree (lru[0].blk); } main_free (lru); lru = NULL; lru_hits = 0; lru_misses = 0; lru_filled = 0; } /* This is called at different times for encoding and decoding. The * encoder calls it immediately, the decoder delays until the * application header is received. */ static int main_set_source (xd3_stream *stream, xd3_cmd cmd, main_file *sfile, xd3_source *source) { int ret = 0; usize_t i; xoff_t source_size = 0; usize_t blksize; XD3_ASSERT (lru == NULL); XD3_ASSERT (stream->src == NULL); XD3_ASSERT (option_srcwinsz >= XD3_MINSRCWINSZ); /* TODO: this code needs refactoring into FIFO, LRU, FAKE. Yuck! * This is simplified from 3.0z which had issues with sizing the * source buffer memory allocation and the source blocksize. */ /* LRU-specific */ main_blklru_list_init (& lru_list); if (allow_fake_source) { /* TODO: refactor * TOOLS/recode-specific: Check "allow_fake_source" mode looks * broken now. */ sfile->mode = XO_READ; sfile->realname = sfile->filename; sfile->nread = 0; } else { /* Either a regular file (possibly compressed) or a FIFO * (possibly compressed). */ if ((ret = main_file_open (sfile, sfile->filename, XO_READ))) { return ret; } /* If the file is regular we know it's size. If the file turns * out to be externally compressed, size_known may change. */ sfile->size_known = (main_file_stat (sfile, &source_size) == 0); } /* Note: The API requires a power-of-two blocksize and srcwinsz * (-B). The logic here will use a single block if the entire file * is known to fit into srcwinsz. */ option_srcwinsz = xd3_xoff_roundup (option_srcwinsz); /* Though called "lru", it is not LRU-specific. We always allocate * a maximum number of source block buffers. If the entire file * fits into srcwinsz, this buffer will stay as the only * (lru_size==1) source block. Otherwise, we know that at least * option_srcwinsz bytes are available. Split the source window * into buffers. */ if ((lru = (main_blklru*) main_malloc (MAX_LRU_SIZE * sizeof (main_blklru))) == NULL) { ret = ENOMEM; return ret; } memset (lru, 0, sizeof(lru[0]) * MAX_LRU_SIZE); /* Allocate the entire buffer. */ if ((lru[0].blk = (uint8_t*) main_bufalloc (option_srcwinsz)) == NULL) { ret = ENOMEM; return ret; } /* Main calls main_getblk_func() once before xd3_set_source(). This * is the point at which external decompression may begin. Set the * system for a single block. */ lru_size = 1; lru[0].blkno = XD3_INVALID_OFFSET; blksize = option_srcwinsz; main_blklru_list_push_back (& lru_list, & lru[0]); XD3_ASSERT (blksize != 0); /* Initialize xd3_source. */ source->blksize = blksize; source->name = sfile->filename; source->ioh = sfile; source->curblkno = XD3_INVALID_OFFSET; source->curblk = NULL; source->max_winsize = option_srcwinsz; if ((ret = main_getblk_func (stream, source, 0)) != 0) { XPR(NT "error reading source: %s: %s\n", sfile->filename, xd3_mainerror (ret)); return ret; } source->onblk = lru[0].size; /* xd3 sets onblk */ /* If the file is smaller than a block, size is known. */ if (!sfile->size_known && source->onblk < blksize) { source_size = source->onblk; source->onlastblk = source_size; sfile->size_known = 1; } /* If the size is not known or is greater than the buffer size, we * split the buffer across MAX_LRU_SIZE blocks (already allocated in * "lru"). */ if (!sfile->size_known || source_size > option_srcwinsz) { /* Modify block 0, change blocksize. */ blksize = option_srcwinsz / MAX_LRU_SIZE; source->blksize = blksize; source->onblk = blksize; source->onlastblk = blksize; source->max_blkno = MAX_LRU_SIZE - 1; lru[0].size = blksize; lru_size = MAX_LRU_SIZE; /* Setup rest of blocks. */ for (i = 1; i < lru_size; i += 1) { lru[i].blk = lru[0].blk + (blksize * i); lru[i].blkno = i; lru[i].size = blksize; main_blklru_list_push_back (& lru_list, & lru[i]); } } if (! sfile->size_known) { /* If the size is not know, we must use FIFO discipline. */ do_src_fifo = 1; } /* Call the appropriate set_source method, handle errors, print * verbose message, etc. */ if (sfile->size_known) { ret = xd3_set_source_and_size (stream, source, source_size); } else { ret = xd3_set_source (stream, source); } if (ret) { XPR(NT XD3_LIB_ERRMSG (stream, ret)); return ret; } XD3_ASSERT (stream->src == source); XD3_ASSERT (source->blksize == blksize); if (option_verbose) { static shortbuf srcszbuf; static shortbuf srccntbuf; static shortbuf winszbuf; static shortbuf blkszbuf; static shortbuf nbufs; if (sfile->size_known) { short_sprintf (srcszbuf, "source size %s [%"Q"u]", main_format_bcnt (source_size, &srccntbuf), source_size); } else { short_sprintf (srcszbuf, "%s", "source size unknown"); } nbufs.buf[0] = 0; if (option_verbose > 1) { short_sprintf (nbufs, " #bufs %"W"u", lru_size); } XPR(NT "source %s %s blksize %s window %s%s%s\n", sfile->filename, srcszbuf.buf, main_format_bcnt (blksize, &blkszbuf), main_format_bcnt (option_srcwinsz, &winszbuf), nbufs.buf, do_src_fifo ? " (FIFO)" : ""); } return 0; } static int main_getblk_lru (xd3_source *source, xoff_t blkno, main_blklru** blrup, int *is_new) { main_blklru *blru = NULL; usize_t i; (*is_new) = 0; if (do_src_fifo) { /* Direct lookup assumes sequential scan w/o skipping blocks. */ int idx = blkno % lru_size; blru = & lru[idx]; if (blru->blkno == blkno) { (*blrup) = blru; return 0; } /* No going backwards in a sequential scan. */ if (blru->blkno != XD3_INVALID_OFFSET && blru->blkno > blkno) { return XD3_TOOFARBACK; } } else { /* Sequential search through LRU. */ for (i = 0; i < lru_size; i += 1) { blru = & lru[i]; if (blru->blkno == blkno) { main_blklru_list_remove (blru); main_blklru_list_push_back (& lru_list, blru); (*blrup) = blru; IF_DEBUG1 (DP(RINT "[getblk_lru] HIT blkno = %"Q"u lru_size=%"W"u\n", blkno, lru_size)); return 0; } } IF_DEBUG1 (DP(RINT "[getblk_lru] MISS blkno = %"Q"u lru_size=%"W"u\n", blkno, lru_size)); } if (do_src_fifo) { int idx = blkno % lru_size; blru = & lru[idx]; } else { XD3_ASSERT (! main_blklru_list_empty (& lru_list)); blru = main_blklru_list_pop_front (& lru_list); main_blklru_list_push_back (& lru_list, blru); } lru_filled += 1; (*is_new) = 1; (*blrup) = blru; blru->blkno = XD3_INVALID_OFFSET; return 0; } static int main_read_seek_source (xd3_stream *stream, xd3_source *source, xoff_t blkno) { xoff_t pos = blkno * source->blksize; main_file *sfile = (main_file*) source->ioh; main_blklru *blru; int is_new; size_t nread = 0; int ret = 0; if (!sfile->seek_failed) { ret = main_file_seek (sfile, pos); if (ret == 0) { sfile->source_position = pos; } } if (sfile->seek_failed || ret != 0) { /* For an unseekable file (or other seek error, does it * matter?) */ if (sfile->source_position > pos) { /* Could assert !IS_ENCODE(), this shouldn't happen * because of do_src_fifo during encode. */ if (!option_quiet) { XPR(NT "source can't seek backwards; requested block offset " "%"Q"u source position is %"Q"u\n", pos, sfile->source_position); } sfile->seek_failed = 1; stream->msg = "non-seekable source: " "copy is too far back (try raising -B)"; return XD3_TOOFARBACK; } /* There's a chance here, that an genuine lseek error will cause * xdelta3 to shift into non-seekable mode, entering a degraded * condition. */ if (!sfile->seek_failed && option_verbose) { XPR(NT "source can't seek, will use FIFO for %s\n", sfile->filename); if (option_verbose > 1) { XPR(NT "seek error at offset %"Q"u: %s\n", pos, xd3_mainerror (ret)); } } sfile->seek_failed = 1; if (option_verbose > 1 && pos != sfile->source_position) { XPR(NT "non-seekable source skipping %"Q"u bytes @ %"Q"u\n", pos - sfile->source_position, sfile->source_position); } while (sfile->source_position < pos) { xoff_t skip_blkno; usize_t skip_offset; xd3_blksize_div (sfile->source_position, source, &skip_blkno, &skip_offset); /* Read past unused data */ XD3_ASSERT (pos - sfile->source_position >= source->blksize); XD3_ASSERT (skip_offset == 0); if ((ret = main_getblk_lru (source, skip_blkno, & blru, & is_new))) { return ret; } XD3_ASSERT (is_new); blru->blkno = skip_blkno; if ((ret = main_read_primary_input (sfile, (uint8_t*) blru->blk, source->blksize, & nread))) { return ret; } if (nread != source->blksize) { IF_DEBUG1 (DP(RINT "[getblk] short skip block nread = %"Z"u\n", nread)); stream->msg = "non-seekable input is short"; return XD3_INVALID_INPUT; } sfile->source_position += nread; blru->size = nread; IF_DEBUG1 (DP(RINT "[getblk] skip blkno %"Q"u size %"W"u\n", skip_blkno, blru->size)); XD3_ASSERT (sfile->source_position <= pos); } } return 0; } /* This is the callback for reading a block of source. This function * is blocking and it implements a small LRU. * * Note that it is possible for main_input() to handle getblk requests * in a non-blocking manner. If the callback is NULL then the caller * of xd3_*_input() must handle the XD3_GETSRCBLK return value and * fill the source in the same way. See xd3_getblk for details. To * see an example of non-blocking getblk, see xdelta-test.h. */ static int main_getblk_func (xd3_stream *stream, xd3_source *source, xoff_t blkno) { int ret = 0; xoff_t pos = blkno * source->blksize; main_file *sfile = (main_file*) source->ioh; main_blklru *blru; int is_new; size_t nread = 0; if (allow_fake_source) { source->curblkno = blkno; source->onblk = 0; source->curblk = lru[0].blk; lru[0].size = 0; return 0; } if ((ret = main_getblk_lru (source, blkno, & blru, & is_new))) { return ret; } if (!is_new) { source->curblkno = blkno; source->onblk = blru->size; source->curblk = blru->blk; lru_hits++; return 0; } lru_misses += 1; if (pos != sfile->source_position) { /* Only try to seek when the position is wrong. This means the * decoder will fail when the source buffer is too small, but * only when the input is non-seekable. */ if ((ret = main_read_seek_source (stream, source, blkno))) { return ret; } } XD3_ASSERT (sfile->source_position == pos); if ((ret = main_read_primary_input (sfile, (uint8_t*) blru->blk, source->blksize, & nread))) { return ret; } /* Save the last block read, used to handle non-seekable files. */ sfile->source_position = pos + nread; if (option_verbose > 3) { if (blru->blkno != XD3_INVALID_OFFSET) { if (blru->blkno != blkno) { XPR(NT "source block %"Q"u read %"Z"u ejects %"Q"u (lru_hits=%u, " "lru_misses=%u, lru_filled=%u)\n", blkno, nread, blru->blkno, lru_hits, lru_misses, lru_filled); } else { XPR(NT "source block %"Q"u read %"Z"u (lru_hits=%u, " "lru_misses=%u, lru_filled=%u)\n", blkno, nread, lru_hits, lru_misses, lru_filled); } } else { XPR(NT "source block %"Q"u read %"Z"u (lru_hits=%u, lru_misses=%u, " "lru_filled=%u)\n", blkno, nread, lru_hits, lru_misses, lru_filled); } } source->curblk = blru->blk; source->curblkno = blkno; source->onblk = nread; blru->size = nread; blru->blkno = blkno; IF_DEBUG1 (DP(RINT "[main_getblk] blkno %"Q"u onblk %"Z"u pos %"Q"u " "srcpos %"Q"u\n", blkno, nread, pos, sfile->source_position)); return 0; } ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-cfgs.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /****************************************************************** SOFT string matcher ******************************************************************/ #if XD3_BUILD_SOFT #define TEMPLATE soft #define LLOOK stream->smatcher.large_look #define LSTEP stream->smatcher.large_step #define SLOOK stream->smatcher.small_look #define SCHAIN stream->smatcher.small_chain #define SLCHAIN stream->smatcher.small_lchain #define MAXLAZY stream->smatcher.max_lazy #define LONGENOUGH stream->smatcher.long_enough #define SOFTCFG 1 #include "xdelta3.c" #undef SOFTCFG #undef TEMPLATE #undef LLOOK #undef SLOOK #undef LSTEP #undef SCHAIN #undef SLCHAIN #undef MAXLAZY #undef LONGENOUGH #endif #define SOFTCFG 0 /************************************************************ FASTEST string matcher **********************************************************/ #if XD3_BUILD_FASTEST #define TEMPLATE fastest #define LLOOK 9 #define LSTEP 26 #define SLOOK 4U #define SCHAIN 1 #define SLCHAIN 1 #define MAXLAZY 6 #define LONGENOUGH 6 #include "xdelta3.c" #undef TEMPLATE #undef LLOOK #undef SLOOK #undef LSTEP #undef SCHAIN #undef SLCHAIN #undef MAXLAZY #undef LONGENOUGH #endif /************************************************************ FASTER string matcher **********************************************************/ #if XD3_BUILD_FASTER #define TEMPLATE faster #define LLOOK 9 #define LSTEP 15 #define SLOOK 4U #define SCHAIN 1 #define SLCHAIN 1 #define MAXLAZY 18 #define LONGENOUGH 18 #include "xdelta3.c" #undef TEMPLATE #undef LLOOK #undef SLOOK #undef LSTEP #undef SCHAIN #undef SLCHAIN #undef MAXLAZY #undef LONGENOUGH #endif /****************************************************** FAST string matcher ********************************************************/ #if XD3_BUILD_FAST #define TEMPLATE fast #define LLOOK 9 #define LSTEP 8 #define SLOOK 4U #define SCHAIN 4 #define SLCHAIN 1 #define MAXLAZY 18 #define LONGENOUGH 35 #include "xdelta3.c" #undef TEMPLATE #undef LLOOK #undef SLOOK #undef LSTEP #undef SCHAIN #undef SLCHAIN #undef MAXLAZY #undef LONGENOUGH #endif /************************************************** SLOW string matcher **************************************************************/ #if XD3_BUILD_SLOW #define TEMPLATE slow #define LLOOK 9 #define LSTEP 2 #define SLOOK 4U #define SCHAIN 44 #define SLCHAIN 13 #define MAXLAZY 90 #define LONGENOUGH 70 #include "xdelta3.c" #undef TEMPLATE #undef LLOOK #undef SLOOK #undef LSTEP #undef SCHAIN #undef SLCHAIN #undef MAXLAZY #undef LONGENOUGH #endif /******************************************************** DEFAULT string matcher ************************************************************/ #if XD3_BUILD_DEFAULT #define TEMPLATE default #define LLOOK 9 #define LSTEP 3 #define SLOOK 4U #define SCHAIN 8 #define SLCHAIN 2 #define MAXLAZY 36 #define LONGENOUGH 70 #include "xdelta3.c" #undef TEMPLATE #undef LLOOK #undef SLOOK #undef LSTEP #undef SCHAIN #undef SLCHAIN #undef MAXLAZY #undef LONGENOUGH #endif ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-decode.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef _XDELTA3_DECODE_H_ #define _XDELTA3_DECODE_H_ #include "xdelta3-internal.h" #define SRCORTGT(x) ((((x) & VCD_SRCORTGT) == VCD_SOURCE) ? \ VCD_SOURCE : ((((x) & VCD_SRCORTGT) == \ VCD_TARGET) ? VCD_TARGET : 0)) static inline int xd3_decode_byte (xd3_stream *stream, usize_t *val) { if (stream->avail_in == 0) { stream->msg = "further input required"; return XD3_INPUT; } (*val) = stream->next_in[0]; DECODE_INPUT (1); return 0; } static inline int xd3_decode_bytes (xd3_stream *stream, uint8_t *buf, usize_t *pos, usize_t size) { usize_t want; usize_t take; /* Note: The case where (*pos == size) happens when a zero-length * appheader or code table is transmitted, but there is nothing in * the standard against that. */ while (*pos < size) { if (stream->avail_in == 0) { stream->msg = "further input required"; return XD3_INPUT; } want = size - *pos; take = xd3_min (want, stream->avail_in); memcpy (buf + *pos, stream->next_in, (size_t) take); DECODE_INPUT (take); (*pos) += take; } return 0; } /* Initialize the decoder for a new window. The dec_tgtlen value is * preserved across successive window decodings, and the update to * dec_winstart is delayed until a new window actually starts. This * is to avoid throwing an error due to overflow until the last * possible moment. This makes it possible to encode exactly 4GB * through a 32-bit encoder. */ static int xd3_decode_init_window (xd3_stream *stream) { stream->dec_cpylen = 0; stream->dec_cpyoff = 0; stream->dec_cksumbytes = 0; xd3_init_cache (& stream->acache); return 0; } /* Allocates buffer space for the target window and possibly the * VCD_TARGET copy-window. Also sets the base of the two copy * segments. */ static int xd3_decode_setup_buffers (xd3_stream *stream) { /* If VCD_TARGET is set then the previous buffer may be reused. */ if (stream->dec_win_ind & VCD_TARGET) { /* Note: this implementation is untested, since Xdelta3 itself * does not implement an encoder for VCD_TARGET mode. Thus, mark * unimplemented until needed. */ if (1) { stream->msg = "VCD_TARGET not implemented"; return XD3_UNIMPLEMENTED; } /* But this implementation only supports copying from the last * target window. If the offset is outside that range, it can't * be done. */ if (stream->dec_cpyoff < stream->dec_laststart) { stream->msg = "unsupported VCD_TARGET offset"; return XD3_INVALID_INPUT; } /* See if the two windows are the same. This indicates the * first time VCD_TARGET is used. This causes a second buffer * to be allocated, after that the two are swapped in the * DEC_FINISH case. */ if (stream->dec_lastwin == stream->next_out) { stream->next_out = NULL; stream->space_out = 0; } /* TODO: (See note above, this looks incorrect) */ stream->dec_cpyaddrbase = stream->dec_lastwin + (usize_t) (stream->dec_cpyoff - stream->dec_laststart); } /* See if the current output window is large enough. */ if (stream->space_out < stream->dec_tgtlen) { xd3_free (stream, stream->dec_buffer); stream->space_out = xd3_round_blksize (stream->dec_tgtlen, XD3_ALLOCSIZE); if ((stream->dec_buffer = (uint8_t*) xd3_alloc (stream, stream->space_out, 1)) == NULL) { return ENOMEM; } stream->next_out = stream->dec_buffer; } /* dec_tgtaddrbase refers to an invalid base address, but it is * always used with a sufficiently large instruction offset (i.e., * beyond the copy window). This condition is enforced by * xd3_decode_output_halfinst. */ stream->dec_tgtaddrbase = stream->next_out - stream->dec_cpylen; return 0; } static int xd3_decode_allocate (xd3_stream *stream, usize_t size, uint8_t **buf_ptr, usize_t *buf_alloc) { IF_DEBUG2 (DP(RINT "[xd3_decode_allocate] size %"W"u alloc %"W"u\n", size, *buf_alloc)); if (*buf_ptr != NULL && *buf_alloc < size) { xd3_free (stream, *buf_ptr); *buf_ptr = NULL; } if (*buf_ptr == NULL) { *buf_alloc = xd3_round_blksize (size, XD3_ALLOCSIZE); if ((*buf_ptr = (uint8_t*) xd3_alloc (stream, *buf_alloc, 1)) == NULL) { return ENOMEM; } } return 0; } static int xd3_decode_section (xd3_stream *stream, xd3_desect *section, xd3_decode_state nstate, int copy) { XD3_ASSERT (section->pos <= section->size); XD3_ASSERT (stream->dec_state != nstate); if (section->pos < section->size) { usize_t sect_take; if (stream->avail_in == 0) { return XD3_INPUT; } if ((copy == 0) && (section->pos == 0)) { /* No allocation/copy needed */ section->buf = stream->next_in; sect_take = section->size; IF_DEBUG1 (DP(RINT "[xd3_decode_section] zerocopy %"W"u @ %"W"u avail %"W"u\n", sect_take, section->pos, stream->avail_in)); } else { usize_t sect_need = section->size - section->pos; /* Allocate and copy */ sect_take = xd3_min (sect_need, stream->avail_in); if (section->pos == 0) { int ret; if ((ret = xd3_decode_allocate (stream, section->size, & section->copied1, & section->alloc1))) { return ret; } section->buf = section->copied1; } IF_DEBUG2 (DP(RINT "[xd3_decode_section] take %"W"u @ %"W"u [need %"W"u] avail %"W"u\n", sect_take, section->pos, sect_need, stream->avail_in)); XD3_ASSERT (section->pos + sect_take <= section->alloc1); memcpy (section->copied1 + section->pos, stream->next_in, sect_take); } section->pos += sect_take; stream->dec_winbytes += sect_take; DECODE_INPUT (sect_take); } if (section->pos < section->size) { IF_DEBUG1 (DP(RINT "[xd3_decode_section] further input required %"W"u\n", section->size - section->pos)); stream->msg = "further input required"; return XD3_INPUT; } XD3_ASSERT (section->pos == section->size); stream->dec_state = nstate; section->buf_max = section->buf + section->size; section->pos = 0; return 0; } /* Decode the size and address for half of an instruction (i.e., a * single opcode). This updates the stream->dec_position, which are * bytes already output prior to processing this instruction. Perform * bounds checking for sizes and copy addresses, which uses the * dec_position (which is why these checks are done here). */ static int xd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst) { int ret; /* If the size from the instruction table is zero then read a size value. */ if ((inst->size == 0) && (ret = xd3_read_size (stream, & stream->inst_sect.buf, stream->inst_sect.buf_max, & inst->size))) { return XD3_INVALID_INPUT; } /* For copy instructions, read address. */ if (inst->type >= XD3_CPY) { IF_DEBUG2 ({ static int cnt = 0; XPR(NT "DECODE:%u: COPY at %"Q"u (winoffset %"W"u) " "size %"W"u winaddr %"W"u\n", cnt++, stream->total_out + (stream->dec_position - stream->dec_cpylen), (stream->dec_position - stream->dec_cpylen), inst->size, inst->addr); }); if ((ret = xd3_decode_address (stream, stream->dec_position, inst->type - XD3_CPY, & stream->addr_sect.buf, stream->addr_sect.buf_max, & inst->addr))) { return ret; } /* Cannot copy an address before it is filled-in. */ if (inst->addr >= stream->dec_position) { stream->msg = "address too large"; return XD3_INVALID_INPUT; } /* Check: a VCD_TARGET or VCD_SOURCE copy cannot exceed the remaining * buffer space in its own segment. */ if (inst->addr < stream->dec_cpylen && inst->addr + inst->size > stream->dec_cpylen) { stream->msg = "size too large"; return XD3_INVALID_INPUT; } } else { IF_DEBUG2 ({ if (inst->type == XD3_ADD) { static int cnt; XPR(NT "DECODE:%d: ADD at %"Q"u (winoffset %"W"u) size %"W"u\n", cnt++, (stream->total_out + stream->dec_position - stream->dec_cpylen), stream->dec_position - stream->dec_cpylen, inst->size); } else { static int cnt; XD3_ASSERT (inst->type == XD3_RUN); XPR(NT "DECODE:%d: RUN at %"Q"u (winoffset %"W"u) size %"W"u\n", cnt++, stream->total_out + stream->dec_position - stream->dec_cpylen, stream->dec_position - stream->dec_cpylen, inst->size); } }); } /* Check: The instruction will not overflow the output buffer. */ if (stream->dec_position + inst->size > stream->dec_maxpos) { stream->msg = "size too large"; return XD3_INVALID_INPUT; } stream->dec_position += inst->size; return 0; } /* Decode a single opcode and then decode the two half-instructions. */ static int xd3_decode_instruction (xd3_stream *stream) { int ret; const xd3_dinst *inst; if (stream->inst_sect.buf == stream->inst_sect.buf_max) { stream->msg = "instruction underflow"; return XD3_INVALID_INPUT; } inst = &stream->code_table[*stream->inst_sect.buf++]; stream->dec_current1.type = inst->type1; stream->dec_current2.type = inst->type2; stream->dec_current1.size = inst->size1; stream->dec_current2.size = inst->size2; /* For each instruction with a real operation, decode the * corresponding size and addresses if necessary. Assume a * code-table may have NOOP in either position, although this is * unlikely. */ if (inst->type1 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1))) { return ret; } if (inst->type2 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current2))) { return ret; } return 0; } /* Output the result of a single half-instruction. OPT: This the decoder hotspot. Modifies "hinst", see below. */ static int xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst) { /* This method is reentrant for copy instructions which may return * XD3_GETSRCBLK to the caller. Each time through a copy takes the * minimum of inst->size and the available space on whichever block * supplies the data */ usize_t take = inst->size; if (USIZE_T_OVERFLOW (stream->avail_out, take) || stream->avail_out + take > stream->space_out) { stream->msg = "overflow while decoding"; return XD3_INVALID_INPUT; } XD3_ASSERT (inst->type != XD3_NOOP); switch (inst->type) { case XD3_RUN: { /* Only require a single data byte. */ if (stream->data_sect.buf == stream->data_sect.buf_max) { stream->msg = "data underflow"; return XD3_INVALID_INPUT; } memset (stream->next_out + stream->avail_out, stream->data_sect.buf[0], take); stream->data_sect.buf += 1; stream->avail_out += take; inst->type = XD3_NOOP; break; } case XD3_ADD: { /* Require at least TAKE data bytes. */ if (stream->data_sect.buf + take > stream->data_sect.buf_max) { stream->msg = "data underflow"; return XD3_INVALID_INPUT; } memcpy (stream->next_out + stream->avail_out, stream->data_sect.buf, take); stream->data_sect.buf += take; stream->avail_out += take; inst->type = XD3_NOOP; break; } default: { usize_t i; const uint8_t *src; uint8_t *dst; int overlap; /* See if it copies from the VCD_TARGET/VCD_SOURCE window or * the target window. Out-of-bounds checks for the addresses * and sizes are performed in xd3_decode_parse_halfinst. This * if/else must set "overlap", "src", and "dst". */ if (inst->addr < stream->dec_cpylen) { /* In both branches we are copying from outside the * current decoder window, the first (VCD_TARGET) is * unimplemented. */ overlap = 0; /* This branch sets "src". As a side-effect, we modify * "inst" so that if we reenter this method after a * XD3_GETSRCBLK response the state is correct. So if the * instruction can be fulfilled by a contiguous block of * memory then we will set: * * inst->type = XD3_NOOP; * inst->size = 0; */ if (stream->dec_win_ind & VCD_TARGET) { /* TODO: Users have requested long-distance copies of * similar material within a target (e.g., for dup * supression in backups). This code path is probably * dead due to XD3_UNIMPLEMENTED in xd3_decode_setup_buffers */ inst->size = 0; inst->type = XD3_NOOP; stream->msg = "VCD_TARGET not implemented"; return XD3_UNIMPLEMENTED; } else { /* In this case we have to read a source block, which * could return control to the caller. We need to * know the first block number needed for this * copy. */ xd3_source *source = stream->src; xoff_t block = source->cpyoff_blocks; usize_t blkoff = source->cpyoff_blkoff; const usize_t blksize = source->blksize; int ret; xd3_blksize_add (&block, &blkoff, source, inst->addr); XD3_ASSERT (blkoff < blksize); if ((ret = xd3_getblk (stream, block))) { /* could be a XD3_GETSRCBLK failure. */ if (ret == XD3_TOOFARBACK) { stream->msg = "non-seekable source in decode"; ret = XD3_INTERNAL; } return ret; } src = source->curblk + blkoff; /* This block is either full, or a partial block that * must contain enough bytes. */ if ((source->onblk != blksize) && (blkoff + take > source->onblk)) { IF_DEBUG1 (XPR(NT "[srcfile] short at blkno %"Q"u onblk " "%"W"u blksize %"W"u blkoff %"W"u take %"W"u\n", block, source->onblk, blksize, blkoff, take)); stream->msg = "source file too short"; return XD3_INVALID_INPUT; } XD3_ASSERT (blkoff != blksize); /* Check if we have enough data on this block to * finish the instruction. */ if (blkoff + take <= blksize) { inst->type = XD3_NOOP; inst->size = 0; } else { take = blksize - blkoff; inst->size -= take; inst->addr += take; /* because (blkoff + take > blksize), above */ XD3_ASSERT (inst->size != 0); } } } else { /* TODO: the memcpy/overlap optimization, etc. Overlap * here could be more specific, it's whether (inst->addr - * srclen) + inst->size > input_pos ? And is the system * memcpy really any good? */ overlap = 1; /* For a target-window copy, we know the entire range is * in-memory. The dec_tgtaddrbase is negatively offset by * dec_cpylen because the addresses start beyond that * point. */ src = stream->dec_tgtaddrbase + inst->addr; inst->type = XD3_NOOP; inst->size = 0; } dst = stream->next_out + stream->avail_out; stream->avail_out += take; if (overlap) { /* Can't just memcpy here due to possible overlap. */ for (i = take; i != 0; i -= 1) { *dst++ = *src++; } } else { memcpy (dst, src, take); } } } return 0; } static int xd3_decode_finish_window (xd3_stream *stream) { stream->dec_winbytes = 0; stream->dec_state = DEC_FINISH; stream->data_sect.pos = 0; stream->inst_sect.pos = 0; stream->addr_sect.pos = 0; return XD3_OUTPUT; } static int xd3_decode_secondary_sections (xd3_stream *secondary_stream) { #if SECONDARY_ANY int ret; #define DECODE_SECONDARY_SECTION(UPPER,LOWER) \ ((secondary_stream->dec_del_ind & VCD_ ## UPPER ## COMP) && \ (ret = xd3_decode_secondary (secondary_stream, \ & secondary_stream-> LOWER ## _sect, \ & xd3_sec_ ## LOWER (secondary_stream)))) if (DECODE_SECONDARY_SECTION (DATA, data) || DECODE_SECONDARY_SECTION (INST, inst) || DECODE_SECONDARY_SECTION (ADDR, addr)) { return ret; } #undef DECODE_SECONDARY_SECTION #endif return 0; } static int xd3_decode_sections (xd3_stream *stream) { usize_t need, more, take; int copy, ret; if ((stream->flags & XD3_JUST_HDR) != 0) { /* Nothing left to do. */ return xd3_decode_finish_window (stream); } /* To avoid extra copying, allocate three sections at once (but * check for overflow). */ need = stream->inst_sect.size; if (USIZE_T_OVERFLOW (need, stream->addr_sect.size)) { stream->msg = "decoder section size overflow"; return XD3_INTERNAL; } need += stream->addr_sect.size; if (USIZE_T_OVERFLOW (need, stream->data_sect.size)) { stream->msg = "decoder section size overflow"; return XD3_INTERNAL; } need += stream->data_sect.size; /* The window may be entirely processed. */ XD3_ASSERT (stream->dec_winbytes <= need); /* Compute how much more input is needed. */ more = (need - stream->dec_winbytes); /* How much to consume. */ take = xd3_min (more, stream->avail_in); /* See if the input is completely available, to avoid copy. */ copy = (take != more); /* If the window is skipped... */ if ((stream->flags & XD3_SKIP_WINDOW) != 0) { /* Skip the available input. */ DECODE_INPUT (take); stream->dec_winbytes += take; if (copy) { stream->msg = "further input required"; return XD3_INPUT; } return xd3_decode_finish_window (stream); } /* Process all but the DATA section. */ switch (stream->dec_state) { default: stream->msg = "internal error"; return XD3_INVALID_INPUT; case DEC_DATA: if ((ret = xd3_decode_section (stream, & stream->data_sect, DEC_INST, copy))) { return ret; } case DEC_INST: if ((ret = xd3_decode_section (stream, & stream->inst_sect, DEC_ADDR, copy))) { return ret; } case DEC_ADDR: if ((ret = xd3_decode_section (stream, & stream->addr_sect, DEC_EMIT, copy))) { return ret; } } XD3_ASSERT (stream->dec_winbytes == need); if ((ret = xd3_decode_secondary_sections (stream))) { return ret; } if (stream->flags & XD3_SKIP_EMIT) { return xd3_decode_finish_window (stream); } /* OPT: A possible optimization is to avoid allocating memory in * decode_setup_buffers and to avoid a large memcpy when the window * consists of a single VCD_SOURCE copy instruction. */ if ((ret = xd3_decode_setup_buffers (stream))) { return ret; } return 0; } static int xd3_decode_emit (xd3_stream *stream) { int ret; /* Produce output: originally structured to allow reentrant code * that fills as much of the output buffer as possible, but VCDIFF * semantics allows to copy from anywhere from the target window, so * instead allocate a sufficiently sized buffer after the target * window length is decoded. * * This code still needs to be reentrant to allow XD3_GETSRCBLK to * return control. This is handled by setting the * stream->dec_currentN instruction types to XD3_NOOP after they * have been processed. */ XD3_ASSERT (! (stream->flags & XD3_SKIP_EMIT)); XD3_ASSERT (stream->dec_tgtlen <= stream->space_out); while (stream->inst_sect.buf != stream->inst_sect.buf_max || stream->dec_current1.type != XD3_NOOP || stream->dec_current2.type != XD3_NOOP) { /* Decode next instruction pair. */ if ((stream->dec_current1.type == XD3_NOOP) && (stream->dec_current2.type == XD3_NOOP) && (ret = xd3_decode_instruction (stream))) { return ret; } /* Output dec_current1 */ while ((stream->dec_current1.type != XD3_NOOP)) { if ((ret = xd3_decode_output_halfinst (stream, & stream->dec_current1))) { return ret; } } /* Output dec_current2 */ while (stream->dec_current2.type != XD3_NOOP) { if ((ret = xd3_decode_output_halfinst (stream, & stream->dec_current2))) { return ret; } } } if (stream->avail_out != stream->dec_tgtlen) { IF_DEBUG2 (DP(RINT "AVAIL_OUT(%"W"u) != DEC_TGTLEN(%"W"u)\n", stream->avail_out, stream->dec_tgtlen)); stream->msg = "wrong window length"; return XD3_INVALID_INPUT; } if (stream->data_sect.buf != stream->data_sect.buf_max) { stream->msg = "extra data section"; return XD3_INVALID_INPUT; } if (stream->addr_sect.buf != stream->addr_sect.buf_max) { stream->msg = "extra address section"; return XD3_INVALID_INPUT; } /* OPT: Should cksum computation be combined with the above loop? */ if ((stream->dec_win_ind & VCD_ADLER32) != 0 && (stream->flags & XD3_ADLER32_NOVER) == 0) { uint32_t a32 = adler32 (1L, stream->next_out, stream->avail_out); if (a32 != stream->dec_adler32) { stream->msg = "target window checksum mismatch"; return XD3_INVALID_INPUT; } } /* Finished with a window. */ return xd3_decode_finish_window (stream); } int xd3_decode_input (xd3_stream *stream) { int ret; if (stream->enc_state != 0) { stream->msg = "encoder/decoder transition"; return XD3_INVALID_INPUT; } #define BYTE_CASE(expr,x,nstate) \ do { \ if ( (expr) && \ ((ret = xd3_decode_byte (stream, & (x))) != 0) ) { return ret; } \ stream->dec_state = (nstate); \ } while (0) #define OFFSET_CASE(expr,x,nstate) \ do { \ if ( (expr) && \ ((ret = xd3_decode_offset (stream, & (x))) != 0) ) { return ret; } \ stream->dec_state = (nstate); \ } while (0) #define SIZE_CASE(expr,x,nstate) \ do { \ if ( (expr) && \ ((ret = xd3_decode_size (stream, & (x))) != 0) ) { return ret; } \ stream->dec_state = (nstate); \ } while (0) switch (stream->dec_state) { case DEC_VCHEAD: { if ((ret = xd3_decode_bytes (stream, stream->dec_magic, & stream->dec_magicbytes, 4))) { return ret; } if (stream->dec_magic[0] != VCDIFF_MAGIC1 || stream->dec_magic[1] != VCDIFF_MAGIC2 || stream->dec_magic[2] != VCDIFF_MAGIC3) { stream->msg = "not a VCDIFF input"; return XD3_INVALID_INPUT; } if (stream->dec_magic[3] != 0) { stream->msg = "VCDIFF input version > 0 is not supported"; return XD3_INVALID_INPUT; } stream->dec_state = DEC_HDRIND; } case DEC_HDRIND: { if ((ret = xd3_decode_byte (stream, & stream->dec_hdr_ind))) { return ret; } if ((stream->dec_hdr_ind & VCD_INVHDR) != 0) { stream->msg = "unrecognized header indicator bits set"; return XD3_INVALID_INPUT; } stream->dec_state = DEC_SECONDID; } case DEC_SECONDID: /* Secondary compressor ID: only if VCD_SECONDARY is set */ if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0) { BYTE_CASE (1, stream->dec_secondid, DEC_TABLEN); switch (stream->dec_secondid) { case VCD_FGK_ID: FGK_CASE (stream); case VCD_DJW_ID: DJW_CASE (stream); case VCD_LZMA_ID: LZMA_CASE (stream); default: stream->msg = "unknown secondary compressor ID"; return XD3_INVALID_INPUT; } } case DEC_TABLEN: /* Length of code table data: only if VCD_CODETABLE is set */ SIZE_CASE ((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->dec_codetblsz, DEC_NEAR); /* The codetblsz counts the two NEAR/SAME bytes */ if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) { if (stream->dec_codetblsz <= 2) { stream->msg = "invalid code table size"; return ENOMEM; } stream->dec_codetblsz -= 2; } case DEC_NEAR: /* Near modes: only if VCD_CODETABLE is set */ BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->acache.s_near, DEC_SAME); case DEC_SAME: /* Same modes: only if VCD_CODETABLE is set */ BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->acache.s_same, DEC_TABDAT); case DEC_TABDAT: /* Compressed code table data */ if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) { stream->msg = "VCD_CODETABLE support was removed"; return XD3_UNIMPLEMENTED; } else { /* Use the default table. */ stream->acache.s_near = __rfc3284_code_table_desc.near_modes; stream->acache.s_same = __rfc3284_code_table_desc.same_modes; stream->code_table = xd3_rfc3284_code_table (); } if ((ret = xd3_alloc_cache (stream))) { return ret; } stream->dec_state = DEC_APPLEN; case DEC_APPLEN: /* Length of application data */ SIZE_CASE((stream->dec_hdr_ind & VCD_APPHEADER) != 0, stream->dec_appheadsz, DEC_APPDAT); case DEC_APPDAT: /* Application data */ if (stream->dec_hdr_ind & VCD_APPHEADER) { /* Note: we add an additional byte for padding, to allow 0-termination. Check for overflow: */ if (USIZE_T_OVERFLOW(stream->dec_appheadsz, 1)) { stream->msg = "exceptional appheader size"; return XD3_INVALID_INPUT; } if ((stream->dec_appheader == NULL) && (stream->dec_appheader = (uint8_t*) xd3_alloc (stream, stream->dec_appheadsz+1, 1)) == NULL) { return ENOMEM; } stream->dec_appheader[stream->dec_appheadsz] = 0; if ((ret = xd3_decode_bytes (stream, stream->dec_appheader, & stream->dec_appheadbytes, stream->dec_appheadsz))) { return ret; } } /* xoff_t -> usize_t is safe because this is the first block. */ stream->dec_hdrsize = (usize_t) stream->total_in; stream->dec_state = DEC_WININD; case DEC_WININD: { /* Start of a window: the window indicator */ if ((ret = xd3_decode_byte (stream, & stream->dec_win_ind))) { return ret; } stream->current_window = stream->dec_window_count; if (XOFF_T_OVERFLOW (stream->dec_winstart, stream->dec_tgtlen)) { stream->msg = "decoder file offset overflow"; return XD3_INVALID_INPUT; } stream->dec_winstart += stream->dec_tgtlen; if ((stream->dec_win_ind & VCD_INVWIN) != 0) { stream->msg = "unrecognized window indicator bits set"; return XD3_INVALID_INPUT; } if ((ret = xd3_decode_init_window (stream))) { return ret; } stream->dec_state = DEC_CPYLEN; IF_DEBUG2 (DP(RINT "--------- TARGET WINDOW %"Q"u -----------\n", stream->current_window)); } case DEC_CPYLEN: /* Copy window length: only if VCD_SOURCE or VCD_TARGET is set */ SIZE_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpylen, DEC_CPYOFF); /* Set the initial, logical decoder position (HERE address) in * dec_position. This is set to just after the source/copy * window, as we are just about to output the first byte of * target window. */ stream->dec_position = stream->dec_cpylen; case DEC_CPYOFF: /* Copy window offset: only if VCD_SOURCE or VCD_TARGET is set */ OFFSET_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpyoff, DEC_ENCLEN); /* Copy offset and copy length may not overflow. */ if (XOFF_T_OVERFLOW (stream->dec_cpyoff, stream->dec_cpylen)) { stream->msg = "decoder copy window overflows a file offset"; return XD3_INVALID_INPUT; } /* Check copy window bounds: VCD_TARGET window may not exceed current position. */ if ((stream->dec_win_ind & VCD_TARGET) && (stream->dec_cpyoff + stream->dec_cpylen > stream->dec_winstart)) { stream->msg = "VCD_TARGET window out of bounds"; return XD3_INVALID_INPUT; } case DEC_ENCLEN: /* Length of the delta encoding */ SIZE_CASE(1, stream->dec_enclen, DEC_TGTLEN); case DEC_TGTLEN: /* Length of target window */ SIZE_CASE(1, stream->dec_tgtlen, DEC_DELIND); /* Set the maximum decoder position, beyond which we should not * decode any data. This is the maximum value for dec_position. * This may not exceed the size of a usize_t. */ if (USIZE_T_OVERFLOW (stream->dec_cpylen, stream->dec_tgtlen)) { stream->msg = "decoder target window overflows a usize_t"; return XD3_INVALID_INPUT; } /* Check for malicious files. */ if (stream->dec_tgtlen > XD3_HARDMAXWINSIZE) { stream->msg = "hard window size exceeded"; return XD3_INVALID_INPUT; } stream->dec_maxpos = stream->dec_cpylen + stream->dec_tgtlen; case DEC_DELIND: /* Delta indicator */ BYTE_CASE(1, stream->dec_del_ind, DEC_DATALEN); if ((stream->dec_del_ind & VCD_INVDEL) != 0) { stream->msg = "unrecognized delta indicator bits set"; return XD3_INVALID_INPUT; } /* Delta indicator is only used with secondary compression. */ if ((stream->dec_del_ind != 0) && (stream->sec_type == NULL)) { stream->msg = "invalid delta indicator bits set"; return XD3_INVALID_INPUT; } /* Section lengths */ case DEC_DATALEN: SIZE_CASE(1, stream->data_sect.size, DEC_INSTLEN); case DEC_INSTLEN: SIZE_CASE(1, stream->inst_sect.size, DEC_ADDRLEN); case DEC_ADDRLEN: SIZE_CASE(1, stream->addr_sect.size, DEC_CKSUM); case DEC_CKSUM: /* Window checksum. */ if ((stream->dec_win_ind & VCD_ADLER32) != 0) { int i; if ((ret = xd3_decode_bytes (stream, stream->dec_cksum, & stream->dec_cksumbytes, 4))) { return ret; } for (i = 0; i < 4; i += 1) { stream->dec_adler32 = (stream->dec_adler32 << 8) | stream->dec_cksum[i]; } } stream->dec_state = DEC_DATA; /* Check dec_enclen for redundency, otherwise it is not really used. */ { usize_t enclen_check = (1 + (xd3_sizeof_size (stream->dec_tgtlen) + xd3_sizeof_size (stream->data_sect.size) + xd3_sizeof_size (stream->inst_sect.size) + xd3_sizeof_size (stream->addr_sect.size)) + stream->data_sect.size + stream->inst_sect.size + stream->addr_sect.size + ((stream->dec_win_ind & VCD_ADLER32) ? 4 : 0)); if (stream->dec_enclen != enclen_check) { stream->msg = "incorrect encoding length (redundent)"; return XD3_INVALID_INPUT; } } /* Returning here gives the application a chance to inspect the * header, skip the window, etc. */ if (stream->current_window == 0) { return XD3_GOTHEADER; } else { return XD3_WINSTART; } case DEC_DATA: case DEC_INST: case DEC_ADDR: /* Next read the three sections. */ if ((ret = xd3_decode_sections (stream))) { return ret; } case DEC_EMIT: /* To speed VCD_SOURCE block-address calculations, the source * cpyoff_blocks and cpyoff_blkoff are pre-computed. */ if (stream->dec_win_ind & VCD_SOURCE) { xd3_source *src = stream->src; if (src == NULL) { stream->msg = "source input required"; return XD3_INVALID_INPUT; } xd3_blksize_div(stream->dec_cpyoff, src, &src->cpyoff_blocks, &src->cpyoff_blkoff); IF_DEBUG2(DP(RINT "[decode_cpyoff] %"Q"u " "cpyblkno %"Q"u " "cpyblkoff %"W"u " "blksize %"W"u\n", stream->dec_cpyoff, src->cpyoff_blocks, src->cpyoff_blkoff, src->blksize)); } /* xd3_decode_emit returns XD3_OUTPUT on every success. */ if ((ret = xd3_decode_emit (stream)) == XD3_OUTPUT) { stream->total_out += stream->avail_out; } return ret; case DEC_FINISH: { if (stream->dec_win_ind & VCD_TARGET) { if (stream->dec_lastwin == NULL) { stream->dec_lastwin = stream->next_out; stream->dec_lastspace = stream->space_out; } else { xd3_swap_uint8p (& stream->dec_lastwin, & stream->next_out); xd3_swap_usize_t (& stream->dec_lastspace, & stream->space_out); } } stream->dec_lastlen = stream->dec_tgtlen; stream->dec_laststart = stream->dec_winstart; stream->dec_window_count += 1; /* Note: the updates to dec_winstart & current_window are * deferred until after the next DEC_WININD byte is read. */ stream->dec_state = DEC_WININD; return XD3_WINFINISH; } default: stream->msg = "invalid state"; return XD3_INVALID_INPUT; } } #endif // _XDELTA3_DECODE_H_ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-djw.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef _XDELTA3_DJW_H_ #define _XDELTA3_DJW_H_ /* The following people deserve much credit for the algorithms and * techniques contained in this file: Julian Seward Bzip2 sources, implementation of the multi-table Huffman technique. Jean-loup Gailly and Mark Adler and L. Peter Deutsch Zlib source code, RFC 1951 Daniel S. Hirschberg and Debra A. LeLewer "Efficient Decoding of Prefix Codes" Communications of the ACM, April 1990 33(4). David J. Wheeler Program bred3.c, bexp3 and accompanying documents bred3.ps, huff.ps. This contains the idea behind the multi-table Huffman and 1-2 coding techniques. ftp://ftp.cl.cam.ac.uk/users/djw3/ */ /* OPT: during the multi-table iteration, pick the worst-overall * performing table and replace it with exactly the frequencies of the * worst-overall performing sector or N-worst performing sectors. */ /* REF: See xdfs-0.222 and xdfs-0.226 for some old experiments with * the Bzip prefix coding strategy. xdfs-0.256 contains the last of * the other-format tests, including RFC1950 and the RFC1950+MTF * tests. */ #define DJW_MAX_CODELEN 20U /* Maximum length of an alphabet code. */ /* Code lengths are themselves code-length encoded, so the total number of * codes is: [RUN_0, RUN_1, 1-DJW_MAX_CODELEN] */ #define DJW_TOTAL_CODES (DJW_MAX_CODELEN+2) #define RUN_0 0U /* Symbols used in MTF+1/2 coding. */ #define RUN_1 1U /* Number of code lengths always encoded (djw_encode_basic array) */ #define DJW_BASIC_CODES 5U #define DJW_RUN_CODES 2U /* Number of run codes */ /* Offset of extra codes */ #define DJW_EXTRA_12OFFSET (DJW_BASIC_CODES + DJW_RUN_CODES) /* Number of optionally encoded code lengths (djw_encode_extra array) */ #define DJW_EXTRA_CODES 15U /* Number of bits to code [0-DJW_EXTRA_CODES] */ #define DJW_EXTRA_CODE_BITS 4U #define DJW_MAX_GROUPS 8U /* Max number of group coding tables */ #define DJW_GROUP_BITS 3U /* Number of bits to code [1-DJW_MAX_GROUPS] */ #define DJW_SECTORSZ_MULT 5U /* Multiplier for encoded sectorsz */ #define DJW_SECTORSZ_BITS 5U /* Number of bits to code group size */ #define DJW_SECTORSZ_MAX ((1U << DJW_SECTORSZ_BITS) * DJW_SECTORSZ_MULT) /* Maximum number of iterations to find group tables. */ #define DJW_MAX_ITER 6U /* Minimum number of bits an iteration must reduce coding by. */ #define DJW_MIN_IMPROVEMENT 20U /* Maximum code length of a prefix code length */ #define DJW_MAX_CLCLEN 15U /* Number of bits to code [0-DJW_MAX_CLCLEN] */ #define DJW_CLCLEN_BITS 4U #define DJW_MAX_GBCLEN 7U /* Maximum code length of a group selector */ /* Number of bits to code [0-DJW_MAX_GBCLEN] * TODO: Actually, should never have zero code lengths here, or else a group * went unused. Write a test for this: if a group goes unused, eliminate * it? */ #define DJW_GBCLEN_BITS 3U /* It has to save at least this many bits... */ #define EFFICIENCY_BITS 16U typedef struct _djw_stream djw_stream; typedef struct _djw_heapen djw_heapen; typedef struct _djw_prefix djw_prefix; typedef uint32_t djw_weight; struct _djw_heapen { uint32_t depth; uint32_t freq; uint32_t parent; }; struct _djw_prefix { usize_t scount; uint8_t *symbol; usize_t mcount; uint8_t *mtfsym; uint8_t *repcnt; }; struct _djw_stream { int unused; }; /* Each Huffman table consists of 256 "code length" (CLEN) codes, * which are themselves Huffman coded after eliminating repeats and * move-to-front coding. The prefix consists of all the CLEN codes in * djw_encode_basic plus a 4-bit value stating how many of the * djw_encode_extra codes are actually coded (the rest are presumed * zero, or unused CLEN codes). * * These values of these two arrays were arrived at by studying the * distribution of min and max clen over a collection of DATA, INST, * and ADDR inputs. The goal is to specify the order of * djw_extra_codes that is most likely to minimize the number of extra * codes that must be encoded. * * Results: 158896 sections were counted by compressing files (window * size 512K) listed with: `find / -type f ( -user jmacd -o -perm +444 * )` * * The distribution of CLEN codes for each efficient invocation of the * secondary compressor (taking the best number of groups/sector size) * was recorded. Then we look at the distribution of min and max clen * values, counting the number of times the value C_low is less than * the min and C_high is greater than the max. Values >= C_high and * <= C_low will not have their lengths coded. The results are sorted * and the least likely 15 are placed into the djw_encode_extra[] * array in order. These values are used as the initial MTF ordering. clow[1] = 155119 clow[2] = 140325 clow[3] = 84072 --- clow[4] = 7225 clow[5] = 1093 clow[6] = 215 --- chigh[4] = 1 chigh[5] = 30 chigh[6] = 218 chigh[7] = 2060 chigh[8] = 13271 --- chigh[9] = 39463 chigh[10] = 77360 chigh[11] = 118298 chigh[12] = 141360 chigh[13] = 154086 chigh[14] = 157967 chigh[15] = 158603 chigh[16] = 158864 chigh[17] = 158893 chigh[18] = 158895 chigh[19] = 158896 chigh[20] = 158896 */ static const uint8_t djw_encode_12extra[DJW_EXTRA_CODES] = { 9, 10, 3, 11, 2, 12, 13, 1, 14, 15, 16, 17, 18, 19, 20, }; static const uint8_t djw_encode_12basic[DJW_BASIC_CODES] = { 4, 5, 6, 7, 8, }; /*********************************************************************/ /* DECLS */ /*********************************************************************/ static djw_stream* djw_alloc (xd3_stream *stream); static int djw_init (xd3_stream *stream, djw_stream *h, int is_encode); static void djw_destroy (xd3_stream *stream, djw_stream *h); #if XD3_ENCODER static int xd3_encode_huff (xd3_stream *stream, djw_stream *sec_stream, xd3_output *input, xd3_output *output, xd3_sec_cfg *cfg); #endif static int xd3_decode_huff (xd3_stream *stream, djw_stream *sec_stream, const uint8_t **input, const uint8_t *const input_end, uint8_t **output, const uint8_t *const output_end); /*********************************************************************/ /* HUFFMAN */ /*********************************************************************/ static djw_stream* djw_alloc (xd3_stream *stream) { return (djw_stream*) xd3_alloc (stream, sizeof (djw_stream), 1); } static int djw_init (xd3_stream *stream, djw_stream *h, int is_encode) { /* Fields are initialized prior to use. */ return 0; } static void djw_destroy (xd3_stream *stream, djw_stream *h) { xd3_free (stream, h); } /*********************************************************************/ /* HEAP */ /*********************************************************************/ static inline int heap_less (const djw_heapen *a, const djw_heapen *b) { return a->freq < b->freq || (a->freq == b->freq && a->depth < b->depth); } static inline void heap_insert (usize_t *heap, const djw_heapen *ents, usize_t p, const usize_t e) { /* Insert ents[e] into next slot heap[p] */ usize_t pp = p/2; /* P's parent */ while (heap_less (& ents[e], & ents[heap[pp]])) { heap[p] = heap[pp]; p = pp; pp = p/2; } heap[p] = e; } static inline djw_heapen* heap_extract (usize_t *heap, const djw_heapen *ents, usize_t heap_last) { usize_t smallest = heap[1]; usize_t p, pc, t; /* Caller decrements heap_last, so heap_last+1 is the replacement elt. */ heap[1] = heap[heap_last+1]; /* Re-heapify */ for (p = 1; ; p = pc) { pc = p*2; /* Reached bottom of heap */ if (pc > heap_last) { break; } /* See if second child is smaller. */ if (pc < heap_last && heap_less (& ents[heap[pc+1]], & ents[heap[pc]])) { pc += 1; } /* If pc is not smaller than p, heap property re-established. */ if (! heap_less (& ents[heap[pc]], & ents[heap[p]])) { break; } t = heap[pc]; heap[pc] = heap[p]; heap[p] = t; } return (djw_heapen*) & ents[smallest]; } #if XD3_DEBUG static void heap_check (usize_t *heap, djw_heapen *ents, usize_t heap_last) { usize_t i; for (i = 1; i <= heap_last; i += 1) { /* Heap property: child not less than parent */ XD3_ASSERT (! heap_less (& ents[heap[i]], & ents[heap[i/2]])); IF_DEBUG2 (DP(RINT "heap[%"W"u] = %u\n", i, ents[heap[i]].freq)); } } #endif /*********************************************************************/ /* MTF, 1/2 */ /*********************************************************************/ static inline usize_t djw_update_mtf (uint8_t *mtf, usize_t mtf_i) { int k; usize_t sym = mtf[mtf_i]; for (k = mtf_i; k != 0; k -= 1) { mtf[k] = mtf[k-1]; } mtf[0] = sym; return sym; } static inline void djw_update_1_2 (int *mtf_run, usize_t *mtf_i, uint8_t *mtfsym, djw_weight *freq) { uint8_t code; do { /* Offset by 1, since any number of RUN_ symbols implies run>0... */ *mtf_run -= 1; code = (*mtf_run & 1) ? RUN_1 : RUN_0; mtfsym[(*mtf_i)++] = code; freq[code] += 1; *mtf_run >>= 1; } while (*mtf_run >= 1); *mtf_run = 0; } static void djw_init_clen_mtf_1_2 (uint8_t *clmtf) { usize_t i, cl_i = 0; clmtf[cl_i++] = 0; for (i = 0; i < DJW_BASIC_CODES; i += 1) { clmtf[cl_i++] = djw_encode_12basic[i]; } for (i = 0; i < DJW_EXTRA_CODES; i += 1) { clmtf[cl_i++] = djw_encode_12extra[i]; } } /*********************************************************************/ /* PREFIX CODES */ /*********************************************************************/ #if XD3_ENCODER static usize_t djw_build_prefix (const djw_weight *freq, uint8_t *clen, usize_t asize, usize_t maxlen) { /* Heap with 0th entry unused, prefix tree with up to ALPHABET_SIZE-1 * internal nodes, never more than ALPHABET_SIZE entries actually in the * heap (minimum weight subtrees during prefix construction). First * ALPHABET_SIZE entries are the actual symbols, next ALPHABET_SIZE-1 are * internal nodes. */ djw_heapen ents[ALPHABET_SIZE * 2]; usize_t heap[ALPHABET_SIZE + 1]; usize_t heap_last; /* Index of the last _valid_ heap entry. */ usize_t ents_size; /* Number of entries, including 0th fake entry */ usize_t overflow; /* Number of code lengths that overflow */ usize_t total_bits; usize_t i; IF_DEBUG (usize_t first_bits = 0); /* Insert real symbol frequences. */ for (i = 0; i < asize; i += 1) { ents[i+1].freq = freq[i]; IF_DEBUG2 (DP(RINT "ents[%"W"i] = freq[%"W"u] = %d\n", i+1, i, freq[i])); } again: /* The loop is re-entered each time an overflow occurs. Re-initialize... */ heap_last = 0; ents_size = 1; overflow = 0; total_bits = 0; /* 0th entry terminates the while loop in heap_insert (it's the parent of * the smallest element, always less-than) */ heap[0] = 0; ents[0].depth = 0; ents[0].freq = 0; /* Initial heap. */ for (i = 0; i < asize; i += 1, ents_size += 1) { ents[ents_size].depth = 0; ents[ents_size].parent = 0; if (ents[ents_size].freq != 0) { heap_insert (heap, ents, ++heap_last, ents_size); } } IF_DEBUG (heap_check (heap, ents, heap_last)); /* Must be at least one symbol, or else we can't get here. */ XD3_ASSERT (heap_last != 0); /* If there is only one symbol, fake a second to prevent zero-length * codes. */ if (heap_last == 1) { /* Pick either the first or last symbol. */ usize_t s = freq[0] ? asize-1 : 0; ents[s+1].freq = 1; goto again; } /* Build prefix tree. */ while (heap_last > 1) { djw_heapen *h1 = heap_extract (heap, ents, --heap_last); djw_heapen *h2 = heap_extract (heap, ents, --heap_last); ents[ents_size].freq = h1->freq + h2->freq; ents[ents_size].depth = 1 + xd3_max (h1->depth, h2->depth); ents[ents_size].parent = 0; h1->parent = h2->parent = ents_size; heap_insert (heap, ents, ++heap_last, ents_size++); } IF_DEBUG (heap_check (heap, ents, heap_last)); /* Now compute prefix code lengths, counting parents. */ for (i = 1; i < asize+1; i += 1) { usize_t b = 0; if (ents[i].freq != 0) { usize_t p = i; while ((p = ents[p].parent) != 0) { b += 1; } if (b > maxlen) { overflow = 1; } total_bits += b * freq[i-1]; } /* clen is 0-origin, unlike ents. */ IF_DEBUG2 (DP(RINT "clen[%"W"u] = %"W"u\n", i-1, b)); clen[i-1] = b; } IF_DEBUG (if (first_bits == 0) first_bits = total_bits); if (! overflow) { IF_DEBUG2 (if (first_bits != total_bits) { DP(RINT "code length overflow changed %"W"u bits\n", total_bits - first_bits); }); return total_bits; } /* OPT: There is a non-looping way to fix overflow shown in zlib, but this * is easier (for now), as done in bzip2. */ for (i = 1; i < asize+1; i += 1) { ents[i].freq = ents[i].freq / 2 + 1; } goto again; } static void djw_build_codes (usize_t *codes, const uint8_t *clen, usize_t asize, usize_t abs_max) { usize_t i, l; usize_t min_clen = DJW_MAX_CODELEN; usize_t max_clen = 0; usize_t code = 0; /* Find the min and max code length */ for (i = 0; i < asize; i += 1) { if (clen[i] > 0 && clen[i] < min_clen) { min_clen = clen[i]; } max_clen = xd3_max (max_clen, (usize_t) clen[i]); } XD3_ASSERT (max_clen <= abs_max); /* Generate a code for each symbol with the appropriate length. */ for (l = min_clen; l <= max_clen; l += 1) { for (i = 0; i < asize; i += 1) { if (clen[i] == l) { codes[i] = code++; } } code <<= 1; } IF_DEBUG2 ({ for (i = 0; i < asize; i += 1) { DP(RINT "code[%"W"u] = %"W"u\n", i, codes[i]); } }); } /*********************************************************************/ /* MOVE-TO-FRONT */ /*********************************************************************/ static void djw_compute_mtf_1_2 (djw_prefix *prefix, uint8_t *mtf, djw_weight *freq_out, usize_t nsym) { size_t i, j, k; usize_t sym; usize_t size = prefix->scount; usize_t mtf_i = 0; int mtf_run = 0; /* This +2 is for the RUN_0, RUN_1 codes */ memset (freq_out, 0, sizeof (freq_out[0]) * (nsym+2)); for (i = 0; i < size; ) { /* OPT: Bzip optimizes this algorithm a little by effectively checking * j==0 before the MTF update. */ sym = prefix->symbol[i++]; for (j = 0; mtf[j] != sym; j += 1) { } XD3_ASSERT (j <= nsym); for (k = j; k >= 1; k -= 1) { mtf[k] = mtf[k-1]; } mtf[0] = sym; if (j == 0) { mtf_run += 1; continue; } if (mtf_run > 0) { djw_update_1_2 (& mtf_run, & mtf_i, prefix->mtfsym, freq_out); } /* Non-zero symbols are offset by RUN_1 */ prefix->mtfsym[mtf_i++] = (uint8_t)(j+RUN_1); freq_out[j+RUN_1] += 1; } if (mtf_run > 0) { djw_update_1_2 (& mtf_run, & mtf_i, prefix->mtfsym, freq_out); } prefix->mcount = mtf_i; } /* Counts character frequencies of the input buffer, returns the size. */ static usize_t djw_count_freqs (djw_weight *freq, xd3_output *input) { xd3_output *in; usize_t size = 0; memset (freq, 0, sizeof (freq[0]) * ALPHABET_SIZE); for (in = input; in; in = in->next_page) { const uint8_t *p = in->base; const uint8_t *p_max = p + in->next; size += in->next; do { ++freq[*p]; } while (++p < p_max); } IF_DEBUG2 ({int i; DP(RINT "freqs: "); for (i = 0; i < ALPHABET_SIZE; i += 1) { DP(RINT "%u ", freq[i]); } DP(RINT "\n");}); return size; } static void djw_compute_multi_prefix (usize_t groups, uint8_t clen[DJW_MAX_GROUPS][ALPHABET_SIZE], djw_prefix *prefix) { usize_t gp, i; prefix->scount = ALPHABET_SIZE; memcpy (prefix->symbol, clen[0], ALPHABET_SIZE); for (gp = 1; gp < groups; gp += 1) { for (i = 0; i < ALPHABET_SIZE; i += 1) { if (clen[gp][i] == 0) { continue; } prefix->symbol[prefix->scount++] = clen[gp][i]; } } } static void djw_compute_prefix_1_2 (djw_prefix *prefix, djw_weight *freq) { /* This +1 is for the 0 code-length. */ uint8_t clmtf[DJW_MAX_CODELEN+1]; djw_init_clen_mtf_1_2 (clmtf); djw_compute_mtf_1_2 (prefix, clmtf, freq, DJW_MAX_CODELEN); } static int djw_encode_prefix (xd3_stream *stream, xd3_output **output, bit_state *bstate, djw_prefix *prefix) { int ret; size_t i; usize_t num_to_encode; djw_weight clfreq[DJW_TOTAL_CODES]; uint8_t clclen[DJW_TOTAL_CODES]; usize_t clcode[DJW_TOTAL_CODES]; /* Move-to-front encode prefix symbols, count frequencies */ djw_compute_prefix_1_2 (prefix, clfreq); /* Compute codes */ djw_build_prefix (clfreq, clclen, DJW_TOTAL_CODES, DJW_MAX_CLCLEN); djw_build_codes (clcode, clclen, DJW_TOTAL_CODES, DJW_MAX_CLCLEN); /* Compute number of extra codes beyond basic ones for this template. */ num_to_encode = DJW_TOTAL_CODES; while (num_to_encode > DJW_EXTRA_12OFFSET && clclen[num_to_encode-1] == 0) { num_to_encode -= 1; } XD3_ASSERT (num_to_encode - DJW_EXTRA_12OFFSET < (1 << DJW_EXTRA_CODE_BITS)); /* Encode: # of extra codes */ if ((ret = xd3_encode_bits (stream, output, bstate, DJW_EXTRA_CODE_BITS, num_to_encode - DJW_EXTRA_12OFFSET))) { return ret; } /* Encode: MTF code lengths */ for (i = 0; i < num_to_encode; i += 1) { if ((ret = xd3_encode_bits (stream, output, bstate, DJW_CLCLEN_BITS, clclen[i]))) { return ret; } } /* Encode: CLEN code lengths */ for (i = 0; i < prefix->mcount; i += 1) { usize_t mtf_sym = prefix->mtfsym[i]; usize_t bits = clclen[mtf_sym]; usize_t code = clcode[mtf_sym]; if ((ret = xd3_encode_bits (stream, output, bstate, bits, code))) { return ret; } } return 0; } static void djw_compute_selector_1_2 (djw_prefix *prefix, usize_t groups, djw_weight *gbest_freq) { uint8_t grmtf[DJW_MAX_GROUPS]; usize_t i; for (i = 0; i < groups; i += 1) { grmtf[i] = i; } djw_compute_mtf_1_2 (prefix, grmtf, gbest_freq, groups); } static int xd3_encode_howmany_groups (xd3_stream *stream, xd3_sec_cfg *cfg, usize_t input_size, usize_t *ret_groups, usize_t *ret_sector_size) { usize_t cfg_groups = 0; usize_t cfg_sector_size = 0; usize_t sugg_groups = 0; usize_t sugg_sector_size = 0; if (cfg->ngroups != 0) { if (cfg->ngroups > DJW_MAX_GROUPS) { stream->msg = "invalid secondary encoder group number"; return XD3_INTERNAL; } cfg_groups = cfg->ngroups; } if (cfg->sector_size != 0) { if (cfg->sector_size < DJW_SECTORSZ_MULT || cfg->sector_size > DJW_SECTORSZ_MAX || (cfg->sector_size % DJW_SECTORSZ_MULT) != 0) { stream->msg = "invalid secondary encoder sector size"; return XD3_INTERNAL; } cfg_sector_size = cfg->sector_size; } if (cfg_groups == 0 || cfg_sector_size == 0) { /* These values were found empirically using xdelta3-tune around version * xdfs-0.256. */ switch (cfg->data_type) { case DATA_SECTION: if (input_size < 1000) { sugg_groups = 1; sugg_sector_size = 0; } else if (input_size < 4000) { sugg_groups = 2; sugg_sector_size = 10; } else if (input_size < 7000) { sugg_groups = 3; sugg_sector_size = 10; } else if (input_size < 10000) { sugg_groups = 4; sugg_sector_size = 10; } else if (input_size < 25000) { sugg_groups = 5; sugg_sector_size = 10; } else if (input_size < 50000) { sugg_groups = 7; sugg_sector_size = 20; } else if (input_size < 100000) { sugg_groups = 8; sugg_sector_size = 30; } else { sugg_groups = 8; sugg_sector_size = 70; } break; case INST_SECTION: if (input_size < 7000) { sugg_groups = 1; sugg_sector_size = 0; } else if (input_size < 10000) { sugg_groups = 2; sugg_sector_size = 50; } else if (input_size < 25000) { sugg_groups = 3; sugg_sector_size = 50; } else if (input_size < 50000) { sugg_groups = 6; sugg_sector_size = 40; } else if (input_size < 100000) { sugg_groups = 8; sugg_sector_size = 40; } else { sugg_groups = 8; sugg_sector_size = 40; } break; case ADDR_SECTION: if (input_size < 9000) { sugg_groups = 1; sugg_sector_size = 0; } else if (input_size < 25000) { sugg_groups = 2; sugg_sector_size = 130; } else if (input_size < 50000) { sugg_groups = 3; sugg_sector_size = 130; } else if (input_size < 100000) { sugg_groups = 5; sugg_sector_size = 130; } else { sugg_groups = 7; sugg_sector_size = 130; } break; } if (cfg_groups == 0) { cfg_groups = sugg_groups; } if (cfg_sector_size == 0) { cfg_sector_size = sugg_sector_size; } } if (cfg_groups != 1 && cfg_sector_size == 0) { switch (cfg->data_type) { case DATA_SECTION: cfg_sector_size = 20; break; case INST_SECTION: cfg_sector_size = 50; break; case ADDR_SECTION: cfg_sector_size = 130; break; } } (*ret_groups) = cfg_groups; (*ret_sector_size) = cfg_sector_size; XD3_ASSERT (cfg_groups > 0 && cfg_groups <= DJW_MAX_GROUPS); XD3_ASSERT (cfg_groups == 1 || (cfg_sector_size >= DJW_SECTORSZ_MULT && cfg_sector_size <= DJW_SECTORSZ_MAX)); return 0; } static int xd3_encode_huff (xd3_stream *stream, djw_stream *h, xd3_output *input, xd3_output *output, xd3_sec_cfg *cfg) { int ret; usize_t groups, sector_size; bit_state bstate = BIT_STATE_ENCODE_INIT; xd3_output *in; usize_t output_bits; usize_t input_bits; usize_t input_bytes; usize_t initial_offset = output->next; djw_weight real_freq[ALPHABET_SIZE]; uint8_t *gbest = NULL; uint8_t *gbest_mtf = NULL; input_bytes = djw_count_freqs (real_freq, input); input_bits = input_bytes * 8; XD3_ASSERT (input_bytes > 0); if ((ret = xd3_encode_howmany_groups (stream, cfg, input_bytes, & groups, & sector_size))) { return ret; } if (0) { regroup: /* Sometimes we dynamically decide there are too many groups. Arrive * here. */ output->next = initial_offset; xd3_bit_state_encode_init (& bstate); } /* Encode: # of groups (3 bits) */ if ((ret = xd3_encode_bits (stream, & output, & bstate, DJW_GROUP_BITS, groups-1))) { goto failure; } if (groups == 1) { /* Single Huffman group. */ usize_t code[ALPHABET_SIZE]; /* Codes */ uint8_t clen[ALPHABET_SIZE]; uint8_t prefix_mtfsym[ALPHABET_SIZE]; djw_prefix prefix; output_bits = djw_build_prefix (real_freq, clen, ALPHABET_SIZE, DJW_MAX_CODELEN); djw_build_codes (code, clen, ALPHABET_SIZE, DJW_MAX_CODELEN); if (output_bits + EFFICIENCY_BITS >= input_bits && ! cfg->inefficient) { goto nosecond; } /* Encode: prefix */ prefix.mtfsym = prefix_mtfsym; prefix.symbol = clen; prefix.scount = ALPHABET_SIZE; if ((ret = djw_encode_prefix (stream, & output, & bstate, & prefix))) { goto failure; } if (output_bits + (8 * output->next) + EFFICIENCY_BITS >= input_bits && ! cfg->inefficient) { goto nosecond; } /* Encode: data */ for (in = input; in; in = in->next_page) { const uint8_t *p = in->base; const uint8_t *p_max = p + in->next; do { usize_t sym = *p++; usize_t bits = clen[sym]; IF_DEBUG (output_bits -= bits); if ((ret = xd3_encode_bits (stream, & output, & bstate, bits, code[sym]))) { goto failure; } } while (p < p_max); } XD3_ASSERT (output_bits == 0); } else { /* DJW Huffman */ djw_weight evolve_freq[DJW_MAX_GROUPS][ALPHABET_SIZE]; uint8_t evolve_clen[DJW_MAX_GROUPS][ALPHABET_SIZE]; djw_weight left = input_bytes; usize_t gp; usize_t niter = 0; usize_t select_bits; usize_t sym1 = 0, sym2 = 0, s; usize_t gcost[DJW_MAX_GROUPS]; usize_t gbest_code[DJW_MAX_GROUPS+2]; uint8_t gbest_clen[DJW_MAX_GROUPS+2]; usize_t gbest_max = 1 + (input_bytes - 1) / sector_size; usize_t best_bits = 0; usize_t gbest_no; usize_t gpcnt; const uint8_t *p; IF_DEBUG2 (usize_t gcount[DJW_MAX_GROUPS]); /* Encode: sector size (5 bits) */ if ((ret = xd3_encode_bits (stream, & output, & bstate, DJW_SECTORSZ_BITS, (sector_size/DJW_SECTORSZ_MULT)-1))) { goto failure; } /* Dynamic allocation. */ if (gbest == NULL) { if ((gbest = (uint8_t*) xd3_alloc (stream, gbest_max, 1)) == NULL) { ret = ENOMEM; goto failure; } } if (gbest_mtf == NULL) { if ((gbest_mtf = (uint8_t*) xd3_alloc (stream, gbest_max, 1)) == NULL) { ret = ENOMEM; goto failure; } } /* OPT: Some of the inner loops can be optimized, as shown in bzip2 */ /* Generate initial code length tables. */ for (gp = 0; gp < groups; gp += 1) { djw_weight sum = 0; djw_weight goal = left / (groups - gp); IF_DEBUG2 (usize_t nz = 0); /* Due to the single-code granularity of this distribution, it may * be that we can't generate a distribution for each group. In that * case subtract one group and try again. If (inefficient), we're * testing group behavior, so don't mess things up. */ if (goal == 0 && !cfg->inefficient) { IF_DEBUG2 (DP(RINT "too many groups (%"W"u), dropping one\n", groups)); groups -= 1; goto regroup; } /* Sum == goal is possible when (cfg->inefficient)... */ while (sum < goal) { XD3_ASSERT (sym2 < ALPHABET_SIZE); IF_DEBUG2 (nz += real_freq[sym2] != 0); sum += real_freq[sym2++]; } IF_DEBUG2(DP(RINT "group %"W"u has symbols %"W"u..%"W"u (%"W"u non-zero) " "(%u/%"W"u = %.3f)\n", gp, sym1, sym2, nz, sum, input_bytes, sum / (double)input_bytes);); for (s = 0; s < ALPHABET_SIZE; s += 1) { evolve_clen[gp][s] = (s >= sym1 && s <= sym2) ? 1 : 16; } left -= sum; sym1 = sym2+1; } repeat: niter += 1; gbest_no = 0; memset (evolve_freq, 0, sizeof (evolve_freq[0]) * groups); IF_DEBUG2 (memset (gcount, 0, sizeof (gcount[0]) * groups)); /* For each input page (loop is irregular to allow non-pow2-size group * size. */ in = input; p = in->base; /* For each group-size sector. */ do { const uint8_t *p0 = p; xd3_output *in0 = in; usize_t best = 0; usize_t winner = 0; /* Select best group for each sector, update evolve_freq. */ memset (gcost, 0, sizeof (gcost[0]) * groups); /* For each byte in sector. */ for (gpcnt = 0; gpcnt < sector_size; gpcnt += 1) { /* For each group. */ for (gp = 0; gp < groups; gp += 1) { gcost[gp] += evolve_clen[gp][*p]; } /* Check end-of-input-page. */ # define GP_PAGE() \ if ((usize_t)(++p - in->base) == in->next) \ { \ in = in->next_page; \ if (in == NULL) { break; } \ p = in->base; \ } GP_PAGE (); } /* Find min cost group for this sector */ best = USIZE_T_MAX; for (gp = 0; gp < groups; gp += 1) { if (gcost[gp] < best) { best = gcost[gp]; winner = gp; } } XD3_ASSERT(gbest_no < gbest_max); gbest[gbest_no++] = winner; IF_DEBUG2 (gcount[winner] += 1); p = p0; in = in0; /* Update group frequencies. */ for (gpcnt = 0; gpcnt < sector_size; gpcnt += 1) { evolve_freq[winner][*p] += 1; GP_PAGE (); } } while (in != NULL); XD3_ASSERT (gbest_no == gbest_max); /* Recompute code lengths. */ output_bits = 0; for (gp = 0; gp < groups; gp += 1) { int i; uint8_t evolve_zero[ALPHABET_SIZE]; int any_zeros = 0; memset (evolve_zero, 0, sizeof (evolve_zero)); /* Cannot allow a zero clen when the real frequency is non-zero. * Note: this means we are going to encode a fairly long code for * these unused entries. An improvement would be to implement a * NOTUSED code for when these are actually zero, but this requires * another data structure (evolve_zero) since we don't know when * evolve_freq[i] == 0... Briefly tested, looked worse. */ for (i = 0; i < ALPHABET_SIZE; i += 1) { if (evolve_freq[gp][i] == 0 && real_freq[i] != 0) { evolve_freq[gp][i] = 1; evolve_zero[i] = 1; any_zeros = 1; } } output_bits += djw_build_prefix (evolve_freq[gp], evolve_clen[gp], ALPHABET_SIZE, DJW_MAX_CODELEN); /* The above faking of frequencies does not matter for the last * iteration, but we don't know when that is yet. However, it also * breaks the output_bits computation. Necessary for accuracy, and * for the (output_bits==0) assert after all bits are output. */ if (any_zeros) { IF_DEBUG2 (usize_t save_total = output_bits); for (i = 0; i < ALPHABET_SIZE; i += 1) { if (evolve_zero[i]) { output_bits -= evolve_clen[gp][i]; } } IF_DEBUG2 (DP(RINT "evolve_zero reduced %"W"u bits in group %"W"u\n", save_total - output_bits, gp)); } } IF_DEBUG2( DP(RINT "pass %"W"u total bits: %"W"u group uses: ", niter, output_bits); for (gp = 0; gp < groups; gp += 1) { DP(RINT "%"W"u ", gcount[gp]); } DP(RINT "\n"); ); /* End iteration. */ IF_DEBUG2 (if (niter > 1 && best_bits < output_bits) { DP(RINT "iteration lost %"W"u bits\n", output_bits - best_bits); }); if (niter == 1 || (niter < DJW_MAX_ITER && (best_bits - output_bits) >= DJW_MIN_IMPROVEMENT)) { best_bits = output_bits; goto repeat; } /* Efficiency check. */ if (output_bits + EFFICIENCY_BITS >= input_bits && ! cfg->inefficient) { goto nosecond; } IF_DEBUG2 (DP(RINT "djw compression: %"W"u -> %0.3f\n", input_bytes, output_bits / 8.0)); /* Encode: prefix */ { uint8_t prefix_symbol[DJW_MAX_GROUPS * ALPHABET_SIZE]; uint8_t prefix_mtfsym[DJW_MAX_GROUPS * ALPHABET_SIZE]; uint8_t prefix_repcnt[DJW_MAX_GROUPS * ALPHABET_SIZE]; djw_prefix prefix; prefix.symbol = prefix_symbol; prefix.mtfsym = prefix_mtfsym; prefix.repcnt = prefix_repcnt; djw_compute_multi_prefix (groups, evolve_clen, & prefix); if ((ret = djw_encode_prefix (stream, & output, & bstate, & prefix))) { goto failure; } } /* Encode: selector frequencies */ { /* DJW_MAX_GROUPS +2 is for RUN_0, RUN_1 symbols. */ djw_weight gbest_freq[DJW_MAX_GROUPS+2]; djw_prefix gbest_prefix; usize_t i; gbest_prefix.scount = gbest_no; gbest_prefix.symbol = gbest; gbest_prefix.mtfsym = gbest_mtf; djw_compute_selector_1_2 (& gbest_prefix, groups, gbest_freq); select_bits = djw_build_prefix (gbest_freq, gbest_clen, groups+1, DJW_MAX_GBCLEN); djw_build_codes (gbest_code, gbest_clen, groups+1, DJW_MAX_GBCLEN); for (i = 0; i < groups+1; i += 1) { if ((ret = xd3_encode_bits (stream, & output, & bstate, DJW_GBCLEN_BITS, gbest_clen[i]))) { goto failure; } } for (i = 0; i < gbest_prefix.mcount; i += 1) { usize_t gp_mtf = gbest_mtf[i]; usize_t gp_sel_bits = gbest_clen[gp_mtf]; usize_t gp_sel_code = gbest_code[gp_mtf]; XD3_ASSERT (gp_mtf < groups+1); if ((ret = xd3_encode_bits (stream, & output, & bstate, gp_sel_bits, gp_sel_code))) { goto failure; } IF_DEBUG (select_bits -= gp_sel_bits); } XD3_ASSERT (select_bits == 0); } /* Efficiency check. */ if (output_bits + select_bits + (8 * output->next) + EFFICIENCY_BITS >= input_bits && ! cfg->inefficient) { goto nosecond; } /* Encode: data */ { usize_t evolve_code[DJW_MAX_GROUPS][ALPHABET_SIZE]; usize_t sector = 0; /* Build code tables for each group. */ for (gp = 0; gp < groups; gp += 1) { djw_build_codes (evolve_code[gp], evolve_clen[gp], ALPHABET_SIZE, DJW_MAX_CODELEN); } /* Now loop over the input. */ in = input; p = in->base; do { /* For each sector. */ usize_t gp_best = gbest[sector]; usize_t *gp_codes = evolve_code[gp_best]; uint8_t *gp_clens = evolve_clen[gp_best]; XD3_ASSERT (sector < gbest_no); sector += 1; /* Encode the sector data. */ for (gpcnt = 0; gpcnt < sector_size; gpcnt += 1) { usize_t sym = *p; usize_t bits = gp_clens[sym]; usize_t code = gp_codes[sym]; IF_DEBUG (output_bits -= bits); if ((ret = xd3_encode_bits (stream, & output, & bstate, bits, code))) { goto failure; } GP_PAGE (); } } while (in != NULL); XD3_ASSERT (select_bits == 0); XD3_ASSERT (output_bits == 0); } } ret = xd3_flush_bits (stream, & output, & bstate); if (0) { nosecond: stream->msg = "secondary compression was inefficient"; ret = XD3_NOSECOND; } failure: xd3_free (stream, gbest); xd3_free (stream, gbest_mtf); return ret; } #endif /* XD3_ENCODER */ /*********************************************************************/ /* DECODE */ /*********************************************************************/ static void djw_build_decoder (xd3_stream *stream, usize_t asize, usize_t abs_max, const uint8_t *clen, uint8_t *inorder, usize_t *base, usize_t *limit, usize_t *min_clenp, usize_t *max_clenp) { usize_t i, l; const uint8_t *ci; usize_t nr_clen [DJW_TOTAL_CODES]; usize_t tmp_base[DJW_TOTAL_CODES]; usize_t min_clen; usize_t max_clen; /* Assumption: the two temporary arrays are large enough to hold abs_max. */ XD3_ASSERT (abs_max <= DJW_MAX_CODELEN); /* This looks something like the start of zlib's inftrees.c */ memset (nr_clen, 0, sizeof (nr_clen[0]) * (abs_max+1)); /* Count number of each code length */ i = asize; ci = clen; do { /* Caller _must_ check that values are in-range. Most of the time the * caller decodes a specific number of bits, which imply the max value, * and the other time the caller decodes a huffman value, which must be * in-range. Therefore, its an assertion and this function cannot * otherwise fail. */ XD3_ASSERT (*ci <= abs_max); nr_clen[*ci++]++; } while (--i != 0); /* Compute min, max. */ for (i = 1; i <= abs_max; i += 1) { if (nr_clen[i]) { break; } } min_clen = i; for (i = abs_max; i != 0; i -= 1) { if (nr_clen[i]) { break; } } max_clen = i; /* Fill the BASE, LIMIT table. */ tmp_base[min_clen] = 0; base[min_clen] = 0; limit[min_clen] = nr_clen[min_clen] - 1; for (i = min_clen + 1; i <= max_clen; i += 1) { usize_t last_limit = ((limit[i-1] + 1) << 1); tmp_base[i] = tmp_base[i-1] + nr_clen[i-1]; limit[i] = last_limit + nr_clen[i] - 1; base[i] = last_limit - tmp_base[i]; } /* Fill the inorder array, canonically ordered codes. */ ci = clen; for (i = 0; i < asize; i += 1) { if ((l = *ci++) != 0) { inorder[tmp_base[l]++] = i; } } *min_clenp = min_clen; *max_clenp = max_clen; } static inline int djw_decode_symbol (xd3_stream *stream, bit_state *bstate, const uint8_t **input, const uint8_t *input_end, const uint8_t *inorder, const usize_t *base, const usize_t *limit, usize_t min_clen, usize_t max_clen, usize_t *sym, usize_t max_sym) { usize_t code = 0; usize_t bits = 0; /* OPT: Supposedly a small lookup table improves speed here... */ /* Code outline is similar to xd3_decode_bits... */ if (bstate->cur_mask == 0x100) { goto next_byte; } for (;;) { do { if (bits == max_clen) { goto corrupt; } bits += 1; code = (code << 1); if (bstate->cur_byte & bstate->cur_mask) { code |= 1; } bstate->cur_mask <<= 1; if (bits >= min_clen && code <= limit[bits]) { goto done; } } while (bstate->cur_mask != 0x100); next_byte: if (*input == input_end) { stream->msg = "secondary decoder end of input"; return XD3_INVALID_INPUT; } bstate->cur_byte = *(*input)++; bstate->cur_mask = 1; } done: if (base[bits] <= code) { usize_t offset = code - base[bits]; if (offset <= max_sym) { IF_DEBUG2 (DP(RINT "(j) %"W"u ", code)); *sym = inorder[offset]; return 0; } } corrupt: stream->msg = "secondary decoder invalid code"; return XD3_INVALID_INPUT; } static int djw_decode_clclen (xd3_stream *stream, bit_state *bstate, const uint8_t **input, const uint8_t *input_end, uint8_t *cl_inorder, usize_t *cl_base, usize_t *cl_limit, usize_t *cl_minlen, usize_t *cl_maxlen, uint8_t *cl_mtf) { int ret; uint8_t cl_clen[DJW_TOTAL_CODES]; usize_t num_codes, value; usize_t i; /* How many extra code lengths to encode. */ if ((ret = xd3_decode_bits (stream, bstate, input, input_end, DJW_EXTRA_CODE_BITS, & num_codes))) { return ret; } num_codes += DJW_EXTRA_12OFFSET; /* Read num_codes. */ for (i = 0; i < num_codes; i += 1) { if ((ret = xd3_decode_bits (stream, bstate, input, input_end, DJW_CLCLEN_BITS, & value))) { return ret; } cl_clen[i] = value; } /* Set the rest to zero. */ for (; i < DJW_TOTAL_CODES; i += 1) { cl_clen[i] = 0; } /* No need to check for in-range clen values, because: */ XD3_ASSERT (1 << DJW_CLCLEN_BITS == DJW_MAX_CLCLEN + 1); /* Build the code-length decoder. */ djw_build_decoder (stream, DJW_TOTAL_CODES, DJW_MAX_CLCLEN, cl_clen, cl_inorder, cl_base, cl_limit, cl_minlen, cl_maxlen); /* Initialize the MTF state. */ djw_init_clen_mtf_1_2 (cl_mtf); return 0; } static inline int djw_decode_1_2 (xd3_stream *stream, bit_state *bstate, const uint8_t **input, const uint8_t *input_end, const uint8_t *inorder, const usize_t *base, const usize_t *limit, const usize_t *minlen, const usize_t *maxlen, uint8_t *mtfvals, usize_t elts, usize_t skip_offset, uint8_t *values) { usize_t n = 0, rep = 0, mtf = 0, s = 0; int ret; while (n < elts) { /* Special case inside generic code: CLEN only: If not the first group, * we already know the zero frequencies. */ if (skip_offset != 0 && n >= skip_offset && values[n-skip_offset] == 0) { values[n++] = 0; continue; } /* Repeat last symbol. */ if (rep != 0) { values[n++] = mtfvals[0]; rep -= 1; continue; } /* Symbol following last repeat code. */ if (mtf != 0) { usize_t sym = djw_update_mtf (mtfvals, mtf); values[n++] = sym; mtf = 0; continue; } /* Decode next symbol/repeat code. */ if ((ret = djw_decode_symbol (stream, bstate, input, input_end, inorder, base, limit, *minlen, *maxlen, & mtf, DJW_TOTAL_CODES))) { return ret; } if (mtf <= RUN_1) { /* Repetition. */ rep = ((mtf + 1) << s); mtf = 0; s += 1; } else { /* Remove the RUN_1 MTF offset. */ mtf -= 1; s = 0; } } /* If (rep != 0) there were too many codes received. */ if (rep != 0) { stream->msg = "secondary decoder invalid repeat code"; return XD3_INVALID_INPUT; } return 0; } static inline int djw_decode_prefix (xd3_stream *stream, bit_state *bstate, const uint8_t **input, const uint8_t *input_end, const uint8_t *cl_inorder, const usize_t *cl_base, const usize_t *cl_limit, const usize_t *cl_minlen, const usize_t *cl_maxlen, uint8_t *cl_mtf, usize_t groups, uint8_t *clen) { return djw_decode_1_2 (stream, bstate, input, input_end, cl_inorder, cl_base, cl_limit, cl_minlen, cl_maxlen, cl_mtf, ALPHABET_SIZE * groups, ALPHABET_SIZE, clen); } static int xd3_decode_huff (xd3_stream *stream, djw_stream *h, const uint8_t **input_pos, const uint8_t *const input_end, uint8_t **output_pos, const uint8_t *const output_end) { const uint8_t *input = *input_pos; uint8_t *output = *output_pos; bit_state bstate = BIT_STATE_DECODE_INIT; uint8_t *sel_group = NULL; usize_t groups, gp; usize_t output_bytes = (usize_t)(output_end - output); usize_t sector_size; usize_t sectors; int ret; /* Invalid input. */ if (output_bytes == 0) { stream->msg = "secondary decoder invalid input"; return XD3_INVALID_INPUT; } /* Decode: number of groups */ if ((ret = xd3_decode_bits (stream, & bstate, & input, input_end, DJW_GROUP_BITS, & groups))) { goto fail; } groups += 1; if (groups > 1) { /* Decode: group size */ if ((ret = xd3_decode_bits (stream, & bstate, & input, input_end, DJW_SECTORSZ_BITS, & sector_size))) { goto fail; } sector_size = (sector_size + 1) * DJW_SECTORSZ_MULT; } else { /* Default for groups == 1 */ sector_size = output_bytes; } sectors = 1 + (output_bytes - 1) / sector_size; /* TODO: In the case of groups==1, lots of extra stack space gets used here. * Could dynamically allocate this memory, which would help with excess * parameter passing, too. Passing too many parameters in this file, * simplify it! */ /* Outer scope: per-group symbol decoder tables. */ { uint8_t inorder[DJW_MAX_GROUPS][ALPHABET_SIZE]; usize_t base [DJW_MAX_GROUPS][DJW_TOTAL_CODES]; usize_t limit [DJW_MAX_GROUPS][DJW_TOTAL_CODES]; usize_t minlen [DJW_MAX_GROUPS]; usize_t maxlen [DJW_MAX_GROUPS]; /* Nested scope: code length decoder tables. */ { uint8_t clen [DJW_MAX_GROUPS][ALPHABET_SIZE]; uint8_t cl_inorder[DJW_TOTAL_CODES]; usize_t cl_base [DJW_MAX_CLCLEN+2]; usize_t cl_limit [DJW_MAX_CLCLEN+2]; uint8_t cl_mtf [DJW_TOTAL_CODES]; usize_t cl_minlen; usize_t cl_maxlen; /* Compute the code length decoder. */ if ((ret = djw_decode_clclen (stream, & bstate, & input, input_end, cl_inorder, cl_base, cl_limit, & cl_minlen, & cl_maxlen, cl_mtf))) { goto fail; } /* Now decode each group decoder. */ if ((ret = djw_decode_prefix (stream, & bstate, & input, input_end, cl_inorder, cl_base, cl_limit, & cl_minlen, & cl_maxlen, cl_mtf, groups, clen[0]))) { goto fail; } /* Prepare the actual decoding tables. */ for (gp = 0; gp < groups; gp += 1) { djw_build_decoder (stream, ALPHABET_SIZE, DJW_MAX_CODELEN, clen[gp], inorder[gp], base[gp], limit[gp], & minlen[gp], & maxlen[gp]); } } /* Decode: selector clens. */ { uint8_t sel_inorder[DJW_MAX_GROUPS+2]; usize_t sel_base [DJW_MAX_GBCLEN+2]; usize_t sel_limit [DJW_MAX_GBCLEN+2]; uint8_t sel_mtf [DJW_MAX_GROUPS+2]; usize_t sel_minlen; usize_t sel_maxlen; /* Setup group selection. */ if (groups > 1) { uint8_t sel_clen[DJW_MAX_GROUPS+1]; for (gp = 0; gp < groups+1; gp += 1) { usize_t value; if ((ret = xd3_decode_bits (stream, & bstate, & input, input_end, DJW_GBCLEN_BITS, & value))) { goto fail; } sel_clen[gp] = value; sel_mtf[gp] = gp; } if ((sel_group = (uint8_t*) xd3_alloc (stream, sectors, 1)) == NULL) { ret = ENOMEM; goto fail; } djw_build_decoder (stream, groups+1, DJW_MAX_GBCLEN, sel_clen, sel_inorder, sel_base, sel_limit, & sel_minlen, & sel_maxlen); if ((ret = djw_decode_1_2 (stream, & bstate, & input, input_end, sel_inorder, sel_base, sel_limit, & sel_minlen, & sel_maxlen, sel_mtf, sectors, 0, sel_group))) { goto fail; } } /* Now decode each sector. */ { /* Initialize for (groups==1) case. */ uint8_t *gp_inorder = inorder[0]; usize_t *gp_base = base[0]; usize_t *gp_limit = limit[0]; usize_t gp_minlen = minlen[0]; usize_t gp_maxlen = maxlen[0]; usize_t c; for (c = 0; c < sectors; c += 1) { usize_t n; if (groups >= 2) { gp = sel_group[c]; XD3_ASSERT (gp < groups); gp_inorder = inorder[gp]; gp_base = base[gp]; gp_limit = limit[gp]; gp_minlen = minlen[gp]; gp_maxlen = maxlen[gp]; } if (output_end < output) { stream->msg = "secondary decoder invalid input"; return XD3_INVALID_INPUT; } /* Decode next sector. */ n = xd3_min (sector_size, (usize_t) (output_end - output)); do { usize_t sym; if ((ret = djw_decode_symbol (stream, & bstate, & input, input_end, gp_inorder, gp_base, gp_limit, gp_minlen, gp_maxlen, & sym, ALPHABET_SIZE))) { goto fail; } *output++ = sym; } while (--n); } } } } IF_REGRESSION (if ((ret = xd3_test_clean_bits (stream, & bstate))) { goto fail; }); XD3_ASSERT (ret == 0); fail: xd3_free (stream, sel_group); (*input_pos) = input; (*output_pos) = output; return ret; } #endif ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-fgk.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. For demonstration purposes only. */ #ifndef _XDELTA3_FGK_h_ #define _XDELTA3_FGK_h_ /* An implementation of the FGK algorithm described by D.E. Knuth in * "Dynamic Huffman Coding" in Journal of Algorithms 6. */ /* A 32bit counter (fgk_weight) is used as the frequency counter for * nodes in the huffman tree. TODO: Need oto test for overflow and/or * reset stats. */ typedef struct _fgk_stream fgk_stream; typedef struct _fgk_node fgk_node; typedef struct _fgk_block fgk_block; typedef unsigned int fgk_bit; typedef uint32_t fgk_weight; struct _fgk_block { union { fgk_node *un_leader; fgk_block *un_freeptr; } un; }; #define block_leader un.un_leader #define block_freeptr un.un_freeptr /* The code can also support fixed huffman encoding/decoding. */ #define IS_ADAPTIVE 1 /* weight is a count of the number of times this element has been seen * in the current encoding/decoding. parent, right_child, and * left_child are pointers defining the tree structure. right and * left point to neighbors in an ordered sequence of weights. The * left child of a node is always guaranteed to have weight not * greater than its sibling. fgk_blockLeader points to the element * with the same weight as itself which is closest to the next * increasing weight block. */ struct _fgk_node { fgk_weight weight; fgk_node *parent; fgk_node *left_child; fgk_node *right_child; fgk_node *left; fgk_node *right; fgk_block *my_block; }; /* alphabet_size is the a count of the number of possible leaves in * the huffman tree. The number of total nodes counting internal * nodes is ((2 * alphabet_size) - 1). zero_freq_count is the number * of elements remaining which have zero frequency. zero_freq_exp and * zero_freq_rem satisfy the equation zero_freq_count = * 2^zero_freq_exp + zero_freq_rem. root_node is the root of the * tree, which is initialized to a node with zero frequency and * contains the 0th such element. free_node contains a pointer to the * next available fgk_node space. alphabet contains all the elements * and is indexed by N. remaining_zeros points to the head of the * list of zeros. */ struct _fgk_stream { usize_t alphabet_size; usize_t zero_freq_count; usize_t zero_freq_exp; usize_t zero_freq_rem; usize_t coded_depth; usize_t total_nodes; usize_t total_blocks; fgk_bit *coded_bits; fgk_block *block_array; fgk_block *free_block; fgk_node *decode_ptr; fgk_node *remaining_zeros; fgk_node *alphabet; fgk_node *root_node; fgk_node *free_node; }; /*********************************************************************/ /* Encoder */ /*********************************************************************/ static fgk_stream* fgk_alloc (xd3_stream *stream /*, usize_t alphabet_size */); static int fgk_init (xd3_stream *stream, fgk_stream *h, int is_encode); static usize_t fgk_encode_data (fgk_stream *h, usize_t n); static inline fgk_bit fgk_get_encoded_bit (fgk_stream *h); static int xd3_encode_fgk (xd3_stream *stream, fgk_stream *sec_stream, xd3_output *input, xd3_output *output, xd3_sec_cfg *cfg); /*********************************************************************/ /* Decoder */ /*********************************************************************/ static inline int fgk_decode_bit (fgk_stream *h, fgk_bit b); static usize_t fgk_decode_data (fgk_stream *h); static void fgk_destroy (xd3_stream *stream, fgk_stream *h); static int xd3_decode_fgk (xd3_stream *stream, fgk_stream *sec_stream, const uint8_t **input, const uint8_t *const input_end, uint8_t **output, const uint8_t *const output_end); /*********************************************************************/ /* Private */ /*********************************************************************/ static unsigned int fgk_find_nth_zero (fgk_stream *h, usize_t n); static usize_t fgk_nth_zero (fgk_stream *h, usize_t n); static void fgk_update_tree (fgk_stream *h, usize_t n); static fgk_node* fgk_increase_zero_weight (fgk_stream *h, usize_t n); static void fgk_eliminate_zero (fgk_stream* h, fgk_node *node); static void fgk_move_right (fgk_stream *h, fgk_node *node); static void fgk_promote (fgk_stream *h, fgk_node *node); static void fgk_init_node (fgk_node *node, usize_t i, usize_t size); static fgk_block* fgk_make_block (fgk_stream *h, fgk_node *l); static void fgk_free_block (fgk_stream *h, fgk_block *b); static void fgk_factor_remaining (fgk_stream *h); static inline void fgk_swap_ptrs (fgk_node **one, fgk_node **two); /*********************************************************************/ /* Basic Routines */ /*********************************************************************/ /* returns an initialized huffman encoder for an alphabet with the * given size. returns NULL if enough memory cannot be allocated */ static fgk_stream* fgk_alloc (xd3_stream *stream /*, int alphabet_size0 */) { usize_t alphabet_size0 = ALPHABET_SIZE; fgk_stream *h; if ((h = (fgk_stream*) xd3_alloc (stream, 1, sizeof (fgk_stream))) == NULL) { return NULL; } h->total_nodes = (2 * alphabet_size0) - 1; h->total_blocks = (2 * h->total_nodes); h->alphabet = (fgk_node*) xd3_alloc (stream, h->total_nodes, sizeof (fgk_node)); h->block_array = (fgk_block*) xd3_alloc (stream, h->total_blocks, sizeof (fgk_block)); h->coded_bits = (fgk_bit*) xd3_alloc (stream, alphabet_size0, sizeof (fgk_bit)); if (h->coded_bits == NULL || h->alphabet == NULL || h->block_array == NULL) { fgk_destroy (stream, h); return NULL; } h->alphabet_size = alphabet_size0; return h; } static int fgk_init (xd3_stream *stream, fgk_stream *h, int is_encode) { usize_t ui; ssize_t si; h->root_node = h->alphabet; h->decode_ptr = h->root_node; h->free_node = h->alphabet + h->alphabet_size; h->remaining_zeros = h->alphabet; h->coded_depth = 0; h->zero_freq_count = h->alphabet_size + 2; /* after two calls to factor_remaining, zero_freq_count == alphabet_size */ fgk_factor_remaining(h); /* set ZFE and ZFR */ fgk_factor_remaining(h); /* set ZFDB according to prev state */ IF_DEBUG (memset (h->alphabet, 0, sizeof (h->alphabet[0]) * h->total_nodes)); for (ui = 0; ui < h->total_blocks-1; ui += 1) { h->block_array[ui].block_freeptr = &h->block_array[ui + 1]; } h->block_array[h->total_blocks - 1].block_freeptr = NULL; h->free_block = h->block_array; /* Zero frequency nodes are inserted in the first alphabet_size * positions, with Value, weight, and a pointer to the next zero * frequency node. */ for (si = h->alphabet_size - 1; si >= 0; si -= 1) { fgk_init_node (h->alphabet + si, (usize_t) si, h->alphabet_size); } return 0; } static void fgk_swap_ptrs(fgk_node **one, fgk_node **two) { fgk_node *tmp = *one; *one = *two; *two = tmp; } /* Takes huffman transmitter h and n, the nth elt in the alphabet, and * returns the number of required to encode n. */ static usize_t fgk_encode_data (fgk_stream* h, usize_t n) { fgk_node *target_ptr = h->alphabet + n; XD3_ASSERT (n < h->alphabet_size); h->coded_depth = 0; /* First encode the binary representation of the nth remaining * zero frequency element in reverse such that bit, which will be * encoded from h->coded_depth down to 0 will arrive in increasing * order following the tree path. If there is only one left, it * is not neccesary to encode these bits. */ if (IS_ADAPTIVE && target_ptr->weight == 0) { usize_t where, shift; usize_t bits; where = fgk_find_nth_zero(h, n); shift = 1; if (h->zero_freq_rem == 0) { bits = h->zero_freq_exp; } else { bits = h->zero_freq_exp + 1; } while (bits > 0) { h->coded_bits[h->coded_depth++] = (shift & where) && 1; bits -= 1; shift <<= 1; }; target_ptr = h->remaining_zeros; } /* The path from root to node is filled into coded_bits in reverse so * that it is encoded in the right order */ while (target_ptr != h->root_node) { h->coded_bits[h->coded_depth++] = (target_ptr->parent->right_child == target_ptr); target_ptr = target_ptr->parent; } if (IS_ADAPTIVE) { fgk_update_tree(h, n); } return h->coded_depth; } /* Should be called as many times as fgk_encode_data returns. */ static inline fgk_bit fgk_get_encoded_bit (fgk_stream *h) { XD3_ASSERT (h->coded_depth > 0); return h->coded_bits[--h->coded_depth]; } /* This procedure updates the tree after alphabet[n] has been encoded * or decoded. */ static void fgk_update_tree (fgk_stream *h, usize_t n) { fgk_node *incr_node; if (h->alphabet[n].weight == 0) { incr_node = fgk_increase_zero_weight (h, n); } else { incr_node = h->alphabet + n; } while (incr_node != h->root_node) { fgk_move_right (h, incr_node); fgk_promote (h, incr_node); incr_node->weight += 1; /* incr the parent */ incr_node = incr_node->parent; /* repeat */ } h->root_node->weight += 1; } static void fgk_move_right (fgk_stream *h, fgk_node *move_fwd) { fgk_node **fwd_par_ptr, **back_par_ptr; fgk_node *move_back, *tmp; move_back = move_fwd->my_block->block_leader; if (move_fwd == move_back || move_fwd->parent == move_back || move_fwd->weight == 0) { return; } move_back->right->left = move_fwd; if (move_fwd->left) { move_fwd->left->right = move_back; } tmp = move_fwd->right; move_fwd->right = move_back->right; if (tmp == move_back) { move_back->right = move_fwd; } else { tmp->left = move_back; move_back->right = tmp; } tmp = move_back->left; move_back->left = move_fwd->left; if (tmp == move_fwd) { move_fwd->left = move_back; } else { tmp->right = move_fwd; move_fwd->left = tmp; } if (move_fwd->parent->right_child == move_fwd) { fwd_par_ptr = &move_fwd->parent->right_child; } else { fwd_par_ptr = &move_fwd->parent->left_child; } if (move_back->parent->right_child == move_back) { back_par_ptr = &move_back->parent->right_child; } else { back_par_ptr = &move_back->parent->left_child; } fgk_swap_ptrs (&move_fwd->parent, &move_back->parent); fgk_swap_ptrs (fwd_par_ptr, back_par_ptr); move_fwd->my_block->block_leader = move_fwd; } /* Shifts node, the leader of its block, into the next block. */ static void fgk_promote (fgk_stream *h, fgk_node *node) { fgk_node *my_left, *my_right; fgk_block *cur_block; my_right = node->right; my_left = node->left; cur_block = node->my_block; if (node->weight == 0) { return; } /* if left is right child, parent of remaining zeros case (?), means parent * has same weight as right child. */ if (my_left == node->right_child && node->left_child && node->left_child->weight == 0) { XD3_ASSERT (node->left_child == h->remaining_zeros); XD3_ASSERT (node->right_child->weight == (node->weight+1)); /* child weight was already incremented */ if (node->weight == (my_right->weight - 1) && my_right != h->root_node) { fgk_free_block (h, cur_block); node->my_block = my_right->my_block; my_left->my_block = my_right->my_block; } return; } if (my_left == h->remaining_zeros) { return; } /* true if not the leftmost node */ if (my_left->my_block == cur_block) { my_left->my_block->block_leader = my_left; } else { fgk_free_block (h, cur_block); } /* node->parent != my_right */ if ((node->weight == (my_right->weight - 1)) && (my_right != h->root_node)) { node->my_block = my_right->my_block; } else { node->my_block = fgk_make_block (h, node); } } /* When an element is seen the first time this is called to remove it from the list of * zero weight elements and introduce a new internal node to the tree. */ static fgk_node* fgk_increase_zero_weight (fgk_stream *h, usize_t n) { fgk_node *this_zero, *new_internal, *zero_ptr; this_zero = h->alphabet + n; if (h->zero_freq_count == 1) { /* this is the last one */ this_zero->right_child = NULL; if (this_zero->right->weight == 1) { this_zero->my_block = this_zero->right->my_block; } else { this_zero->my_block = fgk_make_block (h, this_zero); } h->remaining_zeros = NULL; return this_zero; } zero_ptr = h->remaining_zeros; new_internal = h->free_node++; new_internal->parent = zero_ptr->parent; new_internal->right = zero_ptr->right; new_internal->weight = 0; new_internal->right_child = this_zero; new_internal->left = this_zero; if (h->remaining_zeros == h->root_node) { /* This is the first element to be coded */ h->root_node = new_internal; this_zero->my_block = fgk_make_block (h, this_zero); new_internal->my_block = fgk_make_block (h, new_internal); } else { new_internal->right->left = new_internal; if (zero_ptr->parent->right_child == zero_ptr) { zero_ptr->parent->right_child = new_internal; } else { zero_ptr->parent->left_child = new_internal; } if (new_internal->right->weight == 1) { new_internal->my_block = new_internal->right->my_block; } else { new_internal->my_block = fgk_make_block (h, new_internal); } this_zero->my_block = new_internal->my_block; } fgk_eliminate_zero (h, this_zero); new_internal->left_child = h->remaining_zeros; this_zero->right = new_internal; this_zero->left = h->remaining_zeros; this_zero->parent = new_internal; this_zero->left_child = NULL; this_zero->right_child = NULL; h->remaining_zeros->parent = new_internal; h->remaining_zeros->right = this_zero; return this_zero; } /* When a zero frequency element is encoded, it is followed by the * binary representation of the index into the remaining elements. * Sets a cache to the element before it so that it can be removed * without calling this procedure again. */ static unsigned int fgk_find_nth_zero (fgk_stream* h, usize_t n) { fgk_node *target_ptr = h->alphabet + n; fgk_node *head_ptr = h->remaining_zeros; unsigned int idx = 0; while (target_ptr != head_ptr) { head_ptr = head_ptr->right_child; idx += 1; } return idx; } /* Splices node out of the list of zeros. */ static void fgk_eliminate_zero (fgk_stream* h, fgk_node *node) { if (h->zero_freq_count == 1) { return; } fgk_factor_remaining(h); if (node->left_child == NULL) { h->remaining_zeros = h->remaining_zeros->right_child; h->remaining_zeros->left_child = NULL; } else if (node->right_child == NULL) { node->left_child->right_child = NULL; } else { node->right_child->left_child = node->left_child; node->left_child->right_child = node->right_child; } } static void fgk_init_node (fgk_node *node, usize_t i, usize_t size) { if (i < size - 1) { node->right_child = node + 1; } else { node->right_child = NULL; } if (i >= 1) { node->left_child = node - 1; } else { node->left_child = NULL; } node->weight = 0; node->parent = NULL; node->right = NULL; node->left = NULL; node->my_block = NULL; } /* The data structure used is an array of blocks, which are unions of * free pointers and huffnode pointers. free blocks are a linked list * of free blocks, the front of which is h->free_block. The used * blocks are pointers to the head of each block. */ static fgk_block* fgk_make_block (fgk_stream *h, fgk_node* lead) { fgk_block *ret = h->free_block; XD3_ASSERT (h->free_block != NULL); h->free_block = h->free_block->block_freeptr; ret->block_leader = lead; return ret; } /* Restores the block to the front of the free list. */ static void fgk_free_block (fgk_stream *h, fgk_block *b) { b->block_freeptr = h->free_block; h->free_block = b; } /* sets zero_freq_count, zero_freq_rem, and zero_freq_exp to satsity * the equation given above. */ static void fgk_factor_remaining (fgk_stream *h) { unsigned int i; i = (--h->zero_freq_count); h->zero_freq_exp = 0; while (i > 1) { h->zero_freq_exp += 1; i >>= 1; } i = 1 << h->zero_freq_exp; h->zero_freq_rem = h->zero_freq_count - i; } /* receives a bit at a time and returns true when a complete code has * been received. */ static inline int fgk_decode_bit (fgk_stream* h, fgk_bit b) { XD3_ASSERT (b == 1 || b == 0); if (IS_ADAPTIVE && h->decode_ptr->weight == 0) { usize_t bitsreq; if (h->zero_freq_rem == 0) { bitsreq = h->zero_freq_exp; } else { bitsreq = h->zero_freq_exp + 1; } h->coded_bits[h->coded_depth] = b; h->coded_depth += 1; return h->coded_depth >= bitsreq; } else { if (b) { h->decode_ptr = h->decode_ptr->right_child; } else { h->decode_ptr = h->decode_ptr->left_child; } if (h->decode_ptr->left_child == NULL) { /* If the weight is non-zero, finished. */ if (h->decode_ptr->weight != 0) { return 1; } /* zero_freq_count is dropping to 0, finished. */ return h->zero_freq_count == 1; } else { return 0; } } } static usize_t fgk_nth_zero (fgk_stream* h, usize_t n) { fgk_node *ret = h->remaining_zeros; /* ERROR: if during this loop (ret->right_child == NULL) then the * encoder's zero count is too high. Could return an error code * now, but is probably unnecessary overhead, since the caller * should check integrity anyway. */ for (; n != 0 && ret->right_child != NULL; n -= 1) { ret = ret->right_child; } return (usize_t)(ret - h->alphabet); } /* once fgk_decode_bit returns 1, this retrieves an index into the * alphabet otherwise this returns 0, indicating more bits are * required. */ static usize_t fgk_decode_data (fgk_stream* h) { usize_t elt = (usize_t)(h->decode_ptr - h->alphabet); if (IS_ADAPTIVE && h->decode_ptr->weight == 0) { usize_t i = 0; usize_t n = 0; if (h->coded_depth > 0) { for (; i < h->coded_depth - 1; i += 1) { n |= h->coded_bits[i]; n <<= 1; } } n |= h->coded_bits[i]; elt = fgk_nth_zero(h, n); } h->coded_depth = 0; if (IS_ADAPTIVE) { fgk_update_tree(h, elt); } h->decode_ptr = h->root_node; return elt; } static void fgk_destroy (xd3_stream *stream, fgk_stream *h) { if (h != NULL) { xd3_free (stream, h->alphabet); xd3_free (stream, h->coded_bits); xd3_free (stream, h->block_array); xd3_free (stream, h); } } /*********************************************************************/ /* Xdelta */ /*********************************************************************/ static int xd3_encode_fgk (xd3_stream *stream, fgk_stream *sec_stream, xd3_output *input, xd3_output *output, xd3_sec_cfg *cfg) { bit_state bstate = BIT_STATE_ENCODE_INIT; xd3_output *cur_page; int ret; /* OPT: quit compression early if it looks bad */ for (cur_page = input; cur_page; cur_page = cur_page->next_page) { const uint8_t *inp = cur_page->base; const uint8_t *inp_max = inp + cur_page->next; while (inp < inp_max) { usize_t bits = fgk_encode_data (sec_stream, *inp++); while (bits--) { if ((ret = xd3_encode_bit (stream, & output, & bstate, fgk_get_encoded_bit (sec_stream)))) { return ret; } } } } return xd3_flush_bits (stream, & output, & bstate); } static int xd3_decode_fgk (xd3_stream *stream, fgk_stream *sec_stream, const uint8_t **input_pos, const uint8_t *const input_max, uint8_t **output_pos, const uint8_t *const output_max) { bit_state bstate; uint8_t *output = *output_pos; const uint8_t *input = *input_pos; for (;;) { if (input == input_max) { stream->msg = "secondary decoder end of input"; return XD3_INTERNAL; } bstate.cur_byte = *input++; for (bstate.cur_mask = 1; bstate.cur_mask != 0x100; bstate.cur_mask <<= 1) { int done = fgk_decode_bit (sec_stream, (bstate.cur_byte & bstate.cur_mask) ? 1U : 0U); if (! done) { continue; } *output++ = fgk_decode_data (sec_stream); if (output == output_max) { /* During regression testing: */ IF_REGRESSION ({ int ret; bstate.cur_mask <<= 1; if ((ret = xd3_test_clean_bits (stream, & bstate))) { return ret; } }); (*output_pos) = output; (*input_pos) = input; return 0; } } } } #endif /* _XDELTA3_FGK_ */ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-hash.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef _XDELTA3_HASH_H_ #define _XDELTA3_HASH_H_ #include "xdelta3-internal.h" #if XD3_DEBUG #define SMALL_HASH_DEBUG1(s,inp) \ uint32_t debug_state; \ uint32_t debug_hval = xd3_checksum_hash (& (s)->small_hash, \ xd3_scksum (&debug_state, (inp), (s)->smatcher.small_look)) #define SMALL_HASH_DEBUG2(s,inp) \ XD3_ASSERT (debug_hval == xd3_checksum_hash (& (s)->small_hash, \ xd3_scksum (&debug_state, (inp), (s)->smatcher.small_look))) #else #define SMALL_HASH_DEBUG1(s,inp) #define SMALL_HASH_DEBUG2(s,inp) #endif /* XD3_DEBUG */ #if UNALIGNED_OK #define UNALIGNED_READ32(dest,src) (*(dest)) = (*(uint32_t*)(src)) #else #define UNALIGNED_READ32(dest,src) memcpy((dest), (src), 4); #endif /* These are good hash multipliers for 32-bit and 64-bit LCGs: see * "linear congruential generators of different sizes and good lattice * structure" */ #define xd3_hash_multiplier32 1597334677U #define xd3_hash_multiplier64 1181783497276652981ULL /* TODO: small cksum is hard-coded for 4 bytes (i.e., "look" is unused) */ static inline uint32_t xd3_scksum (uint32_t *state, const uint8_t *base, const usize_t look) { UNALIGNED_READ32(state, base); return (*state) * xd3_hash_multiplier32; } static inline uint32_t xd3_small_cksum_update (uint32_t *state, const uint8_t *base, usize_t look) { UNALIGNED_READ32(state, base+1); return (*state) * xd3_hash_multiplier32; } #if XD3_ENCODER inline usize_t xd3_checksum_hash (const xd3_hash_cfg *cfg, const usize_t cksum) { return (cksum >> cfg->shift) ^ (cksum & cfg->mask); } #if SIZEOF_USIZE_T == 4 inline uint32_t xd3_large32_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look) { uint32_t h = 0; for (usize_t i = 0; i < look; i++) { h += base[i] * cfg->powers[i]; } return h; } inline uint32_t xd3_large32_cksum_update (xd3_hash_cfg *cfg, const uint32_t cksum, const uint8_t *base, const usize_t look) { return xd3_hash_multiplier32 * cksum - cfg->multiplier * base[0] + base[look]; } #endif #if SIZEOF_USIZE_T == 8 inline uint64_t xd3_large64_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look) { uint64_t h = 0; for (usize_t i = 0; i < look; i++) { h += base[i] * cfg->powers[i]; } return h; } inline uint64_t xd3_large64_cksum_update (xd3_hash_cfg *cfg, const uint64_t cksum, const uint8_t *base, const usize_t look) { return xd3_hash_multiplier64 * cksum - cfg->multiplier * base[0] + base[look]; } #endif static usize_t xd3_size_hashtable_bits (usize_t slots) { usize_t bits = (SIZEOF_USIZE_T * 8) - 1; usize_t i; for (i = 3; i <= bits; i += 1) { if (slots < (1U << i)) { /* Note: this is the compaction=1 setting measured in * checksum_test */ bits = i - 1; break; } } return bits; } int xd3_size_hashtable (xd3_stream *stream, usize_t slots, usize_t look, xd3_hash_cfg *cfg) { usize_t bits = xd3_size_hashtable_bits (slots); cfg->size = (1U << bits); cfg->mask = (cfg->size - 1); cfg->shift = (SIZEOF_USIZE_T * 8) - bits; cfg->look = look; if ((cfg->powers = (usize_t*) xd3_alloc0 (stream, look, sizeof (usize_t))) == NULL) { return ENOMEM; } cfg->powers[look-1] = 1; for (int i = look-2; i >= 0; i--) { cfg->powers[i] = cfg->powers[i+1] * xd3_hash_multiplier; } cfg->multiplier = cfg->powers[0] * xd3_hash_multiplier; return 0; } #endif /* XD3_ENCODER */ #endif /* _XDELTA3_HASH_H_ */ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-internal.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef XDELTA3_INTERNAL_H__ #define XDELTA3_INTERNAL_H__ #include "xdelta3.h" typedef struct _main_file main_file; typedef struct _main_extcomp main_extcomp; void main_buffree (void *ptr); void* main_bufalloc (size_t size); void main_file_init (main_file *xfile); int main_file_close (main_file *xfile); void main_file_cleanup (main_file *xfile); int main_file_isopen (main_file *xfile); int main_file_open (main_file *xfile, const char* name, int mode); int main_file_exists (main_file *xfile); int main_file_stat (main_file *xfile, xoff_t *size); int xd3_whole_append_window (xd3_stream *stream); int xd3_main_cmdline (int argc, char **argv); int main_file_read (main_file *ifile, uint8_t *buf, size_t size, size_t *nread, const char *msg); int main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg); void* main_malloc (size_t size); void main_free (void *ptr); int test_compare_files (const char* f0, const char* f1); usize_t xd3_bytes_on_srcblk (xd3_source *src, xoff_t blkno); xoff_t xd3_source_eof(const xd3_source *src); uint32_t xd3_large_cksum_update (uint32_t cksum, const uint8_t *base, usize_t look); int xd3_emit_byte (xd3_stream *stream, xd3_output **outputp, uint8_t code); int xd3_emit_bytes (xd3_stream *stream, xd3_output **outputp, const uint8_t *base, usize_t size); xd3_output* xd3_alloc_output (xd3_stream *stream, xd3_output *old_output); int xd3_encode_init_full (xd3_stream *stream); usize_t xd3_pow2_roundup (usize_t x); long get_millisecs_now (void); int xd3_process_stream (int is_encode, xd3_stream *stream, int (*func) (xd3_stream *), int close_stream, const uint8_t *input, usize_t input_size, uint8_t *output, usize_t *output_size, usize_t output_size_max); #if PYTHON_MODULE || SWIG_MODULE || NOT_MAIN int xd3_main_cmdline (int argc, char **argv); #endif #if REGRESSION_TEST int xd3_selftest (void); #endif /* main_file->mode values */ typedef enum { XO_READ = 0, XO_WRITE = 1 } main_file_modes; #ifndef XD3_POSIX #define XD3_POSIX 0 #endif #ifndef XD3_STDIO #define XD3_STDIO 0 #endif #ifndef XD3_WIN32 #define XD3_WIN32 0 #endif #ifndef NOT_MAIN #define NOT_MAIN 0 #endif /* If none are set, default to posix. */ #if (XD3_POSIX + XD3_STDIO + XD3_WIN32) == 0 #undef XD3_POSIX #define XD3_POSIX 1 #endif struct _main_file { #if XD3_WIN32 HANDLE file; #elif XD3_STDIO FILE *file; #elif XD3_POSIX int file; #endif int mode; /* XO_READ and XO_WRITE */ const char *filename; /* File name or /dev/stdin, * /dev/stdout, /dev/stderr. */ char *filename_copy; /* File name or /dev/stdin, * /dev/stdout, /dev/stderr. */ const char *realname; /* File name or /dev/stdin, * /dev/stdout, /dev/stderr. */ const main_extcomp *compressor; /* External compression struct. */ int flags; /* RD_FIRST, RD_NONEXTERNAL, ... */ xoff_t nread; /* for input position */ xoff_t nwrite; /* for output position */ uint8_t *snprintf_buf; /* internal snprintf() use */ int size_known; /* Set by main_set_souze */ xoff_t source_position; /* for avoiding seek in getblk_func */ int seek_failed; /* after seek fails once, try FIFO */ }; #ifndef UINT32_MAX #define UINT32_MAX 4294967295U #endif #ifndef UINT64_MAX #define UINT64_MAX 18446744073709551615ULL #endif #define UINT32_OFLOW_MASK 0xfe000000U #define UINT64_OFLOW_MASK 0xfe00000000000000ULL /********************************************************************* Integer encoder/decoder functions **********************************************************************/ /* Consume N bytes of input, only used by the decoder. */ #define DECODE_INPUT(n) \ do { \ stream->total_in += (xoff_t) (n); \ stream->avail_in -= (n); \ stream->next_in += (n); \ } while (0) #define DECODE_INTEGER_TYPE(PART,OFLOW) \ while (stream->avail_in != 0) \ { \ usize_t next = stream->next_in[0]; \ \ DECODE_INPUT(1); \ \ if (PART & OFLOW) \ { \ stream->msg = "overflow in decode_integer"; \ return XD3_INVALID_INPUT; \ } \ \ PART = (PART << 7) | (next & 127); \ \ if ((next & 128) == 0) \ { \ (*val) = PART; \ PART = 0; \ return 0; \ } \ } \ \ stream->msg = "further input required"; \ return XD3_INPUT #define READ_INTEGER_TYPE(TYPE, OFLOW) \ TYPE val = 0; \ const uint8_t *inp = (*inpp); \ usize_t next; \ \ do \ { \ if (inp == maxp) \ { \ stream->msg = "end-of-input in read_integer"; \ return XD3_INVALID_INPUT; \ } \ \ if (val & OFLOW) \ { \ stream->msg = "overflow in read_intger"; \ return XD3_INVALID_INPUT; \ } \ \ next = (*inp++); \ val = (val << 7) | (next & 127); \ } \ while (next & 128); \ \ (*valp) = val; \ (*inpp) = inp; \ \ return 0 #define EMIT_INTEGER_TYPE() \ /* max 64-bit value in base-7 encoding is 9.1 bytes */ \ uint8_t buf[10]; \ usize_t bufi = 10; \ \ /* This loop performs division and turns on all MSBs. */ \ do \ { \ buf[--bufi] = (num & 127) | 128; \ num >>= 7U; \ } \ while (num != 0); \ \ /* Turn off MSB of the last byte. */ \ buf[9] &= 127; \ \ return xd3_emit_bytes (stream, output, buf + bufi, 10 - bufi) #define IF_SIZEOF32(x) if (num < (1U << (7 * (x)))) return (x); #define IF_SIZEOF64(x) if (num < (1ULL << (7 * (x)))) return (x); #if USE_UINT32 static inline uint32_t xd3_sizeof_uint32_t (uint32_t num) { IF_SIZEOF32(1); IF_SIZEOF32(2); IF_SIZEOF32(3); IF_SIZEOF32(4); return 5; } static inline int xd3_decode_uint32_t (xd3_stream *stream, uint32_t *val) { DECODE_INTEGER_TYPE (stream->dec_32part, UINT32_OFLOW_MASK); } static inline int xd3_read_uint32_t (xd3_stream *stream, const uint8_t **inpp, const uint8_t *maxp, uint32_t *valp) { READ_INTEGER_TYPE (uint32_t, UINT32_OFLOW_MASK); } #if XD3_ENCODER static inline int xd3_emit_uint32_t (xd3_stream *stream, xd3_output **output, uint32_t num) { EMIT_INTEGER_TYPE (); } #endif /* XD3_ENCODER */ #endif /* USE_UINT32 */ #if USE_UINT64 static inline uint32_t xd3_sizeof_uint64_t (uint64_t num) { IF_SIZEOF64(1); IF_SIZEOF64(2); IF_SIZEOF64(3); IF_SIZEOF64(4); IF_SIZEOF64(5); IF_SIZEOF64(6); IF_SIZEOF64(7); IF_SIZEOF64(8); IF_SIZEOF64(9); return 10; } static inline int xd3_decode_uint64_t (xd3_stream *stream, uint64_t *val) { DECODE_INTEGER_TYPE (stream->dec_64part, UINT64_OFLOW_MASK); } static inline int xd3_read_uint64_t (xd3_stream *stream, const uint8_t **inpp, const uint8_t *maxp, uint64_t *valp) { READ_INTEGER_TYPE (uint64_t, UINT64_OFLOW_MASK); } #if XD3_ENCODER static inline int xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num) { EMIT_INTEGER_TYPE (); } #endif /* XD3_ENCODER */ #endif /* USE_UINT64 */ #if SIZEOF_USIZE_T == 4 #define USIZE_T_MAX UINT32_MAX #define USIZE_T_MAXBLKSZ 0x80000000U #define XD3_MAXSRCWINSZ (1ULL << 31) #define xd3_large_cksum xd3_large32_cksum #define xd3_large_cksum_update xd3_large32_cksum_update #define xd3_hash_multiplier xd3_hash_multiplier32 static inline uint32_t xd3_sizeof_size (usize_t num) { return xd3_sizeof_uint32_t (num); } static inline int xd3_decode_size (xd3_stream *stream, usize_t *valp) { return xd3_decode_uint32_t (stream, (uint32_t*) valp); } static inline int xd3_read_size (xd3_stream *stream, const uint8_t **inpp, const uint8_t *maxp, usize_t *valp) { return xd3_read_uint32_t (stream, inpp, maxp, (uint32_t*) valp); } #if XD3_ENCODER static inline int xd3_emit_size (xd3_stream *stream, xd3_output **output, usize_t num) { return xd3_emit_uint32_t (stream, output, num); } #endif #elif SIZEOF_USIZE_T == 8 #define USIZE_T_MAX UINT64_MAX #define USIZE_T_MAXBLKSZ 0x8000000000000000ULL #define XD3_MAXSRCWINSZ (1ULL << 61) #define xd3_large_cksum xd3_large64_cksum #define xd3_large_cksum_update xd3_large64_cksum_update #define xd3_hash_multiplier xd3_hash_multiplier64 static inline uint32_t xd3_sizeof_size (usize_t num) { return xd3_sizeof_uint64_t (num); } static inline int xd3_decode_size (xd3_stream *stream, usize_t *valp) { return xd3_decode_uint64_t (stream, (uint64_t*) valp); } static inline int xd3_read_size (xd3_stream *stream, const uint8_t **inpp, const uint8_t *maxp, usize_t *valp) { return xd3_read_uint64_t (stream, inpp, maxp, (uint64_t*) valp); } #if XD3_ENCODER static inline int xd3_emit_size (xd3_stream *stream, xd3_output **output, usize_t num) { return xd3_emit_uint64_t (stream, output, num); } #endif #endif /* SIZEOF_USIZE_T */ #if SIZEOF_XOFF_T == 4 #define XOFF_T_MAX UINT32_MAX static inline int xd3_decode_offset (xd3_stream *stream, xoff_t *valp) { return xd3_decode_uint32_t (stream, (uint32_t*) valp); } #if XD3_ENCODER static inline int xd3_emit_offset (xd3_stream *stream, xd3_output **output, xoff_t num) { return xd3_emit_uint32_t (stream, output, num); } #endif #elif SIZEOF_XOFF_T == 8 #define XOFF_T_MAX UINT64_MAX static inline int xd3_decode_offset (xd3_stream *stream, xoff_t *valp) { return xd3_decode_uint64_t (stream, (uint64_t*) valp); } #if XD3_ENCODER static inline int xd3_emit_offset (xd3_stream *stream, xd3_output **output, xoff_t num) { return xd3_emit_uint64_t (stream, output, num); } #endif #endif #define USIZE_T_OVERFLOW(a,b) ((USIZE_T_MAX - (usize_t) (a)) < (usize_t) (b)) #define XOFF_T_OVERFLOW(a,b) ((XOFF_T_MAX - (xoff_t) (a)) < (xoff_t) (b)) int xd3_size_hashtable (xd3_stream *stream, usize_t slots, usize_t look, xd3_hash_cfg *cfg); usize_t xd3_checksum_hash (const xd3_hash_cfg *cfg, const usize_t cksum); #if USE_UINT32 uint32_t xd3_large32_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look); uint32_t xd3_large32_cksum_update (xd3_hash_cfg *cfg, const uint32_t cksum, const uint8_t *base, const usize_t look); #endif /* USE_UINT32 */ #if USE_UINT64 uint64_t xd3_large64_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look); uint64_t xd3_large64_cksum_update (xd3_hash_cfg *cfg, const uint64_t cksum, const uint8_t *base, const usize_t look); #endif /* USE_UINT64 */ #define MAX_LRU_SIZE 32U #define XD3_MINSRCWINSZ (XD3_ALLOCSIZE * MAX_LRU_SIZE) #endif // XDELTA3_INTERNAL_H__ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-list.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef __XDELTA3_LIST__ #define __XDELTA3_LIST__ #define XD3_MAKELIST(LTYPE,ETYPE,LNAME) \ \ static inline ETYPE* \ LTYPE ## _entry (LTYPE* l) \ { \ return (ETYPE*) ((char*) l - (ptrdiff_t) &((ETYPE*) 0)->LNAME); \ } \ \ static inline void \ LTYPE ## _init (LTYPE *l) \ { \ l->next = l; \ l->prev = l; \ } \ \ static inline void \ LTYPE ## _add (LTYPE *prev, LTYPE *next, LTYPE *ins) \ { \ next->prev = ins; \ prev->next = ins; \ ins->next = next; \ ins->prev = prev; \ } \ \ static inline void \ LTYPE ## _push_back (LTYPE *l, ETYPE *i) \ { \ LTYPE ## _add (l->prev, l, & i->LNAME); \ } \ \ static inline void \ LTYPE ## _del (LTYPE *next, \ LTYPE *prev) \ { \ next->prev = prev; \ prev->next = next; \ } \ \ static inline ETYPE* \ LTYPE ## _remove (ETYPE *f) \ { \ LTYPE *i = f->LNAME.next; \ LTYPE ## _del (f->LNAME.next, f->LNAME.prev); \ return LTYPE ## _entry (i); \ } \ \ static inline ETYPE* \ LTYPE ## _pop_back (LTYPE *l) \ { \ LTYPE *i = l->prev; \ LTYPE ## _del (i->next, i->prev); \ return LTYPE ## _entry (i); \ } \ \ static inline ETYPE* \ LTYPE ## _pop_front (LTYPE *l) \ { \ LTYPE *i = l->next; \ LTYPE ## _del (i->next, i->prev); \ return LTYPE ## _entry (i); \ } \ \ static inline int \ LTYPE ## _empty (LTYPE *l) \ { \ return l == l->next; \ } \ \ static inline ETYPE* \ LTYPE ## _front (LTYPE *f) \ { \ return LTYPE ## _entry (f->next); \ } \ \ static inline ETYPE* \ LTYPE ## _back (LTYPE *f) \ { \ return LTYPE ## _entry (f->prev); \ } \ \ static inline int \ LTYPE ## _end (LTYPE *f, ETYPE *i) \ { \ return f == & i->LNAME; \ } \ \ static inline ETYPE* \ LTYPE ## _next (ETYPE *f) \ { \ return LTYPE ## _entry (f->LNAME.next); \ } \ \ static inline usize_t \ LTYPE ## _length (LTYPE *l) \ { \ LTYPE *p; \ usize_t c = 0; \ \ for (p = l->next; p != l; p = p->next) \ { \ c += 1; \ } \ \ return c; \ } \ \ typedef int unused_ ## LTYPE #endif ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-lzma.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Note: The use of the _easy_ decoder means we're not calling the * xd3_stream malloc hooks. TODO(jmacd) Fix if anyone cares. */ #ifndef _XDELTA3_LZMA_H_ #define _XDELTA3_LZMA_H_ #include typedef struct _xd3_lzma_stream xd3_lzma_stream; struct _xd3_lzma_stream { lzma_stream lzma; lzma_options_lzma options; lzma_filter filters[2]; }; static xd3_sec_stream* xd3_lzma_alloc (xd3_stream *stream) { return (xd3_sec_stream*) xd3_alloc (stream, sizeof (xd3_lzma_stream), 1); } static void xd3_lzma_destroy (xd3_stream *stream, xd3_sec_stream *sec_stream) { xd3_lzma_stream *ls = (xd3_lzma_stream*) sec_stream; lzma_end (&ls->lzma); xd3_free (stream, ls); } static int xd3_lzma_init (xd3_stream *stream, xd3_lzma_stream *sec, int is_encode) { int ret; memset (&sec->lzma, 0, sizeof(sec->lzma)); if (is_encode) { uint32_t preset = (stream->flags & XD3_COMPLEVEL_MASK) >> XD3_COMPLEVEL_SHIFT; if (lzma_lzma_preset(&sec->options, preset)) { stream->msg = "invalid lzma preset"; return XD3_INVALID; } sec->filters[0].id = LZMA_FILTER_LZMA2; sec->filters[0].options = &sec->options; sec->filters[1].id = LZMA_VLI_UNKNOWN; ret = lzma_stream_encoder (&sec->lzma, &sec->filters[0], LZMA_CHECK_NONE); } else { ret = lzma_stream_decoder (&sec->lzma, UINT64_MAX, LZMA_TELL_NO_CHECK); } if (ret != LZMA_OK) { stream->msg = "lzma stream init failed"; return XD3_INTERNAL; } return 0; } static int xd3_decode_lzma (xd3_stream *stream, xd3_lzma_stream *sec, const uint8_t **input_pos, const uint8_t *const input_end, uint8_t **output_pos, const uint8_t *const output_end) { uint8_t *output = *output_pos; const uint8_t *input = *input_pos; size_t avail_in = input_end - input; size_t avail_out = output_end - output; sec->lzma.avail_in = avail_in; sec->lzma.next_in = input; sec->lzma.avail_out = avail_out; sec->lzma.next_out = output; while (1) { int lret = lzma_code (&sec->lzma, LZMA_RUN); switch (lret) { case LZMA_NO_CHECK: case LZMA_OK: if (sec->lzma.avail_out == 0) { (*output_pos) = sec->lzma.next_out; (*input_pos) = sec->lzma.next_in; return 0; } break; default: stream->msg = "lzma decoding error"; return XD3_INTERNAL; } } } #if XD3_ENCODER static int xd3_encode_lzma (xd3_stream *stream, xd3_lzma_stream *sec, xd3_output *input, xd3_output *output, xd3_sec_cfg *cfg) { lzma_action action = LZMA_RUN; cfg->inefficient = 1; /* Can't skip windows */ sec->lzma.next_in = NULL; sec->lzma.avail_in = 0; sec->lzma.next_out = (output->base + output->next); sec->lzma.avail_out = (output->avail - output->next); while (1) { int lret; size_t nwrite; if (sec->lzma.avail_in == 0 && input != NULL) { sec->lzma.avail_in = input->next; sec->lzma.next_in = input->base; if ((input = input->next_page) == NULL) { action = LZMA_SYNC_FLUSH; } } lret = lzma_code (&sec->lzma, action); nwrite = (output->avail - output->next) - sec->lzma.avail_out; if (nwrite != 0) { output->next += nwrite; if (output->next == output->avail) { if ((output = xd3_alloc_output (stream, output)) == NULL) { return ENOMEM; } sec->lzma.next_out = output->base; sec->lzma.avail_out = output->avail; } } switch (lret) { case LZMA_OK: break; case LZMA_STREAM_END: return 0; default: stream->msg = "lzma encoding error"; return XD3_INTERNAL; } } return 0; } #endif /* XD3_ENCODER */ #endif /* _XDELTA3_LZMA_H_ */ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-main.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* This is all the extra stuff you need for convenience to users in a * command line application. It contains these major components: * * 1. VCDIFF tools 2. external compression support (this is * POSIX-specific). 3. a general read/write loop that handles all of * the Xdelta decode/encode/VCDIFF-print functions 4. command-line * interpreter 5. an Xdelta application header which stores default * filename, external compression settings 6. output/error printing * 7. basic file support and OS interface */ /* TODO list: 1. do exact gzip-like filename, stdout handling. make a * .vcdiff extension, refuse to encode to stdout without -cf, etc. * 2. Allow the user to add a comment string to the app header without * disturbing the default behavior. */ /* On error handling and printing: * * The xdelta library sets stream->msg to indicate what condition * caused an internal failure, but many failures originate here and * are printed here. The return convention is 0 for success, as * throughout Xdelta code, but special attention is required here for * the operating system calls with different error handling. See the * main_file_* routines. All errors in this file have a message * printed at the time of occurance. Since some of these calls occur * within calls to the library, the error may end up being printed * again with a more general error message. */ /*********************************************************************/ #include #ifndef XD3_POSIX #define XD3_POSIX 0 #endif #ifndef XD3_STDIO #define XD3_STDIO 0 #endif #ifndef XD3_WIN32 #define XD3_WIN32 0 #endif #ifndef NOT_MAIN #define NOT_MAIN 0 #endif /* Combines xd3_strerror() and strerror() */ const char* xd3_mainerror(int err_num); #include "xdelta3-internal.h" int xsnprintf_func (char *str, size_t n, const char *fmt, ...) { va_list a; int ret; va_start (a, fmt); ret = vsnprintf_func (str, n, fmt, a); va_end (a); if (ret < 0) { ret = n; } return ret; } /* Handle externally-compressed inputs. */ #ifndef EXTERNAL_COMPRESSION #define EXTERNAL_COMPRESSION 1 #endif #define PRINTHDR_SPECIAL -4378291 /* The number of soft-config variables. */ #define XD3_SOFTCFG_VARCNT 7 /* this is used as in XPR(NT XD3_LIB_ERRMSG (stream, ret)) to print an * error message from the library. */ #define XD3_LIB_ERRMSG(stream, ret) "%s: %s\n", \ xd3_errstring (stream), xd3_mainerror (ret) #if XD3_POSIX #include /* close, read, write... */ #include #include #endif #ifndef _WIN32 #include /* lots */ #include /* gettimeofday() */ #include /* stat() and fstat() */ #else #if defined(_MSC_VER) #define strtoll _strtoi64 #endif #include #include #ifndef WIFEXITED # define WIFEXITED(stat) (((*((int *) &(stat))) & 0xff) == 0) #endif #ifndef WEXITSTATUS # define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff) #endif #ifndef S_ISREG //# ifdef S_IFREG //# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) //# else # define S_ISREG(m) 1 //# endif #endif /* !S_ISREG */ // For standard input/output handles static STARTUPINFO winStartupInfo; #endif /********************************************************************** ENUMS and TYPES *********************************************************************/ /* These flags (mainly pertaining to main_read() operations) are set * in the main_file->flags variable. All are related to with external * decompression support. * * RD_FIRST causes the external decompression check when the input is * first read. * * RD_NONEXTERNAL disables external decompression for reading a * compressed input, in the case of Xdelta inputs. Note: Xdelta is * supported as an external compression type, which makes is the * reason for this flag. An example to justify this is: to create a * delta between two files that are VCDIFF-compressed. Two external * Xdelta decoders are run to supply decompressed source and target * inputs to the Xdelta encoder. */ typedef enum { RD_FIRST = (1 << 0), RD_NONEXTERNAL = (1 << 1), RD_DECOMPSET = (1 << 2), RD_MAININPUT = (1 << 3), } xd3_read_flags; /* Main commands. For example, CMD_PRINTHDR is the "xdelta printhdr" * command. */ typedef enum { CMD_NONE = 0, CMD_PRINTHDR, CMD_PRINTHDRS, CMD_PRINTDELTA, CMD_RECODE, CMD_MERGE_ARG, CMD_MERGE, #if XD3_ENCODER CMD_ENCODE, #endif CMD_DECODE, CMD_TEST, CMD_CONFIG, } xd3_cmd; #if XD3_ENCODER #define CMD_DEFAULT CMD_ENCODE #define IS_ENCODE(cmd) (cmd == CMD_ENCODE) #else #define CMD_DEFAULT CMD_DECODE #define IS_ENCODE(cmd) (0) #endif typedef struct _main_merge main_merge; typedef struct _main_merge_list main_merge_list; /* Various strings and magic values used to detect and call external * compression. See below for examples. */ struct _main_extcomp { const char *recomp_cmdname; const char *recomp_options; const char *decomp_cmdname; const char *decomp_options; const char *ident; const char *magic; usize_t magic_size; int flags; }; /* Merge state: */ struct _main_merge_list { main_merge_list *next; main_merge_list *prev; }; struct _main_merge { const char *filename; main_merge_list link; }; XD3_MAKELIST(main_merge_list,main_merge,link); /* TODO: really need to put options in a struct so that internal * callers can easily reset state. */ #define DEFAULT_VERBOSE 0 /* Program options: various command line flags and options. */ static int option_stdout = 0; static int option_force = 0; static int option_verbose = DEFAULT_VERBOSE; static int option_quiet = 0; static int option_use_appheader = 1; static uint8_t* option_appheader = NULL; static int option_use_secondary = 1; static const char* option_secondary = NULL; static int option_use_checksum = 1; static const char* option_smatch_config = NULL; static int option_no_compress = 0; static int option_no_output = 0; /* do not write output */ static const char *option_source_filename = NULL; static int option_level = XD3_DEFAULT_LEVEL; static usize_t option_iopt_size = XD3_DEFAULT_IOPT_SIZE; static usize_t option_winsize = XD3_DEFAULT_WINSIZE; /* option_srcwinsz is restricted to [16kB, 2GB] when usize_t is 32 bits. */ static xoff_t option_srcwinsz = XD3_DEFAULT_SRCWINSZ; static usize_t option_sprevsz = XD3_DEFAULT_SPREVSZ; /* These variables are supressed to avoid their use w/o support. main() warns * appropriately when external compression is not enabled. */ #if EXTERNAL_COMPRESSION static int num_subprocs = 0; static int option_force2 = 0; static int option_decompress_inputs = 1; static int option_recompress_outputs = 1; #endif /* This is for comparing "printdelta" output without attention to * copy-instruction modes. */ #if VCDIFF_TOOLS static int option_print_cpymode = 1; /* Note: see reset_defaults(). */ #endif /* Static variables */ IF_DEBUG(static int main_mallocs = 0;) static char* program_name = NULL; static uint8_t* appheader_used = NULL; static uint8_t* main_bdata = NULL; static usize_t main_bsize = 0; /* Hacks for VCDIFF tools, recode command. */ static int allow_fake_source = 0; /* recode_stream is used by both recode/merge for reading vcdiff inputs */ static xd3_stream *recode_stream = NULL; /* merge_stream is used by merge commands for storing the source encoding */ static xd3_stream *merge_stream = NULL; /* This array of compressor types is compiled even if EXTERNAL_COMPRESSION is * false just so the program knows the mapping of IDENT->NAME. */ static main_extcomp extcomp_types[] = { { "bzip2", "-c", "bzip2", "-dc", "B", "BZh", 3, 0 }, { "gzip", "-c", "gzip", "-dc", "G", "\037\213", 2, 0 }, { "compress", "-c", "uncompress", "-c", "Z", "\037\235", 2, 0 }, /* Xz is lzma with a magic number http://tukaani.org/xz/format.html */ { "xz", "-c", "xz", "-dc", "Y", "\xfd\x37\x7a\x58\x5a\x00", 2, 0 }, }; static int main_input (xd3_cmd cmd, main_file *ifile, main_file *ofile, main_file *sfile); static void main_get_appheader (xd3_stream *stream, main_file *ifile, main_file *output, main_file *sfile); static int main_getblk_func (xd3_stream *stream, xd3_source *source, xoff_t blkno); static int main_file_seek (main_file *xfile, xoff_t pos); static int main_read_primary_input (main_file *file, uint8_t *buf, size_t size, size_t *nread); static const char* main_format_bcnt (xoff_t r, shortbuf *buf); static int main_help (void); #if XD3_ENCODER static int xd3_merge_input_output (xd3_stream *stream, xd3_whole_state *source); #endif /* The code in xdelta3-blk.h is essentially part of this unit, see * comments there. */ #include "xdelta3-blkcache.h" static void (*xprintf_message_func)(const char*msg) = NULL; void xprintf (const char *fmt, ...) { char buf[1000]; va_list a; int size; va_start (a, fmt); size = vsnprintf_func (buf, 1000, fmt, a); va_end (a); if (size < 0) { size = sizeof(buf) - 1; buf[size] = 0; } if (xprintf_message_func != NULL) { xprintf_message_func(buf); } else { size_t ignore = fwrite(buf, 1, size, stderr); (void) ignore; } } static int main_version (void) { /* $Format: " XPR(NTR \"Xdelta version $Xdelta3Version$, Copyright (C) Joshua MacDonald\\n\");" $ */ XPR(NTR "Xdelta version 3.1.1, Copyright (C) Joshua MacDonald\n"); XPR(NTR "Xdelta comes with ABSOLUTELY NO WARRANTY.\n"); XPR(NTR "Licensed under the Apache License, Version 2.0\n"); XPR(NTR "See \"LICENSE\" for details.\n"); return EXIT_SUCCESS; } static int main_config (void) { main_version (); XPR(NTR "EXTERNAL_COMPRESSION=%d\n", EXTERNAL_COMPRESSION); XPR(NTR "REGRESSION_TEST=%d\n", REGRESSION_TEST); XPR(NTR "SECONDARY_DJW=%d\n", SECONDARY_DJW); XPR(NTR "SECONDARY_FGK=%d\n", SECONDARY_FGK); XPR(NTR "SECONDARY_LZMA=%d\n", SECONDARY_LZMA); XPR(NTR "UNALIGNED_OK=%d\n", UNALIGNED_OK); XPR(NTR "VCDIFF_TOOLS=%d\n", VCDIFF_TOOLS); XPR(NTR "XD3_ALLOCSIZE=%d\n", XD3_ALLOCSIZE); XPR(NTR "XD3_DEBUG=%d\n", XD3_DEBUG); XPR(NTR "XD3_ENCODER=%d\n", XD3_ENCODER); XPR(NTR "XD3_POSIX=%d\n", XD3_POSIX); XPR(NTR "XD3_STDIO=%d\n", XD3_STDIO); XPR(NTR "XD3_WIN32=%d\n", XD3_WIN32); XPR(NTR "XD3_USE_LARGEFILE64=%d\n", XD3_USE_LARGEFILE64); XPR(NTR "XD3_USE_LARGESIZET=%d\n", XD3_USE_LARGESIZET); XPR(NTR "XD3_DEFAULT_LEVEL=%d\n", XD3_DEFAULT_LEVEL); XPR(NTR "XD3_DEFAULT_IOPT_SIZE=%d\n", XD3_DEFAULT_IOPT_SIZE); XPR(NTR "XD3_DEFAULT_SPREVSZ=%d\n", XD3_DEFAULT_SPREVSZ); XPR(NTR "XD3_DEFAULT_SRCWINSZ=%d\n", XD3_DEFAULT_SRCWINSZ); XPR(NTR "XD3_DEFAULT_WINSIZE=%d\n", XD3_DEFAULT_WINSIZE); XPR(NTR "XD3_HARDMAXWINSIZE=%d\n", XD3_HARDMAXWINSIZE); XPR(NTR "sizeof(void*)=%d\n", (int)sizeof(void*)); XPR(NTR "sizeof(int)=%d\n", (int)sizeof(int)); XPR(NTR "sizeof(long)=%d\n", (int)sizeof(long)); XPR(NTR "sizeof(long long)=%d\n", (int)sizeof(long long)); XPR(NTR "sizeof(unsigned long long)=%d\n", (int)sizeof(unsigned long long)); XPR(NTR "sizeof(size_t)=%d\n", (int)sizeof(size_t)); XPR(NTR "sizeof(uint32_t)=%d\n", (int)sizeof(uint32_t)); XPR(NTR "sizeof(uint64_t)=%d\n", (int)sizeof(uint64_t)); XPR(NTR "sizeof(usize_t)=%d\n", (int)sizeof(usize_t)); XPR(NTR "sizeof(xoff_t)=%d\n", (int)sizeof(xoff_t)); return EXIT_SUCCESS; } static void reset_defaults(void) { option_stdout = 0; option_force = 0; option_verbose = DEFAULT_VERBOSE; option_quiet = 0; option_appheader = NULL; option_use_secondary = 1; option_secondary = NULL; option_smatch_config = NULL; option_no_compress = 0; option_no_output = 0; option_source_filename = NULL; program_name = NULL; appheader_used = NULL; main_bdata = NULL; main_bsize = 0; allow_fake_source = 0; option_smatch_config = NULL; main_lru_reset(); option_use_appheader = 1; option_use_checksum = 1; #if EXTERNAL_COMPRESSION option_force2 = 0; option_decompress_inputs = 1; option_recompress_outputs = 1; num_subprocs = 0; #endif #if VCDIFF_TOOLS option_print_cpymode = 1; #endif option_level = XD3_DEFAULT_LEVEL; option_iopt_size = XD3_DEFAULT_IOPT_SIZE; option_winsize = XD3_DEFAULT_WINSIZE; option_srcwinsz = XD3_DEFAULT_SRCWINSZ; option_sprevsz = XD3_DEFAULT_SPREVSZ; } static void* main_malloc1 (size_t size) { void* r = malloc (size); if (r == NULL) { XPR(NT "malloc: %s\n", xd3_mainerror (ENOMEM)); } return r; } void* main_bufalloc (size_t size) { #if XD3_WIN32 return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); #else return main_malloc1(size); #endif } void* main_malloc (size_t size) { void *r = main_malloc1 (size); if (r) { IF_DEBUG (main_mallocs += 1); } return r; } static void* main_alloc (void *opaque, size_t items, usize_t size) { return main_malloc1 (items * size); } static void main_free1 (void *opaque, void *ptr) { free (ptr); } void main_free (void *ptr) { if (ptr) { IF_DEBUG (main_mallocs -= 1); main_free1 (NULL, ptr); IF_DEBUG (XD3_ASSERT(main_mallocs >= 0)); } } void main_buffree (void *ptr) { #if XD3_WIN32 VirtualFree(ptr, 0, MEM_RELEASE); #else main_free1(NULL, ptr); #endif } /* This ensures that (ret = errno) always indicates failure, in case errno was * accidentally not set. If this prints there's a bug somewhere. */ static int get_errno (void) { #ifndef _WIN32 if (errno == 0) { XPR(NT "you found a bug: expected errno != 0\n"); errno = XD3_INTERNAL; } return errno; #else DWORD err_num = GetLastError(); if (err_num == NO_ERROR) { err_num = XD3_INTERNAL; } return err_num; #endif } const char* xd3_mainerror(int err_num) { #ifndef _WIN32 const char* x = xd3_strerror (err_num); if (x != NULL) { return x; } return strerror(err_num); #else static char err_buf[256]; const char* x = xd3_strerror (err_num); if (x != NULL) { return x; } memset (err_buf, 0, 256); FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err_num, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), err_buf, 256, NULL); if (err_buf[0] != 0 && err_buf[strlen(err_buf) - 1] == '\n') { err_buf[strlen(err_buf) - 1] = 0; } return err_buf; #endif } long get_millisecs_now (void) { #ifndef _WIN32 struct timeval tv; gettimeofday (& tv, NULL); return (tv.tv_sec) * 1000L + (tv.tv_usec) / 1000; #else SYSTEMTIME st; FILETIME ft; __int64 *pi = (__int64*)&ft; GetLocalTime(&st); SystemTimeToFileTime(&st, &ft); return (long)((*pi) / 10000); #endif } /* Always >= 1 millisec, right? */ static long get_millisecs_since (void) { static long last = 0; long now = get_millisecs_now(); long diff = now - last; last = now; return diff; } static const char* main_format_bcnt (xoff_t r, shortbuf *buf) { static const char* fmts[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" }; usize_t i; for (i = 0; i < SIZEOF_ARRAY(fmts) - 1; i += 1) { xoff_t new_r; if (r == 0) { short_sprintf (*buf, "0 %s", fmts[i]); return buf->buf; } if (r >= 1 && r < 10) { short_sprintf (*buf, "%.2f %s", (double) r, fmts[i]); return buf->buf; } if (r >= 10 && r < 100) { short_sprintf (*buf, "%.1f %s", (double) r, fmts[i]); return buf->buf; } if (r >= 100 && r < 1000) { short_sprintf (*buf, "%"Q"u %s", r, fmts[i]); return buf->buf; } new_r = r / 1024; if (new_r < 10) { short_sprintf (*buf, "%.2f %s", (double) r / 1024.0, fmts[i + 1]); return buf->buf; } if (new_r < 100) { short_sprintf (*buf, "%.1f %s", (double) r / 1024.0, fmts[i + 1]); return buf->buf; } r = new_r; } XD3_ASSERT (0); return ""; } static char* main_format_rate (xoff_t bytes, long millis, shortbuf *buf) { xoff_t r = (xoff_t)(1.0 * bytes / (1.0 * millis / 1000.0)); static shortbuf lbuf; main_format_bcnt (r, &lbuf); short_sprintf (*buf, "%s/s", lbuf.buf); return buf->buf; } static char* main_format_millis (long millis, shortbuf *buf) { if (millis < 1000) { short_sprintf (*buf, "%lu ms", millis); } else if (millis < 10000) { short_sprintf (*buf, "%.1f sec", millis / 1000.0); } else { short_sprintf (*buf, "%lu sec", millis / 1000L); } return buf->buf; } /* A safe version of strtol for xoff_t. */ static int main_strtoxoff (const char* s, xoff_t *xo, char which) { char *e; xoff_t x; XD3_ASSERT(s && *s != 0); { #if SIZEOF_XOFF_T == SIZEOF_UNSIGNED_LONG_LONG unsigned long long xx = strtoull (s, &e, 0); unsigned long long bad = ULLONG_MAX; #elif SIZEOF_XOFF_T <= SIZEOF_UNSIGNED_LONG unsigned long xx = strtoul (s, &e, 0); unsigned long long bad = ULONG_MAX; #else /* Something wrong with SIZEOF_XOFF_T, SIZEOF_UNSIGNED_LONG, etc. */ #error Bad configure script #endif if (xx == bad) { XPR(NT "-%c: negative integer: %s\n", which, s); return EXIT_FAILURE; } x = xx; } if (*e != 0) { XPR(NT "-%c: invalid integer: %s\n", which, s); return EXIT_FAILURE; } (*xo) = x; return 0; } static int main_atoux (const char* arg, xoff_t *xo, xoff_t low, xoff_t high, char which) { xoff_t x; int ret; if ((ret = main_strtoxoff (arg, & x, which))) { return ret; } if (x < low) { XPR(NT "-%c: minimum value: %"Q"u\n", which, low); return EXIT_FAILURE; } if (high != 0 && x > high) { XPR(NT "-%c: maximum value: %"Q"u\n", which, high); return EXIT_FAILURE; } (*xo) = x; return 0; } static int main_atou (const char* arg, usize_t *uo, usize_t low, usize_t high, char which) { int ret; xoff_t xo; if ((ret = main_atoux (arg, &xo, low, high, which))) { return ret; } *uo = (usize_t)xo; return 0; } /****************************************************************** FILE BASICS ******************************************************************/ /* With all the variation in file system-call semantics, arguments, * return values and error-handling for the POSIX and STDIO file APIs, * the insides of these functions make me sick, which is why these * wrappers exist. */ #define XOPEN_OPNAME (xfile->mode == XO_READ ? "read" : "write") #define XOPEN_STDIO (xfile->mode == XO_READ ? "rb" : "wb") #define XOPEN_POSIX (xfile->mode == XO_READ ? \ O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC) #define XOPEN_MODE (xfile->mode == XO_READ ? 0 : 0666) #define XF_ERROR(op, name, ret) \ do { if (!option_quiet) { XPR(NT "file %s failed: %s: %s: %s\n", (op), \ XOPEN_OPNAME, (name), xd3_mainerror (ret)); } } while (0) #if XD3_STDIO #define XFNO(f) fileno(f->file) #define XSTDOUT_XF(f) { (f)->file = stdout; (f)->filename = "/dev/stdout"; } #define XSTDIN_XF(f) { (f)->file = stdin; (f)->filename = "/dev/stdin"; } #elif XD3_POSIX #define XFNO(f) f->file #define XSTDOUT_XF(f) \ { (f)->file = STDOUT_FILENO; (f)->filename = "/dev/stdout"; } #define XSTDIN_XF(f) \ { (f)->file = STDIN_FILENO; (f)->filename = "/dev/stdin"; } #elif XD3_WIN32 #define XFNO(f) -1 #define XSTDOUT_XF(f) { \ (f)->file = GetStdHandle(STD_OUTPUT_HANDLE); \ (f)->filename = "(stdout)"; \ } #define XSTDIN_XF(f) { \ (f)->file = GetStdHandle(STD_INPUT_HANDLE); \ (f)->filename = "(stdin)"; \ } #endif void main_file_init (main_file *xfile) { memset (xfile, 0, sizeof (*xfile)); #if XD3_POSIX xfile->file = -1; #endif #if XD3_WIN32 xfile->file = INVALID_HANDLE_VALUE; #endif } int main_file_isopen (main_file *xfile) { #if XD3_STDIO return xfile->file != NULL; #elif XD3_POSIX return xfile->file != -1; #elif XD3_WIN32 return xfile->file != INVALID_HANDLE_VALUE; #endif } int main_file_close (main_file *xfile) { int ret = 0; if (! main_file_isopen (xfile)) { return 0; } #if XD3_STDIO ret = fclose (xfile->file); xfile->file = NULL; #elif XD3_POSIX ret = close (xfile->file); xfile->file = -1; #elif XD3_WIN32 if (!CloseHandle(xfile->file)) { ret = get_errno (); } xfile->file = INVALID_HANDLE_VALUE; #endif if (ret != 0) { XF_ERROR ("close", xfile->filename, ret = get_errno ()); } return ret; } void main_file_cleanup (main_file *xfile) { XD3_ASSERT (xfile != NULL); if (main_file_isopen (xfile)) { main_file_close (xfile); } if (xfile->snprintf_buf != NULL) { main_free(xfile->snprintf_buf); xfile->snprintf_buf = NULL; } if (xfile->filename_copy != NULL) { main_free(xfile->filename_copy); xfile->filename_copy = NULL; } } int main_file_open (main_file *xfile, const char* name, int mode) { int ret = 0; xfile->mode = mode; XD3_ASSERT (name != NULL); XD3_ASSERT (! main_file_isopen (xfile)); if (name[0] == 0) { XPR(NT "invalid file name: empty string\n"); return XD3_INVALID; } IF_DEBUG1(DP(RINT "[main] open source %s\n", name)); #if XD3_STDIO xfile->file = fopen (name, XOPEN_STDIO); ret = (xfile->file == NULL) ? get_errno () : 0; #elif XD3_POSIX /* TODO: Should retry this call if interrupted, similar to read/write */ if ((ret = open (name, XOPEN_POSIX, XOPEN_MODE)) < 0) { ret = get_errno (); } else { xfile->file = ret; ret = 0; } #elif XD3_WIN32 xfile->file = CreateFile(name, (mode == XO_READ) ? GENERIC_READ : GENERIC_WRITE, FILE_SHARE_READ, NULL, (mode == XO_READ) ? OPEN_EXISTING : (option_force ? CREATE_ALWAYS : CREATE_NEW), FILE_ATTRIBUTE_NORMAL, NULL); if (xfile->file == INVALID_HANDLE_VALUE) { ret = get_errno (); } #endif if (ret) { XF_ERROR ("open", name, ret); } else { xfile->realname = name; xfile->nread = 0; } return ret; } int main_file_stat (main_file *xfile, xoff_t *size) { int ret = 0; #if XD3_WIN32 if (GetFileType(xfile->file) != FILE_TYPE_DISK) { return -1; } # if (_WIN32_WINNT >= 0x0500) { LARGE_INTEGER li; if (GetFileSizeEx(xfile->file, &li) == 0) { return get_errno (); } *size = li.QuadPart; } # else { DWORD filesize = GetFileSize(xfile->file, NULL); if (filesize == INVALID_FILE_SIZE) { return get_errno () } *size = filesize; } # endif #else struct stat sbuf; if (fstat (XFNO (xfile), & sbuf) < 0) { ret = get_errno (); return ret; } if (! S_ISREG (sbuf.st_mode)) { return ESPIPE; } (*size) = sbuf.st_size; #endif return ret; } int main_file_exists (main_file *xfile) { struct stat sbuf; return stat (xfile->filename, & sbuf) == 0 && S_ISREG (sbuf.st_mode); } #if (XD3_POSIX || EXTERNAL_COMPRESSION) /* POSIX-generic code takes a function pointer to read() or write(). * This calls the function repeatedly until the buffer is full or EOF. * The NREAD parameter is not set for write, NULL is passed. Return * is signed, < 0 indicate errors, otherwise byte count. */ typedef int (xd3_posix_func) (int fd, uint8_t *buf, usize_t size); static int xd3_posix_io (int fd, uint8_t *buf, size_t size, xd3_posix_func *func, size_t *nread) { int ret; size_t nproc = 0; while (nproc < size) { size_t tryread = xd3_min(size - nproc, 1U << 30); ssize_t result = (*func) (fd, buf + nproc, tryread); if (result < 0) { ret = get_errno (); if (ret != EAGAIN && ret != EINTR) { return ret; } continue; } if (nread != NULL && result == 0) { break; } nproc += result; } if (nread != NULL) { (*nread) = nproc; } return 0; } #endif #if XD3_WIN32 static int xd3_win32_io (HANDLE file, uint8_t *buf, size_t size, int is_read, size_t *nread) { int ret = 0; size_t nproc = 0; while (nproc < size) { DWORD nproc2 = 0; /* hmm */ DWORD nremain = size - nproc; if ((is_read ? ReadFile (file, buf + nproc, nremain, &nproc2, NULL) : WriteFile (file, buf + nproc, nremain, &nproc2, NULL)) == 0) { ret = get_errno(); if (ret != ERROR_HANDLE_EOF && ret != ERROR_BROKEN_PIPE) { return ret; } /* By falling through here, we'll break this loop in the * read case in case of eof or broken pipe. */ } nproc += nproc2; if (nread != NULL && nproc2 == 0) { break; } } if (nread != NULL) { (*nread) = nproc; } return 0; } #endif /* POSIX is unbuffered, while STDIO is buffered. main_file_read() * should always be called on blocks. */ int main_file_read (main_file *ifile, uint8_t *buf, size_t size, size_t *nread, const char *msg) { int ret = 0; IF_DEBUG1(DP(RINT "[main] read %s up to %"Z"u\n", ifile->filename, size)); #if XD3_STDIO size_t result; result = fread (buf, 1, size, ifile->file); if (result < size && ferror (ifile->file)) { ret = get_errno (); } else { *nread = result; } #elif XD3_POSIX ret = xd3_posix_io (ifile->file, buf, size, (xd3_posix_func*) &read, nread); #elif XD3_WIN32 ret = xd3_win32_io (ifile->file, buf, size, 1 /* is_read */, nread); #endif if (ret) { XPR(NT "%s: %s: %s\n", msg, ifile->filename, xd3_mainerror (ret)); } else { if (option_verbose > 4) { XPR(NT "read %s: %"Z"u bytes\n", ifile->filename, (*nread)); } ifile->nread += (*nread); } return ret; } int main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg) { int ret = 0; IF_DEBUG1(DP(RINT "[main] write %"W"u\n bytes", size)); #if XD3_STDIO usize_t result; result = fwrite (buf, 1, size, ofile->file); if (result != size) { ret = get_errno (); } #elif XD3_POSIX ret = xd3_posix_io (ofile->file, buf, size, (xd3_posix_func*) &write, NULL); #elif XD3_WIN32 ret = xd3_win32_io (ofile->file, buf, size, 0, NULL); #endif if (ret) { XPR(NT "%s: %s: %s\n", msg, ofile->filename, xd3_mainerror (ret)); } else { if (option_verbose > 5) { XPR(NT "write %s: %"W"u bytes\n", ofile->filename, size); } ofile->nwrite += size; } return ret; } static int main_file_seek (main_file *xfile, xoff_t pos) { int ret = 0; #if XD3_STDIO if (fseek (xfile->file, pos, SEEK_SET) != 0) { ret = get_errno (); } #elif XD3_POSIX if ((xoff_t) lseek (xfile->file, pos, SEEK_SET) != pos) { ret = get_errno (); } #elif XD3_WIN32 # if (_WIN32_WINNT >= 0x0500) LARGE_INTEGER move, out; move.QuadPart = pos; if (SetFilePointerEx(xfile->file, move, &out, FILE_BEGIN) == 0) { ret = get_errno (); } # else if (SetFilePointer(xfile->file, (LONG)pos, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ret = get_errno (); } # endif #endif return ret; } /* This function simply writes the stream output buffer, if there is * any, for encode, decode and recode commands. (The VCDIFF tools use * main_print_func()). */ static int main_write_output (xd3_stream* stream, main_file *ofile) { int ret; IF_DEBUG1(DP(RINT "[main] write(%s) %"W"u\n bytes", ofile->filename, stream->avail_out)); if (option_no_output) { return 0; } if (stream->avail_out > 0 && (ret = main_file_write (ofile, stream->next_out, stream->avail_out, "write failed"))) { return ret; } return 0; } static int main_set_secondary_flags (xd3_config *config) { int ret; if (!option_use_secondary) { return 0; } if (option_secondary == NULL) { /* Set a default secondary compressor if LZMA is built in, otherwise * default to no secondary compressor. */ if (SECONDARY_LZMA) { config->flags |= XD3_SEC_LZMA; } } else { if (strcmp (option_secondary, "lzma") == 0 && SECONDARY_LZMA) { config->flags |= XD3_SEC_LZMA; } else if (strcmp (option_secondary, "fgk") == 0 && SECONDARY_FGK) { config->flags |= XD3_SEC_FGK; } else if (strncmp (option_secondary, "djw", 3) == 0 && SECONDARY_DJW) { usize_t level = XD3_DEFAULT_SECONDARY_LEVEL; config->flags |= XD3_SEC_DJW; if (strlen (option_secondary) > 3 && (ret = main_atou (option_secondary + 3, &level, 0, 9, 'S')) != 0 && !option_quiet) { return XD3_INVALID; } /* XD3_SEC_NOXXXX flags disable secondary compression on * a per-section basis. For djw, ngroups=1 indicates * minimum work, ngroups=0 uses default settings, which * is > 1 groups by default. */ if (level < 1) { config->flags |= XD3_SEC_NODATA; } if (level < 7) { config->sec_data.ngroups = 1; } else { config->sec_data.ngroups = 0; } if (level < 3) { config->flags |= XD3_SEC_NOINST; } if (level < 8) { config->sec_inst.ngroups = 1; } else { config->sec_inst.ngroups = 0; } if (level < 5) { config->flags |= XD3_SEC_NOADDR; } if (level < 9) { config->sec_addr.ngroups = 1; } else { config->sec_addr.ngroups = 0; } } else if (*option_secondary == 0 || strcmp (option_secondary, "none") == 0) { } else { if (!option_quiet) { XPR(NT "unrecognized or not compiled secondary compressor: %s\n", option_secondary); } return XD3_INVALID; } } if (option_verbose) { XPR(NT "secondary compression: %s\n", (config->flags | XD3_SEC_LZMA) ? "lzma" : ((config->flags | XD3_SEC_FGK) ? "fgk" : ((config->flags | XD3_SEC_DJW) ? "djw" : "none"))); } return 0; } /****************************************************************** VCDIFF TOOLS *****************************************************************/ #include "xdelta3-merge.h" #if VCDIFF_TOOLS /* The following macros let VCDIFF print using main_file_write(), * for example: * * VC(UT "trying to be portable: %d\n", x)VE; */ #define SNPRINTF_BUFSIZE 1024 #define VC do { if (((ret = xsnprintf_func #define UT (char*)xfile->snprintf_buf, SNPRINTF_BUFSIZE, #define VE ) >= SNPRINTF_BUFSIZE \ && (ret = main_print_overflow(ret)) != 0) \ || (ret = main_file_write(xfile, xfile->snprintf_buf, \ (usize_t)ret, "print")) != 0) \ { return ret; } } while (0) static int main_print_overflow (int x) { XPR(NT "internal print buffer overflow: %d bytes\n", x); return XD3_INTERNAL; } /* This function prints a single VCDIFF window. */ static int main_print_window (xd3_stream* stream, main_file *xfile) { int ret; usize_t size = 0; VC(UT " Offset Code Type1 Size1 @Addr1 + Type2 Size2 @Addr2\n")VE; while (stream->inst_sect.buf < stream->inst_sect.buf_max) { usize_t code = stream->inst_sect.buf[0]; const uint8_t *addr_before = stream->addr_sect.buf; const uint8_t *inst_before = stream->inst_sect.buf; usize_t addr_bytes; usize_t inst_bytes; usize_t size_before = size; if ((ret = xd3_decode_instruction (stream))) { XPR(NT "instruction decode error at %"Q"u: %s\n", stream->dec_winstart + size, stream->msg); return ret; } addr_bytes = (usize_t)(stream->addr_sect.buf - addr_before); inst_bytes = (usize_t)(stream->inst_sect.buf - inst_before); VC(UT " %06"Q"u %03"W"u %s %6"W"u", stream->dec_winstart + size, option_print_cpymode ? code : 0, xd3_rtype_to_string ((xd3_rtype) stream->dec_current1.type, option_print_cpymode), stream->dec_current1.size)VE; if (stream->dec_current1.type != XD3_NOOP) { if (stream->dec_current1.type >= XD3_CPY) { if (stream->dec_current1.addr >= stream->dec_cpylen) { VC(UT " T@%-6"W"u", stream->dec_current1.addr - stream->dec_cpylen)VE; } else { VC(UT " S@%-6"Q"u", stream->dec_cpyoff + stream->dec_current1.addr)VE; } } else { VC(UT " ")VE; } size += stream->dec_current1.size; } if (stream->dec_current2.type != XD3_NOOP) { VC(UT " %s %6"W"u", xd3_rtype_to_string ((xd3_rtype) stream->dec_current2.type, option_print_cpymode), stream->dec_current2.size)VE; if (stream->dec_current2.type >= XD3_CPY) { if (stream->dec_current2.addr >= stream->dec_cpylen) { VC(UT " T@%-6"W"u", stream->dec_current2.addr - stream->dec_cpylen)VE; } else { VC(UT " S@%-6"Q"u", stream->dec_cpyoff + stream->dec_current2.addr)VE; } } size += stream->dec_current2.size; } VC(UT "\n")VE; if (option_verbose && addr_bytes + inst_bytes >= (size - size_before) && (stream->dec_current1.type >= XD3_CPY || stream->dec_current2.type >= XD3_CPY)) { VC(UT " %06"Q"u (inefficiency) %"W"u encoded as %"W"u bytes\n", stream->dec_winstart + size_before, size - size_before, addr_bytes + inst_bytes)VE; } } if (stream->dec_tgtlen != size && (stream->flags & XD3_SKIP_WINDOW) == 0) { XPR(NT "target window size inconsistency"); return XD3_INTERNAL; } if (stream->dec_position != stream->dec_maxpos) { XPR(NT "target window position inconsistency"); return XD3_INTERNAL; } if (stream->addr_sect.buf != stream->addr_sect.buf_max) { XPR(NT "address section inconsistency"); return XD3_INTERNAL; } return 0; } static int main_print_vcdiff_file (main_file *xfile, main_file *file, const char *type) { int ret; /* Used by above macros */ if (file->filename) { VC(UT "XDELTA filename (%s): %s\n", type, file->filename)VE; } if (file->compressor) { VC(UT "XDELTA ext comp (%s): %s\n", type, file->compressor->recomp_cmdname)VE; } return 0; } /* This function prints a VCDIFF input, mainly for debugging purposes. */ static int main_print_func (xd3_stream* stream, main_file *xfile) { int ret; if (option_no_output) { return 0; } if (xfile->snprintf_buf == NULL) { if ((xfile->snprintf_buf = (uint8_t*)main_malloc(SNPRINTF_BUFSIZE)) == NULL) { return ENOMEM; } } if (stream->dec_winstart == 0) { VC(UT "VCDIFF version: 0\n")VE; VC(UT "VCDIFF header size: %"W"u\n", stream->dec_hdrsize)VE; VC(UT "VCDIFF header indicator: ")VE; if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0) VC(UT "VCD_SECONDARY ")VE; if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) VC(UT "VCD_CODETABLE ")VE; if ((stream->dec_hdr_ind & VCD_APPHEADER) != 0) VC(UT "VCD_APPHEADER ")VE; if (stream->dec_hdr_ind == 0) VC(UT "none")VE; VC(UT "\n")VE; IF_SEC(VC(UT "VCDIFF secondary compressor: %s\n", stream->sec_type ? stream->sec_type->name : "none")VE); IF_NSEC(VC(UT "VCDIFF secondary compressor: unsupported\n")VE); if (stream->dec_hdr_ind & VCD_APPHEADER) { uint8_t *apphead; usize_t appheadsz; ret = xd3_get_appheader (stream, & apphead, & appheadsz); if (ret == 0 && appheadsz > 0) { int sq = option_quiet; main_file i, o, s; XD3_ASSERT (apphead != NULL); VC(UT "VCDIFF application header: ")VE; if ((ret = main_file_write (xfile, apphead, appheadsz, "print")) != 0) { return ret; } VC(UT "\n")VE; main_file_init (& i); main_file_init (& o); main_file_init (& s); option_quiet = 1; main_get_appheader (stream, &i, & o, & s); option_quiet = sq; if ((ret = main_print_vcdiff_file (xfile, & o, "output"))) { return ret; } if ((ret = main_print_vcdiff_file (xfile, & s, "source"))) { return ret; } main_file_cleanup (& i); main_file_cleanup (& o); main_file_cleanup (& s); } } } else { VC(UT "\n")VE; } VC(UT "VCDIFF window number: %"Q"u\n", stream->current_window)VE; VC(UT "VCDIFF window indicator: ")VE; if ((stream->dec_win_ind & VCD_SOURCE) != 0) VC(UT "VCD_SOURCE ")VE; if ((stream->dec_win_ind & VCD_TARGET) != 0) VC(UT "VCD_TARGET ")VE; if ((stream->dec_win_ind & VCD_ADLER32) != 0) VC(UT "VCD_ADLER32 ")VE; if (stream->dec_win_ind == 0) VC(UT "none")VE; VC(UT "\n")VE; if ((stream->dec_win_ind & VCD_ADLER32) != 0) { VC(UT "VCDIFF adler32 checksum: %08X\n", stream->dec_adler32)VE; } if (stream->dec_del_ind != 0) { VC(UT "VCDIFF delta indicator: ")VE; if ((stream->dec_del_ind & VCD_DATACOMP) != 0) VC(UT "VCD_DATACOMP ")VE; if ((stream->dec_del_ind & VCD_INSTCOMP) != 0) VC(UT "VCD_INSTCOMP ")VE; if ((stream->dec_del_ind & VCD_ADDRCOMP) != 0) VC(UT "VCD_ADDRCOMP ")VE; if (stream->dec_del_ind == 0) VC(UT "none")VE; VC(UT "\n")VE; } if (stream->dec_winstart != 0) { VC(UT "VCDIFF window at offset: %"Q"u\n", stream->dec_winstart)VE; } if (SRCORTGT (stream->dec_win_ind)) { VC(UT "VCDIFF copy window length: %"W"u\n", stream->dec_cpylen)VE; VC(UT "VCDIFF copy window offset: %"Q"u\n", stream->dec_cpyoff)VE; } VC(UT "VCDIFF delta encoding length: %"W"u\n", (usize_t)stream->dec_enclen)VE; VC(UT "VCDIFF target window length: %"W"u\n", (usize_t)stream->dec_tgtlen)VE; VC(UT "VCDIFF data section length: %"W"u\n", (usize_t)stream->data_sect.size)VE; VC(UT "VCDIFF inst section length: %"W"u\n", (usize_t)stream->inst_sect.size)VE; VC(UT "VCDIFF addr section length: %"W"u\n", (usize_t)stream->addr_sect.size)VE; ret = 0; if ((stream->flags & XD3_JUST_HDR) != 0) { /* Print a header -- finished! */ ret = PRINTHDR_SPECIAL; } else if ((stream->flags & XD3_SKIP_WINDOW) == 0) { ret = main_print_window (stream, xfile); } return ret; } static int main_recode_copy (xd3_stream* stream, xd3_output* output, xd3_desect* input) { int ret; XD3_ASSERT(output != NULL); XD3_ASSERT(output->next_page == NULL); if ((ret = xd3_decode_allocate (recode_stream, input->size, &output->base, &output->avail))) { XPR(NT XD3_LIB_ERRMSG (stream, ret)); return ret; } memcpy (output->base, /* Note: decoder advances buf, so get base of buffer with * buf_max - size */ input->buf_max - input->size, input->size); output->next = input->size; return 0; } // Re-encode one window static int main_recode_func (xd3_stream* stream, main_file *ofile) { int ret; xd3_source decode_source; XD3_ASSERT(stream->dec_state == DEC_FINISH); XD3_ASSERT(recode_stream->enc_state == ENC_INIT || recode_stream->enc_state == ENC_INPUT); // Copy partial decoder output to partial encoder inputs if ((ret = main_recode_copy (recode_stream, DATA_HEAD(recode_stream), &stream->data_sect)) || (ret = main_recode_copy (recode_stream, INST_HEAD(recode_stream), &stream->inst_sect)) || (ret = main_recode_copy (recode_stream, ADDR_HEAD(recode_stream), &stream->addr_sect))) { return ret; } // This jumps to xd3_emit_hdr() recode_stream->enc_state = ENC_FLUSH; recode_stream->avail_in = stream->dec_tgtlen; if (SRCORTGT (stream->dec_win_ind)) { recode_stream->src = & decode_source; decode_source.srclen = stream->dec_cpylen; decode_source.srcbase = stream->dec_cpyoff; } if (option_use_checksum && (stream->dec_win_ind & VCD_ADLER32) != 0) { recode_stream->flags |= XD3_ADLER32_RECODE; recode_stream->recode_adler32 = stream->dec_adler32; } if (option_use_appheader != 0 && option_appheader != NULL) { xd3_set_appheader (recode_stream, option_appheader, (usize_t) strlen ((char*) option_appheader)); } else if (option_use_appheader != 0 && option_appheader == NULL) { if (stream->dec_appheader != NULL) { xd3_set_appheader (recode_stream, stream->dec_appheader, stream->dec_appheadsz); } } // Output loop for (;;) { switch((ret = xd3_encode_input (recode_stream))) { case XD3_INPUT: { /* finished recoding one window */ stream->total_out = recode_stream->total_out; return 0; } case XD3_OUTPUT: { /* main_file_write below */ break; } case XD3_GOTHEADER: case XD3_WINSTART: case XD3_WINFINISH: { /* ignore */ continue; } case XD3_GETSRCBLK: case 0: { return XD3_INTERNAL; } default: return ret; } if ((ret = main_write_output (recode_stream, ofile))) { return ret; } xd3_consume_output (recode_stream); } } #endif /* VCDIFF_TOOLS */ /******************************************************************* VCDIFF merging ******************************************************************/ #if VCDIFF_TOOLS /* Modifies static state. */ static int main_init_recode_stream (void) { int ret; int stream_flags = XD3_ADLER32_NOVER | XD3_SKIP_EMIT; int recode_flags; xd3_config recode_config; XD3_ASSERT (recode_stream == NULL); if ((recode_stream = (xd3_stream*) main_malloc(sizeof(xd3_stream))) == NULL) { return ENOMEM; } recode_flags = (stream_flags & XD3_SEC_TYPE); recode_config.alloc = main_alloc; recode_config.freef = main_free1; xd3_init_config(&recode_config, recode_flags); if ((ret = main_set_secondary_flags (&recode_config)) || (ret = xd3_config_stream (recode_stream, &recode_config)) || (ret = xd3_encode_init_partial (recode_stream)) || (ret = xd3_whole_state_init (recode_stream))) { XPR(NT XD3_LIB_ERRMSG (recode_stream, ret)); xd3_free_stream (recode_stream); recode_stream = NULL; return ret; } return 0; } /* This processes the sequence of -m arguments. The final input * is processed as part of the ordinary main_input() loop. */ static int main_merge_arguments (main_merge_list* merges) { int ret = 0; int count = 0; main_merge *merge = NULL; xd3_stream merge_input; if (main_merge_list_empty (merges)) { return 0; } if ((ret = xd3_config_stream (& merge_input, NULL)) || (ret = xd3_whole_state_init (& merge_input))) { XPR(NT XD3_LIB_ERRMSG (& merge_input, ret)); return ret; } merge = main_merge_list_front (merges); while (!main_merge_list_end (merges, merge)) { main_file mfile; main_file_init (& mfile); mfile.filename = merge->filename; mfile.flags = RD_NONEXTERNAL; if ((ret = main_file_open (& mfile, merge->filename, XO_READ))) { goto error; } ret = main_input (CMD_MERGE_ARG, & mfile, NULL, NULL); if (ret == 0) { if (count++ == 0) { /* The first merge source is the next merge input. */ xd3_swap_whole_state (& recode_stream->whole_target, & merge_input.whole_target); } else { /* Merge the recode_stream with merge_input. */ ret = xd3_merge_input_output (recode_stream, & merge_input.whole_target); /* Save the next merge source in merge_input. */ xd3_swap_whole_state (& recode_stream->whole_target, & merge_input.whole_target); } } main_file_cleanup (& mfile); if (recode_stream != NULL) { xd3_free_stream (recode_stream); main_free (recode_stream); recode_stream = NULL; } if (main_bdata != NULL) { main_buffree (main_bdata); main_bdata = NULL; main_bsize = 0; } if (ret != 0) { goto error; } merge = main_merge_list_next (merge); } XD3_ASSERT (merge_stream == NULL); if ((merge_stream = (xd3_stream*) main_malloc (sizeof(xd3_stream))) == NULL) { ret = ENOMEM; goto error; } if ((ret = xd3_config_stream (merge_stream, NULL)) || (ret = xd3_whole_state_init (merge_stream))) { XPR(NT XD3_LIB_ERRMSG (& merge_input, ret)); goto error; } xd3_swap_whole_state (& merge_stream->whole_target, & merge_input.whole_target); ret = 0; error: xd3_free_stream (& merge_input); return ret; } /* This processes each window of the final merge input. This routine * does not output, it buffers the entire delta into memory. */ static int main_merge_func (xd3_stream* stream, main_file *no_write) { int ret; if ((ret = xd3_whole_append_window (stream))) { return ret; } return 0; } /* This is called after all windows have been read, as a final step in * main_input(). This is only called for the final merge step. */ static int main_merge_output (xd3_stream *stream, main_file *ofile) { int ret; usize_t inst_pos = 0; xoff_t output_pos = 0; xd3_source recode_source; usize_t window_num = 0; int at_least_once = 0; /* merge_stream is set if there were arguments. this stream's input * needs to be applied to the merge_stream source. */ if ((merge_stream != NULL) && (ret = xd3_merge_input_output (stream, & merge_stream->whole_target))) { XPR(NT XD3_LIB_ERRMSG (stream, ret)); return ret; } if (option_use_appheader != 0 && option_appheader != NULL) { xd3_set_appheader (recode_stream, option_appheader, (usize_t) strlen ((char*) option_appheader)); } /* Enter the ENC_INPUT state and bypass the next_in == NULL test * and (leftover) input buffering logic. */ XD3_ASSERT(recode_stream->enc_state == ENC_INIT); recode_stream->enc_state = ENC_INPUT; recode_stream->next_in = main_bdata; recode_stream->flags |= XD3_FLUSH; /* This encodes the entire target. */ while (inst_pos < stream->whole_target.instlen || !at_least_once) { xoff_t window_start = output_pos; int window_srcset = 0; xoff_t window_srcmin = 0; xoff_t window_srcmax = 0; usize_t window_pos = 0; usize_t window_size; /* at_least_once ensures that we encode at least one window, * which handles the 0-byte case. */ at_least_once = 1; XD3_ASSERT (recode_stream->enc_state == ENC_INPUT); if ((ret = xd3_encode_input (recode_stream)) != XD3_WINSTART) { XPR(NT "invalid merge state: %s\n", xd3_mainerror (ret)); return XD3_INVALID; } /* Window sizes must match from the input to the output, so that * target copies are in-range (and so that checksums carry * over). */ XD3_ASSERT (window_num < stream->whole_target.wininfolen); window_size = stream->whole_target.wininfo[window_num].length; /* Output position should also match. */ if (output_pos != stream->whole_target.wininfo[window_num].offset) { XPR(NT "internal merge error: offset mismatch\n"); return XD3_INVALID; } if (option_use_checksum && (stream->dec_win_ind & VCD_ADLER32) != 0) { recode_stream->flags |= XD3_ADLER32_RECODE; recode_stream->recode_adler32 = stream->whole_target.wininfo[window_num].adler32; } window_num++; if (main_bsize < window_size) { main_buffree (main_bdata); main_bdata = NULL; main_bsize = 0; if ((main_bdata = (uint8_t*) main_bufalloc (window_size)) == NULL) { return ENOMEM; } main_bsize = window_size; } /* This encodes a single target window. */ while (window_pos < window_size && inst_pos < stream->whole_target.instlen) { xd3_winst *inst = &stream->whole_target.inst[inst_pos]; usize_t take = xd3_min(inst->size, window_size - window_pos); xoff_t addr; switch (inst->type) { case XD3_RUN: if ((ret = xd3_emit_run (recode_stream, window_pos, take, &stream->whole_target.adds[inst->addr]))) { return ret; } break; case XD3_ADD: /* Adds are implicit, put them into the input buffer. */ memcpy (main_bdata + window_pos, stream->whole_target.adds + inst->addr, take); break; default: /* XD3_COPY + copy mode */ if (inst->mode != 0) { if (window_srcset) { window_srcmin = xd3_min (window_srcmin, inst->addr); window_srcmax = xd3_max (window_srcmax, inst->addr + take); } else { window_srcset = 1; window_srcmin = inst->addr; window_srcmax = inst->addr + take; } addr = inst->addr; } else { XD3_ASSERT (inst->addr >= window_start); addr = inst->addr - window_start; } IF_DEBUG2 ({ XPR(NTR "[merge copy] winpos %"W"u take %"W"u " "addr %"Q"u mode %u\n", window_pos, take, addr, inst->mode); }); if ((ret = xd3_found_match (recode_stream, window_pos, take, addr, inst->mode != 0))) { return ret; } break; } window_pos += take; output_pos += take; if (take == inst->size) { inst_pos += 1; } else { /* Modify the instruction for the next pass. */ if (inst->type != XD3_RUN) { inst->addr += take; } inst->size -= take; } } xd3_avail_input (recode_stream, main_bdata, window_pos); recode_stream->enc_state = ENC_INSTR; if (window_srcset) { recode_stream->srcwin_decided = 1; recode_stream->src = &recode_source; recode_source.srclen = (usize_t)(window_srcmax - window_srcmin); recode_source.srcbase = window_srcmin; recode_stream->taroff = recode_source.srclen; XD3_ASSERT (recode_source.srclen != 0); } else { recode_stream->srcwin_decided = 0; recode_stream->src = NULL; recode_stream->taroff = 0; } for (;;) { switch ((ret = xd3_encode_input (recode_stream))) { case XD3_INPUT: { goto done_window; } case XD3_OUTPUT: { /* main_file_write below */ break; } case XD3_GOTHEADER: case XD3_WINSTART: case XD3_WINFINISH: { /* ignore */ continue; } case XD3_GETSRCBLK: case 0: { return XD3_INTERNAL; } default: return ret; } if ((ret = main_write_output(recode_stream, ofile))) { return ret; } xd3_consume_output (recode_stream); } done_window: (void) 0; } return 0; } #endif /******************************************************************* Input decompression, output recompression ******************************************************************/ #if EXTERNAL_COMPRESSION /* This is tricky POSIX-specific code with lots of fork(), pipe(), * dup(), waitpid(), and exec() business. Most of this code * originated in PRCS1, which did automatic package-file * decompression. It works with both XD3_POSIX and XD3_STDIO file * disciplines. * * To automatically detect compressed inputs requires a child process * to reconstruct the input stream, which was advanced in order to * detect compression, because it may not be seekable. In other * words, the main program reads part of the input stream, and if it * detects a compressed input it then forks a pipe copier process, * which copies the first-read block out of the main-program's memory, * then streams the remaining compressed input into the * input-decompression pipe. */ #include #include #include #include /* Remember which pipe FD is which. */ #define PIPE_READ_FD 0 #define PIPE_WRITE_FD 1 #define MAX_SUBPROCS 4 /* max(source + copier + output, source + copier + input + copier). */ static pid_t ext_subprocs[MAX_SUBPROCS]; /* Like write(), applies to a fd instead of a main_file, for the pipe * copier subprocess. Does not print an error, to facilitate ignoring * trailing garbage, see main_pipe_copier(). */ static int main_pipe_write (int outfd, uint8_t *exist_buf, usize_t remain) { int ret; if ((ret = xd3_posix_io (outfd, exist_buf, remain, (xd3_posix_func*) &write, NULL))) { return ret; } return 0; } /* A simple error-reporting waitpid interface. */ static int main_waitpid_check(pid_t pid) { int status; int ret = 0; if (waitpid (pid, & status, 0) < 0) { ret = get_errno (); XPR(NT "external compression [pid %d] wait: %s\n", pid, xd3_mainerror (ret)); } else if (! WIFEXITED (status)) { // SIGPIPE will be delivered to the child process whenever it // writes data after this process closes the pipe, // happens if xdelta does not require access to the entire // source file. Considered normal. if (! WIFSIGNALED (status) || WTERMSIG (status) != SIGPIPE) { ret = ECHILD; XPR(NT "external compression [pid %d] signal %d\n", pid, WIFSIGNALED (status) ? WTERMSIG (status) : WSTOPSIG (status)); } else if (option_verbose) { XPR(NT "external compression sigpipe\n"); } } else if (WEXITSTATUS (status) != 0) { ret = ECHILD; if (option_verbose > 1) { /* Presumably, the error was printed by the subprocess. */ XPR(NT "external compression [pid %d] exit %d\n", pid, WEXITSTATUS (status)); } } return ret; } /* Wait for any existing child processes to check for abnormal exit. */ static int main_external_compression_finish (void) { int i; int ret; for (i = 0; i < num_subprocs; i += 1) { if (! ext_subprocs[i]) { continue; } if ((ret = main_waitpid_check (ext_subprocs[i]))) { return ret; } ext_subprocs[i] = 0; } return 0; } /* Kills any outstanding compression process. */ static void main_external_compression_cleanup (void) { int i; for (i = 0; i < num_subprocs; i += 1) { if (! ext_subprocs[i]) { continue; } kill (ext_subprocs[i], SIGTERM); ext_subprocs[i] = 0; } } /* This runs as a forked process of main_input_decompress_setup() to * copy input to the decompression process. First, the available * input is copied out of the existing buffer, then the buffer is * reused to continue reading from the compressed input file. */ static int main_pipe_copier (uint8_t *pipe_buf, usize_t pipe_bufsize, size_t nread, main_file *ifile, int outfd) { int ret; xoff_t skipped = 0; /* Prevent SIGPIPE signals, allow EPIPE return values instead. This * is safe to comment-out, except that the -F flag will not work * properly (the parent would need to treat WTERMSIG(status) == * SIGPIPE). */ struct sigaction sa; sa.sa_handler = SIG_IGN; sigaction (SIGPIPE, &sa, NULL); for (;;) { /* force_drain will be set when option_force and EPIPE cause us * to skip data. This is reset each time through the loop, so * the break condition below works. */ int force_drain = 0; if (nread > 0 && (ret = main_pipe_write (outfd, pipe_buf, nread))) { if (ret == EPIPE) { /* This causes the loop to continue reading until nread * == 0. */ skipped += nread; force_drain = 1; } else { XPR(NT "pipe write failed: %s\n", xd3_mainerror (ret)); return ret; } } if (nread < pipe_bufsize && !force_drain) { break; } if ((ret = main_file_read (ifile, pipe_buf, pipe_bufsize, & nread, "pipe read failed")) < 0) { return ret; } } if (option_verbose && skipped != 0) { XPR(NT "skipping %"Q"u bytes in %s\n", skipped, ifile->filename); } return 0; } /* This function is called after we have read some amount of data from * the input file and detected a compressed input. Here we start a * decompression subprocess by forking twice. The first process runs * the decompression command, the second process copies data to the * input of the first. */ static int main_input_decompress_setup (const main_extcomp *decomp, main_file *ifile, uint8_t *input_buf, usize_t input_bufsize, uint8_t *pipe_buf, usize_t pipe_bufsize, usize_t pipe_avail, size_t *nread) { /* The two pipes: input and output file descriptors. */ int outpipefd[2], inpipefd[2]; int input_fd = -1; /* The resulting input_fd (output of decompression). */ pid_t decomp_id, copier_id; /* The two subprocs. */ int ret; outpipefd[0] = outpipefd[1] = -1; inpipefd[0] = inpipefd[1] = -1; if (pipe (outpipefd) || pipe (inpipefd)) { XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } if ((decomp_id = fork ()) < 0) { XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } /* The first child runs the decompression process: */ if (decomp_id == 0) { if (option_verbose > 2) { XPR(NT "external decompression pid %d\n", getpid ()); } /* Setup pipes: write to the outpipe, read from the inpipe. */ if (dup2 (outpipefd[PIPE_WRITE_FD], STDOUT_FILENO) < 0 || dup2 (inpipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || close (outpipefd[PIPE_READ_FD]) || close (outpipefd[PIPE_WRITE_FD]) || close (inpipefd[PIPE_READ_FD]) || close (inpipefd[PIPE_WRITE_FD]) || execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, decomp->decomp_options, option_force2 ? "-f" : NULL, NULL)) { XPR(NT "child process %s failed to execute: %s\n", decomp->decomp_cmdname, xd3_mainerror (get_errno ())); } _exit (127); } XD3_ASSERT(num_subprocs < MAX_SUBPROCS); ext_subprocs[num_subprocs++] = decomp_id; if ((copier_id = fork ()) < 0) { XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } /* The second child runs the copier process: */ if (copier_id == 0) { int exitval = 0; if (option_verbose > 2) { XPR(NT "child pipe-copier pid %d\n", getpid ()); } if (close (inpipefd[PIPE_READ_FD]) || close (outpipefd[PIPE_READ_FD]) || close (outpipefd[PIPE_WRITE_FD]) || main_pipe_copier (pipe_buf, pipe_bufsize, pipe_avail, ifile, inpipefd[PIPE_WRITE_FD]) || close (inpipefd[PIPE_WRITE_FD])) { XPR(NT "child copier process failed: %s\n", xd3_mainerror (get_errno ())); exitval = 1; } _exit (exitval); } XD3_ASSERT(num_subprocs < MAX_SUBPROCS); ext_subprocs[num_subprocs++] = copier_id; /* The parent closes both pipes after duplicating the output of * compression. */ input_fd = dup (outpipefd[PIPE_READ_FD]); if (input_fd < 0 || main_file_close (ifile) || close (outpipefd[PIPE_READ_FD]) || close (outpipefd[PIPE_WRITE_FD]) || close (inpipefd[PIPE_READ_FD]) || close (inpipefd[PIPE_WRITE_FD])) { XPR(NT "dup/close failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } #if XD3_STDIO /* Note: fdopen() acquires the fd, closes it when finished. */ if ((ifile->file = fdopen (input_fd, "r")) == NULL) { XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } #elif XD3_POSIX ifile->file = input_fd; #endif ifile->compressor = decomp; /* Now the input file is decompressed. */ return main_file_read (ifile, input_buf, input_bufsize, nread, "input decompression failed"); pipe_cleanup: close (input_fd); close (outpipefd[PIPE_READ_FD]); close (outpipefd[PIPE_WRITE_FD]); close (inpipefd[PIPE_READ_FD]); close (inpipefd[PIPE_WRITE_FD]); return ret; } /* This routine is called when the first buffer of input data is read * by the main program (unless input decompression is disabled by * command-line option). If it recognizes the magic number of a known * input type it invokes decompression. * * Skips decompression if the decompression type or the file type is * RD_NONEXTERNAL. * * Behaves exactly like main_file_read, otherwise. * * This function uses a separate buffer to read the first small block * of input. If a compressed input is detected, the separate buffer * is passed to the pipe copier. This avoids using the same size * buffer in both cases. */ static int main_secondary_decompress_check (main_file *file, uint8_t *input_buf, size_t input_size, size_t *nread) { int ret; usize_t i; usize_t try_read = xd3_min (input_size, XD3_ALLOCSIZE); size_t check_nread = 0; uint8_t check_buf[XD3_ALLOCSIZE]; /* TODO: heap allocate */ const main_extcomp *decompressor = NULL; if ((ret = main_file_read (file, check_buf, try_read, & check_nread, "input read failed"))) { return ret; } if (file->flags & RD_DECOMPSET) { /* This allows the application header to override the magic * number, for whatever reason. */ decompressor = file->compressor; } else { for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) { const main_extcomp *decomp = & extcomp_types[i]; if (check_nread > decomp->magic_size) { /* The following expr checks if we are trying to read a * VCDIFF input, in which case do not treat it as * "secondary" decompression. */ int skip_this_type = (decomp->flags & RD_NONEXTERNAL) && (file->flags & RD_NONEXTERNAL); if (skip_this_type) { continue; } if (memcmp (check_buf, decomp->magic, decomp->magic_size) == 0) { decompressor = decomp; break; } } } } if (decompressor != NULL) { if (! option_quiet) { XPR(NT "externally compressed input: %s %s%s < %s\n", decompressor->decomp_cmdname, decompressor->decomp_options, (option_force2 ? " -f" : ""), file->filename); if (file->flags & RD_MAININPUT) { XPR(NT "WARNING: the encoder is automatically decompressing the input file;\n"); XPR(NT "WARNING: the decoder will automatically recompress the output file;\n"); XPR(NT "WARNING: this may result in different compressed data and checksums\n"); XPR(NT "WARNING: despite being identical data; if this is an issue, use -D\n"); XPR(NT "WARNING: to avoid decompression and/or use -R to avoid recompression\n"); XPR(NT "WARNING: and/or manually decompress the input file; if you know the\n"); XPR(NT "WARNING: compression settings that will produce identical output\n"); XPR(NT "WARNING: you may set those flags using the environment (e.g., GZIP=-9)\n"); } } file->size_known = 0; return main_input_decompress_setup (decompressor, file, input_buf, input_size, check_buf, XD3_ALLOCSIZE, check_nread, nread); } /* Now read the rest of the input block. */ (*nread) = 0; if (check_nread == try_read) { ret = main_file_read (file, input_buf + try_read, input_size - try_read, nread, "input read failed"); } memcpy (input_buf, check_buf, check_nread); (*nread) += check_nread; return 0; } /* Initiate re-compression of the output stream. This is easier than * input decompression because we know beforehand that the stream will * be compressed, whereas the input has already been read when we * decide it should be decompressed. Thus, it only requires one * subprocess and one pipe. */ static int main_recompress_output (main_file *ofile) { pid_t recomp_id; /* One subproc. */ int pipefd[2]; /* One pipe. */ int output_fd = -1; int ret; const main_extcomp *recomp = ofile->compressor; pipefd[0] = pipefd[1] = -1; if (pipe (pipefd)) { XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } if ((recomp_id = fork ()) < 0) { XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } /* The child runs the recompression process: */ if (recomp_id == 0) { if (option_verbose > 2) { XPR(NT "external recompression pid %d\n", getpid ()); } /* Setup pipes: write to the output file, read from the pipe. */ if (dup2 (XFNO (ofile), STDOUT_FILENO) < 0 || dup2 (pipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || close (pipefd[PIPE_READ_FD]) || close (pipefd[PIPE_WRITE_FD]) || execlp (recomp->recomp_cmdname, recomp->recomp_cmdname, recomp->recomp_options, option_force2 ? "-f" : NULL, NULL)) { XPR(NT "child process %s failed to execute: %s\n", recomp->recomp_cmdname, xd3_mainerror (get_errno ())); } _exit (127); } XD3_ASSERT(num_subprocs < MAX_SUBPROCS); ext_subprocs[num_subprocs++] = recomp_id; /* The parent closes both pipes after duplicating the output-fd for * writing to the compression pipe. */ output_fd = dup (pipefd[PIPE_WRITE_FD]); if (output_fd < 0 || main_file_close (ofile) || close (pipefd[PIPE_READ_FD]) || close (pipefd[PIPE_WRITE_FD])) { XPR(NT "close failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } #if XD3_STDIO /* Note: fdopen() acquires the fd, closes it when finished. */ if ((ofile->file = fdopen (output_fd, "w")) == NULL) { XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } #elif XD3_POSIX ofile->file = output_fd; #endif /* Now the output file will be compressed. */ return 0; pipe_cleanup: close (output_fd); close (pipefd[PIPE_READ_FD]); close (pipefd[PIPE_WRITE_FD]); return ret; } #endif /* EXTERNAL_COMPRESSION */ /* Identify the compressor that was used based on its ident string, * which is passed in the application header. */ static const main_extcomp* main_ident_compressor (const char *ident) { usize_t i; for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) { if (strcmp (extcomp_types[i].ident, ident) == 0) { return & extcomp_types[i]; } } return NULL; } /* Return the main_extcomp record to use for this identifier, if possible. */ static const main_extcomp* main_get_compressor (const char *ident) { const main_extcomp *ext = main_ident_compressor (ident); if (ext == NULL) { if (! option_quiet) { XPR(NT "warning: cannot recompress output: " "unrecognized external compression ID: %s\n", ident); } return NULL; } else if (! EXTERNAL_COMPRESSION) { if (! option_quiet) { XPR(NT "warning: external support not compiled: " "original input was compressed: %s\n", ext->recomp_cmdname); } return NULL; } else { return ext; } } /********************************************************************* APPLICATION HEADER *******************************************************************/ #if XD3_ENCODER static const char* main_apphead_string (const char* x) { const char *y; if (x == NULL) { return ""; } if (strcmp (x, "/dev/stdin") == 0 || strcmp (x, "/dev/stdout") == 0 || strcmp (x, "/dev/stderr") == 0) { return "-"; } // TODO: this is not portable return (y = strrchr (x, '/')) == NULL ? x : y + 1; } static int main_set_appheader (xd3_stream *stream, main_file *input, main_file *sfile) { /* The user may disable the application header. Once the appheader * is set, this disables setting it again. */ if (appheader_used || ! option_use_appheader) { return 0; } /* The user may specify the application header, otherwise format the default header. */ if (option_appheader) { appheader_used = option_appheader; } else { const char *iname; const char *icomp; const char *sname; const char *scomp; usize_t len; iname = main_apphead_string (input->filename); icomp = (input->compressor == NULL) ? "" : input->compressor->ident; len = (usize_t) strlen (iname) + (usize_t) strlen (icomp) + 2; if (sfile->filename != NULL) { sname = main_apphead_string (sfile->filename); scomp = (sfile->compressor == NULL) ? "" : sfile->compressor->ident; len += (usize_t) strlen (sname) + (usize_t) strlen (scomp) + 2; } else { sname = scomp = ""; } if ((appheader_used = (uint8_t*) main_malloc (len)) == NULL) { return ENOMEM; } if (sfile->filename == NULL) { snprintf_func ((char*)appheader_used, len, "%s/%s", iname, icomp); } else { snprintf_func ((char*)appheader_used, len, "%s/%s/%s/%s", iname, icomp, sname, scomp); } } xd3_set_appheader (stream, appheader_used, (usize_t) strlen ((char*)appheader_used)); return 0; } #endif static void main_get_appheader_params (main_file *file, char **parsed, int output, const char *type, main_file *other) { /* Set the filename if it was not specified. If output, option_stdout (-c) * overrides. */ if (file->filename == NULL && ! (output && option_stdout) && strcmp (parsed[0], "-") != 0) { file->filename = parsed[0]; if (other->filename != NULL) { /* Take directory from the other file, if it has one. */ /* TODO: This results in nonsense names like /dev/foo.tar.gz * and probably the filename-default logic interferes with * multi-file operation and the standard file extension? * Possibly the name header is bad, should be off by default. * Possibly we just want to remember external/compression * settings. */ const char *last_slash = strrchr(other->filename, '/'); if (last_slash != NULL) { usize_t dlen = (usize_t) (last_slash - other->filename); XD3_ASSERT(file->filename_copy == NULL); file->filename_copy = (char*) main_malloc(dlen + 2 + (usize_t) strlen(file->filename)); strncpy(file->filename_copy, other->filename, dlen); file->filename_copy[dlen] = '/'; strcpy(file->filename_copy + dlen + 1, parsed[0]); file->filename = file->filename_copy; } } if (! option_quiet) { XPR(NT "using default %s filename: %s\n", type, file->filename); } } /* Set the compressor, initiate de/recompression later. */ if (file->compressor == NULL && *parsed[1] != 0) { file->flags |= RD_DECOMPSET; file->compressor = main_get_compressor (parsed[1]); } } static void main_get_appheader (xd3_stream *stream, main_file *ifile, main_file *output, main_file *sfile) { uint8_t *apphead; usize_t appheadsz; int ret; /* The user may disable the application header. Once the appheader * is set, this disables setting it again. */ if (! option_use_appheader) { return; } ret = xd3_get_appheader (stream, & apphead, & appheadsz); /* Ignore failure, it only means we haven't received a header yet. */ if (ret != 0) { return; } if (appheadsz > 0) { char *start = (char*)apphead; char *slash; int place = 0; const int kMaxArgs = 4; char *parsed[4]; memset (parsed, 0, sizeof (parsed)); while ((slash = strchr (start, '/')) != NULL && place < (kMaxArgs-1)) { *slash = 0; parsed[place++] = start; start = slash + 1; } parsed[place++] = start; /* First take the output parameters. */ if (place == 2 || place == 4) { main_get_appheader_params (output, parsed, 1, "output", ifile); } /* Then take the source parameters. */ if (place == 4) { main_get_appheader_params (sfile, parsed+2, 0, "source", ifile); } } option_use_appheader = 0; return; } /********************************************************************* Main I/O routines **********************************************************************/ /* This function acts like the above except it may also try to * recognize a compressed input (source or target) when the first * buffer of data is read. The EXTERNAL_COMPRESSION code is called to * search for magic numbers. */ static int main_read_primary_input (main_file *file, uint8_t *buf, size_t size, size_t *nread) { #if EXTERNAL_COMPRESSION if (option_decompress_inputs && file->flags & RD_FIRST) { file->flags &= ~RD_FIRST; return main_secondary_decompress_check (file, buf, size, nread); } #endif return main_file_read (file, buf, size, nread, "input read failed"); } /* Open the main output file, sets a default file name, initiate * recompression. This function is expected to fprint any error * messages. */ static int main_open_output (xd3_stream *stream, main_file *ofile) { int ret; if (option_no_output) { return 0; } if (ofile->filename == NULL) { XSTDOUT_XF (ofile); if (option_verbose > 1) { XPR(NT "using standard output: %s\n", ofile->filename); } } else { /* Stat the file to check for overwrite. */ if (option_force == 0 && main_file_exists (ofile)) { if (!option_quiet) { XPR(NT "to overwrite output file specify -f: %s\n", ofile->filename); } return EEXIST; } if ((ret = main_file_open (ofile, ofile->filename, XO_WRITE))) { return ret; } if (option_verbose > 1) { XPR(NT "output %s\n", ofile->filename); } } #if EXTERNAL_COMPRESSION /* Do output recompression. */ if (ofile->compressor != NULL && option_recompress_outputs == 1) { if (! option_quiet) { XPR(NT "externally compressed output: %s %s%s > %s\n", ofile->compressor->recomp_cmdname, ofile->compressor->recomp_options, (option_force2 ? " -f" : ""), ofile->filename); } if ((ret = main_recompress_output (ofile))) { return ret; } } #endif return 0; } static usize_t main_get_winsize (main_file *ifile) { xoff_t file_size = 0; usize_t size = option_winsize; static shortbuf iszbuf; if (main_file_stat (ifile, &file_size) == 0) { size = (usize_t) xd3_min (file_size, (xoff_t) size); } size = xd3_max (size, XD3_ALLOCSIZE); if (option_verbose > 1) { XPR(NT "input %s window size %s\n", ifile->filename, main_format_bcnt (size, &iszbuf)); } return size; } /********************************************************************* Main routines ********************************************************************/ /* This is a generic input function. It calls the xd3_encode_input or * xd3_decode_input functions and makes calls to the various input * handling routines above, which coordinate external decompression. */ static int main_input (xd3_cmd cmd, main_file *ifile, main_file *ofile, main_file *sfile) { int ret; xd3_stream stream; size_t nread = 0; usize_t winsize; int stream_flags = 0; xd3_config config; xd3_source source; xoff_t last_total_in = 0; xoff_t last_total_out = 0; long start_time; int stdout_only = 0; int (*input_func) (xd3_stream*); int (*output_func) (xd3_stream*, main_file *); memset (& stream, 0, sizeof (stream)); memset (& source, 0, sizeof (source)); memset (& config, 0, sizeof (config)); config.alloc = main_alloc; config.freef = main_free1; config.iopt_size = option_iopt_size; config.sprevsz = option_sprevsz; do_src_fifo = 0; start_time = get_millisecs_now (); if (option_use_checksum) { stream_flags |= XD3_ADLER32; } /* main_input setup. */ switch ((int) cmd) { #if VCDIFF_TOOLS if (1) { case CMD_PRINTHDR: stream_flags |= XD3_JUST_HDR; } else if (1) { case CMD_PRINTHDRS: stream_flags |= XD3_SKIP_WINDOW; } else { case CMD_PRINTDELTA: stream_flags |= XD3_SKIP_EMIT; } ifile->flags |= RD_NONEXTERNAL; input_func = xd3_decode_input; output_func = main_print_func; stream_flags |= XD3_ADLER32_NOVER; stdout_only = 1; break; case CMD_RECODE: case CMD_MERGE: case CMD_MERGE_ARG: /* No source will be read */ stream_flags |= XD3_ADLER32_NOVER | XD3_SKIP_EMIT; ifile->flags |= RD_NONEXTERNAL; input_func = xd3_decode_input; if ((ret = main_init_recode_stream ())) { return EXIT_FAILURE; } if (cmd == CMD_RECODE) { output_func = main_recode_func; } else { output_func = main_merge_func; } break; #endif /* VCDIFF_TOOLS */ #if XD3_ENCODER case CMD_ENCODE: do_src_fifo = 1; input_func = xd3_encode_input; output_func = main_write_output; if (option_no_compress) { stream_flags |= XD3_NOCOMPRESS; } if (option_smatch_config) { const char *s = option_smatch_config; char *e; long values[XD3_SOFTCFG_VARCNT]; int got; config.smatch_cfg = XD3_SMATCH_SOFT; for (got = 0; got < XD3_SOFTCFG_VARCNT; got += 1, s = e + 1) { values[got] = strtol (s, &e, 10); if ((values[got] < 0) || (e == s) || (got < XD3_SOFTCFG_VARCNT-1 && *e == 0) || (got == XD3_SOFTCFG_VARCNT-1 && *e != 0)) { XPR(NT "invalid string match specifier (-C) %d: %s\n", got, s); return EXIT_FAILURE; } } config.smatcher_soft.large_look = values[0]; config.smatcher_soft.large_step = values[1]; config.smatcher_soft.small_look = values[2]; config.smatcher_soft.small_chain = values[3]; config.smatcher_soft.small_lchain = values[4]; config.smatcher_soft.max_lazy = values[5]; config.smatcher_soft.long_enough = values[6]; } else { if (option_verbose > 2) { XPR(NT "compression level: %d\n", option_level); } if (option_level == 0) { stream_flags |= XD3_NOCOMPRESS; config.smatch_cfg = XD3_SMATCH_FASTEST; } else if (option_level == 1) { config.smatch_cfg = XD3_SMATCH_FASTEST; } else if (option_level == 2) { config.smatch_cfg = XD3_SMATCH_FASTER; } else if (option_level <= 5) { config.smatch_cfg = XD3_SMATCH_FAST; } else if (option_level == 6) { config.smatch_cfg = XD3_SMATCH_DEFAULT; } else { config.smatch_cfg = XD3_SMATCH_SLOW; } } break; #endif case CMD_DECODE: if (option_use_checksum == 0) { stream_flags |= XD3_ADLER32_NOVER; } ifile->flags |= RD_NONEXTERNAL; input_func = xd3_decode_input; output_func = main_write_output; break; default: XPR(NT "internal error\n"); return EXIT_FAILURE; } main_bsize = winsize = main_get_winsize (ifile); if ((main_bdata = (uint8_t*) main_bufalloc (winsize)) == NULL) { return EXIT_FAILURE; } config.winsize = winsize; config.getblk = main_getblk_func; config.flags = stream_flags; if ((ret = main_set_secondary_flags (&config)) || (ret = xd3_config_stream (& stream, & config))) { XPR(NT XD3_LIB_ERRMSG (& stream, ret)); return EXIT_FAILURE; } #if VCDIFF_TOOLS if ((cmd == CMD_MERGE || cmd == CMD_MERGE_ARG) && (ret = xd3_whole_state_init (& stream))) { XPR(NT XD3_LIB_ERRMSG (& stream, ret)); return EXIT_FAILURE; } #endif if (cmd != CMD_DECODE) { /* When not decoding, set source now. The decoder delays this * step until XD3_GOTHEADER. */ if (sfile && sfile->filename != NULL) { if ((ret = main_set_source (& stream, cmd, sfile, & source))) { return EXIT_FAILURE; } XD3_ASSERT(stream.src != NULL); } } if (cmd == CMD_PRINTHDR || cmd == CMD_PRINTHDRS || cmd == CMD_PRINTDELTA || cmd == CMD_RECODE) { if (sfile->filename == NULL) { allow_fake_source = 1; sfile->filename = ""; main_set_source (& stream, cmd, sfile, & source); } } /* This times each window. */ get_millisecs_since (); /* Main input loop. */ do { xoff_t input_offset; xoff_t input_remain; usize_t try_read; input_offset = ifile->nread; input_remain = XOFF_T_MAX - input_offset; try_read = (usize_t) xd3_min ((xoff_t) config.winsize, input_remain); if ((ret = main_read_primary_input (ifile, main_bdata, try_read, & nread))) { return EXIT_FAILURE; } /* If we've reached EOF tell the stream to flush. */ if (nread < try_read) { stream.flags |= XD3_FLUSH; } #if XD3_ENCODER /* After the first main_read_primary_input completes, we know * all the information needed to encode the application * header. */ if (cmd == CMD_ENCODE && (ret = main_set_appheader (& stream, ifile, sfile))) { return EXIT_FAILURE; } #endif xd3_avail_input (& stream, main_bdata, nread); /* If we read zero bytes after encoding at least one window... */ if (nread == 0 && stream.current_window > 0) { break; } again: ret = input_func (& stream); switch (ret) { case XD3_INPUT: continue; case XD3_GOTHEADER: { XD3_ASSERT (stream.current_window == 0); /* Need to process the appheader as soon as possible. It may * contain a suggested default filename/decompression routine for * the ofile, and it may contain default/decompression routine for * the sources. */ if (cmd == CMD_DECODE) { /* May need to set the sfile->filename if none was given. */ main_get_appheader (& stream, ifile, ofile, sfile); /* Now open the source file. */ if ((sfile->filename != NULL) && (ret = main_set_source (& stream, cmd, sfile, & source))) { return EXIT_FAILURE; } } } /* FALLTHROUGH */ case XD3_WINSTART: { /* e.g., set or unset XD3_SKIP_WINDOW. */ goto again; } case XD3_OUTPUT: { /* Defer opening the output file until the stream produces its * first output for both encoder and decoder, this way we * delay long enough for the decoder to receive the * application header. (Or longer if there are skipped * windows, but I can't think of any reason not to delay * open.) */ if (ofile != NULL && ! main_file_isopen (ofile) && (ret = main_open_output (& stream, ofile)) != 0) { return EXIT_FAILURE; } if ((ret = output_func (& stream, ofile)) && (ret != PRINTHDR_SPECIAL)) { return EXIT_FAILURE; } if (ret == PRINTHDR_SPECIAL) { xd3_abort_stream (& stream); ret = EXIT_SUCCESS; goto done; } ret = 0; xd3_consume_output (& stream); goto again; } case XD3_WINFINISH: { if (IS_ENCODE (cmd) || cmd == CMD_DECODE || cmd == CMD_RECODE) { if (! option_quiet && IS_ENCODE (cmd) && main_file_isopen (sfile)) { /* Warn when no source copies are found */ if (option_verbose && ! xd3_encoder_used_source (& stream)) { XPR(NT "warning: input window %"Q"u..%"Q"u has " "no source copies\n", stream.current_window * winsize, (stream.current_window+1) * winsize); XD3_ASSERT (stream.src != NULL); } /* Limited i-buffer size affects source copies * when the sourcewin is decided early. */ if (option_verbose > 1 && stream.srcwin_decided_early && stream.i_slots_used > stream.iopt_size) { XPR(NT "warning: input position %"Q"u overflowed " "instruction buffer, needed %"W"u (vs. %"W"u), " "consider changing -I\n", stream.current_window * winsize, stream.i_slots_used, stream.iopt_size); } } if (option_verbose) { shortbuf rrateavg, wrateavg, tm; shortbuf rdb, wdb; shortbuf trdb, twdb; shortbuf srcpos; long millis = get_millisecs_since (); usize_t this_read = (usize_t)(stream.total_in - last_total_in); usize_t this_write = (usize_t)(stream.total_out - last_total_out); last_total_in = stream.total_in; last_total_out = stream.total_out; if (option_verbose > 1) { XPR(NT "%"Q"u: in %s (%s): out %s (%s): " "total in %s: out %s: %s: srcpos %s\n", stream.current_window, main_format_bcnt (this_read, &rdb), main_format_rate (this_read, millis, &rrateavg), main_format_bcnt (this_write, &wdb), main_format_rate (this_write, millis, &wrateavg), main_format_bcnt (stream.total_in, &trdb), main_format_bcnt (stream.total_out, &twdb), main_format_millis (millis, &tm), main_format_bcnt (stream.srcwin_cksum_pos, &srcpos)); } else { XPR(NT "%"Q"u: in %s: out %s: total in %s: " "out %s: %s\n", stream.current_window, main_format_bcnt (this_read, &rdb), main_format_bcnt (this_write, &wdb), main_format_bcnt (stream.total_in, &trdb), main_format_bcnt (stream.total_out, &twdb), main_format_millis (millis, &tm)); } } } goto again; } default: /* input_func() error */ XPR(NT XD3_LIB_ERRMSG (& stream, ret)); if (! option_quiet && ret == XD3_INVALID_INPUT && sfile != NULL && sfile->filename != NULL) { XPR(NT "normally this indicates that the source file is incorrect\n"); XPR(NT "please verify the source file with sha1sum or equivalent\n"); } return EXIT_FAILURE; } } while (nread == config.winsize); done: /* Close the inputs. (ifile must be open, sfile may be open) */ main_file_close (ifile); if (sfile != NULL) { main_file_close (sfile); } #if VCDIFF_TOOLS if (cmd == CMD_MERGE && (ret = main_merge_output (& stream, ofile))) { return EXIT_FAILURE; } if (cmd == CMD_MERGE_ARG) { xd3_swap_whole_state (& stream.whole_target, & recode_stream->whole_target); } #endif /* VCDIFF_TOOLS */ /* If output file is not open yet because of delayed-open, it means * we never encountered a window in the delta, but it could have had * a VCDIFF header? TODO: solve this elsewhere. For now, it prints * "nothing to output" below, but the check doesn't happen in case * of option_no_output. */ if (! option_no_output && ofile != NULL) { if (!stdout_only && ! main_file_isopen (ofile)) { XPR(NT "nothing to output: %s\n", ifile->filename); return EXIT_FAILURE; } /* Have to close the output before calling * main_external_compression_finish, or else it hangs. */ if (main_file_close (ofile) != 0) { return EXIT_FAILURE; } } #if EXTERNAL_COMPRESSION if ((ret = main_external_compression_finish ())) { XPR(NT "external compression commands failed\n"); return EXIT_FAILURE; } #endif if ((ret = xd3_close_stream (& stream))) { XPR(NT XD3_LIB_ERRMSG (& stream, ret)); return EXIT_FAILURE; } #if XD3_ENCODER if (option_verbose > 1 && cmd == CMD_ENCODE) { XPR(NT "scanner configuration: %s\n", stream.smatcher.name); XPR(NT "target hash table size: %"W"u\n", stream.small_hash.size); if (sfile != NULL && sfile->filename != NULL) { XPR(NT "source hash table size: %"W"u\n", stream.large_hash.size); } } if (option_verbose > 2 && cmd == CMD_ENCODE) { XPR(NT "source copies: %"Q"u (%"Q"u bytes)\n", stream.n_scpy, stream.l_scpy); XPR(NT "target copies: %"Q"u (%"Q"u bytes)\n", stream.n_tcpy, stream.l_tcpy); XPR(NT "adds: %"Q"u (%"Q"u bytes)\n", stream.n_add, stream.l_add); XPR(NT "runs: %"Q"u (%"Q"u bytes)\n", stream.n_run, stream.l_run); } #endif xd3_free_stream (& stream); if (option_verbose) { shortbuf tm; long end_time = get_millisecs_now (); xoff_t nwrite = ofile != NULL ? ofile->nwrite : 0; XPR(NT "finished in %s; input %"Q"u output %"Q"u bytes (%0.2f%%)\n", main_format_millis (end_time - start_time, &tm), ifile->nread, nwrite, 100.0 * nwrite / ifile->nread); } return EXIT_SUCCESS; } /* free memory before exit, reset single-use variables. */ static void main_cleanup (void) { if (appheader_used != NULL && appheader_used != option_appheader) { main_free (appheader_used); appheader_used = NULL; } main_buffree (main_bdata); main_bdata = NULL; main_bsize = 0; main_lru_cleanup(); if (recode_stream != NULL) { xd3_free_stream (recode_stream); main_free (recode_stream); recode_stream = NULL; } if (merge_stream != NULL) { xd3_free_stream (merge_stream); main_free (merge_stream); merge_stream = NULL; } XD3_ASSERT (main_mallocs == 0); } static void setup_environment (int argc, char **argv, int *argc_out, char ***argv_out, char ***argv_free, char **env_free) { int n, i, i0; char *p, *v = getenv("XDELTA"); if (v == NULL) { (*argc_out) = argc; (*argv_out) = argv; (*argv_free) = NULL; (*env_free) = NULL; return; } (*env_free) = (char*) main_malloc((usize_t) strlen(v) + 1); strcpy(*env_free, v); /* Space needed for extra args, at least # of spaces */ n = argc + 1; for (p = *env_free; *p != 0; ) { if (*p++ == ' ') { n++; } } (*argv_free) = (char**) main_malloc(sizeof(char*) * (n + 1)); (*argv_out) = (*argv_free); (*argv_out)[0] = argv[0]; (*argv_out)[n] = NULL; i = 1; for (p = *env_free; *p != 0; ) { (*argv_out)[i++] = p; while (*p != ' ' && *p != 0) { p++; } while (*p == ' ') { *p++ = 0; } } for (i0 = 1; i0 < argc; i0++) { (*argv_out)[i++] = argv[i0]; } /* Counting spaces is an upper bound, argv stays NULL terminated. */ (*argc_out) = i; while (i <= n) { (*argv_out)[i++] = NULL; } } #if PYTHON_MODULE || SWIG_MODULE || NOT_MAIN int xd3_main_cmdline (int argc, char **argv) #else int main (int argc, char **argv) #endif { static const char *flags = "0123456789cdefhnqvDFJNORVs:m:B:C:E:I:L:O:M:P:W:A::S::"; xd3_cmd cmd; main_file ifile; main_file ofile; main_file sfile; main_merge_list merge_order; main_merge *merge; int my_optind; const char *my_optarg; const char *my_optstr; const char *sfilename; int env_argc; char **env_argv; char **free_argv; /* malloc() in setup_environment() */ char *free_value; /* malloc() in setup_environment() */ int ret; #ifdef _WIN32 GetStartupInfo(&winStartupInfo); setvbuf(stderr, NULL, _IONBF, 0); /* Do not buffer stderr */ #endif main_file_init (& ifile); main_file_init (& ofile); main_file_init (& sfile); main_merge_list_init (& merge_order); reset_defaults(); free_argv = NULL; free_value = NULL; setup_environment(argc, argv, &env_argc, &env_argv, &free_argv, &free_value); cmd = CMD_NONE; sfilename = NULL; my_optind = 1; argv = env_argv; argc = env_argc; program_name = env_argv[0]; takearg: my_optarg = NULL; my_optstr = argv[my_optind]; /* This doesn't use getopt() because it makes trouble for -P & python which * reenter main() and thus care about freeing all memory. I never had much * trust for getopt anyway, it's too opaque. This implements a fairly * standard non-long-option getopt with support for named operations (e.g., * "xdelta3 [encode|decode|printhdr...] < in > out"). */ if (my_optstr) { if (*my_optstr == '-') { my_optstr += 1; } else if (cmd == CMD_NONE) { goto nonflag; } else { my_optstr = NULL; } } while (my_optstr) { const char *s; my_optarg = NULL; if ((ret = *my_optstr++) == 0) { my_optind += 1; goto takearg; } /* Option handling: first check for one ':' following the option in * flags, then check for two. The syntax allows: * * 1. -Afoo defines optarg="foo" * 2. -A foo defines optarg="foo" * 3. -A "" defines optarg="" (allows empty-string) * 4. -A [EOA or -moreargs] error (mandatory case) * 5. -A [EOA -moreargs] defines optarg=NULL (optional case) * 6. -A=foo defines optarg="foo" * 7. -A= defines optarg="" (mandatory case) * 8. -A= defines optarg=NULL (optional case) * * See tests in test_command_line_arguments(). */ s = strchr (flags, ret); if (s && s[1] && s[1] == ':') { int option = s[2] && s[2] == ':'; /* Case 1, set optarg to the remaining characters. */ my_optarg = my_optstr; my_optstr = ""; /* Case 2-5 */ if (*my_optarg == 0) { /* Condition 4-5 */ int have_arg = (my_optind < (argc - 1) && *argv[my_optind+1] != '-'); if (! have_arg) { if (! option) { /* Case 4 */ XPR(NT "-%c: requires an argument\n", ret); ret = EXIT_FAILURE; goto cleanup; } /* Case 5. */ my_optarg = NULL; } else { /* Case 2-3. */ my_optarg = argv[++my_optind]; } } /* Case 6-8. */ else if (*my_optarg == '=') { /* Remove the = in all cases. */ my_optarg += 1; if (option && *my_optarg == 0) { /* Case 8. */ my_optarg = NULL; } } } switch (ret) { /* case: if no '-' was found, maybe check for a command name. */ nonflag: if (strcmp (my_optstr, "decode") == 0) { cmd = CMD_DECODE; } else if (strcmp (my_optstr, "encode") == 0) { #if XD3_ENCODER cmd = CMD_ENCODE; #else XPR(NT "encoder support not compiled\n"); return EXIT_FAILURE; #endif } else if (strcmp (my_optstr, "config") == 0) { cmd = CMD_CONFIG; } #if REGRESSION_TEST else if (strcmp (my_optstr, "test") == 0) { cmd = CMD_TEST; } #endif #if VCDIFF_TOOLS else if (strcmp (my_optstr, "printhdr") == 0) { cmd = CMD_PRINTHDR; } else if (strcmp (my_optstr, "printhdrs") == 0) { cmd = CMD_PRINTHDRS; } else if (strcmp (my_optstr, "printdelta") == 0) { cmd = CMD_PRINTDELTA; } else if (strcmp (my_optstr, "recode") == 0) { cmd = CMD_RECODE; } else if (strcmp (my_optstr, "merge") == 0) { cmd = CMD_MERGE; } #endif /* If no option was found and still no command, let the default * command be encode. The remaining args are treated as * filenames. */ if (cmd == CMD_NONE) { cmd = CMD_DEFAULT; my_optstr = NULL; break; } else { /* But if we find a command name, continue the getopt loop. */ my_optind += 1; goto takearg; } /* gzip-like options */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': option_level = ret - '0'; break; case 'f': option_force = 1; break; case 'F': #if EXTERNAL_COMPRESSION option_force2 = 1; #else XPR(NT "warning: -F option ignored, " "external compression support was not compiled\n"); break; #endif case 'v': option_verbose += 1; option_quiet = 0; break; case 'q': option_quiet = 1; option_verbose = 0; break; case 'c': option_stdout = 1; break; case 'd': if (cmd == CMD_NONE) { cmd = CMD_DECODE; } else { ret = main_help (); goto exit; } break; case 'e': #if XD3_ENCODER if (cmd == CMD_NONE) { cmd = CMD_ENCODE; } else { ret = main_help (); goto exit; } break; #else XPR(NT "encoder support not compiled\n"); return EXIT_FAILURE; #endif case 'n': option_use_checksum = 0; break; case 'N': option_no_compress = 1; break; case 'C': option_smatch_config = my_optarg; break; case 'J': option_no_output = 1; break; case 'S': if (my_optarg == NULL) { option_use_secondary = 0; option_secondary = NULL; } else { option_use_secondary = 1; option_secondary = my_optarg; } break; case 'A': if (my_optarg == NULL) { option_use_appheader = 0; } else { option_appheader = (uint8_t*) my_optarg; } break; case 'B': { xoff_t bsize; if ((ret = main_atoux (my_optarg, & bsize, XD3_MINSRCWINSZ, XD3_MAXSRCWINSZ, 'B'))) { goto exit; } option_srcwinsz = bsize; break; } case 'I': if ((ret = main_atou (my_optarg, & option_iopt_size, 0, 0, 'I'))) { goto exit; } break; case 'P': if ((ret = main_atou (my_optarg, & option_sprevsz, 0, 0, 'P'))) { goto exit; } break; case 'W': if ((ret = main_atou (my_optarg, & option_winsize, XD3_ALLOCSIZE, XD3_HARDMAXWINSIZE, 'W'))) { goto exit; } break; case 'D': #if EXTERNAL_COMPRESSION == 0 if (option_verbose > 0) { XPR(NT "warning: -D option ignored, " "external compression support was not compiled\n"); } #else option_decompress_inputs = 0; #endif break; case 'R': #if EXTERNAL_COMPRESSION == 0 if (option_verbose > 0) { XPR(NT "warning: -R option ignored, " "external compression support was not compiled\n"); } #else option_recompress_outputs = 0; #endif break; case 's': if (sfilename != NULL) { XPR(NT "specify only one source file\n"); goto cleanup; } sfilename = my_optarg; break; case 'm': if ((merge = (main_merge*) main_malloc (sizeof (main_merge))) == NULL) { goto cleanup; } main_merge_list_push_back (& merge_order, merge); merge->filename = my_optarg; break; case 'V': ret = main_version (); goto exit; default: ret = main_help (); goto exit; } } option_source_filename = sfilename; /* In case there were no arguments, set the default command. */ if (cmd == CMD_NONE) { cmd = CMD_DEFAULT; } argc -= my_optind; argv += my_optind; /* There may be up to two more arguments. */ if (argc > 2) { XPR(NT "too many filenames: %s ...\n", argv[2]); goto cleanup; } ifile.flags = RD_FIRST | RD_MAININPUT; sfile.flags = RD_FIRST; sfile.filename = option_source_filename; /* The infile takes the next argument, if there is one. But if not, infile * is set to stdin. */ if (argc > 0) { ifile.filename = argv[0]; if ((ret = main_file_open (& ifile, ifile.filename, XO_READ))) { goto cleanup; } } else { XSTDIN_XF (& ifile); } /* The ofile takes the following argument, if there is one. But if not, it * is left NULL until the application header is processed. It will be set * in main_open_output. */ if (argc > 1) { /* Check for conflicting arguments. */ if (option_stdout && ! option_quiet) { XPR(NT "warning: -c option overrides output filename: %s\n", argv[1]); } if (! option_stdout) { ofile.filename = argv[1]; } } #if VCDIFF_TOOLS if (cmd == CMD_MERGE && (ret = main_merge_arguments (&merge_order))) { goto cleanup; } #endif /* VCDIFF_TOOLS */ switch (cmd) { case CMD_PRINTHDR: case CMD_PRINTHDRS: case CMD_PRINTDELTA: #if XD3_ENCODER case CMD_ENCODE: case CMD_RECODE: case CMD_MERGE: #endif case CMD_DECODE: ret = main_input (cmd, & ifile, & ofile, & sfile); break; #if REGRESSION_TEST case CMD_TEST: main_config (); ret = xd3_selftest (); break; #endif case CMD_CONFIG: ret = main_config (); break; default: ret = main_help (); break; } if (0) { cleanup: ret = EXIT_FAILURE; exit: (void)0; } #if EXTERNAL_COMPRESSION main_external_compression_cleanup (); #endif main_file_cleanup (& ifile); main_file_cleanup (& ofile); main_file_cleanup (& sfile); while (! main_merge_list_empty (& merge_order)) { merge = main_merge_list_pop_front (& merge_order); main_free (merge); } main_free (free_argv); main_free (free_value); main_cleanup (); fflush (stdout); fflush (stderr); return ret; } static int main_help (void) { main_version(); /* Note: update wiki when command-line features change */ XPR(NTR "usage: xdelta3 [command/options] [input [output]]\n"); XPR(NTR "make patch:\n"); XPR(NTR "\n"); XPR(NTR " xdelta3.exe -e -s old_file new_file delta_file\n"); XPR(NTR "\n"); XPR(NTR "apply patch:\n"); XPR(NTR "\n"); XPR(NTR " xdelta3.exe -d -s old_file delta_file decoded_new_file\n"); XPR(NTR "\n"); XPR(NTR "special command names:\n"); XPR(NTR " config prints xdelta3 configuration\n"); XPR(NTR " decode decompress the input\n"); XPR(NTR " encode compress the input%s\n", XD3_ENCODER ? "" : " [Not compiled]"); #if REGRESSION_TEST XPR(NTR " test run the builtin tests\n"); #endif #if VCDIFF_TOOLS XPR(NTR "special commands for VCDIFF inputs:\n"); XPR(NTR " printdelta print information about the entire delta\n"); XPR(NTR " printhdr print information about the first window\n"); XPR(NTR " printhdrs print information about all windows\n"); XPR(NTR " recode encode with new application/secondary settings\n"); XPR(NTR " merge merge VCDIFF inputs (see below)\n"); #endif XPR(NTR "merge patches:\n"); XPR(NTR "\n"); XPR(NTR " xdelta3 merge -m 1.vcdiff -m 2.vcdiff 3.vcdiff merged.vcdiff\n"); XPR(NTR "\n"); XPR(NTR "standard options:\n"); XPR(NTR " -0 .. -9 compression level\n"); XPR(NTR " -c use stdout\n"); XPR(NTR " -d decompress\n"); XPR(NTR " -e compress%s\n", XD3_ENCODER ? "" : " [Not compiled]"); XPR(NTR " -f force (overwrite, ignore trailing garbage)\n"); #if EXTERNAL_COMPRESSION XPR(NTR " -F force the external-compression subprocess\n"); #endif XPR(NTR " -h show help\n"); XPR(NTR " -q be quiet\n"); XPR(NTR " -v be verbose (max 2)\n"); XPR(NTR " -V show version\n"); XPR(NTR "memory options:\n"); XPR(NTR " -B bytes source window size\n"); XPR(NTR " -W bytes input window size\n"); XPR(NTR " -P size compression duplicates window\n"); XPR(NTR " -I size instruction buffer size (0 = unlimited)\n"); XPR(NTR "compression options:\n"); XPR(NTR " -s source source file to copy from (if any)\n"); XPR(NTR " -S [lzma|djw|fgk] enable/disable secondary compression\n"); XPR(NTR " -N disable small string-matching compression\n"); XPR(NTR " -D disable external decompression (encode/decode)\n"); XPR(NTR " -R disable external recompression (decode)\n"); XPR(NTR " -n disable checksum (encode/decode)\n"); XPR(NTR " -C soft config (encode, undocumented)\n"); XPR(NTR " -A [apphead] disable/provide application header (encode)\n"); XPR(NTR " -J disable output (check/compute only)\n"); XPR(NTR " -m arguments for \"merge\"\n"); XPR(NTR "the XDELTA environment variable may contain extra args:\n"); XPR(NTR " XDELTA=\"-s source-x.y.tar.gz\" \\\n"); XPR(NTR " tar --use-compress-program=xdelta3 \\\n"); XPR(NTR " -cf target-x.z.tar.gz.vcdiff target-x.y\n"); return EXIT_FAILURE; } ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-merge.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef _XDELTA3_MERGE_H_ #define _XDELTA3_MERGE_H_ int xd3_merge_inputs (xd3_stream *stream, xd3_whole_state *source, xd3_whole_state *input); static int xd3_whole_state_init (xd3_stream *stream) { XD3_ASSERT (stream->whole_target.adds == NULL); XD3_ASSERT (stream->whole_target.inst == NULL); XD3_ASSERT (stream->whole_target.wininfo == NULL); XD3_ASSERT (stream->whole_target.length == 0); stream->whole_target.adds_alloc = XD3_ALLOCSIZE; stream->whole_target.inst_alloc = XD3_ALLOCSIZE; stream->whole_target.wininfo_alloc = XD3_ALLOCSIZE; if ((stream->whole_target.adds = (uint8_t*) xd3_alloc (stream, stream->whole_target.adds_alloc, 1)) == NULL || (stream->whole_target.inst = (xd3_winst*) xd3_alloc (stream, stream->whole_target.inst_alloc, 1)) == NULL || (stream->whole_target.wininfo = (xd3_wininfo*) xd3_alloc (stream, stream->whole_target.wininfo_alloc, 1)) == NULL) { return ENOMEM; } return 0; } static void xd3_swap_whole_state (xd3_whole_state *a, xd3_whole_state *b) { xd3_whole_state tmp; XD3_ASSERT (a->inst != NULL && a->adds != NULL); XD3_ASSERT (b->inst != NULL && b->adds != NULL); XD3_ASSERT (b->wininfo != NULL && b->wininfo != NULL); memcpy (&tmp, a, sizeof (xd3_whole_state)); memcpy (a, b, sizeof (xd3_whole_state)); memcpy (b, &tmp, sizeof (xd3_whole_state)); } static int xd3_realloc_buffer (xd3_stream *stream, usize_t current_units, usize_t unit_size, usize_t new_units, usize_t *alloc_size, void **alloc_ptr) { usize_t needed; usize_t new_alloc; usize_t cur_size; uint8_t *new_buf; needed = (current_units + new_units) * unit_size; if (needed <= *alloc_size) { return 0; } cur_size = current_units * unit_size; new_alloc = xd3_round_blksize (needed * 2, XD3_ALLOCSIZE); if ((new_buf = (uint8_t*) xd3_alloc (stream, new_alloc, 1)) == NULL) { return ENOMEM; } if (cur_size != 0) { memcpy (new_buf, *alloc_ptr, cur_size); } if (*alloc_ptr != NULL) { xd3_free (stream, *alloc_ptr); } *alloc_size = new_alloc; *alloc_ptr = new_buf; return 0; } /* allocate one new output instruction */ static int xd3_whole_alloc_winst (xd3_stream *stream, xd3_winst **winstp) { int ret; if ((ret = xd3_realloc_buffer (stream, stream->whole_target.instlen, sizeof (xd3_winst), 1, & stream->whole_target.inst_alloc, (void**) & stream->whole_target.inst))) { return ret; } *winstp = &stream->whole_target.inst[stream->whole_target.instlen++]; return 0; } static int xd3_whole_alloc_adds (xd3_stream *stream, usize_t count) { return xd3_realloc_buffer (stream, stream->whole_target.addslen, 1, count, & stream->whole_target.adds_alloc, (void**) & stream->whole_target.adds); } static int xd3_whole_alloc_wininfo (xd3_stream *stream, xd3_wininfo **wininfop) { int ret; if ((ret = xd3_realloc_buffer (stream, stream->whole_target.wininfolen, sizeof (xd3_wininfo), 1, & stream->whole_target.wininfo_alloc, (void**) & stream->whole_target.wininfo))) { return ret; } *wininfop = &stream->whole_target.wininfo[stream->whole_target.wininfolen++]; return 0; } static int xd3_whole_append_inst (xd3_stream *stream, xd3_hinst *inst) { int ret; xd3_winst *winst; if ((ret = xd3_whole_alloc_winst (stream, &winst))) { return ret; } winst->type = inst->type; winst->mode = 0; winst->size = inst->size; winst->position = stream->whole_target.length; stream->whole_target.length += inst->size; if (((inst->type == XD3_ADD) || (inst->type == XD3_RUN)) && (ret = xd3_whole_alloc_adds (stream, (inst->type == XD3_RUN ? 1 : inst->size)))) { return ret; } switch (inst->type) { case XD3_RUN: winst->addr = stream->whole_target.addslen; stream->whole_target.adds[stream->whole_target.addslen++] = *stream->data_sect.buf++; break; case XD3_ADD: winst->addr = stream->whole_target.addslen; memcpy (stream->whole_target.adds + stream->whole_target.addslen, stream->data_sect.buf, inst->size); stream->data_sect.buf += inst->size; stream->whole_target.addslen += inst->size; break; default: if (inst->addr < stream->dec_cpylen) { winst->mode = SRCORTGT (stream->dec_win_ind); winst->addr = stream->dec_cpyoff + inst->addr; } else { winst->addr = (stream->dec_winstart + inst->addr - stream->dec_cpylen); } break; } return 0; } int xd3_whole_append_window (xd3_stream *stream) { int ret; xd3_wininfo *wininfo; if ((ret = xd3_whole_alloc_wininfo (stream, &wininfo))) { return ret; } wininfo->length = stream->dec_tgtlen; wininfo->offset = stream->dec_winstart; wininfo->adler32 = stream->dec_adler32; while (stream->inst_sect.buf < stream->inst_sect.buf_max) { if ((ret = xd3_decode_instruction (stream))) { return ret; } if ((stream->dec_current1.type != XD3_NOOP) && (ret = xd3_whole_append_inst (stream, & stream->dec_current1))) { return ret; } if ((stream->dec_current2.type != XD3_NOOP) && (ret = xd3_whole_append_inst (stream, & stream->dec_current2))) { return ret; } } return 0; } /* xd3_merge_input_output applies *source to *stream, returns the * result in stream. */ static int xd3_merge_input_output (xd3_stream *stream, xd3_whole_state *source) { int ret; xd3_stream tmp_stream; memset (& tmp_stream, 0, sizeof (tmp_stream)); if ((ret = xd3_config_stream (& tmp_stream, NULL)) || (ret = xd3_whole_state_init (& tmp_stream)) || (ret = xd3_merge_inputs (& tmp_stream, source, & stream->whole_target))) { XPR(NT XD3_LIB_ERRMSG (&tmp_stream, ret)); return ret; } /* the output is in tmp_stream.whole_state, swap into input */ xd3_swap_whole_state (& stream->whole_target, & tmp_stream.whole_target); /* total allocation counts are preserved */ xd3_free_stream (& tmp_stream); return 0; } static int xd3_merge_run (xd3_stream *stream, xd3_whole_state *target, xd3_winst *iinst) { int ret; xd3_winst *oinst; if ((ret = xd3_whole_alloc_winst (stream, &oinst)) || (ret = xd3_whole_alloc_adds (stream, 1))) { return ret; } oinst->type = iinst->type; oinst->mode = iinst->mode; oinst->size = iinst->size; oinst->addr = stream->whole_target.addslen; XD3_ASSERT (stream->whole_target.length == iinst->position); oinst->position = stream->whole_target.length; stream->whole_target.length += iinst->size; stream->whole_target.adds[stream->whole_target.addslen++] = target->adds[iinst->addr]; return 0; } static int xd3_merge_add (xd3_stream *stream, xd3_whole_state *target, xd3_winst *iinst) { int ret; xd3_winst *oinst; if ((ret = xd3_whole_alloc_winst (stream, &oinst)) || (ret = xd3_whole_alloc_adds (stream, iinst->size))) { return ret; } oinst->type = iinst->type; oinst->mode = iinst->mode; oinst->size = iinst->size; oinst->addr = stream->whole_target.addslen; XD3_ASSERT (stream->whole_target.length == iinst->position); oinst->position = stream->whole_target.length; stream->whole_target.length += iinst->size; memcpy(stream->whole_target.adds + stream->whole_target.addslen, target->adds + iinst->addr, iinst->size); stream->whole_target.addslen += iinst->size; return 0; } static int xd3_merge_target_copy (xd3_stream *stream, xd3_winst *iinst) { int ret; xd3_winst *oinst; if ((ret = xd3_whole_alloc_winst (stream, &oinst))) { return ret; } XD3_ASSERT (stream->whole_target.length == iinst->position); memcpy (oinst, iinst, sizeof (*oinst)); return 0; } static int xd3_merge_find_position (xd3_stream *stream, xd3_whole_state *source, xoff_t address, usize_t *inst_num) { usize_t low; usize_t high; if (address >= source->length) { stream->msg = "Invalid copy offset in merge"; return XD3_INVALID_INPUT; } low = 0; high = source->instlen; while (low != high) { xoff_t mid_lpos; xoff_t mid_hpos; usize_t mid = low + (high - low) / 2; mid_lpos = source->inst[mid].position; if (address < mid_lpos) { high = mid; continue; } mid_hpos = mid_lpos + source->inst[mid].size; if (address >= mid_hpos) { low = mid + 1; continue; } *inst_num = mid; return 0; } stream->msg = "Internal error in merge"; return XD3_INTERNAL; } static int xd3_merge_source_copy (xd3_stream *stream, xd3_whole_state *source, const xd3_winst *iinst_orig) { int ret; xd3_winst iinst; usize_t sinst_num; memcpy (& iinst, iinst_orig, sizeof (iinst)); XD3_ASSERT (iinst.mode == VCD_SOURCE); if ((ret = xd3_merge_find_position (stream, source, iinst.addr, &sinst_num))) { return ret; } while (iinst.size > 0) { xd3_winst *sinst; xd3_winst *minst; usize_t sinst_offset; usize_t sinst_left; usize_t this_take; XD3_ASSERT (sinst_num < source->instlen); sinst = &source->inst[sinst_num]; XD3_ASSERT (iinst.addr >= sinst->position); sinst_offset = (usize_t)(iinst.addr - sinst->position); XD3_ASSERT (sinst->size > sinst_offset); sinst_left = sinst->size - sinst_offset; this_take = xd3_min (iinst.size, sinst_left); XD3_ASSERT (this_take > 0); if ((ret = xd3_whole_alloc_winst (stream, &minst))) { return ret; } minst->size = this_take; minst->type = sinst->type; minst->position = iinst.position; minst->mode = 0; switch (sinst->type) { case XD3_RUN: if ((ret = xd3_whole_alloc_adds (stream, 1))) { return ret; } minst->addr = stream->whole_target.addslen; stream->whole_target.adds[stream->whole_target.addslen++] = source->adds[sinst->addr]; break; case XD3_ADD: if ((ret = xd3_whole_alloc_adds (stream, this_take))) { return ret; } minst->addr = stream->whole_target.addslen; memcpy(stream->whole_target.adds + stream->whole_target.addslen, source->adds + sinst->addr + sinst_offset, this_take); stream->whole_target.addslen += this_take; break; default: if (sinst->mode != 0) { minst->mode = sinst->mode; minst->addr = sinst->addr + sinst_offset; } else { // Note: A better implementation will construct the // mapping of output ranges, starting from the input // range, applying deltas in forward order, using an // interval tree. This code uses recursion to construct // each copied range, recursively (using binary search // in xd3_merge_find_position). // // TODO: This code can cause stack overflow. Fix as // described above. xd3_winst tinst; tinst.type = XD3_CPY; tinst.mode = iinst.mode; tinst.addr = sinst->addr + sinst_offset; tinst.size = this_take; tinst.position = iinst.position; // The instruction allocated in this frame will not be used. stream->whole_target.instlen -= 1; if ((ret = xd3_merge_source_copy (stream, source, &tinst))) { return ret; } } break; } iinst.position += this_take; iinst.addr += this_take; iinst.size -= this_take; sinst_num += 1; } return 0; } /* xd3_merge_inputs() applies *input to *source, returns its result in * stream. */ int xd3_merge_inputs (xd3_stream *stream, xd3_whole_state *source, xd3_whole_state *input) { int ret = 0; usize_t i; size_t input_i; for (i = 0; i < input->wininfolen; ++i) { xd3_wininfo *copyinfo; if ((ret = xd3_whole_alloc_wininfo (stream, ©info))) { return ret; } *copyinfo = input->wininfo[i]; } /* iterate over each instruction. */ for (input_i = 0; ret == 0 && input_i < input->instlen; ++input_i) { xd3_winst *iinst = &input->inst[input_i]; switch (iinst->type) { case XD3_RUN: ret = xd3_merge_run (stream, input, iinst); break; case XD3_ADD: ret = xd3_merge_add (stream, input, iinst); break; default: if (iinst->mode == 0) { ret = xd3_merge_target_copy (stream, iinst); } else if (iinst->mode == VCD_TARGET) { ret = XD3_INVALID_INPUT; } else { ret = xd3_merge_source_copy (stream, source, iinst); } /* The whole_target.length is not updated in the xd3_merge*copy * routine because of recursion in xd3_merge_source_copy. */ stream->whole_target.length += iinst->size; break; } } return ret; } #endif ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-second.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef _XDELTA3_SECOND_H_ #define _XDELTA3_SECOND_H_ static inline void xd3_bit_state_encode_init (bit_state *bits) { bits->cur_byte = 0; bits->cur_mask = 1; } static inline int xd3_decode_bits (xd3_stream *stream, bit_state *bits, const uint8_t **input, const uint8_t *input_max, usize_t nbits, usize_t *valuep) { usize_t value = 0; usize_t vmask = 1 << nbits; if (bits->cur_mask == 0x100) { goto next_byte; } for (;;) { do { vmask >>= 1; if (bits->cur_byte & bits->cur_mask) { value |= vmask; } bits->cur_mask <<= 1; if (vmask == 1) { goto done; } } while (bits->cur_mask != 0x100); next_byte: if (*input == input_max) { stream->msg = "secondary decoder end of input"; return XD3_INTERNAL; } bits->cur_byte = *(*input)++; bits->cur_mask = 1; } done: IF_DEBUG2 (DP(RINT "(d) %"W"u ", value)); (*valuep) = value; return 0; } #if REGRESSION_TEST /* There may be extra bits at the end of secondary decompression, this macro * checks for non-zero bits. This is overly strict, but helps pass the * single-bit-error regression test. */ static int xd3_test_clean_bits (xd3_stream *stream, bit_state *bits) { for (; bits->cur_mask != 0x100; bits->cur_mask <<= 1) { if (bits->cur_byte & bits->cur_mask) { stream->msg = "secondary decoder garbage"; return XD3_INTERNAL; } } return 0; } #endif static int xd3_get_secondary (xd3_stream *stream, xd3_sec_stream **sec_streamp, int is_encode) { if (*sec_streamp == NULL) { int ret; if ((*sec_streamp = stream->sec_type->alloc (stream)) == NULL) { stream->msg = "error initializing secondary stream"; return XD3_INVALID; } if ((ret = stream->sec_type->init (stream, *sec_streamp, is_encode)) != 0) { return ret; } } return 0; } static int xd3_decode_secondary (xd3_stream *stream, xd3_desect *sect, xd3_sec_stream **sec_streamp) { usize_t dec_size; uint8_t *out_used; int ret; if ((ret = xd3_get_secondary (stream, sec_streamp, 0)) != 0) { return ret; } /* Decode the size, allocate the buffer. */ if ((ret = xd3_read_size (stream, & sect->buf, sect->buf_max, & dec_size)) || (ret = xd3_decode_allocate (stream, dec_size, & sect->copied2, & sect->alloc2))) { return ret; } if (dec_size == 0) { stream->msg = "secondary decoder invalid output size"; return XD3_INVALID_INPUT; } out_used = sect->copied2; if ((ret = stream->sec_type->decode (stream, *sec_streamp, & sect->buf, sect->buf_max, & out_used, out_used + dec_size))) { return ret; } if (sect->buf != sect->buf_max) { stream->msg = "secondary decoder finished with unused input"; return XD3_INTERNAL; } if (out_used != sect->copied2 + dec_size) { stream->msg = "secondary decoder short output"; return XD3_INTERNAL; } sect->buf = sect->copied2; sect->buf_max = sect->copied2 + dec_size; sect->size = dec_size; return 0; } #if XD3_ENCODER static inline int xd3_encode_bit (xd3_stream *stream, xd3_output **output, bit_state *bits, usize_t bit) { int ret; if (bit) { bits->cur_byte |= bits->cur_mask; } /* OPT: Might help to buffer more than 8 bits at once. */ if (bits->cur_mask == 0x80) { if ((ret = xd3_emit_byte (stream, output, bits->cur_byte)) != 0) { return ret; } bits->cur_mask = 1; bits->cur_byte = 0; } else { bits->cur_mask <<= 1; } return 0; } static inline int xd3_flush_bits (xd3_stream *stream, xd3_output **output, bit_state *bits) { return (bits->cur_mask == 1) ? 0 : xd3_emit_byte (stream, output, bits->cur_byte); } static inline int xd3_encode_bits (xd3_stream *stream, xd3_output **output, bit_state *bits, usize_t nbits, usize_t value) { int ret; usize_t mask = 1 << nbits; XD3_ASSERT (nbits > 0); XD3_ASSERT (nbits < sizeof (usize_t) * 8); XD3_ASSERT (value < mask); do { mask >>= 1; if ((ret = xd3_encode_bit (stream, output, bits, value & mask))) { return ret; } } while (mask != 1); IF_DEBUG2 (DP(RINT "(e) %"W"u ", value)); return 0; } static int xd3_encode_secondary (xd3_stream *stream, xd3_output **head, xd3_output **tail, xd3_sec_stream **sec_streamp, xd3_sec_cfg *cfg, int *did_it) { xd3_output *tmp_head; xd3_output *tmp_tail; usize_t comp_size; usize_t orig_size; int ret; orig_size = xd3_sizeof_output (*head); if (orig_size < SECONDARY_MIN_INPUT) { return 0; } if ((ret = xd3_get_secondary (stream, sec_streamp, 1)) != 0) { return ret; } tmp_head = xd3_alloc_output (stream, NULL); /* Encode the size, encode the data. Encoding the size makes it * simpler, but is a little gross. Should not need the entire * section in contiguous memory, but it is much easier this way. */ if ((ret = xd3_emit_size (stream, & tmp_head, orig_size)) || (ret = stream->sec_type->encode (stream, *sec_streamp, *head, tmp_head, cfg))) { goto getout; } /* If the secondary compressor determines it's no good, it returns * XD3_NOSECOND. */ /* Setup tmp_tail, comp_size */ tmp_tail = tmp_head; comp_size = tmp_head->next; while (tmp_tail->next_page != NULL) { tmp_tail = tmp_tail->next_page; comp_size += tmp_tail->next; } XD3_ASSERT (comp_size == xd3_sizeof_output (tmp_head)); XD3_ASSERT (tmp_tail != NULL); if (comp_size < (orig_size - SECONDARY_MIN_SAVINGS) || cfg->inefficient) { if (comp_size < orig_size) { IF_DEBUG1(DP(RINT "[encode_secondary] saved %"W"u bytes: %"W"u -> %"W"u (%0.2f%%)\n", orig_size - comp_size, orig_size, comp_size, 100.0 * (double) comp_size / (double) orig_size)); } xd3_free_output (stream, *head); *head = tmp_head; *tail = tmp_tail; *did_it = 1; } else { getout: if (ret == XD3_NOSECOND) { ret = 0; } xd3_free_output (stream, tmp_head); } return ret; } #endif /* XD3_ENCODER */ #endif /* _XDELTA3_SECOND_H_ */ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3-test.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ static const uint32_t TEST_SEED1 = 5489UL; #define MT_LEN 624 #define MT_IA 397 static const uint32_t UPPER_MASK = 0x80000000; static const uint32_t LOWER_MASK = 0x7FFFFFFF; static const uint32_t MATRIX_A = 0x9908B0DF; #ifndef SHELL_TESTS #define SHELL_TESTS 1 #endif typedef struct mtrand mtrand; struct mtrand { int mt_index_; uint32_t mt_buffer_[MT_LEN]; }; int test_compare_files (const char* tgt, const char *rec); void mt_init(mtrand *mt, uint32_t seed); uint32_t mt_random (mtrand *mt); int test_setup (void); /* The Mersenne Twister code used herein is code to Michael Brundage. Thanks! * http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation.html */ void mt_init(mtrand *mt, uint32_t seed) { int i; mt->mt_buffer_[0] = seed; mt->mt_index_ = MT_LEN; for (i = 1; i < MT_LEN; i++) { /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ /* 2002/01/09 modified by Makoto Matsumoto */ mt->mt_buffer_[i] = (1812433253UL * (mt->mt_buffer_[i-1] ^ (mt->mt_buffer_[i-1] >> 30)) + i); } } uint32_t mt_random (mtrand *mt) { uint32_t y; unsigned long mag01[2]; mag01[0] = 0; mag01[1] = MATRIX_A; if (mt->mt_index_ >= MT_LEN) { int kk; for (kk = 0; kk < MT_LEN - MT_IA; kk++) { y = (mt->mt_buffer_[kk] & UPPER_MASK) | (mt->mt_buffer_[kk + 1] & LOWER_MASK); mt->mt_buffer_[kk] = mt->mt_buffer_[kk + MT_IA] ^ (y >> 1) ^ mag01[y & 0x1UL]; } for (;kk < MT_LEN - 1; kk++) { y = (mt->mt_buffer_[kk] & UPPER_MASK) | (mt->mt_buffer_[kk + 1] & LOWER_MASK); mt->mt_buffer_[kk] = mt->mt_buffer_[kk + (MT_IA - MT_LEN)] ^ (y >> 1) ^ mag01[y & 0x1UL]; } y = (mt->mt_buffer_[MT_LEN - 1] & UPPER_MASK) | (mt->mt_buffer_[0] & LOWER_MASK); mt->mt_buffer_[MT_LEN - 1] = mt->mt_buffer_[MT_IA - 1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mt->mt_index_ = 0; } y = mt->mt_buffer_[mt->mt_index_++]; y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } static mtrand static_mtrand; #include static uint32_t mt_exp_rand (uint32_t mean, uint32_t max_value) { double mean_d = mean; double erand = log (1.0 / (mt_random (&static_mtrand) / (double)UINT32_MAX)); uint32_t x = (uint32_t) (mean_d * erand + 0.5); return xd3_min (x, max_value); } #if SHELL_TESTS #include #endif #define MSG_IS(x) (stream->msg != NULL && strcmp ((x), stream->msg) == 0) static const usize_t TWO_MEGS_AND_DELTA = (3 << 20); static const usize_t ADDR_CACHE_ROUNDS = 10000; static const usize_t TEST_FILE_MEAN = 16384; static const double TEST_ADD_MEAN = 128; static const double TEST_ADD_MAX = 512; static const double TEST_ADD_RATIO = 0.1; static const double TEST_EPSILON = 0.25; #define TESTBUFSIZE (1024 * 16) #define TESTFILESIZE (1024) static char TEST_TARGET_FILE[TESTFILESIZE]; static char TEST_SOURCE_FILE[TESTFILESIZE]; static char TEST_DELTA_FILE[TESTFILESIZE]; static char TEST_RECON_FILE[TESTFILESIZE]; static char TEST_RECON2_FILE[TESTFILESIZE]; static char TEST_COPY_FILE[TESTFILESIZE]; static char TEST_NOPERM_FILE[TESTFILESIZE]; #define CHECK(cond) \ if (!(cond)) { \ XPR(NT __FILE__":%d: check failure: " #cond, __LINE__); \ abort(); } #if SHELL_TESTS /* Use a fixed soft config so that test values are fixed. See also * test_compress_text(). */ static const char* test_softcfg_str = "-C9,3,4,8,2,36,70"; #endif /*********************************************************************** TEST HELPERS ***********************************************************************/ static void DOT (void) { XPR(NTR "."); } static int do_cmd (xd3_stream *stream, const char *buf) { int ret; if ((ret = system (buf)) != 0) { if (WIFEXITED (ret)) { stream->msg = "command exited non-zero"; IF_DEBUG1 (XPR(NT "command was: %s\n", buf)); } else { stream->msg = "abnormal command termination"; } return ret; } return 0; } static int do_fail (xd3_stream *stream, const char *buf) { int ret; ret = system (buf); if (! WIFEXITED (ret) || WEXITSTATUS (ret) != 1) { stream->msg = "command should have not succeeded"; XPR(NT "command was %s\n", buf); return XD3_INTERNAL; } return 0; } /* Test that the exponential distribution actually produces its mean. */ static int test_random_numbers (xd3_stream *stream, int ignore) { usize_t i; usize_t sum = 0; usize_t mean = 50; usize_t n_rounds = 1000000; double average, error; double allowed_error = 0.1; mt_init (& static_mtrand, 0x9f73f7fe); for (i = 0; i < n_rounds; i += 1) { sum += mt_exp_rand (mean, UINT32_MAX); } average = (double) sum / (double) n_rounds; error = average - (double) mean; if (error < allowed_error && error > -allowed_error) { return 0; } /*XPR(NT "error is %f\n", error);*/ stream->msg = "random distribution looks broken"; return XD3_INTERNAL; } static int test_printf_xoff (xd3_stream *stream, int ignore) { char buf[64]; xoff_t x = XOFF_T_MAX; snprintf_func (buf, sizeof(buf), "%"Q"u", x); const char *expect = XD3_USE_LARGEFILE64 ? "18446744073709551615" : "4294967295"; if (strcmp (buf, expect) == 0) { return 0; } return XD3_INTERNAL; } static void test_unlink (char* file) { int ret; if (file != NULL && *file != 0 && (ret = unlink (file)) != 0 && errno != ENOENT) { XPR(NT "unlink %s failed: %s\n", file, strerror(ret)); } } static void test_cleanup (void) { #if 1 test_unlink (TEST_TARGET_FILE); test_unlink (TEST_SOURCE_FILE); test_unlink (TEST_DELTA_FILE); test_unlink (TEST_RECON_FILE); test_unlink (TEST_RECON2_FILE); test_unlink (TEST_COPY_FILE); test_unlink (TEST_NOPERM_FILE); #endif } int test_setup (void) { static int x = 0; pid_t pid = getpid(); x++; test_cleanup(); snprintf_func (TEST_TARGET_FILE, TESTFILESIZE, "/tmp/xdtest.%d.target.%d", pid, x); snprintf_func (TEST_SOURCE_FILE, TESTFILESIZE, "/tmp/xdtest.%d.source.%d", pid, x); snprintf_func (TEST_DELTA_FILE, TESTFILESIZE, "/tmp/xdtest.%d.delta.%d", pid, x); snprintf_func (TEST_RECON_FILE, TESTFILESIZE, "/tmp/xdtest.%d.recon.%d", pid, x); snprintf_func (TEST_RECON2_FILE, TESTFILESIZE, "/tmp/xdtest.%d.recon2.%d", pid, x); snprintf_func (TEST_COPY_FILE, TESTFILESIZE, "/tmp/xdtest.%d.copy.%d", pid, x); snprintf_func (TEST_NOPERM_FILE, TESTFILESIZE, "/tmp/xdtest.%d.noperm.%d", pid, x); test_cleanup(); return 0; } static int test_make_inputs (xd3_stream *stream, xoff_t *ss_out, xoff_t *ts_out) { usize_t ts = (mt_random (&static_mtrand) % TEST_FILE_MEAN) + TEST_FILE_MEAN / 2; usize_t ss = (mt_random (&static_mtrand) % TEST_FILE_MEAN) + TEST_FILE_MEAN / 2; uint8_t *buf = (uint8_t*) malloc (ts + ss), *sbuf = buf, *tbuf = buf + ss; usize_t sadd = 0, sadd_max = (usize_t)(ss * TEST_ADD_RATIO); FILE *tf = NULL, *sf = NULL; usize_t i, j; int ret; if (buf == NULL) { return ENOMEM; } if ((tf = fopen (TEST_TARGET_FILE, "w")) == NULL || (ss_out != NULL && (sf = fopen (TEST_SOURCE_FILE, "w")) == NULL)) { stream->msg = "write failed"; ret = get_errno (); goto failure; } if (ss_out != NULL) { for (i = 0; i < ss; ) { sbuf[i++] = (uint8_t) mt_random (&static_mtrand); } } /* Then modify the data to produce copies, everything not copied is * an add. The following logic produces the TEST_ADD_RATIO. The * variable SADD contains the number of adds so far, which should * not exceed SADD_MAX. */ /* XPR(NT "ss = %u ts = %u\n", ss, ts); */ for (i = 0; i < ts; ) { usize_t left = ts - i; usize_t next = mt_exp_rand ((uint32_t) TEST_ADD_MEAN, (uint32_t) TEST_ADD_MAX); usize_t add_left = sadd_max - sadd; double add_prob = (left == 0) ? 0 : (add_left / (double) left); int do_copy; next = xd3_min (left, next); do_copy = (next > add_left || (mt_random (&static_mtrand) / \ (double)USIZE_T_MAX) >= add_prob); if (ss_out == NULL) { do_copy &= (i > 0); } else { do_copy &= (ss - next) > 0; } if (do_copy) { /* Copy */ size_t offset = mt_random (&static_mtrand) % ((ss_out == NULL) ? i : (ss - next)); /* XPR(NT "[%u] copy %u at %u ", i, next, offset); */ for (j = 0; j < next; j += 1) { char c = ((ss_out == NULL) ? tbuf : sbuf)[offset + j]; /* XPR(NT "%x%x", (c >> 4) & 0xf, c & 0xf); */ tbuf[i++] = c; } /* XPR(NT "\n"); */ } else { /* Add */ /* XPR(NT "[%u] add %u ", i, next); */ for (j = 0; j < next; j += 1) { char c = (char) mt_random (&static_mtrand); /* XPR(NT "%x%x", (c >> 4) & 0xf, c & 0xf); */ tbuf[i++] = c; } /* XPR(NT "\n"); */ sadd += next; } } /* XPR(NT "sadd = %u max = %u\n", sadd, sadd_max); */ if ((fwrite (tbuf, 1, ts, tf) != ts) || (ss_out != NULL && (fwrite (sbuf, 1, ss, sf) != ss))) { stream->msg = "write failed"; ret = get_errno (); goto failure; } if ((ret = fclose (tf)) || (ss_out != NULL && (ret = fclose (sf)))) { stream->msg = "close failed"; ret = get_errno (); goto failure; } if (ts_out) { (*ts_out) = ts; } if (ss_out) { (*ss_out) = ss; } failure: free (buf); return ret; } int test_compare_files (const char* tgt, const char *rec) { FILE *orig, *recons; static uint8_t obuf[TESTBUFSIZE], rbuf[TESTBUFSIZE]; xoff_t offset = 0; size_t i; size_t oc, rc; xoff_t diffs = 0; if ((orig = fopen (tgt, "r")) == NULL) { XPR(NT "open %s failed\n", tgt); return get_errno (); } if ((recons = fopen (rec, "r")) == NULL) { XPR(NT "open %s failed\n", rec); return get_errno (); } for (;;) { oc = fread (obuf, 1, TESTBUFSIZE, orig); rc = fread (rbuf, 1, TESTBUFSIZE, recons); if (oc != rc) { return XD3_INTERNAL; } if (oc == 0) { break; } for (i = 0; i < oc; i += 1) { if (obuf[i] != rbuf[i]) { XPR(NT "byte %u (read %u @ %"Q"u) %d != %d\n", (int)i, (int)oc, offset, obuf[i], rbuf[i]); diffs++; return XD3_INTERNAL; } } offset += oc; } fclose (orig); fclose (recons); if (diffs != 0) { return XD3_INTERNAL; } return 0; } static int test_copy_to (const char *from, const char *to) { char buf[TESTBUFSIZE]; int ret; snprintf_func (buf, TESTBUFSIZE, "cp -f %s %s", from, to); if ((ret = system (buf)) != 0) { return XD3_INTERNAL; } return 0; } static int test_save_copy (const char *origname) { return test_copy_to(origname, TEST_COPY_FILE); } static int test_file_size (const char* file, xoff_t *size) { struct stat sbuf; int ret; (*size) = 0; if (stat (file, & sbuf) < 0) { ret = get_errno (); XPR(NT "stat failed: %s: %s\n", file, strerror (ret)); return ret; } if (! S_ISREG (sbuf.st_mode)) { ret = XD3_INTERNAL; XPR(NT "not a regular file: %s: %s\n", file, strerror (ret)); return ret; } (*size) = sbuf.st_size; return 0; } /*********************************************************************** READ OFFSET ***********************************************************************/ /* Common test for read_integer errors: encodes a 64-bit value and * then attempts to read as a 32-bit value. If TRUNC is non-zero, * attempts to get errors by shortening the input, otherwise it should * overflow. Expects XD3_INTERNAL and MSG. */ static int test_read_integer_error (xd3_stream *stream, usize_t trunto, const char *msg) { uint64_t eval = 1ULL << 34; uint32_t rval; xd3_output *buf = NULL; const uint8_t *max; const uint8_t *inp; int ret; buf = xd3_alloc_output (stream, buf); if ((ret = xd3_emit_uint64_t (stream, & buf, eval))) { goto fail; } again: inp = buf->base; max = buf->base + buf->next - trunto; if ((ret = xd3_read_uint32_t (stream, & inp, max, & rval)) != XD3_INVALID_INPUT || !MSG_IS (msg)) { ret = XD3_INTERNAL; } else if (trunto && trunto < buf->next) { trunto += 1; goto again; } else { ret = 0; } fail: xd3_free_output (stream, buf); return ret; } /* Test integer overflow using the above routine. */ static int test_decode_integer_overflow (xd3_stream *stream, int unused) { return test_read_integer_error (stream, 0, "overflow in read_intger"); } /* Test integer EOI using the above routine. */ static int test_decode_integer_end_of_input (xd3_stream *stream, int unused) { return test_read_integer_error (stream, 1, "end-of-input in read_integer"); } /* Test that emit_integer/decode_integer/sizeof_integer/read_integer * work on correct inputs. Tests powers of (2^7), plus or minus, up * to the maximum value. */ #define TEST_ENCODE_DECODE_INTEGER(TYPE,ONE,MAX) \ xd3_output *rbuf = NULL; \ xd3_output *dbuf = NULL; \ TYPE values[64]; \ usize_t nvalues = 0; \ usize_t i; \ int ret = 0; \ \ for (i = 0; i < (sizeof (TYPE) * 8); i += 7) \ { \ values[nvalues++] = (ONE << i) - ONE; \ values[nvalues++] = (ONE << i); \ values[nvalues++] = (ONE << i) + ONE; \ } \ \ values[nvalues++] = MAX-ONE; \ values[nvalues++] = MAX; \ \ rbuf = xd3_alloc_output (stream, rbuf); \ dbuf = xd3_alloc_output (stream, dbuf); \ \ for (i = 0; i < nvalues; i += 1) \ { \ const uint8_t *max; \ const uint8_t *inp; \ TYPE val; \ \ DOT (); \ rbuf->next = 0; \ \ if ((ret = xd3_emit_ ## TYPE (stream, & rbuf, values[i])) || \ (ret = xd3_emit_ ## TYPE (stream, & dbuf, values[i]))) \ { \ goto fail; \ } \ \ inp = rbuf->base; \ max = rbuf->base + rbuf->next; \ \ if (rbuf->next != xd3_sizeof_ ## TYPE (values[i])) \ { \ ret = XD3_INTERNAL; \ goto fail; \ } \ \ if ((ret = xd3_read_ ## TYPE (stream, & inp, max, & val))) \ { \ goto fail; \ } \ \ if (val != values[i]) \ { \ ret = XD3_INTERNAL; \ goto fail; \ } \ \ DOT (); \ } \ \ stream->next_in = dbuf->base; \ stream->avail_in = dbuf->next; \ \ for (i = 0; i < nvalues; i += 1) \ { \ TYPE val; \ \ if ((ret = xd3_decode_ ## TYPE (stream, & val))) \ { \ goto fail; \ } \ \ if (val != values[i]) \ { \ ret = XD3_INTERNAL; \ goto fail; \ } \ } \ \ if (stream->avail_in != 0) \ { \ ret = XD3_INTERNAL; \ goto fail; \ } \ \ fail: \ xd3_free_output (stream, rbuf); \ xd3_free_output (stream, dbuf); \ \ return ret static int test_encode_decode_uint32_t (xd3_stream *stream, int unused) { TEST_ENCODE_DECODE_INTEGER(uint32_t,1U,UINT32_MAX); } static int test_encode_decode_uint64_t (xd3_stream *stream, int unused) { TEST_ENCODE_DECODE_INTEGER(uint64_t,1ULL,UINT64_MAX); } static int test_usize_t_overflow (xd3_stream *stream, int unused) { if (USIZE_T_OVERFLOW (USIZE_T_MAX, 0)) { goto fail; } if (USIZE_T_OVERFLOW (0, USIZE_T_MAX)) { goto fail; } if (USIZE_T_OVERFLOW (USIZE_T_MAX / 2, USIZE_T_MAX / 2)) { goto fail; } if (USIZE_T_OVERFLOW (USIZE_T_MAX / 2, USIZE_T_MAX / 2 + 1)) { goto fail; } if (! USIZE_T_OVERFLOW (USIZE_T_MAX, 1)) { goto fail; } if (! USIZE_T_OVERFLOW (1, USIZE_T_MAX)) { goto fail; } if (! USIZE_T_OVERFLOW (USIZE_T_MAX / 2 + 1, USIZE_T_MAX / 2 + 1)) { goto fail; } return 0; fail: stream->msg = "incorrect overflow computation"; return XD3_INTERNAL; } static int test_forward_match (xd3_stream *stream, int unused) { usize_t i; uint8_t buf1[256], buf2[256]; memset(buf1, 0, 256); memset(buf2, 0, 256); for (i = 0; i < 256; i++) { CHECK(xd3_forward_match(buf1, buf2, i) == i); } for (i = 0; i < 255; i++) { buf2[i] = 1; CHECK(xd3_forward_match(buf1, buf2, 256) == i); buf2[i] = 0; } return 0; } /*********************************************************************** Address cache ***********************************************************************/ static int test_address_cache (xd3_stream *stream, int unused) { int ret; usize_t i; usize_t offset; usize_t *addrs; uint8_t *big_buf, *buf_max; const uint8_t *buf; xd3_output *outp; uint8_t *modes; int mode_counts[16]; stream->acache.s_near = stream->code_table_desc->near_modes; stream->acache.s_same = stream->code_table_desc->same_modes; if ((ret = xd3_encode_init_partial (stream))) { return ret; } addrs = (usize_t*) xd3_alloc (stream, sizeof (usize_t), ADDR_CACHE_ROUNDS); modes = (uint8_t*) xd3_alloc (stream, sizeof (uint8_t), ADDR_CACHE_ROUNDS); memset (mode_counts, 0, sizeof (mode_counts)); memset (modes, 0, ADDR_CACHE_ROUNDS); addrs[0] = 0; mt_init (& static_mtrand, 0x9f73f7fc); /* First pass: encode addresses */ xd3_init_cache (& stream->acache); for (offset = 1; offset < ADDR_CACHE_ROUNDS; offset += 1) { double p; usize_t addr; usize_t prev_i; usize_t nearby; p = (mt_random (&static_mtrand) / (double)UINT32_MAX); prev_i = mt_random (&static_mtrand) % offset; nearby = (mt_random (&static_mtrand) % 256) % offset; nearby = xd3_max (1U, nearby); if (p < 0.1) { addr = addrs[offset-nearby]; } else if (p < 0.4) { addr = xd3_min (addrs[prev_i] + nearby, offset-1); } else { addr = prev_i; } if ((ret = xd3_encode_address (stream, addr, offset, & modes[offset]))) { return ret; } addrs[offset] = addr; mode_counts[modes[offset]] += 1; } /* Copy addresses into a contiguous buffer. */ big_buf = (uint8_t*) xd3_alloc (stream, xd3_sizeof_output (ADDR_HEAD (stream)), 1); for (offset = 0, outp = ADDR_HEAD (stream); outp != NULL; offset += outp->next, outp = outp->next_page) { memcpy (big_buf + offset, outp->base, outp->next); } buf_max = big_buf + offset; buf = big_buf; /* Second pass: decode addresses */ xd3_init_cache (& stream->acache); for (offset = 1; offset < ADDR_CACHE_ROUNDS; offset += 1) { usize_t addr; if ((ret = xd3_decode_address (stream, offset, modes[offset], & buf, buf_max, & addr))) { return ret; } if (addr != addrs[offset]) { stream->msg = "incorrect decoded address"; return XD3_INTERNAL; } } /* Check that every byte, mode was used. */ if (buf != buf_max) { stream->msg = "address bytes not used"; return XD3_INTERNAL; } for (i = 0; i < (2 + stream->acache.s_same + stream->acache.s_near); i += 1) { if (mode_counts[i] == 0) { stream->msg = "address mode not used"; return XD3_INTERNAL; } } xd3_free (stream, modes); xd3_free (stream, addrs); xd3_free (stream, big_buf); return 0; } /*********************************************************************** Encode and decode with single bit error ***********************************************************************/ /* It compresses from 256 to around 185 bytes. * Avoids matching addresses that are a single-bit difference. * Avoids matching address 0. */ static const uint8_t test_text[] = "this is a story\n" "abouttttttttttt\n" "- his is a stor\n" "- about nothing " " all. boutique -" "his story is a -" "about " "what happens all" " the time what -" "am I ttttttt the" " person said, so" " what, per son -" " gory story is -" " about nothing -" "tttttt to test -" "his sto nothing"; static const uint8_t test_apphead[] = "header test"; static int test_compress_text (xd3_stream *stream, uint8_t *encoded, usize_t *encoded_size) { int ret; xd3_config cfg; int oflags = stream->flags; int flags = stream->flags | XD3_FLUSH; xd3_free_stream (stream); xd3_init_config (& cfg, flags); /* This configuration is fixed so that the "expected non-error" the counts in * decompress_single_bit_errors are too. See test_coftcfg_str. */ cfg.smatch_cfg = XD3_SMATCH_SOFT; cfg.smatcher_soft.name = "test"; cfg.smatcher_soft.large_look = 64; /* no source, not used */ cfg.smatcher_soft.large_step = 64; /* no source, not used */ cfg.smatcher_soft.small_look = 4; cfg.smatcher_soft.small_chain = 128; cfg.smatcher_soft.small_lchain = 16; cfg.smatcher_soft.max_lazy = 8; cfg.smatcher_soft.long_enough = 128; xd3_config_stream (stream, & cfg); (*encoded_size) = 0; xd3_set_appheader (stream, test_apphead, (usize_t) strlen ((char*) test_apphead)); if ((ret = xd3_encode_stream (stream, test_text, sizeof (test_text), encoded, encoded_size, 4*sizeof (test_text)))) { goto fail; } if ((ret = xd3_close_stream (stream))) { goto fail; } fail: xd3_free_stream (stream); xd3_init_config (& cfg, oflags); xd3_config_stream (stream, & cfg); return ret; } static int test_decompress_text (xd3_stream *stream, uint8_t *enc, usize_t enc_size, usize_t test_desize) { xd3_config cfg; char decoded[sizeof (test_text)]; uint8_t *apphead; usize_t apphead_size; usize_t decoded_size; const char *msg; int ret; usize_t pos = 0; int flags = stream->flags; usize_t take; input: /* Test decoding test_desize input bytes at a time */ take = xd3_min (enc_size - pos, test_desize); CHECK(take > 0); xd3_avail_input (stream, enc + pos, take); again: ret = xd3_decode_input (stream); pos += take; take = 0; switch (ret) { case XD3_OUTPUT: break; case XD3_WINSTART: case XD3_GOTHEADER: goto again; case XD3_INPUT: if (pos < enc_size) { goto input; } /* else fallthrough */ case XD3_WINFINISH: default: goto fail; } CHECK(ret == XD3_OUTPUT); CHECK(pos == enc_size); if (stream->avail_out != sizeof (test_text)) { stream->msg = "incorrect output size"; ret = XD3_INTERNAL; goto fail; } decoded_size = stream->avail_out; memcpy (decoded, stream->next_out, stream->avail_out); xd3_consume_output (stream); if ((ret = xd3_get_appheader (stream, & apphead, & apphead_size))) { goto fail; } if (apphead_size != strlen ((char*) test_apphead) || memcmp (apphead, test_apphead, strlen ((char*) test_apphead)) != 0) { stream->msg = "incorrect appheader"; ret = XD3_INTERNAL; goto fail; } if ((ret = xd3_decode_input (stream)) != XD3_WINFINISH || (ret = xd3_close_stream (stream)) != 0) { goto fail; } if (decoded_size != sizeof (test_text) || memcmp (decoded, test_text, sizeof (test_text)) != 0) { stream->msg = "incorrect output text"; ret = EIO; } fail: msg = stream->msg; xd3_free_stream (stream); xd3_init_config (& cfg, flags); xd3_config_stream (stream, & cfg); stream->msg = msg; return ret; } static int test_decompress_single_bit_error (xd3_stream *stream, int expected_non_failures) { int ret; usize_t i; uint8_t encoded[4*sizeof (test_text)]; /* make room for alt code table */ usize_t encoded_size; int non_failures = 0; int cksum = (stream->flags & XD3_ADLER32) != 0; //#define DEBUG_TEST_FAILURES #ifndef DEBUG_TEST_FAILURES #define TEST_FAILURES() #else /* For checking non-failure cases by hand, enable this macro and run * xdelta printdelta with print_cpymode disabled. Every non-failure * should change a copy address mode, which doesn't cause a failure * because the address cache starts out with all zeros. ./xdelta3 test for i in test_text.xz.*; do ./xdelta3 printdelta $i > $i.out; diff $i.out test_text.xz.0.out; done */ system ("rm -rf test_text.*"); { char buf[TESTBUFSIZE]; FILE *f; snprintf_func (buf, TESTBUFSIZE, "test_text"); f = fopen (buf, "w"); fwrite (test_text,1,sizeof (test_text),f); fclose (f); } #define TEST_FAILURES() \ do { \ char buf[TESTBUFSIZE]; \ FILE *f; \ snprintf_func (buf, TESTBUFSIZE, "test_text.xz.%d", non_failures); \ f = fopen (buf, "w"); \ fwrite (encoded,1,encoded_size,f); \ fclose (f); \ } while (0) #endif stream->sec_data.inefficient = 1; stream->sec_inst.inefficient = 1; stream->sec_addr.inefficient = 1; /* Encode text, test correct input */ if ((ret = test_compress_text (stream, encoded, & encoded_size))) { /*stream->msg = "without error: encode failure";*/ return ret; } if ((ret = test_decompress_text (stream, encoded, encoded_size, sizeof (test_text) / 4))) { /*stream->msg = "without error: decode failure";*/ return ret; } TEST_FAILURES(); for (i = 0; i < encoded_size*8; i += 1) { /* Single bit error. */ encoded[i/8] ^= 1 << (i%8); if ((ret = test_decompress_text (stream, encoded, encoded_size, sizeof (test_text))) == 0) { non_failures += 1; #ifdef DEBUG_TEST_FAILURES XPR(NT "%u[%u] non-failure %u\n", i/8, i%8, non_failures); #endif TEST_FAILURES(); } else { /*XPR(NT "%u[%u] failure: %s\n", i/8, i%8, stream->msg);*/ } /* decompress_text returns EIO when the final memcmp() fails, but that * should never happen with checksumming on. */ if (cksum && ret == EIO) { /*XPR(NT "%u[%u] cksum mismatch\n", i/8, i%8);*/ stream->msg = "checksum mismatch"; return XD3_INTERNAL; } /* Undo single bit error. */ encoded[i/8] ^= 1 << (i%8); } /* Test correct input again */ if ((ret = test_decompress_text (stream, encoded, encoded_size, 1))) { /*stream->msg = "without error: decode failure";*/ return ret; } /* Check expected non-failures */ if (non_failures > expected_non_failures) { XPR(NT "non-failures %u > expected %u", non_failures, expected_non_failures); stream->msg = "incorrect"; return XD3_INTERNAL; } DOT (); return 0; } /*********************************************************************** Secondary compression tests ***********************************************************************/ #if SECONDARY_ANY typedef int (*sec_dist_func) (xd3_stream *stream, xd3_output *data); static int sec_dist_func1 (xd3_stream *stream, xd3_output *data); static int sec_dist_func2 (xd3_stream *stream, xd3_output *data); static int sec_dist_func3 (xd3_stream *stream, xd3_output *data); static int sec_dist_func4 (xd3_stream *stream, xd3_output *data); static int sec_dist_func5 (xd3_stream *stream, xd3_output *data); static int sec_dist_func6 (xd3_stream *stream, xd3_output *data); static int sec_dist_func7 (xd3_stream *stream, xd3_output *data); static int sec_dist_func8 (xd3_stream *stream, xd3_output *data); static int sec_dist_func9 (xd3_stream *stream, xd3_output *data); static int sec_dist_func10 (xd3_stream *stream, xd3_output *data); static int sec_dist_func11 (xd3_stream *stream, xd3_output *data); static sec_dist_func sec_dists[] = { sec_dist_func1, sec_dist_func2, sec_dist_func3, sec_dist_func4, sec_dist_func5, sec_dist_func6, sec_dist_func7, sec_dist_func8, sec_dist_func9, sec_dist_func10, sec_dist_func11, }; /* Test ditsribution: 100 bytes of the same character (13). */ static int sec_dist_func1 (xd3_stream *stream, xd3_output *data) { int i, ret; for (i = 0; i < 100; i += 1) { if ((ret = xd3_emit_byte (stream, & data, 13))) { return ret; } } return 0; } /* Test ditsribution: uniform covering half the alphabet. */ static int sec_dist_func2 (xd3_stream *stream, xd3_output *data) { int i, ret; for (i = 0; i < ALPHABET_SIZE; i += 1) { if ((ret = xd3_emit_byte (stream, & data, i%(ALPHABET_SIZE/2)))) { return ret; } } return 0; } /* Test ditsribution: uniform covering the entire alphabet. */ static int sec_dist_func3 (xd3_stream *stream, xd3_output *data) { int i, ret; for (i = 0; i < ALPHABET_SIZE; i += 1) { if ((ret = xd3_emit_byte (stream, & data, i%ALPHABET_SIZE))) { return ret; } } return 0; } /* Test distribution: An exponential distribution covering half the alphabet */ static int sec_dist_func4 (xd3_stream *stream, xd3_output *data) { int i, ret, x; for (i = 0; i < ALPHABET_SIZE*20; i += 1) { x = mt_exp_rand (10, ALPHABET_SIZE/2); if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; } } return 0; } /* Test distribution: An exponential distribution covering the entire alphabet */ static int sec_dist_func5 (xd3_stream *stream, xd3_output *data) { int i, ret, x; for (i = 0; i < ALPHABET_SIZE*20; i += 1) { x = mt_exp_rand (10, ALPHABET_SIZE-1); if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; } } return 0; } /* Test distribution: An uniform random distribution covering half the alphabet */ static int sec_dist_func6 (xd3_stream *stream, xd3_output *data) { int i, ret, x; for (i = 0; i < ALPHABET_SIZE*20; i += 1) { x = mt_random (&static_mtrand) % (ALPHABET_SIZE/2); if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; } } return 0; } /* Test distribution: An uniform random distribution covering the entire alphabet */ static int sec_dist_func7 (xd3_stream *stream, xd3_output *data) { int i, ret, x; for (i = 0; i < ALPHABET_SIZE*200; i += 1) { x = mt_random (&static_mtrand) % ALPHABET_SIZE; if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; } } return 0; } /* Test distribution: A small number of frequent characters, difficult * to divide into many groups */ static int sec_dist_func8 (xd3_stream *stream, xd3_output *data) { int i, ret; for (i = 0; i < ALPHABET_SIZE*5; i += 1) { if ((ret = xd3_emit_byte (stream, & data, 0))) { return ret; } if ((ret = xd3_emit_byte (stream, & data, 64))) { return ret; } if ((ret = xd3_emit_byte (stream, & data, 128))) { return ret; } if ((ret = xd3_emit_byte (stream, & data, 255))) { return ret; } } return 0; } /* Test distribution: One that causes many FGK block promotions (found a bug) */ static int sec_dist_func9 (xd3_stream *stream, xd3_output *data) { int i, ret; int ramp = 0; int rcount = 0; int prom = 0; int pcount = 0; /* 200 was long enough to trigger it--only when stricter checking * that counted all blocks was turned on, but it seems I deleted * this code. (missing fgk_free_block on line 398). */ for (i = 0; i < ALPHABET_SIZE*200; i += 1) { repeat: if (ramp < ALPHABET_SIZE) { /* Initially Nth symbol has (N+1) frequency */ if (rcount <= ramp) { rcount += 1; if ((ret = xd3_emit_byte (stream, & data, ramp))) { return ret; } continue; } ramp += 1; rcount = 0; goto repeat; } /* Thereafter, promote least freq to max freq */ if (pcount == ALPHABET_SIZE) { pcount = 0; prom = (prom + 1) % ALPHABET_SIZE; } pcount += 1; if ((ret = xd3_emit_byte (stream, & data, prom))) { return ret; } } return 0; } /* Test distribution: freq[i] == i*i, creates a 21-bit code length, fixed in 3.0r. */ static int sec_dist_func10 (xd3_stream *stream, xd3_output *data) { int i, j, ret; for (i = 0; i < ALPHABET_SIZE; i += 1) { for (j = 0; j <= (i*i); j += 1) { if ((ret = xd3_emit_byte (stream, & data, i))) { return ret; } } } return 0; } /* Test distribution: fibonacci */ static int sec_dist_func11 (xd3_stream *stream, xd3_output *data) { int sum0 = 0; int sum1 = 1; int i, j, ret; for (i = 0; i < 33; ++i) { for (j = 0; j < (sum0 + sum1); ++j) { if ((ret = xd3_emit_byte (stream, & data, i))) { return ret; } } sum0 = sum1; sum1 = j; } return 0; } static int test_secondary_decode (xd3_stream *stream, const xd3_sec_type *sec, usize_t input_size, usize_t compress_size, const uint8_t *dec_input, const uint8_t *dec_correct, uint8_t *dec_output) { int ret; xd3_sec_stream *dec_stream; const uint8_t *dec_input_used, *dec_input_end; uint8_t *dec_output_used, *dec_output_end; if ((dec_stream = sec->alloc (stream)) == NULL) { return ENOMEM; } if ((ret = sec->init (stream, dec_stream, 0)) != 0) { goto fail; } dec_input_used = dec_input; dec_input_end = dec_input + compress_size; dec_output_used = dec_output; dec_output_end = dec_output + input_size; if ((ret = sec->decode (stream, dec_stream, & dec_input_used, dec_input_end, & dec_output_used, dec_output_end))) { goto fail; } if (dec_input_used != dec_input_end) { stream->msg = "unused input"; ret = XD3_INTERNAL; goto fail; } if (dec_output_used != dec_output_end) { stream->msg = "unfinished output"; ret = XD3_INTERNAL; goto fail; } if (memcmp (dec_output, dec_correct, input_size) != 0) { stream->msg = "incorrect output"; ret = XD3_INTERNAL; goto fail; } fail: sec->destroy (stream, dec_stream); return ret; } static int test_secondary (xd3_stream *stream, const xd3_sec_type *sec, usize_t groups) { usize_t test_i; int ret; xd3_output *in_head, *out_head, *p; usize_t p_off, input_size, compress_size; uint8_t *dec_input = NULL, *dec_output = NULL, *dec_correct = NULL; xd3_sec_stream *enc_stream; xd3_sec_cfg cfg; memset (& cfg, 0, sizeof (cfg)); cfg.inefficient = 1; for (cfg.ngroups = 1; cfg.ngroups <= groups; cfg.ngroups += 1) { XPR(NTR "\n..."); for (test_i = 0; test_i < SIZEOF_ARRAY (sec_dists); test_i += 1) { mt_init (& static_mtrand, 0x9f73f7fc); in_head = xd3_alloc_output (stream, NULL); out_head = xd3_alloc_output (stream, NULL); enc_stream = sec->alloc (stream); dec_input = NULL; dec_output = NULL; dec_correct = NULL; if (in_head == NULL || out_head == NULL || enc_stream == NULL) { goto nomem; } if ((ret = sec_dists[test_i] (stream, in_head))) { goto fail; } if ((ret = sec->init (stream, enc_stream, 1)) != 0) { goto fail; } /* Encode data */ if ((ret = sec->encode (stream, enc_stream, in_head, out_head, & cfg))) { XPR(NT "test %"W"u: encode: %s", test_i, stream->msg); goto fail; } /* Calculate sizes, allocate contiguous arrays for decoding */ input_size = xd3_sizeof_output (in_head); compress_size = xd3_sizeof_output (out_head); XPR(NTR "%.3f", 8.0 * (double) compress_size / (double) input_size); if ((dec_input = (uint8_t*) xd3_alloc (stream, compress_size, 1)) == NULL || (dec_output = (uint8_t*) xd3_alloc (stream, input_size, 1)) == NULL || (dec_correct = (uint8_t*) xd3_alloc (stream, input_size, 1)) == NULL) { goto nomem; } /* Fill the compressed data array */ for (p_off = 0, p = out_head; p != NULL; p_off += p->next, p = p->next_page) { memcpy (dec_input + p_off, p->base, p->next); } CHECK(p_off == compress_size); /* Fill the input data array */ for (p_off = 0, p = in_head; p != NULL; p_off += p->next, p = p->next_page) { memcpy (dec_correct + p_off, p->base, p->next); } CHECK(p_off == input_size); if ((ret = test_secondary_decode (stream, sec, input_size, compress_size, dec_input, dec_correct, dec_output))) { XPR(NT "test %"W"u: decode: %s", test_i, stream->msg); goto fail; } /* Single-bit error test, only cover the first 10 bytes. * Some non-failures are expected in the Huffman case: * Changing the clclen array, for example, may not harm the * decoding. Really looking for faults here. */ { int i; int bytes = xd3_min (compress_size, 10U); for (i = 0; i < bytes * 8; i += 1) { dec_input[i/8] ^= 1 << (i%8); if ((ret = test_secondary_decode (stream, sec, input_size, compress_size, dec_input, dec_correct, dec_output)) == 0) { /*XPR(NT "test %u: decode single-bit [%u/%u] error non-failure", test_i, i/8, i%8);*/ } dec_input[i/8] ^= 1 << (i%8); if ((i % (2*bytes)) == (2*bytes)-1) { DOT (); } } ret = 0; } if (0) { nomem: ret = ENOMEM; } fail: sec->destroy (stream, enc_stream); xd3_free_output (stream, in_head); xd3_free_output (stream, out_head); xd3_free (stream, dec_input); xd3_free (stream, dec_output); xd3_free (stream, dec_correct); if (ret != 0) { return ret; } } } return 0; } IF_FGK (static int test_secondary_fgk (xd3_stream *stream, usize_t gp) { return test_secondary (stream, & fgk_sec_type, gp); }) IF_DJW (static int test_secondary_huff (xd3_stream *stream, usize_t gp) { return test_secondary (stream, & djw_sec_type, gp); }) IF_LZMA (static int test_secondary_lzma (xd3_stream *stream, usize_t gp) { return test_secondary (stream, & lzma_sec_type, gp); }) #endif /* SECONDARY_ANY */ /*********************************************************************** TEST INSTRUCTION TABLE ***********************************************************************/ /* Test that xd3_choose_instruction() does the right thing for its code * table. */ static int test_choose_instruction (xd3_stream *stream, int ignore) { int i; stream->code_table = (*stream->code_table_func) (); for (i = 0; i < 256; i += 1) { const xd3_dinst *d = stream->code_table + i; xd3_rinst prev, inst; CHECK(d->type1 > 0); memset (& prev, 0, sizeof (prev)); memset (& inst, 0, sizeof (inst)); if (d->type2 == 0) { inst.type = d->type1; if ((inst.size = d->size1) == 0) { inst.size = TESTBUFSIZE; } XD3_CHOOSE_INSTRUCTION (stream, NULL, & inst); if (inst.code2 != 0 || inst.code1 != i) { stream->msg = "wrong single instruction"; return XD3_INTERNAL; } } else { prev.type = d->type1; prev.size = d->size1; inst.type = d->type2; inst.size = d->size2; XD3_CHOOSE_INSTRUCTION (stream, & prev, & inst); if (prev.code2 != i) { stream->msg = "wrong double instruction"; return XD3_INTERNAL; } } } return 0; } static int test_checksum_step (xd3_stream *stream, int ignore) { const int bufsize = 128; uint8_t buf[128]; for (int i = 0; i < bufsize; i++) { buf[i] = mt_random (&static_mtrand) & 0xff; } for (usize_t cksize = 4; cksize <= 32; cksize += 3) { xd3_hash_cfg h1; usize_t x; int ret; if ((ret = xd3_size_hashtable (stream, XD3_ALLOCSIZE, cksize, &h1)) != 0) { return ret; } x = xd3_large_cksum (&h1, buf, cksize); for (usize_t pos = 0; pos <= (bufsize - cksize); pos++) { usize_t y = xd3_large_cksum (&h1, buf + pos, cksize); if (x != y) { stream->msg = "checksum != incremental checksum"; return XD3_INTERNAL; } x = xd3_large_cksum_update (&h1, x, buf + pos, cksize); } xd3_free (stream, h1.powers); } return 0; } /*********************************************************************** 64BIT STREAMING ***********************************************************************/ /* This test encodes and decodes a series of 1 megabyte windows, each * containing a long run of zeros along with a single xoff_t size * record to indicate the sequence. */ static int test_streaming (xd3_stream *in_stream, uint8_t *encbuf, uint8_t *decbuf, uint8_t *delbuf, usize_t megs) { xd3_stream estream, dstream; int ret; usize_t i, delsize, decsize; xd3_config cfg; xd3_init_config (& cfg, in_stream->flags); cfg.flags |= XD3_COMPLEVEL_6; if ((ret = xd3_config_stream (& estream, & cfg)) || (ret = xd3_config_stream (& dstream, & cfg))) { goto fail; } for (i = 0; i < megs; i += 1) { ((usize_t*) encbuf)[0] = i; if ((i % 200) == 199) { DOT (); } if ((ret = xd3_process_stream (1, & estream, xd3_encode_input, 0, encbuf, 1 << 20, delbuf, & delsize, 1 << 20))) { in_stream->msg = estream.msg; goto fail; } if ((ret = xd3_process_stream (0, & dstream, xd3_decode_input, 0, delbuf, delsize, decbuf, & decsize, 1 << 20))) { in_stream->msg = dstream.msg; goto fail; } if (decsize != 1 << 20 || memcmp (encbuf, decbuf, 1 << 20) != 0) { in_stream->msg = "wrong result"; ret = XD3_INTERNAL; goto fail; } } if ((ret = xd3_close_stream (& estream)) || (ret = xd3_close_stream (& dstream))) { goto fail; } fail: xd3_free_stream (& estream); xd3_free_stream (& dstream); return ret; } /* Run tests of data streaming of over and around 4GB of data. */ static int test_compressed_stream_overflow (xd3_stream *stream, int ignore) { int ret; int i; uint8_t *buf; if ((buf = (uint8_t*) malloc (TWO_MEGS_AND_DELTA)) == NULL) { return ENOMEM; } memset (buf, 0, TWO_MEGS_AND_DELTA); for (i = 0; i < (2 << 20); i += 256) { int j; int off = mt_random(& static_mtrand) % 10; for (j = 0; j < 256; j++) { buf[i + j] = j + off; } } /* Test overflow of a 32-bit file offset. */ if (SIZEOF_XOFF_T == 4) { ret = test_streaming (stream, buf, buf + (1 << 20), buf + (2 << 20), (1 << 12) + 1); if (ret == XD3_INVALID_INPUT && MSG_IS ("decoder file offset overflow")) { ret = 0; } else { XPR(NT XD3_LIB_ERRMSG (stream, ret)); stream->msg = "expected overflow condition"; ret = XD3_INTERNAL; goto fail; } } /* Test transfer of exactly 32bits worth of data. */ if ((ret = test_streaming (stream, buf, buf + (1 << 20), buf + (2 << 20), 1 << 12))) { goto fail; } fail: free (buf); return ret; } /*********************************************************************** COMMAND LINE ***********************************************************************/ #if SHELL_TESTS /* For each pair of command templates in the array below, test that * encoding and decoding commands work. Also check for the expected * size delta, which should be approximately TEST_ADD_RATIO times the * file size created by test_make_inputs. Due to differences in the * application header, it is suppressed (-A) so that all delta files * are the same. */ static int test_command_line_arguments (xd3_stream *stream, int ignore) { int i, ret; static const char* cmdpairs[] = { /* standard input, output */ "%s %s -A < %s > %s", "%s -d < %s > %s", "%s %s -A -e < %s > %s", "%s -d < %s > %s", "%s %s -A= encode < %s > %s", "%s decode < %s > %s", "%s %s -A -q encode < %s > %s", "%s -qdq < %s > %s", /* file input, standard output */ "%s %s -A= %s > %s", "%s -d %s > %s", "%s %s -A -e %s > %s", "%s -d %s > %s", "%s %s encode -A= %s > %s", "%s decode %s > %s", /* file input, output */ "%s %s -A= %s %s", "%s -d %s %s", "%s %s -A -e %s %s", "%s -d %s %s", "%s %s -A= encode %s %s", "%s decode %s %s", /* option placement */ "%s %s -A -f %s %s", "%s -f -d %s %s", "%s %s -e -A= %s %s", "%s -d -f %s %s", "%s %s -f encode -A= %s %s", "%s -f decode -f %s %s", }; char ecmd[TESTBUFSIZE], dcmd[TESTBUFSIZE]; int pairs = SIZEOF_ARRAY (cmdpairs) / 2; xoff_t tsize; xoff_t dsize; double ratio; mt_init (& static_mtrand, 0x9f73f7fc); for (i = 0; i < pairs; i += 1) { test_setup (); if ((ret = test_make_inputs (stream, NULL, & tsize))) { return ret; } snprintf_func (ecmd, TESTBUFSIZE, cmdpairs[2*i], program_name, test_softcfg_str, TEST_TARGET_FILE, TEST_DELTA_FILE); snprintf_func (dcmd, TESTBUFSIZE, cmdpairs[2*i+1], program_name, TEST_DELTA_FILE, TEST_RECON_FILE); /* Encode and decode. */ if ((ret = system (ecmd)) != 0) { XPR(NT "encode command: %s\n", ecmd); stream->msg = "encode cmd failed"; return XD3_INTERNAL; } if ((ret = system (dcmd)) != 0) { XPR(NT "decode command: %s\n", dcmd); stream->msg = "decode cmd failed"; return XD3_INTERNAL; } /* Compare the target file. */ if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_RECON_FILE))) { return ret; } if ((ret = test_file_size (TEST_DELTA_FILE, & dsize))) { return ret; } ratio = (double) dsize / (double) tsize; /* Check that it is not too small, not too large. */ if (ratio >= TEST_ADD_RATIO + TEST_EPSILON) { XPR(NT "test encode with size ratio %.4f, " "expected < %.4f (%"Q"u, %"Q"u)\n", ratio, TEST_ADD_RATIO + TEST_EPSILON, dsize, tsize); stream->msg = "strange encoding"; return XD3_INTERNAL; } if (ratio <= TEST_ADD_RATIO * (1.0 - 2 * TEST_EPSILON)) { XPR(NT "test encode with size ratio %.4f, " "expected > %.4f\n", ratio, TEST_ADD_RATIO - TEST_EPSILON); stream->msg = "strange encoding"; return XD3_INTERNAL; } /* Also check that test_compare_files works. The delta and original should * not be identical. */ if ((ret = test_compare_files (TEST_DELTA_FILE, TEST_TARGET_FILE)) == 0) { stream->msg = "broken test_compare_files"; return XD3_INTERNAL; } test_cleanup (); DOT (); } return 0; } static int check_vcdiff_header (xd3_stream *stream, const char *input, const char *line_start, const char *matches, int yes_or_no) { int ret; char vcmd[TESTBUFSIZE], gcmd[TESTBUFSIZE]; snprintf_func (vcmd, TESTBUFSIZE, "%s printhdr -f %s %s", program_name, input, TEST_RECON2_FILE); if ((ret = system (vcmd)) != 0) { XPR(NT "printhdr command: %s\n", vcmd); stream->msg = "printhdr cmd failed"; return XD3_INTERNAL; } snprintf_func (gcmd, TESTBUFSIZE, "grep \"%s.*%s.*\" %s > /dev/null", line_start, matches, TEST_RECON2_FILE); if (yes_or_no) { if ((ret = do_cmd (stream, gcmd))) { XPR(NT "%s\n", gcmd); return ret; } } else { if ((ret = do_fail (stream, gcmd))) { XPR(NT "%s\n", gcmd); return ret; } } return 0; } static int test_recode_command2 (xd3_stream *stream, int has_source, int variant, int change) { int has_adler32 = (variant & 0x1) != 0; int has_apphead = (variant & 0x2) != 0; int has_secondary = (variant & 0x4) != 0; int change_adler32 = (change & 0x1) != 0; int change_apphead = (change & 0x2) != 0; int change_secondary = (change & 0x4) != 0; int recoded_adler32 = change_adler32 ? !has_adler32 : has_adler32; int recoded_apphead = change_apphead ? !has_apphead : has_apphead; int recoded_secondary = change_secondary ? !has_secondary : has_secondary; char ecmd[TESTBUFSIZE], recmd[TESTBUFSIZE], dcmd[TESTBUFSIZE]; xoff_t tsize, ssize; int ret; test_setup (); if ((ret = test_make_inputs (stream, has_source ? & ssize : NULL, & tsize))) { return ret; } /* First encode */ snprintf_func (ecmd, TESTBUFSIZE, "%s %s -f %s %s %s %s %s %s %s", program_name, test_softcfg_str, has_adler32 ? "" : "-n ", has_apphead ? "-A=encode_apphead " : "-A= ", has_secondary ? "-S djw " : "-S none ", has_source ? "-s " : "", has_source ? TEST_SOURCE_FILE : "", TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = system (ecmd)) != 0) { XPR(NT "encode command: %s\n", ecmd); stream->msg = "encode cmd failed"; return XD3_INTERNAL; } /* Now recode */ snprintf_func (recmd, TESTBUFSIZE, "%s recode %s -f %s %s %s %s %s", program_name, test_softcfg_str, recoded_adler32 ? "" : "-n ", !change_apphead ? "" : (recoded_apphead ? "-A=recode_apphead " : "-A= "), recoded_secondary ? "-S djw " : "-S= ", TEST_DELTA_FILE, TEST_COPY_FILE); if ((ret = system (recmd)) != 0) { XPR(NT "recode command: %s\n", recmd); stream->msg = "recode cmd failed"; return XD3_INTERNAL; } /* Check recode changes. */ if ((ret = check_vcdiff_header (stream, TEST_COPY_FILE, "VCDIFF window indicator", "VCD_SOURCE", has_source))) { return ret; } if ((ret = check_vcdiff_header (stream, TEST_COPY_FILE, "VCDIFF header indicator", "VCD_SECONDARY", recoded_secondary))) { return ret; } if ((ret = check_vcdiff_header (stream, TEST_COPY_FILE, "VCDIFF window indicator", "VCD_ADLER32", /* Recode can't generate an adler32 * checksum, it can only preserve it or * remove it. */ has_adler32 && recoded_adler32))) { return ret; } if (!change_apphead) { if ((ret = check_vcdiff_header (stream, TEST_COPY_FILE, "VCDIFF header indicator", "VCD_APPHEADER", has_apphead))) { return ret; } if ((ret = check_vcdiff_header (stream, TEST_COPY_FILE, "VCDIFF application header", "encode_apphead", has_apphead))) { return ret; } } else { if ((ret = check_vcdiff_header (stream, TEST_COPY_FILE, "VCDIFF header indicator", "VCD_APPHEADER", recoded_apphead))) { return ret; } if (recoded_apphead && (ret = check_vcdiff_header (stream, TEST_COPY_FILE, "VCDIFF application header", "recode_apphead", 1))) { return ret; } } /* Now decode */ snprintf_func (dcmd, TESTBUFSIZE, "%s -fd %s %s %s %s ", program_name, has_source ? "-s " : "", has_source ? TEST_SOURCE_FILE : "", TEST_COPY_FILE, TEST_RECON_FILE); if ((ret = system (dcmd)) != 0) { XPR(NT "decode command: %s\n", dcmd); stream->msg = "decode cmd failed"; return XD3_INTERNAL; } /* Now compare. */ if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_RECON_FILE))) { return ret; } test_cleanup (); return 0; } static int test_recode_command (xd3_stream *stream, int ignore) { /* Things to test: * - with and without a source file (recode does not change) * * (recode may or may not change -- 8 variations) * - with and without adler32 * - with and without app header * - with and without secondary */ int has_source; int variant; int change; int ret; for (has_source = 0; has_source < 2; has_source++) { for (variant = 0; variant < 8; variant++) { for (change = 0; change < 8; change++) { if ((ret = test_recode_command2 (stream, has_source, variant, change))) { return ret; } } DOT (); } } return 0; } #if SECONDARY_LZMA static int test_secondary_lzma_default (xd3_stream *stream, int ignore) { char ecmd[TESTBUFSIZE]; int ret; test_setup (); if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; } /* First encode */ snprintf_func (ecmd, TESTBUFSIZE, "%s -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = system (ecmd)) != 0) { return XD3_INTERNAL; } if ((ret = check_vcdiff_header (stream, TEST_DELTA_FILE, "VCDIFF secondary compressor", "lzma", 1))) { return ret; } test_cleanup (); return 0; } #endif /* SECONDARY_LZMA */ #endif /* SHELL_TESTS */ /*********************************************************************** EXTERNAL I/O DECOMPRESSION/RECOMPRESSION ***********************************************************************/ #if EXTERNAL_COMPRESSION /* This performs one step of the test_externally_compressed_io * function described below. It builds a pipe containing both Xdelta * and external compression/decompression that should not modify the * data passing through. */ static int test_compressed_pipe (xd3_stream *stream, main_extcomp *ext, char* buf, const char* comp_options, const char* decomp_options, int do_ext_recomp, const char* msg) { int ret; char decomp_buf[TESTBUFSIZE]; if (do_ext_recomp) { snprintf_func (decomp_buf, TESTBUFSIZE, " | %s %s", ext->decomp_cmdname, ext->decomp_options); } else { decomp_buf[0] = 0; } snprintf_func (buf, TESTBUFSIZE, "%s %s < %s | %s %s | %s %s%s > %s", ext->recomp_cmdname, ext->recomp_options, TEST_TARGET_FILE, program_name, comp_options, program_name, decomp_options, decomp_buf, TEST_RECON_FILE); if ((ret = system (buf)) != 0) { stream->msg = msg; return XD3_INTERNAL; } if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_RECON_FILE))) { return XD3_INTERNAL; } DOT (); return 0; } /* We want to test that a pipe such as: * * --> | gzip -cf | xdelta3 -cf | xdelta3 -dcf | gzip -dcf | --> * * is transparent, i.e., does not modify the stream of data. However, * we also want to verify that at the center the data is properly * compressed, i.e., that we do not just have a re-compressed gzip * format, that we have an VCDIFF format. We do this in two steps. * First test the above pipe, then test with suppressed output * recompression (-D). The result should be the original input: * * --> | gzip -cf | xdelta3 -cf | xdelta3 -Ddcf | --> * * Finally we want to test that -D also disables input decompression: * * --> | gzip -cf | xdelta3 -Dcf | xdelta3 -Ddcf | gzip -dcf | --> */ static int test_externally_compressed_io (xd3_stream *stream, int ignore) { usize_t i; int ret; char buf[TESTBUFSIZE]; mt_init (& static_mtrand, 0x9f73f7fc); if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; } for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) { main_extcomp *ext = & extcomp_types[i]; /* Test for the existence of the external command first, if not skip. */ snprintf_func (buf, TESTBUFSIZE, "%s %s < /dev/null > /dev/null", ext->recomp_cmdname, ext->recomp_options); if ((ret = system (buf)) != 0) { XPR(NT "%s=0", ext->recomp_cmdname); continue; } if ((ret = test_compressed_pipe (stream, ext, buf, "-cfq", "-dcfq", 1, "compression failed: identity pipe")) || (ret = test_compressed_pipe (stream, ext, buf, "-cfq", "-Rdcfq", 0, "compression failed: without recompression")) || (ret = test_compressed_pipe (stream, ext, buf, "-Dcfq", "-Rdcfq", 1, "compression failed: without decompression"))) { return ret; } } return 0; } /* This tests the proper functioning of external decompression for * source files. The source and target files are identical and * compressed by gzip. Decoding such a delta with recompression * disbaled (-R) should produce the original, uncompressed * source/target file. Then it checks with output recompression * enabled--in this case the output should be a compressed copy of the * original source/target file. Then it checks that encoding with * decompression disabled works--the compressed files are identical * and decoding them should always produce a compressed output, * regardless of -R since the encoded delta file had decompression * disabled.. */ static int test_source_decompression (xd3_stream *stream, int ignore) { int ret; char buf[TESTBUFSIZE]; const main_extcomp *ext; xoff_t dsize; mt_init (& static_mtrand, 0x9f73f7fc); test_setup (); if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; } /* Use gzip. */ if ((ext = main_get_compressor ("G")) == NULL) { XPR(NT "skipped"); return 0; } /* Save an uncompressed copy. */ if ((ret = test_save_copy (TEST_TARGET_FILE))) { return ret; } /* Compress the source. */ snprintf_func (buf, TESTBUFSIZE, "%s -1 %s < %s > %s", ext->recomp_cmdname, ext->recomp_options, TEST_COPY_FILE, TEST_SOURCE_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Compress the target. */ snprintf_func (buf, TESTBUFSIZE, "%s -9 %s < %s > %s", ext->recomp_cmdname, ext->recomp_options, TEST_COPY_FILE, TEST_TARGET_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Now the two identical files are compressed. Delta-encode the target, * with decompression. */ snprintf_func (buf, TESTBUFSIZE, "%s -e -vfq -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Check that the compressed file is small (b/c inputs are * identical). */ if ((ret = test_file_size (TEST_DELTA_FILE, & dsize))) { return ret; } /* Deltas for identical files should be very small. */ if (dsize > 200) { XPR(NT "external compression did not happen\n"); stream->msg = "external compression did not happen"; return XD3_INTERNAL; } /* Decode the delta file with recompression disabled, should get an * uncompressed file out. */ snprintf_func (buf, TESTBUFSIZE, "%s -v -dq -R -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } if ((ret = test_compare_files (TEST_COPY_FILE, TEST_RECON_FILE))) { return ret; } /* Decode the delta file with recompression, should get a compressed file * out. But we can't compare compressed files directly. */ snprintf_func (buf, TESTBUFSIZE, "%s -v -dqf -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } snprintf_func (buf, TESTBUFSIZE, "%s %s < %s > %s", ext->decomp_cmdname, ext->decomp_options, TEST_RECON_FILE, TEST_RECON2_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } if ((ret = test_compare_files (TEST_COPY_FILE, TEST_RECON2_FILE))) { return ret; } /* Encode with decompression disabled */ snprintf_func (buf, TESTBUFSIZE, "%s -e -D -vfq -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Decode the delta file with decompression disabled, should get the * identical compressed file out. */ snprintf_func (buf, TESTBUFSIZE, "%s -d -D -vfq -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_RECON_FILE))) { return ret; } test_cleanup(); return 0; } #endif /*********************************************************************** FORCE, STDOUT ***********************************************************************/ /* This tests that output will not overwrite an existing file unless * -f was specified. The test is for encoding (the same code handles * it for decoding). */ static int test_force_behavior (xd3_stream *stream, int ignore) { int ret; char buf[TESTBUFSIZE]; /* Create empty target file */ test_setup (); snprintf_func (buf, TESTBUFSIZE, "cp /dev/null %s", TEST_TARGET_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Encode to delta file */ snprintf_func (buf, TESTBUFSIZE, "%s -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Encode again, should fail. */ snprintf_func (buf, TESTBUFSIZE, "%s -q -e %s %s ", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_fail (stream, buf))) { return ret; } /* Force it, should succeed. */ snprintf_func (buf, TESTBUFSIZE, "%s -f -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } test_cleanup(); return 0; } /* This checks the proper operation of the -c flag. When specified * the default output becomes stdout, otherwise the input must be * provided (encode) or it may be defaulted (decode w/ app header). */ static int test_stdout_behavior (xd3_stream *stream, int ignore) { int ret; char buf[TESTBUFSIZE]; test_setup(); snprintf_func (buf, TESTBUFSIZE, "cp /dev/null %s", TEST_TARGET_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Without -c, encode writes to delta file */ snprintf_func (buf, TESTBUFSIZE, "%s -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* With -c, encode writes to stdout */ snprintf_func (buf, TESTBUFSIZE, "%s -e -c %s > %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Without -c, decode writes to target file name, but it fails because the * file exists. */ snprintf_func (buf, TESTBUFSIZE, "%s -q -d %s ", program_name, TEST_DELTA_FILE); if ((ret = do_fail (stream, buf))) { return ret; } /* With -c, decode writes to stdout */ snprintf_func (buf, TESTBUFSIZE, "%s -d -c %s > /dev/null", program_name, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } test_cleanup(); return 0; } /* This tests that the no-output flag (-J) works. */ static int test_no_output (xd3_stream *stream, int ignore) { int ret; char buf[TESTBUFSIZE]; test_setup (); snprintf_func (buf, TESTBUFSIZE, "touch %s && chmod 0000 %s", TEST_NOPERM_FILE, TEST_NOPERM_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; } /* Try no_output encode w/out unwritable output file */ snprintf_func (buf, TESTBUFSIZE, "%s -q -f -e %s %s", program_name, TEST_TARGET_FILE, TEST_NOPERM_FILE); if ((ret = do_fail (stream, buf))) { return ret; } snprintf_func (buf, TESTBUFSIZE, "%s -J -e %s %s", program_name, TEST_TARGET_FILE, TEST_NOPERM_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } /* Now really write the delta to test decode no-output */ snprintf_func (buf, TESTBUFSIZE, "%s -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } snprintf_func (buf, TESTBUFSIZE, "%s -q -f -d %s %s", program_name, TEST_DELTA_FILE, TEST_NOPERM_FILE); if ((ret = do_fail (stream, buf))) { return ret; } snprintf_func (buf, TESTBUFSIZE, "%s -J -d %s %s", program_name, TEST_DELTA_FILE, TEST_NOPERM_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } test_cleanup (); return 0; } /* This tests that the default appheader works */ static int test_appheader (xd3_stream *stream, int ignore) { int i; int ret; char buf[TESTBUFSIZE]; char bogus[TESTBUFSIZE]; xoff_t ssize, tsize; test_setup (); if ((ret = test_make_inputs (stream, &ssize, &tsize))) { return ret; } snprintf_func (buf, TESTBUFSIZE, "%s -q -f -e -s %s %s %s", program_name, TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } if ((ret = test_copy_to (program_name, TEST_RECON2_FILE))) { return ret; } snprintf_func (buf, TESTBUFSIZE, "chmod 0700 %s", TEST_RECON2_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } if ((ret = test_save_copy (TEST_TARGET_FILE))) { return ret; } if ((ret = test_copy_to (TEST_SOURCE_FILE, TEST_TARGET_FILE))) { return ret; } if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_COPY_FILE)) == 0) { return XD3_INVALID; // I.e., files are different! } // Test that the target file is restored. snprintf_func (buf, TESTBUFSIZE, "(cd /tmp && %s -q -f -d %s)", TEST_RECON2_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_COPY_FILE)) != 0) { return ret; } // Test a malicious string w/ entries > 4 in the appheader by having // the encoder write it: for (i = 0; i < TESTBUFSIZE / 4; ++i) { bogus[2*i] = 'G'; bogus[2*i+1] = '/'; } bogus[TESTBUFSIZE/2-1] = 0; snprintf_func (buf, TESTBUFSIZE, "%s -q -f -A=%s -e -s %s %s %s", program_name, bogus, TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf))) { return ret; } // Then read it: snprintf_func (buf, TESTBUFSIZE, "(cd /tmp && %s -q -f -d %s)", TEST_RECON2_FILE, TEST_DELTA_FILE); if ((ret = do_cmd (stream, buf)) == 0) { return XD3_INVALID; // Impossible } if (!WIFEXITED(ret)) { return XD3_INVALID; // Must have crashed! } test_cleanup (); return 0; } /*********************************************************************** Source identical optimization ***********************************************************************/ /* Computing a delta should be fastest when the two inputs are * identical, this checks it. The library is called to compute a * delta between a 10000 byte file, 1000 byte winsize, 500 byte source * blocksize. The same buffer is used for both source and target. */ static int test_identical_behavior (xd3_stream *stream, int ignore) { #define IDB_TGTSZ 10000 /* Not a power of two b/c of hard-coded expectations below. */ #define IDB_BLKSZ 512 #define IDB_WINSZ 1000 #define IDB_DELSZ 1000 #define IDB_WINCNT (IDB_TGTSZ / IDB_WINSZ) int ret, i; uint8_t buf[IDB_TGTSZ]; uint8_t del[IDB_DELSZ]; uint8_t rec[IDB_TGTSZ]; xd3_source source; int nextencwin = 0; int winstarts = 0, winfinishes = 0; usize_t delpos = 0, recsize; xd3_config config; memset(&source, 0, sizeof(source)); for (i = 0; i < IDB_TGTSZ; i += 1) { buf[i] = (uint8_t) mt_random (&static_mtrand); } stream->winsize = IDB_WINSZ; source.blksize = IDB_BLKSZ; source.name = ""; source.curblk = NULL; source.curblkno = 0; if ((ret = xd3_set_source (stream, & source))) { goto fail; } /* Compute an delta between identical source and targets. */ for (;;) { ret = xd3_encode_input (stream); if (ret == XD3_INPUT) { xd3_avail_input (stream, buf + (IDB_WINSZ * nextencwin), IDB_WINSZ); nextencwin += 1; continue; } if (ret == XD3_GETSRCBLK) { source.curblkno = source.getblkno; source.onblk = IDB_BLKSZ; source.curblk = buf + source.getblkno * IDB_BLKSZ; continue; } if (ret == XD3_WINSTART) { winstarts++; continue; } if (ret == XD3_WINFINISH) { winfinishes++; if (winfinishes == IDB_WINCNT) { break; } continue; } if (ret != XD3_OUTPUT) { goto fail; } CHECK(delpos + stream->avail_out <= IDB_DELSZ); memcpy (del + delpos, stream->next_out, stream->avail_out); delpos += stream->avail_out; xd3_consume_output (stream); } CHECK(winfinishes == IDB_WINCNT); CHECK(winstarts == IDB_WINCNT); CHECK(nextencwin == IDB_WINCNT); /* Reset. */ memset(&source, 0, sizeof(source)); source.blksize = IDB_TGTSZ; source.onblk = IDB_TGTSZ; source.curblk = buf; source.curblkno = 0; if ((ret = xd3_close_stream (stream))) { goto fail; } xd3_free_stream (stream); xd3_init_config (& config, 0); if ((ret = xd3_config_stream (stream, & config))) { goto fail; } if ((ret = xd3_set_source_and_size (stream, & source, IDB_TGTSZ))) { goto fail; } /* Decode. */ if ((ret = xd3_decode_stream (stream, del, delpos, rec, & recsize, IDB_TGTSZ))) { goto fail; } /* Check result size and data. */ if (recsize != IDB_TGTSZ) { stream->msg = "wrong size reconstruction"; goto fail; } if (memcmp (rec, buf, IDB_TGTSZ) != 0) { stream->msg = "wrong data reconstruction"; goto fail; } /* Check that there was one copy per window. */ IF_DEBUG (if (stream->n_scpy != IDB_WINCNT || stream->n_add != 0 || stream->n_run != 0) { stream->msg = "wrong copy count"; goto fail; }); /* Check that no checksums were computed because the initial match was presumed. */ IF_DEBUG (if (stream->large_ckcnt != 0) { stream->msg = "wrong checksum behavior"; goto fail; }); ret = 0; fail: return ret; } /*********************************************************************** String matching test ***********************************************************************/ /* Check particular matching behaviors by calling * xd3_string_match_soft directly with specific arguments. */ typedef struct _string_match_test string_match_test; typedef enum { SM_NONE = 0, SM_LAZY = (1 << 1), } string_match_flags; struct _string_match_test { const char *input; int flags; const char *result; }; static const string_match_test match_tests[] = { /* nothing */ { "1234567890", SM_NONE, "" }, /* basic run, copy */ { "11111111112323232323", SM_NONE, "R0/10 C12/8@10" }, /* no run smaller than MIN_RUN=8 */ { "1111111", SM_NONE, "C1/6@0" }, { "11111111", SM_NONE, "R0/8" }, /* simple promotion: the third copy address depends on promotion */ { "ABCDEF_ABCDEF^ABCDEF", SM_NONE, "C7/6@0 C14/6@7" }, /* { "ABCDEF_ABCDEF^ABCDEF", SM_PROMOTE, "C7/6@0 C14/6@0" }, forgotten */ /* simple lazy: there is a better copy starting with "23 X" than "123 " */ { "123 23 XYZ 123 XYZ", SM_NONE, "C11/4@0" }, { "123 23 XYZ 123 XYZ", SM_LAZY, "C11/4@0 C12/6@4" }, /* trylazy: no lazy matches unless there are at least two characters beyond * the first match */ { "2123_121212", SM_LAZY, "C7/4@5" }, { "2123_1212123", SM_LAZY, "C7/4@5" }, { "2123_1212123_", SM_LAZY, "C7/4@5 C8/5@0" }, /* trylazy: no lazy matches if the copy is >= MAXLAZY=10 */ { "2123_121212123_", SM_LAZY, "C7/6@5 C10/5@0" }, { "2123_12121212123_", SM_LAZY, "C7/8@5 C12/5@0" }, { "2123_1212121212123_", SM_LAZY, "C7/10@5" }, /* lazy run: check a run overlapped by a longer copy */ { "11111112 111111112 1", SM_LAZY, "C1/6@0 R9/8 C10/10@0" }, /* lazy match: match_length,run_l >= min_match tests, shouldn't get any * copies within the run, no run within the copy */ { "^________^________ ", SM_LAZY, "R1/8 C9/9@0" }, /* chain depth: it only goes back 10. this checks that the 10th match hits * and the 11th misses. */ { "1234 1234_1234-1234=1234+1234[1234]1234{1234}1234<1234 ", SM_NONE, "C5/4@0 C10/4@5 C15/4@10 C20/4@15 C25/4@20 C30/4@25 C35/4@30 C40/4@35 C45/4@40 C50/5@0" }, { "1234 1234_1234-1234=1234+1234[1234]1234{1234}1234<1234>1234 ", SM_NONE, "C5/4@0 C10/4@5 C15/4@10 C20/4@15 C25/4@20 C30/4@25 C35/4@30 C40/4@35 C45/4@40 C50/4@45 C55/4@50" }, /* ssmatch test */ { "ABCDE___ABCDE*** BCDE***", SM_NONE, "C8/5@0 C17/4@1" }, /*{ "ABCDE___ABCDE*** BCDE***", SM_SSMATCH, "C8/5@0 C17/7@9" }, forgotten */ }; static int test_string_matching (xd3_stream *stream, int ignore) { usize_t i; int ret; xd3_config config; char rbuf[TESTBUFSIZE]; for (i = 0; i < SIZEOF_ARRAY (match_tests); i += 1) { const string_match_test *test = & match_tests[i]; char *rptr = rbuf; usize_t len = (usize_t) strlen (test->input); xd3_free_stream (stream); xd3_init_config (& config, 0); config.smatch_cfg = XD3_SMATCH_SOFT; config.smatcher_soft.large_look = 4; config.smatcher_soft.large_step = 4; config.smatcher_soft.small_look = 4; config.smatcher_soft.small_chain = 10; config.smatcher_soft.small_lchain = 10; config.smatcher_soft.max_lazy = (test->flags & SM_LAZY) ? 10 : 0; config.smatcher_soft.long_enough = 10; if ((ret = xd3_config_stream (stream, & config))) { return ret; } if ((ret = xd3_encode_init_full (stream))) { return ret; } xd3_avail_input (stream, (uint8_t*)test->input, len); if ((ret = stream->smatcher.string_match (stream))) { return ret; } *rptr = 0; while (! xd3_rlist_empty (& stream->iopt_used)) { xd3_rinst *inst = xd3_rlist_pop_front (& stream->iopt_used); switch (inst->type) { case XD3_RUN: *rptr++ = 'R'; break; case XD3_CPY: *rptr++ = 'C'; break; default: CHECK(0); } snprintf_func (rptr, rbuf+TESTBUFSIZE-rptr, "%"W"u/%"W"u", inst->pos, inst->size); rptr += strlen (rptr); if (inst->type == XD3_CPY) { *rptr++ = '@'; snprintf_func (rptr, rbuf+TESTBUFSIZE-rptr, "%"Q"u", inst->addr); rptr += strlen (rptr); } *rptr++ = ' '; xd3_rlist_push_back (& stream->iopt_free, inst); } if (rptr != rbuf) { rptr -= 1; *rptr = 0; } if (strcmp (rbuf, test->result) != 0) { XPR(NT "test %"W"u: expected %s: got %s", i, test->result, rbuf); stream->msg = "wrong result"; return XD3_INTERNAL; } } return 0; } /* * This is a test for many overlapping instructions. It must be a lazy * matcher. */ static int test_iopt_flush_instructions (xd3_stream *stream, int ignore) { int ret, i; usize_t tpos = 0; usize_t delta_size, recon_size; xd3_config config; uint8_t target[TESTBUFSIZE]; uint8_t delta[TESTBUFSIZE]; uint8_t recon[TESTBUFSIZE]; xd3_free_stream (stream); xd3_init_config (& config, 0); config.smatch_cfg = XD3_SMATCH_SOFT; config.smatcher_soft.large_look = 16; config.smatcher_soft.large_step = 16; config.smatcher_soft.small_look = 4; config.smatcher_soft.small_chain = 128; config.smatcher_soft.small_lchain = 16; config.smatcher_soft.max_lazy = 8; config.smatcher_soft.long_enough = 128; if ((ret = xd3_config_stream (stream, & config))) { return ret; } for (i = 1; i < 250; i++) { target[tpos++] = i; target[tpos++] = i+1; target[tpos++] = i+2; target[tpos++] = i+3; target[tpos++] = 0; } for (i = 1; i < 253; i++) { target[tpos++] = i; } if ((ret = xd3_encode_stream (stream, target, tpos, delta, & delta_size, sizeof (delta)))) { return ret; } xd3_free_stream(stream); if ((ret = xd3_config_stream (stream, & config))) { return ret; } if ((ret = xd3_decode_stream (stream, delta, delta_size, recon, & recon_size, sizeof (recon)))) { return ret; } CHECK(tpos == recon_size); CHECK(memcmp(target, recon, recon_size) == 0); return 0; } /* * This tests the 32/64bit ambiguity for source-window matching. */ #if !XD3_USE_LARGESIZET static int test_source_cksum_offset (xd3_stream *stream, int ignore) { xd3_source source; // Inputs are: struct { xoff_t cpos; // stream->srcwin_cksum_pos; xoff_t ipos; // stream->total_in; xoff_t size; // stream->src->size; usize_t input; // input 32-bit offset xoff_t output; // output 64-bit offset } cksum_test[] = { // If cpos is <= 2^32 { 1, 1, 1, 1, 1 }, #if XD3_USE_LARGEFILE64 // cpos ipos size input output // 0x____xxxxxULL, 0x____xxxxxULL, 0x____xxxxxULL, 0x___xxxxxUL, 0x____xxxxxULL { 0x100100000ULL, 0x100000000ULL, 0x100200000ULL, 0x00000000UL, 0x100000000ULL }, { 0x100100000ULL, 0x100000000ULL, 0x100200000ULL, 0xF0000000UL, 0x0F0000000ULL }, { 0x100200000ULL, 0x100100000ULL, 0x100200000ULL, 0x00300000UL, 0x000300000ULL }, { 25771983104ULL, 25770000000ULL, 26414808769ULL, 2139216707UL, 23614053187ULL }, #endif { 0, 0, 0, 0, 0 }, }, *test_ptr; stream->src = &source; for (test_ptr = cksum_test; test_ptr->cpos; test_ptr++) { xoff_t r; stream->srcwin_cksum_pos = test_ptr->cpos; stream->total_in = test_ptr->ipos; r = xd3_source_cksum_offset(stream, test_ptr->input); CHECK(r == test_ptr->output); } return 0; } #endif /* !XD3_USE_LARGESIZET */ static int test_in_memory (xd3_stream *stream, int ignore) { // test_text is 256 bytes uint8_t ibuf[sizeof(test_text)]; uint8_t dbuf[sizeof(test_text)]; uint8_t obuf[sizeof(test_text)]; usize_t size = sizeof(test_text); usize_t dsize, osize; int r1, r2; int eflags = SECONDARY_DJW ? XD3_SEC_DJW : 0; memcpy(ibuf, test_text, size); memset(ibuf + 128, 0, 16); r1 = xd3_encode_memory(ibuf, size, test_text, size, dbuf, &dsize, size, eflags); r2 = xd3_decode_memory(dbuf, dsize, test_text, size, obuf, &osize, size, 0); if (r1 != 0 || r2 != 0 || dsize >= (size/2) || dsize < 1 || osize != size) { stream->msg = "encode/decode size error"; return XD3_INTERNAL; } if (memcmp(obuf, ibuf, size) != 0) { stream->msg = "encode/decode data error"; return XD3_INTERNAL; } return 0; } /*********************************************************************** TEST MAIN ***********************************************************************/ int xd3_selftest (void) { #define DO_TEST(fn,flags,arg) \ do { \ xd3_stream stream; \ xd3_config config; \ xd3_init_config (& config, flags); \ XPR(NT "testing " #fn "%s...", \ flags ? (" (" #flags ")") : ""); \ if ((ret = xd3_config_stream (& stream, & config) == 0) && \ (ret = test_ ## fn (& stream, arg)) == 0) { \ XPR(NTR " success\n"); \ } else { \ XPR(NTR " failed: %s: %s\n", xd3_errstring (& stream), \ xd3_mainerror (ret)); } \ xd3_free_stream (& stream); \ if (ret != 0) { goto failure; } \ } while (0) int ret; DO_TEST (random_numbers, 0, 0); DO_TEST (printf_xoff, 0, 0); DO_TEST (decode_integer_end_of_input, 0, 0); DO_TEST (decode_integer_overflow, 0, 0); DO_TEST (encode_decode_uint32_t, 0, 0); DO_TEST (encode_decode_uint64_t, 0, 0); DO_TEST (usize_t_overflow, 0, 0); DO_TEST (checksum_step, 0, 0); DO_TEST (forward_match, 0, 0); DO_TEST (address_cache, 0, 0); DO_TEST (string_matching, 0, 0); DO_TEST (choose_instruction, 0, 0); DO_TEST (identical_behavior, 0, 0); DO_TEST (in_memory, 0, 0); DO_TEST (iopt_flush_instructions, 0, 0); #if !XD3_USE_LARGESIZET DO_TEST (source_cksum_offset, 0, 0); #endif DO_TEST (decompress_single_bit_error, 0, 3); DO_TEST (decompress_single_bit_error, XD3_ADLER32, 3); IF_LZMA (DO_TEST (decompress_single_bit_error, XD3_SEC_LZMA, 54)); IF_FGK (DO_TEST (decompress_single_bit_error, XD3_SEC_FGK, 3)); IF_DJW (DO_TEST (decompress_single_bit_error, XD3_SEC_DJW, 8)); #if SHELL_TESTS DO_TEST (force_behavior, 0, 0); DO_TEST (stdout_behavior, 0, 0); DO_TEST (no_output, 0, 0); DO_TEST (appheader, 0, 0); DO_TEST (command_line_arguments, 0, 0); #if EXTERNAL_COMPRESSION DO_TEST (source_decompression, 0, 0); DO_TEST (externally_compressed_io, 0, 0); #endif DO_TEST (recode_command, 0, 0); IF_LZMA (DO_TEST (secondary_lzma_default, 0, 0)); #endif IF_LZMA (DO_TEST (secondary_lzma, 0, 1)); IF_DJW (DO_TEST (secondary_huff, 0, DJW_MAX_GROUPS)); IF_FGK (DO_TEST (secondary_fgk, 0, 1)); DO_TEST (compressed_stream_overflow, 0, 0); IF_LZMA (DO_TEST (compressed_stream_overflow, XD3_SEC_LZMA, 0)); failure: test_cleanup (); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; #undef DO_TEST } ================================================ FILE: source-code/dependencies/xdelta3/xdelta3.1 ================================================ .TH XDELTA3 "1" "August 2009" "Xdelta3" .SH NAME xdelta3 \- VCDIFF (RFC 3284) binary diff tool .SH SYNOPSIS .B xdelta3 .RI [ command ] .RI [ options ] .RI [ input .RI [ output ]] .SH DESCRIPTION .B xdelta3 is a binary diff tool that uses the VCDIFF (RFC 3284) format and compression. .SH COMMANDS .TP .BI config prints xdelta3 configuration .TP .BI decode decompress the input, also set by -d .TP .BI encode compress the input, also set by -e (default) .TP .BI test run the builtin tests .TP .BI printdelta print information about the entire delta .TP .BI printhdr print information about the first window .TP .BI printhdrs print information about all windows .TP .BI recode encode with new application/secondary settings .SH OPTIONS standard options: .TP .BI "\-0 .. \-9" compression level .TP .BI "\-c" use stdout .TP .BI "\-d" decompress .TP .BI \-e compress .TP .BI \-f force overwrite .TP .BI \-h show help .TP .BI \-q be quiet .TP .BI \-v be verbose (max 2) .TP .BI \-V show version .TP memory options: .TP .BI \-B .RI bytes source window size .TP .BI \-W .RI bytes input window size .TP .BI \-P .RI size compression duplicates window .TP .BI \-I .RI size instruction buffer size (0 = unlimited) .TP compression options: .TP .BI \-s .RI source source file to copy from (if any) .TP .BI "\-S " [djw|fgk] enable/disable secondary compression .TP .BI \-N disable small string-matching compression .TP .BI \-D disable external decompression (encode/decode) .TP .BI \-R disable external recompression (decode) .TP .BI \-n disable checksum (encode/decode) .TP .BI \-C soft config (encode, undocumented) .TP .BI "\-A " [apphead] disable/provide application header (encode) .TP .BI \-J disable output (check/compute only) .TP .BI \-T use alternate code table (test) .SH NOTES The .B XDELTA environment variable may contain extra args: .RS XDELTA="-s source-x.y.tar.gz" \\ .br tar --use-compress-program=xdelta3 -cf \\ .br target-x.z.tar.gz.vcdiff target-x.y/ .SH EXAMPLES Compress the differences between SOURCE and TARGET, yielding OUT, using "djw" secondary compression: xdelta3 -S djw -s SOURCE TARGET OUT Do the same, using standard input and output: xdelta3 -S djw -s SOURCE < TARGET > OUT To decompress OUT, using SOURCE, yielding TARGET: xdelta3 -d -s SOURCE OUT TARGET .SH AUTHOR xdelta3 was written by Josh MacDonald . .PP This manual page was written by Leo 'costela' Antunes for the Debian project (but may be used by others). ================================================ FILE: source-code/dependencies/xdelta3/xdelta3.c ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ------------------------------------------------------------------- Xdelta 3 The goal of this library is to to implement both the (stand-alone) data-compression and delta-compression aspects of VCDIFF encoding, and to support a programming interface that works like Zlib (http://www.gzip.org/zlib.html). See RFC3284: The VCDIFF Generic Differencing and Compression Data Format. VCDIFF is a unified encoding that combines data-compression and delta-encoding ("differencing"). VCDIFF has a detailed byte-code instruction set with many features. The instruction format supports an immediate size operand for small COPYs and ADDs (e.g., under 18 bytes). There are also instruction "modes", which are used to compress COPY addresses by using two address caches. An instruction mode refers to slots in the NEAR and SAME caches for recent addresses. NEAR remembers the previous 4 (by default) COPY addresses, and SAME catches frequent re-uses of the same address using a 3-way (by default) 256-entry associative cache of [ADDR mod 256], the encoded byte. A hit in the NEAR/SAME cache requires 0/1 ADDR bytes. VCDIFF has a default instruction table, but an alternate instruction tables may themselves be be delta-compressed and included in the encoding header. This allows even more freedom. There are 9 instruction modes in the default code table, 4 near, 3 same, VCD_SELF (absolute encoding) and VCD_HERE (relative to the current position). ---------------------------------------------------------------------- Algorithms Aside from the details of encoding and decoding, there are a bunch of algorithms needed. 1. STRING-MATCH. A two-level fingerprinting approach is used. A single loop computes the two checksums -- small and large -- at successive offsets in the TARGET file. The large checksum is more accurate and is used to discover SOURCE matches, which are potentially very long. The small checksum is used to discover copies within the TARGET. Small matching, which is more expensive, usually dominates the large STRING-MATCH costs in this code - the more exhaustive the search, the better the results. Either of the two string-matching mechanisms may be disabled. 2. INSTRUCTION SELECTION. The IOPT buffer here represents a queue used to store overlapping copy instructions. There are two possible optimizations that go beyond a greedy search. Both of these fall into the category of "non-greedy matching" optimizations. The first optimization stems from backward SOURCE-COPY matching. When a new SOURCE-COPY instruction covers a previous instruction in the target completely, it is erased from the queue. Randal Burns originally analyzed these algorithms and did a lot of related work (\cite the 1.5-pass algorithm). The second optimization comes by the encoding of common very-small COPY and ADD instructions, for which there are special DOUBLE-code instructions, which code two instructions in a single byte. The cost of bad instruction-selection overhead is relatively high for data-compression, relative to delta-compression, so this second optimization is fairly important. With "lazy" matching (the name used in Zlib for a similar optimization), the string-match algorithm searches after a match for potential overlapping copy instructions. In Xdelta and by default, VCDIFF, the minimum match size is 4 bytes, whereas Zlib searches with a 3-byte minimum. This feature, combined with double instructions, provides a nice challenge. Search in this file for "black magic", a heuristic. 3. STREAM ALIGNMENT. Stream alignment is needed to compress large inputs in constant space. See xd3_srcwin_move_point(). 4. WINDOW SELECTION. When the IOPT buffer flushes, in the first call to xd3_iopt_finish_encoding containing any kind of copy instruction, the parameters of the source window must be decided: the offset into the source and the length of the window. Since the IOPT buffer is finite, the program may be forced to fix these values before knowing the best offset/length. 5. SECONDARY COMPRESSION. VCDIFF supports a secondary encoding to be applied to the individual sections of the data format, which are ADDRess, INSTruction, and DATA. Several secondary compressor variations are implemented here, although none is standardized yet. One is an adaptive huffman algorithm -- the FGK algorithm (Faller, Gallager, and Knuth, 1985). This compressor is extremely slow. The other is a simple static Huffman routine, which is the base case of a semi-adaptive scheme published by D.J. Wheeler and first widely used in bzip2 (by Julian Seward). This is a very interesting algorithm, originally published in nearly cryptic form by D.J. Wheeler. !!!NOTE!!! Because these are not standardized, secondary compression remains off by default. ftp://ftp.cl.cam.ac.uk/users/djw3/bred3.{c,ps} -------------------------------------------------------------------- Other Features 1. USER CONVENIENCE For user convenience, it is essential to recognize Gzip-compressed files and automatically Gzip-decompress them prior to delta-compression (or else no delta-compression will be achieved unless the user manually decompresses the inputs). The compressed represention competes with Xdelta, and this must be hidden from the command-line user interface. The Xdelta-1.x encoding was simple, not compressed itself, so Xdelta-1.x uses Zlib internally to compress the representation. This implementation supports external compression, which implements the necessary fork() and pipe() mechanics. There is a tricky step involved to support automatic detection of a compressed input in a non-seekable input. First you read a bit of the input to detect magic headers. When a compressed format is recognized, exec() the external compression program and create a second child process to copy the original input stream. [Footnote: There is a difficulty related to using Gzip externally. It is not possible to decompress and recompress a Gzip file transparently. If FILE.GZ had a cryptographic signature, then, after: (1) Gzip-decompression, (2) Xdelta-encoding, (3) Gzip-compression the signature could be broken. The only way to solve this problem is to guess at Gzip's compression level or control it by other means. I recommend that specific implementations of any compression scheme store information needed to exactly re-compress the input, that way external compression is transparent - however, this won't happen here until it has stabilized.] 2. APPLICATION-HEADER This feature was introduced in RFC3284. It allows any application to include a header within the VCDIFF file format. This allows general inter-application data exchange with support for application-specific extensions to communicate metadata. 3. VCDIFF CHECKSUM An optional checksum value is included with each window, which can be used to validate the final result. This verifies the correct source file was used for decompression as well as the obvious advantage: checking the implementation (and underlying) correctness. 4. LIGHT WEIGHT The code makes efforts to avoid copying data more than necessary. The code delays many initialization tasks until the first use, it optimizes for identical (perfectly matching) inputs. It does not compute any checksums until the first lookup misses. Memory usage is reduced. String-matching is templatized (by slightly gross use of CPP) to hard-code alternative compile-time defaults. The code has few outside dependencies. ---------------------------------------------------------------------- The default rfc3284 instruction table: (see RFC for the explanation) TYPE SIZE MODE TYPE SIZE MODE INDEX -------------------------------------------------------------------- 1. Run 0 0 Noop 0 0 0 2. Add 0, [1,17] 0 Noop 0 0 [1,18] 3. Copy 0, [4,18] 0 Noop 0 0 [19,34] 4. Copy 0, [4,18] 1 Noop 0 0 [35,50] 5. Copy 0, [4,18] 2 Noop 0 0 [51,66] 6. Copy 0, [4,18] 3 Noop 0 0 [67,82] 7. Copy 0, [4,18] 4 Noop 0 0 [83,98] 8. Copy 0, [4,18] 5 Noop 0 0 [99,114] 9. Copy 0, [4,18] 6 Noop 0 0 [115,130] 10. Copy 0, [4,18] 7 Noop 0 0 [131,146] 11. Copy 0, [4,18] 8 Noop 0 0 [147,162] 12. Add [1,4] 0 Copy [4,6] 0 [163,174] 13. Add [1,4] 0 Copy [4,6] 1 [175,186] 14. Add [1,4] 0 Copy [4,6] 2 [187,198] 15. Add [1,4] 0 Copy [4,6] 3 [199,210] 16. Add [1,4] 0 Copy [4,6] 4 [211,222] 17. Add [1,4] 0 Copy [4,6] 5 [223,234] 18. Add [1,4] 0 Copy 4 6 [235,238] 19. Add [1,4] 0 Copy 4 7 [239,242] 20. Add [1,4] 0 Copy 4 8 [243,246] 21. Copy 4 [0,8] Add 1 0 [247,255] -------------------------------------------------------------------- Reading the source: Overview This file includes itself in several passes to macro-expand certain sections with variable forms. Just read ahead, there's only a little confusion. I know this sounds ugly, but hard-coding some of the string-matching parameters results in a 10-15% increase in string-match performance. The only time this hurts is when you have unbalanced #if/endifs. A single compilation unit tames the Makefile. In short, this is to allow the above-described hack without an explodingMakefile. The single compilation unit includes the core library features, configurable string-match templates, optional main() command-line tool, misc optional features, and a regression test. Features are controled with CPP #defines, see Makefile.am. The initial __XDELTA3_C_HEADER_PASS__ starts first, the _INLINE_ and _TEMPLATE_ sections follow. Easy stuff first, hard stuff last. Optional features include: xdelta3-main.h The command-line interface, external compression support, POSIX-specific, info & VCDIFF-debug tools. xdelta3-second.h The common secondary compression routines. xdelta3-decoder.h All decoding routines. xdelta3-djw.h The semi-adaptive huffman secondary encoder. xdelta3-fgk.h The adaptive huffman secondary encoder. xdelta3-test.h The unit test covers major algorithms, encoding and decoding. There are single-bit error decoding tests. There are 32/64-bit file size boundary tests. There are command-line tests. There are compression tests. There are external compression tests. There are string-matching tests. There should be more tests... Additional headers include: xdelta3.h The public header file. xdelta3-cfgs.h The default settings for default, built-in encoders. These are hard-coded at compile-time. There is also a single soft-coded string matcher for experimenting with arbitrary values. xdelta3-list.h A cyclic list template Misc little debug utilities: badcopy.c Randomly modifies an input file based on two parameters: (1) the probability that a byte in the file is replaced with a pseudo-random value, and (2) the mean change size. Changes are generated using an expoential distribution which approximates the expected error_prob distribution. -------------------------------------------------------------------- This file itself is unusually large. I hope to defend this layout with lots of comments. Everything in this file is related to encoding and decoding. I like it all together - the template stuff is just a hack. */ #ifndef __XDELTA3_C_HEADER_PASS__ #define __XDELTA3_C_HEADER_PASS__ #include "xdelta3.h" #include "xdelta3-internal.h" /*********************************************************************** STATIC CONFIGURATION ***********************************************************************/ #ifndef XD3_MAIN /* the main application */ #define XD3_MAIN 0 #endif #ifndef VCDIFF_TOOLS #define VCDIFF_TOOLS XD3_MAIN #endif #ifndef SECONDARY_FGK /* one from the algorithm preservation department: */ #define SECONDARY_FGK 0 /* adaptive Huffman routines */ #endif #ifndef SECONDARY_DJW /* semi-adaptive/static Huffman for the eventual */ #define SECONDARY_DJW 0 /* standardization, off by default until such time. */ #endif #ifndef SECONDARY_LZMA #ifdef HAVE_LZMA_H #define SECONDARY_LZMA 1 #else #define SECONDARY_LZMA 0 #endif #endif #if XD3_ENCODER #define IF_ENCODER(x) x #else #define IF_ENCODER(x) #endif /***********************************************************************/ /* header indicator bits */ #define VCD_SECONDARY (1U << 0) /* uses secondary compressor */ #define VCD_CODETABLE (1U << 1) /* supplies code table data */ #define VCD_APPHEADER (1U << 2) /* supplies application data */ #define VCD_INVHDR (~0x7U) /* window indicator bits */ #define VCD_SOURCE (1U << 0) /* copy window in source file */ #define VCD_TARGET (1U << 1) /* copy window in target file */ #define VCD_ADLER32 (1U << 2) /* has adler32 checksum */ #define VCD_INVWIN (~0x7U) #define VCD_SRCORTGT (VCD_SOURCE | VCD_TARGET) /* delta indicator bits */ #define VCD_DATACOMP (1U << 0) #define VCD_INSTCOMP (1U << 1) #define VCD_ADDRCOMP (1U << 2) #define VCD_INVDEL (~0x7U) typedef enum { VCD_DJW_ID = 1, VCD_LZMA_ID = 2, VCD_FGK_ID = 16 /* Note: these are not standard IANA-allocated IDs! */ } xd3_secondary_ids; typedef enum { SEC_NOFLAGS = 0, /* Note: SEC_COUNT_FREQS Not implemented (to eliminate 1st Huffman pass) */ SEC_COUNT_FREQS = (1 << 0) } xd3_secondary_flags; typedef enum { DATA_SECTION, /* These indicate which section to the secondary * compressor. */ INST_SECTION, /* The header section is not compressed, therefore not * listed here. */ ADDR_SECTION } xd3_section_type; typedef unsigned int xd3_rtype; /***********************************************************************/ #include "xdelta3-list.h" #if XD3_ENCODER XD3_MAKELIST(xd3_rlist, xd3_rinst, link); #endif /***********************************************************************/ #define SECONDARY_MIN_SAVINGS 2 /* Secondary compression has to save at least this many bytes. */ #define SECONDARY_MIN_INPUT 10 /* Secondary compression needs at least this many bytes. */ #define VCDIFF_MAGIC1 0xd6 /* 1st file byte */ #define VCDIFF_MAGIC2 0xc3 /* 2nd file byte */ #define VCDIFF_MAGIC3 0xc4 /* 3rd file byte */ #define VCDIFF_VERSION 0x00 /* 4th file byte */ #define VCD_SELF 0 /* 1st address mode */ #define VCD_HERE 1 /* 2nd address mode */ #define SECONDARY_ANY (SECONDARY_DJW || SECONDARY_FGK || SECONDARY_LZMA) #define ALPHABET_SIZE 256 /* Used in test code--size of the secondary * compressor alphabet. */ #define HASH_CKOFFSET 1U /* Table entries distinguish "no-entry" from * offset 0 using this offset. */ #define MAX_MATCH_SPLIT 18U /* VCDIFF code table: 18 is the default limit * for direct-coded ADD sizes */ #define LEAST_MATCH_INCR 0 /* The least number of bytes an overlapping * match must beat the preceding match by. This * is a bias for the lazy match optimization. A * non-zero value means that an adjacent match * has to be better by more than the step * between them. 0. */ #define MIN_MATCH 4U /* VCDIFF code table: MIN_MATCH=4 */ #define MIN_RUN 8U /* The shortest run, if it is shorter than this * an immediate add/copy will be just as good. * ADD1/COPY6 = 1I+1D+1A bytes, RUN18 = * 1I+1D+1A. */ #define MAX_MODES 9 /* Maximum number of nodes used for * compression--does not limit decompression. */ #define ENC_SECTS 4 /* Number of separate output sections. */ #define HDR_TAIL(s) ((s)->enc_tails[0]) #define DATA_TAIL(s) ((s)->enc_tails[1]) #define INST_TAIL(s) ((s)->enc_tails[2]) #define ADDR_TAIL(s) ((s)->enc_tails[3]) #define HDR_HEAD(s) ((s)->enc_heads[0]) #define DATA_HEAD(s) ((s)->enc_heads[1]) #define INST_HEAD(s) ((s)->enc_heads[2]) #define ADDR_HEAD(s) ((s)->enc_heads[3]) /* Template instances. */ #if XD3_BUILD_SLOW #define IF_BUILD_SLOW(x) x #else #define IF_BUILD_SLOW(x) #endif #if XD3_BUILD_FAST #define IF_BUILD_FAST(x) x #else #define IF_BUILD_FAST(x) #endif #if XD3_BUILD_FASTER #define IF_BUILD_FASTER(x) x #else #define IF_BUILD_FASTER(x) #endif #if XD3_BUILD_FASTEST #define IF_BUILD_FASTEST(x) x #else #define IF_BUILD_FASTEST(x) #endif #if XD3_BUILD_SOFT #define IF_BUILD_SOFT(x) x #else #define IF_BUILD_SOFT(x) #endif #if XD3_BUILD_DEFAULT #define IF_BUILD_DEFAULT(x) x #else #define IF_BUILD_DEFAULT(x) #endif /* Update the run-length state */ #define NEXTRUN(c) do { if ((c) == run_c) { run_l += 1; } \ else { run_c = (c); run_l = 1; } } while (0) /* This CPP-conditional stuff can be cleaned up... */ #if REGRESSION_TEST #define IF_REGRESSION(x) x #else #define IF_REGRESSION(x) #endif /***********************************************************************/ #if XD3_ENCODER static void* xd3_alloc0 (xd3_stream *stream, usize_t elts, usize_t size); static int xd3_alloc_iopt (xd3_stream *stream, usize_t elts); static void xd3_free_output (xd3_stream *stream, xd3_output *output); static int xd3_emit_double (xd3_stream *stream, xd3_rinst *first, xd3_rinst *second, uint8_t code); static int xd3_emit_single (xd3_stream *stream, xd3_rinst *single, uint8_t code); static usize_t xd3_sizeof_output (xd3_output *output); static void xd3_encode_reset (xd3_stream *stream); static int xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos); static int xd3_source_extend_match (xd3_stream *stream); static int xd3_srcwin_setup (xd3_stream *stream); static usize_t xd3_iopt_last_matched (xd3_stream *stream); static int xd3_emit_uint32_t (xd3_stream *stream, xd3_output **output, uint32_t num); static usize_t xd3_smatch (xd3_stream *stream, usize_t base, usize_t scksum, usize_t *match_offset); static int xd3_string_match_init (xd3_stream *stream); static uint32_t xd3_scksum (uint32_t *state, const uint8_t *seg, const usize_t ln); static usize_t xd3_comprun (const uint8_t *seg, usize_t slook, uint8_t *run_cp); static int xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point); static int xd3_emit_run (xd3_stream *stream, usize_t pos, usize_t size, uint8_t *run_c); static xoff_t xd3_source_cksum_offset(xd3_stream *stream, usize_t low); static void xd3_scksum_insert (xd3_stream *stream, usize_t inx, usize_t scksum, usize_t pos); #if XD3_DEBUG static void xd3_verify_run_state (xd3_stream *stream, const uint8_t *inp, usize_t x_run_l, uint8_t *x_run_c); static void xd3_verify_large_state (xd3_stream *stream, const uint8_t *inp, usize_t x_cksum); static void xd3_verify_small_state (xd3_stream *stream, const uint8_t *inp, uint32_t x_cksum); #endif /* XD3_DEBUG */ #endif /* XD3_ENCODER */ static int xd3_decode_allocate (xd3_stream *stream, usize_t size, uint8_t **copied1, usize_t *alloc1); static void* xd3_alloc (xd3_stream *stream, usize_t elts, usize_t size); static void xd3_free (xd3_stream *stream, void *ptr); const char* xd3_strerror (int ret) { switch (ret) { case XD3_INPUT: return "XD3_INPUT"; case XD3_OUTPUT: return "XD3_OUTPUT"; case XD3_GETSRCBLK: return "XD3_GETSRCBLK"; case XD3_GOTHEADER: return "XD3_GOTHEADER"; case XD3_WINSTART: return "XD3_WINSTART"; case XD3_WINFINISH: return "XD3_WINFINISH"; case XD3_TOOFARBACK: return "XD3_TOOFARBACK"; case XD3_INTERNAL: return "XD3_INTERNAL"; case XD3_INVALID: return "XD3_INVALID"; case XD3_INVALID_INPUT: return "XD3_INVALID_INPUT"; case XD3_NOSECOND: return "XD3_NOSECOND"; case XD3_UNIMPLEMENTED: return "XD3_UNIMPLEMENTED"; } return NULL; } /***********************************************************************/ #define xd3_sec_data(s) ((s)->sec_stream_d) #define xd3_sec_inst(s) ((s)->sec_stream_i) #define xd3_sec_addr(s) ((s)->sec_stream_a) struct _xd3_sec_type { uint8_t id; const char *name; xd3_secondary_flags flags; /* xd3_sec_stream is opaque to the generic code */ xd3_sec_stream* (*alloc) (xd3_stream *stream); void (*destroy) (xd3_stream *stream, xd3_sec_stream *sec); int (*init) (xd3_stream *stream, xd3_sec_stream *sec_stream, int is_encode); int (*decode) (xd3_stream *stream, xd3_sec_stream *sec_stream, const uint8_t **input, const uint8_t *input_end, uint8_t **output, const uint8_t *output_end); #if XD3_ENCODER int (*encode) (xd3_stream *stream, xd3_sec_stream *sec_stream, xd3_output *input, xd3_output *output, xd3_sec_cfg *cfg); #endif }; #define BIT_STATE_ENCODE_INIT { 0, 1 } #define BIT_STATE_DECODE_INIT { 0, 0x100 } typedef struct _bit_state bit_state; struct _bit_state { uint8_t cur_byte; usize_t cur_mask; }; #if SECONDARY_ANY == 0 #define IF_SEC(x) #define IF_NSEC(x) x #else /* yuck */ #define IF_SEC(x) x #define IF_NSEC(x) static int xd3_decode_secondary (xd3_stream *stream, xd3_desect *sect, xd3_sec_stream **sec_streamp); #if XD3_ENCODER static int xd3_encode_secondary (xd3_stream *stream, xd3_output **head, xd3_output **tail, xd3_sec_stream **sec_streamp, xd3_sec_cfg *cfg, int *did_it); #endif #endif /* SECONDARY_ANY */ #if SECONDARY_FGK extern const xd3_sec_type fgk_sec_type; #define IF_FGK(x) x #define FGK_CASE(s) \ s->sec_type = & fgk_sec_type; \ break; #else #define IF_FGK(x) #define FGK_CASE(s) \ s->msg = "unavailable secondary compressor: FGK Adaptive Huffman"; \ return XD3_INTERNAL; #endif #if SECONDARY_DJW extern const xd3_sec_type djw_sec_type; #define IF_DJW(x) x #define DJW_CASE(s) \ s->sec_type = & djw_sec_type; \ break; #else #define IF_DJW(x) #define DJW_CASE(s) \ s->msg = "unavailable secondary compressor: DJW Static Huffman"; \ return XD3_INTERNAL; #endif #if SECONDARY_LZMA extern const xd3_sec_type lzma_sec_type; #define IF_LZMA(x) x #define LZMA_CASE(s) \ s->sec_type = & lzma_sec_type; \ break; #else #define IF_LZMA(x) #define LZMA_CASE(s) \ s->msg = "unavailable secondary compressor: LZMA"; \ return XD3_INTERNAL; #endif /***********************************************************************/ #include "xdelta3-hash.h" /* Process template passes - this includes xdelta3.c several times. */ #define __XDELTA3_C_TEMPLATE_PASS__ #include "xdelta3-cfgs.h" #undef __XDELTA3_C_TEMPLATE_PASS__ /* Process the inline pass. */ #define __XDELTA3_C_INLINE_PASS__ #include "xdelta3.c" #undef __XDELTA3_C_INLINE_PASS__ /* Secondary compression */ #if SECONDARY_ANY #include "xdelta3-second.h" #endif #if SECONDARY_FGK #include "xdelta3-fgk.h" const xd3_sec_type fgk_sec_type = { VCD_FGK_ID, "FGK Adaptive Huffman", SEC_NOFLAGS, (xd3_sec_stream* (*)(xd3_stream*)) fgk_alloc, (void (*)(xd3_stream*, xd3_sec_stream*)) fgk_destroy, (int (*)(xd3_stream*, xd3_sec_stream*, int)) fgk_init, (int (*)(xd3_stream*, xd3_sec_stream*, const uint8_t**, const uint8_t*, uint8_t**, const uint8_t*)) xd3_decode_fgk, IF_ENCODER((int (*)(xd3_stream*, xd3_sec_stream*, xd3_output*, xd3_output*, xd3_sec_cfg*)) xd3_encode_fgk) }; #endif #if SECONDARY_DJW #include "xdelta3-djw.h" const xd3_sec_type djw_sec_type = { VCD_DJW_ID, "Static Huffman", SEC_COUNT_FREQS, (xd3_sec_stream* (*)(xd3_stream*)) djw_alloc, (void (*)(xd3_stream*, xd3_sec_stream*)) djw_destroy, (int (*)(xd3_stream*, xd3_sec_stream*, int)) djw_init, (int (*)(xd3_stream*, xd3_sec_stream*, const uint8_t**, const uint8_t*, uint8_t**, const uint8_t*)) xd3_decode_huff, IF_ENCODER((int (*)(xd3_stream*, xd3_sec_stream*, xd3_output*, xd3_output*, xd3_sec_cfg*)) xd3_encode_huff) }; #endif #if SECONDARY_LZMA #include "xdelta3-lzma.h" const xd3_sec_type lzma_sec_type = { VCD_LZMA_ID, "lzma", SEC_NOFLAGS, (xd3_sec_stream* (*)(xd3_stream*)) xd3_lzma_alloc, (void (*)(xd3_stream*, xd3_sec_stream*)) xd3_lzma_destroy, (int (*)(xd3_stream*, xd3_sec_stream*, int)) xd3_lzma_init, (int (*)(xd3_stream*, xd3_sec_stream*, const uint8_t**, const uint8_t*, uint8_t**, const uint8_t*)) xd3_decode_lzma, IF_ENCODER((int (*)(xd3_stream*, xd3_sec_stream*, xd3_output*, xd3_output*, xd3_sec_cfg*)) xd3_encode_lzma) }; #endif #if XD3_MAIN || PYTHON_MODULE || SWIG_MODULE || NOT_MAIN #include "xdelta3-main.h" #endif #if REGRESSION_TEST #include "xdelta3-test.h" #endif #endif /* __XDELTA3_C_HEADER_PASS__ */ #ifdef __XDELTA3_C_INLINE_PASS__ /**************************************************************** Instruction tables *****************************************************************/ /* The following code implements a parametrized description of the * code table given above for a few reasons. It is not necessary for * implementing the standard, to support compression with variable * tables, so an implementation is only required to know the default * code table to begin decompression. (If the encoder uses an * alternate table, the table is included in compressed form inside * the VCDIFF file.) * * Before adding variable-table support there were two functions which * were hard-coded to the default table above. * xd3_compute_default_table() would create the default table by * filling a 256-elt array of xd3_dinst values. The corresponding * function, xd3_choose_instruction(), would choose an instruction * based on the hard-coded parameters of the default code table. * * Notes: The parametrized code table description here only generates * tables of a certain regularity similar to the default table by * allowing to vary the distribution of single- and * double-instructions and change the number of near and same copy * modes. More exotic tables are only possible by extending this * code. * * For performance reasons, both the parametrized and non-parametrized * versions of xd3_choose_instruction remain. The parametrized * version is only needed for testing multi-table decoding support. * If ever multi-table encoding is required, this can be optimized by * compiling static functions for each table. */ /* The XD3_CHOOSE_INSTRUCTION calls xd3_choose_instruction with the * table description when GENERIC_ENCODE_TABLES are in use. The * IF_GENCODETBL macro enables generic-code-table specific code * (removed 10/2014). */ #define XD3_CHOOSE_INSTRUCTION(stream,prev,inst) \ xd3_choose_instruction (prev, inst) /* This structure maintains information needed by * xd3_choose_instruction to compute the code for a double instruction * by first indexing an array of code_table_sizes by copy mode, then * using (offset + (muliplier * X)) */ struct _xd3_code_table_sizes { uint8_t cpy_max; uint8_t offset; uint8_t mult; }; /* This contains a complete description of a code table. */ struct _xd3_code_table_desc { /* Assumes a single RUN instruction */ /* Assumes that MIN_MATCH is 4 */ uint8_t add_sizes; /* Number of immediate-size single adds (default 17) */ uint8_t near_modes; /* Number of near copy modes (default 4) */ uint8_t same_modes; /* Number of same copy modes (default 3) */ uint8_t cpy_sizes; /* Number of immediate-size single copies (default 15) */ uint8_t addcopy_add_max; /* Maximum add size for an add-copy double instruction, all modes (default 4) */ uint8_t addcopy_near_cpy_max; /* Maximum cpy size for an add-copy double instruction, up through VCD_NEAR modes (default 6) */ uint8_t addcopy_same_cpy_max; /* Maximum cpy size for an add-copy double instruction, VCD_SAME modes (default 4) */ uint8_t copyadd_add_max; /* Maximum add size for a copy-add double instruction, all modes (default 1) */ uint8_t copyadd_near_cpy_max; /* Maximum cpy size for a copy-add double instruction, up through VCD_NEAR modes (default 4) */ uint8_t copyadd_same_cpy_max; /* Maximum cpy size for a copy-add double instruction, VCD_SAME modes (default 4) */ xd3_code_table_sizes addcopy_max_sizes[MAX_MODES]; xd3_code_table_sizes copyadd_max_sizes[MAX_MODES]; }; /* The rfc3284 code table is represented: */ static const xd3_code_table_desc __rfc3284_code_table_desc = { 17, /* add sizes */ 4, /* near modes */ 3, /* same modes */ 15, /* copy sizes */ 4, /* add-copy max add */ 6, /* add-copy max cpy, near */ 4, /* add-copy max cpy, same */ 1, /* copy-add max add */ 4, /* copy-add max cpy, near */ 4, /* copy-add max cpy, same */ /* addcopy */ { {6,163,3},{6,175,3},{6,187,3},{6,199,3},{6,211,3},{6,223,3}, {4,235,1},{4,239,1},{4,243,1} }, /* copyadd */ { {4,247,1},{4,248,1},{4,249,1},{4,250,1},{4,251,1},{4,252,1}, {4,253,1},{4,254,1},{4,255,1} }, }; /* Computes code table entries of TBL using the specified description. */ static void xd3_build_code_table (const xd3_code_table_desc *desc, xd3_dinst *tbl) { uint8_t size1, size2; uint8_t mode; usize_t cpy_modes = 2U + desc->near_modes + desc->same_modes; xd3_dinst *d = tbl; (d++)->type1 = XD3_RUN; (d++)->type1 = XD3_ADD; for (size1 = 1; size1 <= desc->add_sizes; size1 += 1, d += 1) { d->type1 = XD3_ADD; d->size1 = size1; } for (mode = 0; mode < cpy_modes; mode += 1) { (d++)->type1 = XD3_CPY + mode; for (size1 = MIN_MATCH; size1 < MIN_MATCH + desc->cpy_sizes; size1 += 1, d += 1) { d->type1 = XD3_CPY + mode; d->size1 = size1; } } for (mode = 0; mode < cpy_modes; mode += 1) { for (size1 = 1; size1 <= desc->addcopy_add_max; size1 += 1) { usize_t max = (mode < 2U + desc->near_modes) ? desc->addcopy_near_cpy_max : desc->addcopy_same_cpy_max; for (size2 = MIN_MATCH; size2 <= max; size2 += 1, d += 1) { d->type1 = XD3_ADD; d->size1 = size1; d->type2 = XD3_CPY + mode; d->size2 = size2; } } } for (mode = 0; mode < cpy_modes; mode += 1) { usize_t max = (mode < 2U + desc->near_modes) ? desc->copyadd_near_cpy_max : desc->copyadd_same_cpy_max; for (size1 = MIN_MATCH; size1 <= max; size1 += 1) { for (size2 = 1; size2 <= desc->copyadd_add_max; size2 += 1, d += 1) { d->type1 = XD3_CPY + mode; d->size1 = size1; d->type2 = XD3_ADD; d->size2 = size2; } } } XD3_ASSERT (d - tbl == 256); } /* This function generates the static default code table. */ static const xd3_dinst* xd3_rfc3284_code_table (void) { static xd3_dinst __rfc3284_code_table[256]; if (__rfc3284_code_table[0].type1 != XD3_RUN) { xd3_build_code_table (& __rfc3284_code_table_desc, __rfc3284_code_table); } return __rfc3284_code_table; } #if XD3_ENCODER /* This version of xd3_choose_instruction is hard-coded for the default table. */ static void xd3_choose_instruction (xd3_rinst *prev, xd3_rinst *inst) { switch (inst->type) { case XD3_RUN: inst->code1 = 0; break; case XD3_ADD: inst->code1 = 1; if (inst->size <= 17) { inst->code1 += inst->size; if ( (inst->size == 1) && (prev != NULL) && (prev->size == 4) && (prev->type >= XD3_CPY) ) { prev->code2 = 247 + (prev->type - XD3_CPY); } } break; default: { uint8_t mode = inst->type - XD3_CPY; XD3_ASSERT (inst->type >= XD3_CPY && inst->type < 12); inst->code1 = 19 + 16 * mode; if (inst->size <= 18 && inst->size >= 4) { inst->code1 += inst->size - 3; if ( (prev != NULL) && (prev->type == XD3_ADD) && (prev->size <= 4) ) { if ( (inst->size <= 6) && (mode <= 5) ) { prev->code2 = (uint8_t)(163 + (mode * 12) + (3 * (prev->size - 1)) + (inst->size - 4)); XD3_ASSERT (prev->code2 <= 234); } else if ( (inst->size == 4) && (mode >= 6) ) { prev->code2 = 235 + ((mode - 6) * 4) + (prev->size - 1); XD3_ASSERT (prev->code2 <= 246); } } } XD3_ASSERT (inst->code1 <= 162); } break; } } #endif /* XD3_ENCODER */ /***********************************************************************/ static inline void xd3_swap_uint8p (uint8_t** p1, uint8_t** p2) { uint8_t *t = (*p1); (*p1) = (*p2); (*p2) = t; } static inline void xd3_swap_usize_t (usize_t* p1, usize_t* p2) { usize_t t = (*p1); (*p1) = (*p2); (*p2) = t; } /* It's not constant time, but it computes the log. */ static int xd3_check_pow2 (xoff_t value, usize_t *logof) { xoff_t x = 1; usize_t nolog; if (logof == NULL) { logof = &nolog; } *logof = 0; for (; x != 0; x <<= 1, *logof += 1) { if (x == value) { return 0; } } return XD3_INTERNAL; } usize_t xd3_pow2_roundup (usize_t x) { usize_t i = 1; while (x > i) { i <<= 1U; } return i; } static xoff_t xd3_xoff_roundup (xoff_t x) { xoff_t i = 1; while (x > i) { i <<= 1U; } return i; } static usize_t xd3_round_blksize (usize_t sz, usize_t blksz) { usize_t mod = sz & (blksz-1); XD3_ASSERT (xd3_check_pow2 (blksz, NULL) == 0); if (mod == 0) { return sz; } if (sz > USIZE_T_MAXBLKSZ) { return USIZE_T_MAXBLKSZ; } return sz + (blksz - mod); } /*********************************************************************** Adler32 stream function: code copied from Zlib, defined in RFC1950 ***********************************************************************/ #define A32_BASE 65521L /* Largest prime smaller than 2^16 */ #define A32_NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define A32_DO1(buf,i) {s1 += buf[i]; s2 += s1;} #define A32_DO2(buf,i) A32_DO1(buf,i); A32_DO1(buf,i+1); #define A32_DO4(buf,i) A32_DO2(buf,i); A32_DO2(buf,i+2); #define A32_DO8(buf,i) A32_DO4(buf,i); A32_DO4(buf,i+4); #define A32_DO16(buf) A32_DO8(buf,0); A32_DO8(buf,8); static uint32_t adler32 (uint32_t adler, const uint8_t *buf, usize_t len) { uint32_t s1 = adler & 0xffffU; uint32_t s2 = (adler >> 16) & 0xffffU; int k; while (len > 0) { k = (len < A32_NMAX) ? len : A32_NMAX; len -= k; while (k >= 16) { A32_DO16(buf); buf += 16; k -= 16; } if (k != 0) { do { s1 += *buf++; s2 += s1; } while (--k); } s1 %= A32_BASE; s2 %= A32_BASE; } return (s2 << 16) | s1; } /*********************************************************************** Run-length function ***********************************************************************/ #if XD3_ENCODER static usize_t xd3_comprun (const uint8_t *seg, usize_t slook, uint8_t *run_cp) { usize_t i; usize_t run_l = 0; uint8_t run_c = 0; for (i = 0; i < slook; i += 1) { NEXTRUN(seg[i]); } (*run_cp) = run_c; return run_l; } #endif /*********************************************************************** Basic encoder/decoder functions ***********************************************************************/ #if XD3_ENCODER inline int xd3_emit_byte (xd3_stream *stream, xd3_output **outputp, uint8_t code) { xd3_output *output = (*outputp); if (output->next == output->avail) { xd3_output *aoutput; if ((aoutput = xd3_alloc_output (stream, output)) == NULL) { return ENOMEM; } output = (*outputp) = aoutput; } output->base[output->next++] = code; return 0; } inline int xd3_emit_bytes (xd3_stream *stream, xd3_output **outputp, const uint8_t *base, usize_t size) { xd3_output *output = (*outputp); do { usize_t take; if (output->next == output->avail) { xd3_output *aoutput; if ((aoutput = xd3_alloc_output (stream, output)) == NULL) { return ENOMEM; } output = (*outputp) = aoutput; } take = xd3_min (output->avail - output->next, size); memcpy (output->base + output->next, base, (size_t) take); output->next += take; size -= take; base += take; } while (size > 0); return 0; } #endif /* XD3_ENCODER */ /*********************************************************************** Address cache stuff ***********************************************************************/ static int xd3_alloc_cache (xd3_stream *stream) { if (stream->acache.near_array != NULL) { xd3_free (stream, stream->acache.near_array); } if (stream->acache.same_array != NULL) { xd3_free (stream, stream->acache.same_array); } if (((stream->acache.s_near > 0) && (stream->acache.near_array = (usize_t*) xd3_alloc (stream, stream->acache.s_near, (usize_t) sizeof (usize_t))) == NULL) || ((stream->acache.s_same > 0) && (stream->acache.same_array = (usize_t*) xd3_alloc (stream, stream->acache.s_same * 256, (usize_t) sizeof (usize_t))) == NULL)) { return ENOMEM; } return 0; } void xd3_init_cache (xd3_addr_cache* acache) { if (acache->s_near > 0) { memset (acache->near_array, 0, acache->s_near * sizeof (usize_t)); acache->next_slot = 0; } if (acache->s_same > 0) { memset (acache->same_array, 0, acache->s_same * 256 * sizeof (usize_t)); } } static void xd3_update_cache (xd3_addr_cache* acache, usize_t addr) { if (acache->s_near > 0) { acache->near_array[acache->next_slot] = addr; acache->next_slot = (acache->next_slot + 1) % acache->s_near; } if (acache->s_same > 0) { acache->same_array[addr % (acache->s_same*256)] = addr; } } #if XD3_ENCODER /* OPT: this gets called a lot, can it be optimized? */ static int xd3_encode_address (xd3_stream *stream, usize_t addr, usize_t here, uint8_t* mode) { usize_t d, bestd; usize_t i, bestm; int ret; xd3_addr_cache* acache = & stream->acache; #define SMALLEST_INT(x) do { if (((x) & ~127U) == 0) { goto good; } } while (0) /* Attempt to find the address mode that yields the smallest integer value * for "d", the encoded address value, thereby minimizing the encoded size * of the address. */ bestd = addr; bestm = VCD_SELF; XD3_ASSERT (addr < here); SMALLEST_INT (bestd); if ((d = here-addr) < bestd) { bestd = d; bestm = VCD_HERE; SMALLEST_INT (bestd); } for (i = 0; i < acache->s_near; i += 1) { /* Note: If we used signed computation here, we'd could compte d * and then check (d >= 0 && d < bestd). */ if (addr >= acache->near_array[i]) { d = addr - acache->near_array[i]; if (d < bestd) { bestd = d; bestm = i+2; /* 2 counts the VCD_SELF, VCD_HERE modes */ SMALLEST_INT (bestd); } } } if (acache->s_same > 0 && acache->same_array[d = addr%(acache->s_same*256)] == addr) { bestd = d%256; /* 2 + s_near offsets past the VCD_NEAR modes */ bestm = acache->s_near + 2 + d/256; if ((ret = xd3_emit_byte (stream, & ADDR_TAIL (stream), bestd))) { return ret; } } else { good: if ((ret = xd3_emit_size (stream, & ADDR_TAIL (stream), bestd))) { return ret; } } xd3_update_cache (acache, addr); (*mode) += bestm; return 0; } #endif static int xd3_decode_address (xd3_stream *stream, usize_t here, usize_t mode, const uint8_t **inpp, const uint8_t *max, usize_t *valp) { int ret; usize_t same_start = 2 + stream->acache.s_near; if (mode < same_start) { if ((ret = xd3_read_size (stream, inpp, max, valp))) { return ret; } switch (mode) { case VCD_SELF: break; case VCD_HERE: (*valp) = here - (*valp); break; default: (*valp) += stream->acache.near_array[mode - 2]; break; } } else { if (*inpp == max) { stream->msg = "address underflow"; return XD3_INVALID_INPUT; } mode -= same_start; (*valp) = stream->acache.same_array[mode*256 + (**inpp)]; (*inpp) += 1; } xd3_update_cache (& stream->acache, *valp); return 0; } /*********************************************************************** Alloc/free ***********************************************************************/ static void* __xd3_alloc_func (void* opaque, size_t items, usize_t size) { return malloc (items * (size_t) size); } static void __xd3_free_func (void* opaque, void* address) { free (address); } static void* xd3_alloc (xd3_stream *stream, usize_t elts, usize_t size) { void *a = stream->alloc (stream->opaque, elts, size); if (a != NULL) { IF_DEBUG (stream->alloc_cnt += 1); IF_DEBUG2 (DP(RINT "[stream %p malloc] size %"W"u ptr %p\n", (void*)stream, elts * size, a)); } else { stream->msg = "out of memory"; } return a; } static void xd3_free (xd3_stream *stream, void *ptr) { if (ptr != NULL) { IF_DEBUG (stream->free_cnt += 1); XD3_ASSERT (stream->free_cnt <= stream->alloc_cnt); IF_DEBUG2 (DP(RINT "[stream %p free] %p\n", (void*)stream, ptr)); stream->free (stream->opaque, ptr); } } #if XD3_ENCODER static void* xd3_alloc0 (xd3_stream *stream, usize_t elts, usize_t size) { void *a = xd3_alloc (stream, elts, size); if (a != NULL) { memset (a, 0, (size_t) (elts * size)); } return a; } xd3_output* xd3_alloc_output (xd3_stream *stream, xd3_output *old_output) { xd3_output *output; uint8_t *base; if (stream->enc_free != NULL) { output = stream->enc_free; stream->enc_free = output->next_page; } else { if ((output = (xd3_output*) xd3_alloc (stream, 1, (usize_t) sizeof (xd3_output))) == NULL) { return NULL; } if ((base = (uint8_t*) xd3_alloc (stream, XD3_ALLOCSIZE, sizeof (uint8_t))) == NULL) { xd3_free (stream, output); return NULL; } output->base = base; output->avail = XD3_ALLOCSIZE; } output->next = 0; if (old_output) { old_output->next_page = output; } output->next_page = NULL; return output; } static usize_t xd3_sizeof_output (xd3_output *output) { usize_t s = 0; for (; output; output = output->next_page) { s += output->next; } return s; } static void xd3_freelist_output (xd3_stream *stream, xd3_output *output) { xd3_output *tmp; while (output) { tmp = output; output = output->next_page; tmp->next = 0; tmp->next_page = stream->enc_free; stream->enc_free = tmp; } } static void xd3_free_output (xd3_stream *stream, xd3_output *output) { xd3_output *next; again: if (output == NULL) { return; } next = output->next_page; xd3_free (stream, output->base); xd3_free (stream, output); output = next; goto again; } #endif /* XD3_ENCODER */ void xd3_free_stream (xd3_stream *stream) { xd3_iopt_buflist *blist = stream->iopt_alloc; while (blist != NULL) { xd3_iopt_buflist *tmp = blist; blist = blist->next; xd3_free (stream, tmp->buffer); xd3_free (stream, tmp); } #if XD3_ENCODER xd3_free (stream, stream->large_table); xd3_free (stream, stream->small_table); xd3_free (stream, stream->large_hash.powers); xd3_free (stream, stream->small_hash.powers); xd3_free (stream, stream->small_prev); { int i; for (i = 0; i < ENC_SECTS; i += 1) { xd3_free_output (stream, stream->enc_heads[i]); } xd3_free_output (stream, stream->enc_free); } #endif xd3_free (stream, stream->acache.near_array); xd3_free (stream, stream->acache.same_array); xd3_free (stream, stream->inst_sect.copied1); xd3_free (stream, stream->addr_sect.copied1); xd3_free (stream, stream->data_sect.copied1); if (stream->dec_lastwin != stream->dec_buffer) { xd3_free (stream, (uint8_t*) stream->dec_lastwin); } xd3_free (stream, stream->dec_buffer); xd3_free (stream, stream->buf_in); xd3_free (stream, stream->dec_appheader); xd3_free (stream, stream->dec_codetbl); xd3_free (stream, stream->code_table_alloc); #if SECONDARY_ANY xd3_free (stream, stream->inst_sect.copied2); xd3_free (stream, stream->addr_sect.copied2); xd3_free (stream, stream->data_sect.copied2); if (stream->sec_type != NULL) { stream->sec_type->destroy (stream, stream->sec_stream_d); stream->sec_type->destroy (stream, stream->sec_stream_i); stream->sec_type->destroy (stream, stream->sec_stream_a); } #endif xd3_free (stream, stream->whole_target.adds); xd3_free (stream, stream->whole_target.inst); xd3_free (stream, stream->whole_target.wininfo); XD3_ASSERT (stream->alloc_cnt == stream->free_cnt); memset (stream, 0, sizeof (xd3_stream)); } #if (XD3_DEBUG > 1 || VCDIFF_TOOLS) static const char* xd3_rtype_to_string (xd3_rtype type, int print_mode) { switch (type) { case XD3_NOOP: return "NOOP "; case XD3_RUN: return "RUN "; case XD3_ADD: return "ADD "; default: break; } if (! print_mode) { return "CPY "; } switch (type) { case XD3_CPY + 0: return "CPY_0"; case XD3_CPY + 1: return "CPY_1"; case XD3_CPY + 2: return "CPY_2"; case XD3_CPY + 3: return "CPY_3"; case XD3_CPY + 4: return "CPY_4"; case XD3_CPY + 5: return "CPY_5"; case XD3_CPY + 6: return "CPY_6"; case XD3_CPY + 7: return "CPY_7"; case XD3_CPY + 8: return "CPY_8"; case XD3_CPY + 9: return "CPY_9"; default: return "CPY>9"; } } #endif /**************************************************************** Stream configuration ******************************************************************/ int xd3_config_stream(xd3_stream *stream, xd3_config *config) { int ret; xd3_config defcfg; xd3_smatcher *smatcher = &stream->smatcher; if (config == NULL) { config = & defcfg; memset (config, 0, sizeof (*config)); } /* Initial setup: no error checks yet */ memset (stream, 0, sizeof (*stream)); stream->winsize = config->winsize ? config->winsize : XD3_DEFAULT_WINSIZE; stream->sprevsz = config->sprevsz ? config->sprevsz : XD3_DEFAULT_SPREVSZ; if (config->iopt_size == 0) { stream->iopt_size = XD3_ALLOCSIZE / sizeof(xd3_rinst); stream->iopt_unlimited = 1; } else { stream->iopt_size = config->iopt_size; } stream->getblk = config->getblk; stream->alloc = config->alloc ? config->alloc : __xd3_alloc_func; stream->free = config->freef ? config->freef : __xd3_free_func; stream->opaque = config->opaque; stream->flags = config->flags; /* Secondary setup. */ stream->sec_data = config->sec_data; stream->sec_inst = config->sec_inst; stream->sec_addr = config->sec_addr; stream->sec_data.data_type = DATA_SECTION; stream->sec_inst.data_type = INST_SECTION; stream->sec_addr.data_type = ADDR_SECTION; /* Check static sizes. */ if (sizeof (usize_t) != SIZEOF_USIZE_T || sizeof (xoff_t) != SIZEOF_XOFF_T || (ret = xd3_check_pow2(XD3_ALLOCSIZE, NULL))) { stream->msg = "incorrect compilation: wrong integer sizes"; return XD3_INTERNAL; } /* Check/set secondary compressor. */ switch (stream->flags & XD3_SEC_TYPE) { case 0: if (stream->flags & XD3_SEC_NOALL) { stream->msg = "XD3_SEC flags require a secondary compressor type"; return XD3_INTERNAL; } break; case XD3_SEC_FGK: FGK_CASE (stream); case XD3_SEC_DJW: DJW_CASE (stream); case XD3_SEC_LZMA: LZMA_CASE (stream); default: stream->msg = "too many secondary compressor types set"; return XD3_INTERNAL; } stream->code_table_desc = & __rfc3284_code_table_desc; stream->code_table_func = xd3_rfc3284_code_table; /* Check sprevsz */ if (smatcher->small_chain == 1 && smatcher->small_lchain == 1) { stream->sprevsz = 0; } else { if ((ret = xd3_check_pow2 (stream->sprevsz, NULL))) { stream->msg = "sprevsz is required to be a power of two"; return XD3_INTERNAL; } stream->sprevmask = stream->sprevsz - 1; } /* Default scanner settings. */ #if XD3_ENCODER switch (config->smatch_cfg) { IF_BUILD_SOFT(case XD3_SMATCH_SOFT: { *smatcher = config->smatcher_soft; smatcher->string_match = __smatcher_soft.string_match; smatcher->name = __smatcher_soft.name; if (smatcher->large_look < MIN_MATCH || smatcher->large_step < 1 || smatcher->small_look < MIN_MATCH) { stream->msg = "invalid soft string-match config"; return XD3_INVALID; } break; }) IF_BUILD_DEFAULT(case XD3_SMATCH_DEFAULT: *smatcher = __smatcher_default; break;) IF_BUILD_SLOW(case XD3_SMATCH_SLOW: *smatcher = __smatcher_slow; break;) IF_BUILD_FASTEST(case XD3_SMATCH_FASTEST: *smatcher = __smatcher_fastest; break;) IF_BUILD_FASTER(case XD3_SMATCH_FASTER: *smatcher = __smatcher_faster; break;) IF_BUILD_FAST(case XD3_SMATCH_FAST: *smatcher = __smatcher_fast; break;) default: stream->msg = "invalid string match config type"; return XD3_INTERNAL; } if (config->smatch_cfg == XD3_SMATCH_DEFAULT && (stream->flags & XD3_COMPLEVEL_MASK) != 0) { int level = (stream->flags & XD3_COMPLEVEL_MASK) >> XD3_COMPLEVEL_SHIFT; switch (level) { case 1: IF_BUILD_FASTEST(*smatcher = __smatcher_fastest; break;) case 2: IF_BUILD_FASTER(*smatcher = __smatcher_faster; break;) case 3: case 4: case 5: IF_BUILD_FAST(*smatcher = __smatcher_fast; break;) case 6: IF_BUILD_DEFAULT(*smatcher = __smatcher_default; break;) default: IF_BUILD_SLOW(*smatcher = __smatcher_slow; break;) IF_BUILD_DEFAULT(*smatcher = __smatcher_default; break;) IF_BUILD_FAST(*smatcher = __smatcher_fast; break;) IF_BUILD_FASTER(*smatcher = __smatcher_faster; break;) IF_BUILD_FASTEST(*smatcher = __smatcher_fastest; break;) } } #endif return 0; } /*********************************************************** Getblk interface ***********************************************************/ inline xoff_t xd3_source_eof(const xd3_source *src) { xoff_t r = (src->max_blkno << src->shiftby) + (xoff_t)src->onlastblk; return r; } inline usize_t xd3_bytes_on_srcblk (xd3_source *src, xoff_t blkno) { usize_t r = (blkno == src->max_blkno ? src->onlastblk : src->blksize); return r; } /* This function interfaces with the client getblk function, checks * its results, updates max_blkno, onlastblk, eof_known. */ static int xd3_getblk (xd3_stream *stream, xoff_t blkno) { int ret; xd3_source *source = stream->src; if (source->curblk == NULL || blkno != source->curblkno) { source->getblkno = blkno; if (stream->getblk == NULL) { IF_DEBUG2 (DP(RINT "[getblk] XD3_GETSRCBLK %"Q"u\n", blkno)); stream->msg = "getblk source input"; return XD3_GETSRCBLK; } ret = stream->getblk (stream, source, blkno); if (ret != 0) { IF_DEBUG2 (DP(RINT "[getblk] app error blkno %"Q"u: %s\n", blkno, xd3_strerror (ret))); return ret; } IF_DEBUG2 (DP(RINT "[getblk] read source block %"Q"u onblk " "%"W"u blksize %"W"u max_blkno %"Q"u\n", blkno, source->onblk, source->blksize, source->max_blkno)); } if (blkno > source->max_blkno) { source->max_blkno = blkno; if (source->onblk == source->blksize) { IF_DEBUG1 (DP(RINT "[getblk] full source blkno %"Q"u: " "source length unknown %"Q"u\n", blkno, xd3_source_eof (source))); } else if (!source->eof_known) { IF_DEBUG1 (DP(RINT "[getblk] eof block has %"W"u bytes; " "source length known %"Q"u\n", xd3_bytes_on_srcblk (source, blkno), xd3_source_eof (source))); source->eof_known = 1; } } XD3_ASSERT (source->curblk != NULL); if (blkno == source->max_blkno) { /* In case the application sets the source as 1 block w/ a * preset buffer. */ source->onlastblk = source->onblk; } return 0; } /*********************************************************** Stream open/close ***************************************************************/ int xd3_set_source (xd3_stream *stream, xd3_source *src) { usize_t shiftby; stream->src = src; src->srclen = 0; src->srcbase = 0; /* Enforce power-of-two blocksize so that source-block number * calculations are cheap. */ if (xd3_check_pow2 (src->blksize, &shiftby) != 0) { src->blksize = xd3_pow2_roundup(src->blksize); xd3_check_pow2 (src->blksize, &shiftby); IF_DEBUG1 (DP(RINT "raising src_blksz to %"W"u\n", src->blksize)); } src->shiftby = shiftby; src->maskby = (1ULL << shiftby) - 1ULL; if (xd3_check_pow2 (src->max_winsize, NULL) != 0) { src->max_winsize = xd3_xoff_roundup(src->max_winsize); IF_DEBUG1 (DP(RINT "raising src_maxsize to %"W"u\n", src->blksize)); } src->max_winsize = xd3_max (src->max_winsize, XD3_ALLOCSIZE); return 0; } int xd3_set_source_and_size (xd3_stream *stream, xd3_source *user_source, xoff_t source_size) { int ret = xd3_set_source (stream, user_source); if (ret == 0) { stream->src->eof_known = 1; IF_DEBUG2 (DP(RINT "[set source] size known %"Q"u\n", source_size)); xd3_blksize_div(source_size, stream->src, &stream->src->max_blkno, &stream->src->onlastblk); IF_DEBUG1 (DP(RINT "[set source] size known %"Q"u max_blkno %"Q"u\n", source_size, stream->src->max_blkno)); } return ret; } void xd3_abort_stream (xd3_stream *stream) { stream->dec_state = DEC_ABORTED; stream->enc_state = ENC_ABORTED; } int xd3_close_stream (xd3_stream *stream) { if (stream->enc_state != 0 && stream->enc_state != ENC_ABORTED) { if (stream->buf_leftover != NULL) { stream->msg = "encoding is incomplete"; return XD3_INTERNAL; } if (stream->enc_state == ENC_POSTWIN) { #if XD3_ENCODER xd3_encode_reset (stream); #endif stream->current_window += 1; stream->enc_state = ENC_INPUT; } /* If encoding, should be ready for more input but not actually have any. */ if (stream->enc_state != ENC_INPUT || stream->avail_in != 0) { stream->msg = "encoding is incomplete"; return XD3_INTERNAL; } } else { switch (stream->dec_state) { case DEC_VCHEAD: case DEC_WININD: /* TODO: Address the zero-byte ambiguity. Does the encoder * emit a window or not? If so, then catch an error here. * If not, need another routine to say * decode_at_least_one_if_empty. */ case DEC_ABORTED: break; default: /* If decoding, should be ready for the next window. */ stream->msg = "eof in decode"; return XD3_INVALID_INPUT; } } return 0; } /************************************************************** Application header ****************************************************************/ int xd3_get_appheader (xd3_stream *stream, uint8_t **data, usize_t *size) { if (stream->dec_state < DEC_WININD) { stream->msg = "application header not available"; return XD3_INTERNAL; } (*data) = stream->dec_appheader; (*size) = stream->dec_appheadsz; return 0; } /********************************************************** Decoder stuff *************************************************/ #include "xdelta3-decode.h" /**************************************************************** Encoder stuff *****************************************************************/ #if XD3_ENCODER void xd3_set_appheader (xd3_stream *stream, const uint8_t *data, usize_t size) { stream->enc_appheader = data; stream->enc_appheadsz = size; } #if XD3_DEBUG static int xd3_iopt_check (xd3_stream *stream) { usize_t ul = xd3_rlist_length (& stream->iopt_used); usize_t fl = xd3_rlist_length (& stream->iopt_free); return (ul + fl + (stream->iout ? 1 : 0)) == stream->iopt_size; } #endif static xd3_rinst* xd3_iopt_free (xd3_stream *stream, xd3_rinst *i) { xd3_rinst *n = xd3_rlist_remove (i); xd3_rlist_push_back (& stream->iopt_free, i); return n; } static void xd3_iopt_free_nonadd (xd3_stream *stream, xd3_rinst *i) { if (i->type != XD3_ADD) { xd3_rlist_push_back (& stream->iopt_free, i); } } /* When an instruction is ready to flush from the iopt buffer, this * function is called to produce an encoding. It writes the * instruction plus size, address, and data to the various encoding * sections. */ static int xd3_iopt_finish_encoding (xd3_stream *stream, xd3_rinst *inst) { int ret; /* Check for input overflow. */ XD3_ASSERT (inst->pos + inst->size <= stream->avail_in); switch (inst->type) { case XD3_CPY: { /* the address may have an offset if there is a source window. */ usize_t addr; xd3_source *src = stream->src; if (src != NULL) { /* If there is a source copy, the source must have its * source window decided before we can encode. This can * be bad -- we have to make this decision even if no * source matches have been found. */ if (stream->srcwin_decided == 0) { if ((ret = xd3_srcwin_setup (stream))) { return ret; } } else { stream->srcwin_decided_early = (!stream->src->eof_known || (stream->srcwin_cksum_pos < xd3_source_eof (stream->src))); } /* xtra field indicates the copy is from the source */ if (inst->xtra) { XD3_ASSERT (inst->addr >= src->srcbase); XD3_ASSERT (inst->addr + inst->size <= src->srcbase + src->srclen); addr = inst->addr - src->srcbase; stream->n_scpy += 1; stream->l_scpy += inst->size; } else { /* with source window: target copy address is offset * by taroff. */ addr = stream->taroff + inst->addr; stream->n_tcpy += 1; stream->l_tcpy += inst->size; } } else { addr = inst->addr; stream->n_tcpy += 1; stream->l_tcpy += inst->size; } /* Note: used to assert inst->size >= MIN_MATCH, but not true * for merge operations & identical match heuristics. */ /* the "here" position is always offset by taroff */ if ((ret = xd3_encode_address (stream, addr, inst->pos + stream->taroff, & inst->type))) { return ret; } IF_DEBUG2 ({ static int cnt; DP(RINT "[iopt copy:%d] pos %"Q"u-%"Q"u addr %"Q"u-%"Q"u size %"W"u\n", cnt++, stream->total_in + inst->pos, stream->total_in + inst->pos + inst->size, inst->addr, inst->addr + inst->size, inst->size); }); break; } case XD3_RUN: { if ((ret = xd3_emit_byte (stream, & DATA_TAIL (stream), inst->xtra))) { return ret; } stream->n_run += 1; stream->l_run += inst->size; IF_DEBUG2 ({ static int cnt; DP(RINT "[iopt run:%d] pos %"Q"u size %"W"u\n", cnt++, stream->total_in + inst->pos, inst->size); }); break; } case XD3_ADD: { if ((ret = xd3_emit_bytes (stream, & DATA_TAIL (stream), stream->next_in + inst->pos, inst->size))) { return ret; } stream->n_add += 1; stream->l_add += inst->size; IF_DEBUG2 ({ static int cnt; DP(RINT "[iopt add:%d] pos %"Q"u size %"W"u\n", cnt++, stream->total_in + inst->pos, inst->size); }); break; } } /* This is the only place stream->unencoded_offset is incremented. */ XD3_ASSERT (stream->unencoded_offset == inst->pos); stream->unencoded_offset += inst->size; inst->code2 = 0; XD3_CHOOSE_INSTRUCTION (stream, stream->iout, inst); if (stream->iout != NULL) { if (stream->iout->code2 != 0) { if ((ret = xd3_emit_double (stream, stream->iout, inst, stream->iout->code2))) { return ret; } xd3_iopt_free_nonadd (stream, stream->iout); xd3_iopt_free_nonadd (stream, inst); stream->iout = NULL; return 0; } else { if ((ret = xd3_emit_single (stream, stream->iout, stream->iout->code1))) { return ret; } xd3_iopt_free_nonadd (stream, stream->iout); } } stream->iout = inst; return 0; } /* This possibly encodes an add instruction, iadd, which must remain * on the stack until the following call to * xd3_iopt_finish_encoding. */ static int xd3_iopt_add (xd3_stream *stream, usize_t pos, xd3_rinst *iadd) { int ret; usize_t off = stream->unencoded_offset; if (pos > off) { iadd->type = XD3_ADD; iadd->pos = off; iadd->size = pos - off; if ((ret = xd3_iopt_finish_encoding (stream, iadd))) { return ret; } } return 0; } /* This function calls xd3_iopt_finish_encoding to finish encoding an * instruction, and it may also produce an add instruction for an * unmatched region. */ static int xd3_iopt_add_encoding (xd3_stream *stream, xd3_rinst *inst) { int ret; xd3_rinst iadd; if ((ret = xd3_iopt_add (stream, inst->pos, & iadd))) { return ret; } if ((ret = xd3_iopt_finish_encoding (stream, inst))) { return ret; } return 0; } /* Generates a final add instruction to encode the remaining input. */ static int xd3_iopt_add_finalize (xd3_stream *stream) { int ret; xd3_rinst iadd; if ((ret = xd3_iopt_add (stream, stream->avail_in, & iadd))) { return ret; } if (stream->iout) { if ((ret = xd3_emit_single (stream, stream->iout, stream->iout->code1))) { return ret; } xd3_iopt_free_nonadd (stream, stream->iout); stream->iout = NULL; } return 0; } /* Compact the instruction buffer by choosing the best non-overlapping * instructions when lazy string-matching. There are no ADDs in the * iopt buffer because those are synthesized in xd3_iopt_add_encoding * and during xd3_iopt_add_finalize. */ static int xd3_iopt_flush_instructions (xd3_stream *stream, int force) { xd3_rinst *r1 = xd3_rlist_front (& stream->iopt_used); xd3_rinst *r2; xd3_rinst *r3; usize_t r1end; usize_t r2end; usize_t r2off; usize_t r2moff; usize_t gap; usize_t flushed; int ret; XD3_ASSERT (xd3_iopt_check (stream)); /* Note: once tried to skip this step if it's possible to assert * there are no overlapping instructions. Doesn't work because * xd3_opt_erase leaves overlapping instructions. */ while (! xd3_rlist_end (& stream->iopt_used, r1) && ! xd3_rlist_end (& stream->iopt_used, r2 = xd3_rlist_next (r1))) { r1end = r1->pos + r1->size; /* If the instructions do not overlap, continue. */ if (r1end <= r2->pos) { r1 = r2; continue; } r2end = r2->pos + r2->size; /* The min_match adjustments prevent this. */ XD3_ASSERT (r2end > (r1end + LEAST_MATCH_INCR)); /* If r3 is available... */ if (! xd3_rlist_end (& stream->iopt_used, r3 = xd3_rlist_next (r2))) { /* If r3 starts before r1 finishes or just about, r2 is irrelevant */ if (r3->pos <= r1end + 1) { xd3_iopt_free (stream, r2); continue; } } else if (! force) { /* Unless force, end the loop when r3 is not available. */ break; } r2off = r2->pos - r1->pos; r2moff = r2end - r1end; gap = r2end - r1->pos; /* If the two matches overlap almost entirely, choose the better match * and discard the other. The else branch can still create inefficient * copies, e.g., a 4-byte copy that takes 4 bytes to encode, which * xd3_smatch() wouldn't allow by its crude efficiency check. However, * in this case there are adjacent copies which mean the add would cost * one extra byte. Allow the inefficiency here. */ if (gap < 2*MIN_MATCH || r2moff <= 2 || r2off <= 2) { /* Only one match should be used, choose the longer one. */ if (r1->size < r2->size) { xd3_iopt_free (stream, r1); r1 = r2; } else { /* We are guaranteed that r1 does not overlap now, so advance past r2 */ r1 = xd3_iopt_free (stream, r2); } continue; } else { /* Shorten one of the instructions -- could be optimized * based on the address cache. */ usize_t average; usize_t newsize; usize_t adjust1; XD3_ASSERT (r1end > r2->pos && r2end > r1->pos); /* Try to balance the length of both instructions, but avoid * making both longer than MAX_MATCH_SPLIT . */ average = gap / 2; newsize = xd3_min (MAX_MATCH_SPLIT, gap - average); /* Should be possible to simplify this code. */ if (newsize > r1->size) { /* shorten r2 */ adjust1 = r1end - r2->pos; } else if (newsize > r2->size) { /* shorten r1 */ adjust1 = r1end - r2->pos; XD3_ASSERT (r1->size > adjust1); r1->size -= adjust1; /* don't shorten r2 */ adjust1 = 0; } else { /* shorten r1 */ adjust1 = r1->size - newsize; if (r2->pos > r1end - adjust1) { adjust1 -= r2->pos - (r1end - adjust1); } XD3_ASSERT (r1->size > adjust1); r1->size -= adjust1; /* shorten r2 */ XD3_ASSERT (r1->pos + r1->size >= r2->pos); adjust1 = r1->pos + r1->size - r2->pos; } /* Fallthrough above if-else, shorten r2 */ XD3_ASSERT (r2->size > adjust1); r2->size -= adjust1; r2->pos += adjust1; r2->addr += adjust1; XD3_ASSERT (r1->size >= MIN_MATCH); XD3_ASSERT (r2->size >= MIN_MATCH); r1 = r2; } } XD3_ASSERT (xd3_iopt_check (stream)); /* If forcing, pick instructions until the list is empty, otherwise * this empties 50% of the queue. */ for (flushed = 0; ! xd3_rlist_empty (& stream->iopt_used); ) { xd3_rinst *renc = xd3_rlist_pop_front (& stream->iopt_used); if ((ret = xd3_iopt_add_encoding (stream, renc))) { return ret; } if (! force) { if (++flushed > stream->iopt_size / 2) { break; } /* If there are only two instructions remaining, break, * because they were not optimized. This means there were * more than 50% eliminated by the loop above. */ r1 = xd3_rlist_front (& stream->iopt_used); if (xd3_rlist_end(& stream->iopt_used, r1) || xd3_rlist_end(& stream->iopt_used, r2 = xd3_rlist_next (r1)) || xd3_rlist_end(& stream->iopt_used, r3 = xd3_rlist_next (r2))) { break; } } } XD3_ASSERT (xd3_iopt_check (stream)); XD3_ASSERT (!force || xd3_rlist_length (& stream->iopt_used) == 0); return 0; } static int xd3_iopt_get_slot (xd3_stream *stream, xd3_rinst** iptr) { xd3_rinst *i; int ret; if (xd3_rlist_empty (& stream->iopt_free)) { if (stream->iopt_unlimited) { usize_t elts = XD3_ALLOCSIZE / sizeof(xd3_rinst); if ((ret = xd3_alloc_iopt (stream, elts))) { return ret; } stream->iopt_size += elts; } else { if ((ret = xd3_iopt_flush_instructions (stream, 0))) { return ret; } XD3_ASSERT (! xd3_rlist_empty (& stream->iopt_free)); } } i = xd3_rlist_pop_back (& stream->iopt_free); xd3_rlist_push_back (& stream->iopt_used, i); (*iptr) = i; ++stream->i_slots_used; return 0; } /* A copy is about to be emitted that extends backwards to POS, * therefore it may completely cover some existing instructions in the * buffer. If an instruction is completely covered by this new match, * erase it. If the new instruction is covered by the previous one, * return 1 to skip it. */ static void xd3_iopt_erase (xd3_stream *stream, usize_t pos, usize_t size) { while (! xd3_rlist_empty (& stream->iopt_used)) { xd3_rinst *r = xd3_rlist_back (& stream->iopt_used); /* Verify that greedy is working. The previous instruction * should end before the new one begins. */ XD3_ASSERT ((stream->flags & XD3_BEGREEDY) == 0 || (r->pos + r->size <= pos)); /* Verify that min_match is working. The previous instruction * should end before the new one ends. */ XD3_ASSERT ((stream->flags & XD3_BEGREEDY) != 0 || (r->pos + r->size < pos + size)); /* See if the last instruction starts before the new * instruction. If so, there is nothing to erase. */ if (r->pos < pos) { return; } /* Otherwise, the new instruction covers the old one, delete it and repeat. */ xd3_rlist_remove (r); xd3_rlist_push_back (& stream->iopt_free, r); --stream->i_slots_used; } } /* This function tells the last matched input position. */ static usize_t xd3_iopt_last_matched (xd3_stream *stream) { xd3_rinst *r; if (xd3_rlist_empty (& stream->iopt_used)) { return 0; } r = xd3_rlist_back (& stream->iopt_used); return r->pos + r->size; } /********************************************************* Emit routines ***********************************************************/ static int xd3_emit_single (xd3_stream *stream, xd3_rinst *single, uint8_t code) { int has_size = stream->code_table[code].size1 == 0; int ret; IF_DEBUG2 (DP(RINT "[emit1] %"W"u %s (%"W"u) code %u\n", single->pos, xd3_rtype_to_string ((xd3_rtype) single->type, 0), single->size, code)); if ((ret = xd3_emit_byte (stream, & INST_TAIL (stream), code))) { return ret; } if (has_size) { if ((ret = xd3_emit_size (stream, & INST_TAIL (stream), single->size))) { return ret; } } return 0; } static int xd3_emit_double (xd3_stream *stream, xd3_rinst *first, xd3_rinst *second, uint8_t code) { int ret; /* All double instructions use fixed sizes, so all we need to do is * output the instruction code, no sizes. */ XD3_ASSERT (stream->code_table[code].size1 != 0 && stream->code_table[code].size2 != 0); if ((ret = xd3_emit_byte (stream, & INST_TAIL (stream), code))) { return ret; } IF_DEBUG2 (DP(RINT "[emit2]: %"W"u %s (%"W"u) %s (%"W"u) code %u\n", first->pos, xd3_rtype_to_string ((xd3_rtype) first->type, 0), first->size, xd3_rtype_to_string ((xd3_rtype) second->type, 0), second->size, code)); return 0; } /* This enters a potential run instruction into the iopt buffer. The * position argument is relative to the target window. */ static int xd3_emit_run (xd3_stream *stream, usize_t pos, usize_t size, uint8_t *run_c) { xd3_rinst* ri; int ret; if ((ret = xd3_iopt_get_slot (stream, & ri))) { return ret; } ri->type = XD3_RUN; ri->xtra = *run_c; ri->pos = pos; ri->size = size; return 0; } /* This enters a potential copy instruction into the iopt buffer. The * position argument is relative to the target window.. */ int xd3_found_match (xd3_stream *stream, usize_t pos, usize_t size, xoff_t addr, int is_source) { xd3_rinst* ri; int ret; if ((ret = xd3_iopt_get_slot (stream, & ri))) { return ret; } ri->type = XD3_CPY; ri->xtra = is_source; ri->pos = pos; ri->size = size; ri->addr = addr; return 0; } static int xd3_emit_hdr (xd3_stream *stream) { int ret; int use_secondary = stream->sec_type != NULL; int use_adler32 = stream->flags & (XD3_ADLER32 | XD3_ADLER32_RECODE); int vcd_source = xd3_encoder_used_source (stream); uint8_t win_ind = 0; uint8_t del_ind = 0; usize_t enc_len; usize_t tgt_len; usize_t data_len; usize_t inst_len; usize_t addr_len; if (stream->current_window == 0) { uint8_t hdr_ind = 0; int use_appheader = stream->enc_appheader != NULL; if (use_secondary) { hdr_ind |= VCD_SECONDARY; } if (use_appheader) { hdr_ind |= VCD_APPHEADER; } if ((ret = xd3_emit_byte (stream, & HDR_TAIL (stream), VCDIFF_MAGIC1)) != 0 || (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), VCDIFF_MAGIC2)) != 0 || (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), VCDIFF_MAGIC3)) != 0 || (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), VCDIFF_VERSION)) != 0 || (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), hdr_ind)) != 0) { return ret; } /* Secondary compressor ID */ #if SECONDARY_ANY if (use_secondary && (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), stream->sec_type->id))) { return ret; } #endif /* Application header */ if (use_appheader) { if ((ret = xd3_emit_size (stream, & HDR_TAIL (stream), stream->enc_appheadsz)) || (ret = xd3_emit_bytes (stream, & HDR_TAIL (stream), stream->enc_appheader, stream->enc_appheadsz))) { return ret; } } } /* try to compress this window */ #if SECONDARY_ANY if (use_secondary) { int data_sec = 0; int inst_sec = 0; int addr_sec = 0; # define ENCODE_SECONDARY_SECTION(UPPER,LOWER) \ ((stream->flags & XD3_SEC_NO ## UPPER) == 0 && \ (ret = xd3_encode_secondary (stream, \ & UPPER ## _HEAD (stream), \ & UPPER ## _TAIL (stream), \ & xd3_sec_ ## LOWER (stream), \ & stream->sec_ ## LOWER, \ & LOWER ## _sec))) if (ENCODE_SECONDARY_SECTION (DATA, data) || ENCODE_SECONDARY_SECTION (INST, inst) || ENCODE_SECONDARY_SECTION (ADDR, addr)) { return ret; } del_ind |= (data_sec ? VCD_DATACOMP : 0); del_ind |= (inst_sec ? VCD_INSTCOMP : 0); del_ind |= (addr_sec ? VCD_ADDRCOMP : 0); } #endif /* if (vcd_target) { win_ind |= VCD_TARGET; } */ if (vcd_source) { win_ind |= VCD_SOURCE; } if (use_adler32) { win_ind |= VCD_ADLER32; } /* window indicator */ if ((ret = xd3_emit_byte (stream, & HDR_TAIL (stream), win_ind))) { return ret; } /* source window */ if (vcd_source) { /* or (vcd_target) { ... } */ if ((ret = xd3_emit_size (stream, & HDR_TAIL (stream), stream->src->srclen)) || (ret = xd3_emit_offset (stream, & HDR_TAIL (stream), stream->src->srcbase))) { return ret; } } tgt_len = stream->avail_in; data_len = xd3_sizeof_output (DATA_HEAD (stream)); inst_len = xd3_sizeof_output (INST_HEAD (stream)); addr_len = xd3_sizeof_output (ADDR_HEAD (stream)); /* The enc_len field is a redundency for future extensions. */ enc_len = (1 + (xd3_sizeof_size (tgt_len) + xd3_sizeof_size (data_len) + xd3_sizeof_size (inst_len) + xd3_sizeof_size (addr_len)) + data_len + inst_len + addr_len + (use_adler32 ? 4 : 0)); if ((ret = xd3_emit_size (stream, & HDR_TAIL (stream), enc_len)) || (ret = xd3_emit_size (stream, & HDR_TAIL (stream), tgt_len)) || (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), del_ind)) || (ret = xd3_emit_size (stream, & HDR_TAIL (stream), data_len)) || (ret = xd3_emit_size (stream, & HDR_TAIL (stream), inst_len)) || (ret = xd3_emit_size (stream, & HDR_TAIL (stream), addr_len))) { return ret; } if (use_adler32) { uint8_t send[4]; uint32_t a32; if (stream->flags & XD3_ADLER32) { a32 = adler32 (1L, stream->next_in, stream->avail_in); } else { a32 = stream->recode_adler32; } /* Four bytes. */ send[0] = (uint8_t) (a32 >> 24); send[1] = (uint8_t) (a32 >> 16); send[2] = (uint8_t) (a32 >> 8); send[3] = (uint8_t) (a32 & 0x000000FFU); if ((ret = xd3_emit_bytes (stream, & HDR_TAIL (stream), send, 4))) { return ret; } } return 0; } /**************************************************************** Encode routines ****************************************************************/ static int xd3_encode_buffer_leftover (xd3_stream *stream) { usize_t take; usize_t room; /* Allocate the buffer. */ if (stream->buf_in == NULL && (stream->buf_in = (uint8_t*) xd3_alloc (stream, stream->winsize, 1)) == NULL) { return ENOMEM; } IF_DEBUG2 (DP(RINT "[leftover] flush?=%s\n", (stream->flags & XD3_FLUSH) ? "yes" : "no")); /* Take leftover input first. */ if (stream->buf_leftover != NULL) { XD3_ASSERT (stream->buf_avail == 0); XD3_ASSERT (stream->buf_leftavail < stream->winsize); IF_DEBUG2 (DP(RINT "[leftover] previous %"W"u avail %"W"u\n", stream->buf_leftavail, stream->avail_in)); memcpy (stream->buf_in, stream->buf_leftover, stream->buf_leftavail); stream->buf_leftover = NULL; stream->buf_avail = stream->buf_leftavail; } /* Copy into the buffer. */ room = stream->winsize - stream->buf_avail; take = xd3_min (room, stream->avail_in); memcpy (stream->buf_in + stream->buf_avail, stream->next_in, take); stream->buf_avail += take; if (take < stream->avail_in) { /* Buffer is full */ stream->buf_leftover = stream->next_in + take; stream->buf_leftavail = stream->avail_in - take; } else if ((stream->buf_avail < stream->winsize) && !(stream->flags & XD3_FLUSH)) { /* Buffer has space */ IF_DEBUG2 (DP(RINT "[leftover] emptied %"W"u\n", take)); return XD3_INPUT; } /* Use the buffer: */ IF_DEBUG2 (DP(RINT "[leftover] take %"W"u remaining %"W"u\n", take, stream->buf_leftavail)); stream->next_in = stream->buf_in; stream->avail_in = stream->buf_avail; stream->buf_avail = 0; return 0; } /* Allocates one block of xd3_rlist elements */ static int xd3_alloc_iopt (xd3_stream *stream, usize_t elts) { usize_t i; xd3_iopt_buflist* last = (xd3_iopt_buflist*) xd3_alloc (stream, sizeof (xd3_iopt_buflist), 1); if (last == NULL || (last->buffer = (xd3_rinst*) xd3_alloc (stream, sizeof (xd3_rinst), elts)) == NULL) { return ENOMEM; } last->next = stream->iopt_alloc; stream->iopt_alloc = last; for (i = 0; i < elts; i += 1) { xd3_rlist_push_back (& stream->iopt_free, & last->buffer[i]); } return 0; } /* This function allocates all memory initially used by the encoder. */ static int xd3_encode_init (xd3_stream *stream, int full_init) { int ret; int i; if (full_init) { int large_comp = (stream->src != NULL); int small_comp = ! (stream->flags & XD3_NOCOMPRESS); /* Memory allocations for checksum tables are delayed until * xd3_string_match_init in the first call to string_match--that way * identical or short inputs require no table allocation. */ if (large_comp) { /* TODO Need to check for overflow here. */ usize_t hash_values = stream->src->max_winsize / stream->smatcher.large_step; if ((ret = xd3_size_hashtable (stream, hash_values, stream->smatcher.large_look, & stream->large_hash))) { return ret; } } if (small_comp) { /* TODO: This is under devel: used to have min (sprevsz) here, which sort * of makes sense, but observed fast performance w/ larger tables, which * also sort of makes sense. @@@ */ usize_t hash_values = stream->winsize; if ((ret = xd3_size_hashtable (stream, hash_values, stream->smatcher.small_look, & stream->small_hash))) { return ret; } } } /* data buffers */ for (i = 0; i < ENC_SECTS; i += 1) { if ((stream->enc_heads[i] = stream->enc_tails[i] = xd3_alloc_output (stream, NULL)) == NULL) { return ENOMEM; } } /* iopt buffer */ xd3_rlist_init (& stream->iopt_used); xd3_rlist_init (& stream->iopt_free); if (xd3_alloc_iopt (stream, stream->iopt_size) != 0) { goto fail; } XD3_ASSERT (xd3_rlist_length (& stream->iopt_free) == stream->iopt_size); XD3_ASSERT (xd3_rlist_length (& stream->iopt_used) == 0); /* address cache, code table */ stream->acache.s_near = stream->code_table_desc->near_modes; stream->acache.s_same = stream->code_table_desc->same_modes; stream->code_table = stream->code_table_func (); return xd3_alloc_cache (stream); fail: return ENOMEM; } int xd3_encode_init_full (xd3_stream *stream) { return xd3_encode_init (stream, 1); } int xd3_encode_init_partial (xd3_stream *stream) { return xd3_encode_init (stream, 0); } /* Called after the ENC_POSTOUT state, this puts the output buffers * back into separate lists and re-initializes some variables. (The * output lists were spliced together during the ENC_FLUSH state.) */ static void xd3_encode_reset (xd3_stream *stream) { int i; xd3_output *olist; stream->avail_in = 0; stream->small_reset = 1; stream->i_slots_used = 0; if (stream->src != NULL) { stream->src->srcbase = 0; stream->src->srclen = 0; stream->srcwin_decided = 0; stream->srcwin_decided_early = 0; stream->match_minaddr = 0; stream->match_maxaddr = 0; stream->taroff = 0; } /* Reset output chains. */ olist = stream->enc_heads[0]; for (i = 0; i < ENC_SECTS; i += 1) { XD3_ASSERT (olist != NULL); stream->enc_heads[i] = olist; stream->enc_tails[i] = olist; olist = olist->next_page; stream->enc_heads[i]->next = 0; stream->enc_heads[i]->next_page = NULL; stream->enc_tails[i]->next_page = NULL; stream->enc_tails[i] = stream->enc_heads[i]; } xd3_freelist_output (stream, olist); } /* The main encoding routine. */ int xd3_encode_input (xd3_stream *stream) { int ret, i; if (stream->dec_state != 0) { stream->msg = "encoder/decoder transition"; return XD3_INTERNAL; } switch (stream->enc_state) { case ENC_INIT: /* Only reached on first time through: memory setup. */ if ((ret = xd3_encode_init_full (stream))) { return ret; } stream->enc_state = ENC_INPUT; case ENC_INPUT: /* If there is no input yet, just return. This checks for * next_in == NULL, not avail_in == 0 since zero bytes is a * valid input. There is an assertion in xd3_avail_input() that * next_in != NULL for this reason. By returning right away we * avoid creating an input buffer before the caller has supplied * its first data. It is possible for xd3_avail_input to be * called both before and after the first call to * xd3_encode_input(). */ if (stream->next_in == NULL) { return XD3_INPUT; } enc_flush: /* See if we should buffer the input: either if there is already * a leftover buffer, or if the input is short of winsize * without flush. The label at this point is reached by a goto * below, when there is leftover input after postout. */ if ((stream->buf_leftover != NULL) || (stream->buf_avail != 0) || (stream->avail_in < stream->winsize && ! (stream->flags & XD3_FLUSH))) { if ((ret = xd3_encode_buffer_leftover (stream))) { return ret; } } /* Initalize the address cache before each window. */ xd3_init_cache (& stream->acache); stream->input_position = 0; stream->min_match = MIN_MATCH; stream->unencoded_offset = 0; stream->enc_state = ENC_SEARCH; IF_DEBUG2 (DP(RINT "[WINSTART:%"Q"u] input bytes %"W"u offset %"Q"u\n", stream->current_window, stream->avail_in, stream->total_in)); return XD3_WINSTART; case ENC_SEARCH: IF_DEBUG2 (DP(RINT "[SEARCH] match_state %d avail_in %"W"u %s\n", stream->match_state, stream->avail_in, stream->src ? "source" : "no source")); /* Reentrant matching. */ if (stream->src != NULL) { switch (stream->match_state) { case MATCH_TARGET: /* Try matching forward at the start of the target. * This is entered the first time through, to check for * a perfect match, and whenever there is a source match * that extends to the end of the previous window. The * match_srcpos field is initially zero and later set * during xd3_source_extend_match. */ if (stream->avail_in > 0) { /* This call can't fail because the source window is * unrestricted. */ ret = xd3_source_match_setup (stream, stream->match_srcpos); XD3_ASSERT (ret == 0); stream->match_state = MATCH_FORWARD; } else { stream->match_state = MATCH_SEARCHING; stream->match_fwd = 0; } XD3_ASSERT (stream->match_fwd == 0); case MATCH_FORWARD: case MATCH_BACKWARD: if (stream->avail_in != 0) { if ((ret = xd3_source_extend_match (stream)) != 0) { return ret; } /* The search has to make forward progress here * or else it can get stuck in a match-backward * (getsrcblk) then match-forward (getsrcblk), * find insufficient match length, then repeat * exactly the same search. */ stream->input_position += stream->match_fwd; } case MATCH_SEARCHING: /* Continue string matching. (It's possible that the * initial match continued through the entire input, in * which case we're still in MATCH_FORWARD and should * remain so for the next input window.) */ break; } } /* String matching... */ if (stream->avail_in != 0 && (ret = stream->smatcher.string_match (stream))) { return ret; } stream->enc_state = ENC_INSTR; case ENC_INSTR: /* Note: Jump here to encode VCDIFF deltas w/o using this * string-matching code. Merging code enters here. */ /* Flush the instrution buffer, then possibly add one more * instruction, then emit the header. */ if ((ret = xd3_iopt_flush_instructions (stream, 1)) || (ret = xd3_iopt_add_finalize (stream))) { return ret; } stream->enc_state = ENC_FLUSH; case ENC_FLUSH: /* Note: main_recode_func() bypasses string-matching by setting * ENC_FLUSH. */ if ((ret = xd3_emit_hdr (stream))) { return ret; } /* Begin output. */ stream->enc_current = HDR_HEAD (stream); /* Chain all the outputs together. After doing this, it looks * as if there is only one section. The other enc_heads are set * to NULL to avoid freeing them more than once. */ for (i = 1; i < ENC_SECTS; i += 1) { stream->enc_tails[i-1]->next_page = stream->enc_heads[i]; stream->enc_heads[i] = NULL; } enc_output: stream->enc_state = ENC_POSTOUT; stream->next_out = stream->enc_current->base; stream->avail_out = stream->enc_current->next; stream->total_out += stream->avail_out; /* If there is any output in this buffer, return it, otherwise * fall through to handle the next buffer or finish the window * after all buffers have been output. */ if (stream->avail_out > 0) { /* This is the only place xd3_encode returns XD3_OUTPUT */ return XD3_OUTPUT; } case ENC_POSTOUT: if (stream->avail_out != 0) { stream->msg = "missed call to consume output"; return XD3_INTERNAL; } /* Continue outputting one buffer at a time, until the next is NULL. */ if ((stream->enc_current = stream->enc_current->next_page) != NULL) { goto enc_output; } stream->total_in += stream->avail_in; stream->enc_state = ENC_POSTWIN; IF_DEBUG2 (DP(RINT "[WINFINISH:%"Q"u] in=%"Q"u\n", stream->current_window, stream->total_in)); return XD3_WINFINISH; case ENC_POSTWIN: xd3_encode_reset (stream); stream->current_window += 1; stream->enc_state = ENC_INPUT; /* If there is leftover input to flush, repeat. */ if (stream->buf_leftover != NULL) { goto enc_flush; } /* Ready for more input. */ return XD3_INPUT; default: stream->msg = "invalid state"; return XD3_INTERNAL; } } #endif /* XD3_ENCODER */ /***************************************************************** Client convenience functions ******************************************************************/ int xd3_process_stream (int is_encode, xd3_stream *stream, int (*func) (xd3_stream *), int close_stream, const uint8_t *input, usize_t input_size, uint8_t *output, usize_t *output_size, usize_t output_size_max) { usize_t ipos = 0; usize_t n = xd3_min (stream->winsize, input_size); (*output_size) = 0; stream->flags |= XD3_FLUSH; xd3_avail_input (stream, input + ipos, n); ipos += n; for (;;) { int ret; switch ((ret = func (stream))) { case XD3_OUTPUT: { /* memcpy below */ break; } case XD3_INPUT: { n = xd3_min(stream->winsize, input_size - ipos); if (n == 0) { goto done; } xd3_avail_input (stream, input + ipos, n); ipos += n; continue; } case XD3_GOTHEADER: { /* ignore */ continue; } case XD3_WINSTART: { /* ignore */ continue; } case XD3_WINFINISH: { /* ignore */ continue; } case XD3_GETSRCBLK: { /* When the getblk function is NULL, it is necessary to * provide the complete source as a single block using * xd3_set_source_and_size, otherwise this error. The * library should never ask for another source block. */ stream->msg = "library requested source block"; return XD3_INTERNAL; } case 0: { /* xd3_encode_input/xd3_decode_input never return 0 */ stream->msg = "invalid return: 0"; return XD3_INTERNAL; } default: return ret; } if (*output_size + stream->avail_out > output_size_max) { stream->msg = "insufficient output space"; return ENOSPC; } memcpy (output + *output_size, stream->next_out, stream->avail_out); *output_size += stream->avail_out; xd3_consume_output (stream); } done: return (close_stream == 0) ? 0 : xd3_close_stream (stream); } static int xd3_process_memory (int is_encode, int (*func) (xd3_stream *), const uint8_t *input, usize_t input_size, const uint8_t *source, usize_t source_size, uint8_t *output, usize_t *output_size, usize_t output_size_max, int flags) { xd3_stream stream; xd3_config config; xd3_source src; int ret; memset (& stream, 0, sizeof (stream)); memset (& config, 0, sizeof (config)); if (input == NULL || output == NULL) { stream.msg = "invalid input/output buffer"; ret = XD3_INTERNAL; goto exit; } config.flags = flags; if (is_encode) { config.winsize = xd3_min(input_size, (usize_t) XD3_DEFAULT_WINSIZE); config.sprevsz = xd3_pow2_roundup (config.winsize); } if ((ret = xd3_config_stream (&stream, &config)) != 0) { goto exit; } if (source != NULL) { memset (& src, 0, sizeof (src)); src.blksize = source_size; src.onblk = source_size; src.curblk = source; src.curblkno = 0; src.max_winsize = source_size; if ((ret = xd3_set_source_and_size (&stream, &src, source_size)) != 0) { goto exit; } } if ((ret = xd3_process_stream (is_encode, & stream, func, 1, input, input_size, output, output_size, output_size_max)) != 0) { goto exit; } exit: if (ret != 0) { IF_DEBUG2 (DP(RINT "process_memory: %d: %s\n", ret, stream.msg)); } xd3_free_stream(&stream); return ret; } int xd3_decode_stream (xd3_stream *stream, const uint8_t *input, usize_t input_size, uint8_t *output, usize_t *output_size, usize_t output_size_max) { return xd3_process_stream (0, stream, & xd3_decode_input, 1, input, input_size, output, output_size, output_size_max); } int xd3_decode_memory (const uint8_t *input, usize_t input_size, const uint8_t *source, usize_t source_size, uint8_t *output, usize_t *output_size, usize_t output_size_max, int flags) { return xd3_process_memory (0, & xd3_decode_input, input, input_size, source, source_size, output, output_size, output_size_max, flags); } #if XD3_ENCODER int xd3_encode_stream (xd3_stream *stream, const uint8_t *input, usize_t input_size, uint8_t *output, usize_t *output_size, usize_t output_size_max) { return xd3_process_stream (1, stream, & xd3_encode_input, 1, input, input_size, output, output_size, output_size_max); } int xd3_encode_memory (const uint8_t *input, usize_t input_size, const uint8_t *source, usize_t source_size, uint8_t *output, usize_t *output_size, usize_t output_size_max, int flags) { return xd3_process_memory (1, & xd3_encode_input, input, input_size, source, source_size, output, output_size, output_size_max, flags); } #endif /************************************************************* String matching helpers *************************************************************/ #if XD3_ENCODER /* Do the initial xd3_string_match() checksum table setup. * Allocations are delayed until first use to avoid allocation * sometimes (e.g., perfect matches, zero-length inputs). */ static int xd3_string_match_init (xd3_stream *stream) { const int DO_SMALL = ! (stream->flags & XD3_NOCOMPRESS); const int DO_LARGE = (stream->src != NULL); if (DO_LARGE && stream->large_table == NULL) { if ((stream->large_table = (usize_t*) xd3_alloc0 (stream, stream->large_hash.size, sizeof (usize_t))) == NULL) { return ENOMEM; } } if (DO_SMALL) { /* Subsequent calls can return immediately after checking reset. */ if (stream->small_table != NULL) { /* The target hash table is reinitialized once per window. */ /* TODO: This would not have to be reinitialized if absolute * offsets were being stored. */ if (stream->small_reset) { stream->small_reset = 0; memset (stream->small_table, 0, sizeof (usize_t) * stream->small_hash.size); } return 0; } if ((stream->small_table = (usize_t*) xd3_alloc0 (stream, stream->small_hash.size, sizeof (usize_t))) == NULL) { return ENOMEM; } /* If there is a previous table needed. */ if (stream->smatcher.small_lchain > 1 || stream->smatcher.small_chain > 1) { if ((stream->small_prev = (xd3_slist*) xd3_alloc (stream, stream->sprevsz, sizeof (xd3_slist))) == NULL) { return ENOMEM; } } } return 0; } #if XD3_USE_LARGEFILE64 && !XD3_USE_LARGESIZET /* This function handles the 32/64bit ambiguity -- file positions are 64bit * but the hash table for source-offsets is 32bit. */ static xoff_t xd3_source_cksum_offset(xd3_stream *stream, usize_t low) { xoff_t scp = stream->srcwin_cksum_pos; xoff_t s0 = scp >> 32; usize_t sr = (usize_t) scp; if (s0 == 0) { return low; } /* This should not be >= because srcwin_cksum_pos is the next * position to index. */ if (low > sr) { return (--s0 << 32) | low; } return (s0 << 32) | low; } #else static xoff_t xd3_source_cksum_offset(xd3_stream *stream, usize_t low) { return low; } #endif /* This function sets up the stream->src fields srcbase, srclen. The * call is delayed until these values are needed to encode a copy * address. At this point the decision has to be made. */ static int xd3_srcwin_setup (xd3_stream *stream) { xd3_source *src = stream->src; xoff_t length, x; /* Check the undecided state. */ XD3_ASSERT (src->srclen == 0 && src->srcbase == 0); /* Avoid repeating this call. */ stream->srcwin_decided = 1; /* If the stream is flushing, then the iopt buffer was able to * contain the complete encoding. If no copies were issued no * source window is actually needed. This prevents the VCDIFF * header from including source base/len. xd3_emit_hdr checks for * srclen == 0. */ if (stream->enc_state == ENC_INSTR && stream->match_maxaddr == 0) { goto done; } /* Check for overflow, srclen is usize_t - this can't happen unless * XD3_DEFAULT_SRCBACK and related parameters are extreme - should * use smaller windows. */ length = stream->match_maxaddr - stream->match_minaddr; x = USIZE_T_MAX; if (length > x) { stream->msg = "source window length overflow (not 64bit)"; return XD3_INTERNAL; } /* If ENC_INSTR, then we know the exact source window to use because * no more copies can be issued. */ if (stream->enc_state == ENC_INSTR) { src->srcbase = stream->match_minaddr; src->srclen = (usize_t) length; XD3_ASSERT (src->srclen); goto done; } /* Otherwise, we have to make a guess. More copies may still be * issued, but we have to decide the source window base and length * now. * TODO: This may not working well in practice, more testing needed. */ src->srcbase = stream->match_minaddr; src->srclen = xd3_max ((usize_t) length, stream->avail_in + (stream->avail_in >> 2)); if (src->eof_known) { /* Note: if the source size is known, we must reduce srclen or * code that expects to pass a single block w/ getblk == NULL * will not function, as the code will return GETSRCBLK asking * for the second block. */ src->srclen = xd3_min (src->srclen, xd3_source_eof(src) - src->srcbase); } IF_DEBUG1 (DP(RINT "[srcwin_setup_constrained] base %"Q"u len %"W"u\n", src->srcbase, src->srclen)); XD3_ASSERT (src->srclen); done: /* Set the taroff. This convenience variable is used even when stream->src == NULL. */ stream->taroff = src->srclen; return 0; } /* Sets the bounding region for a newly discovered source match, prior * to calling xd3_source_extend_match(). This sets the match_maxfwd, * match_maxback variables. Note: srcpos is an absolute position * (xoff_t) but the match_maxfwd, match_maxback variables are usize_t. * Returns 0 if the setup succeeds, or 1 if the source position lies * outside an already-decided srcbase/srclen window. */ static int xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) { xd3_source *const src = stream->src; usize_t greedy_or_not; stream->match_maxback = 0; stream->match_maxfwd = 0; stream->match_back = 0; stream->match_fwd = 0; /* This avoids a non-blocking endless loop caused by scanning * backwards across a block boundary, only to find not enough * matching bytes to beat the current min_match due to a better lazy * target match: the re-entry to xd3_string_match() repeats the same * long match because the input position hasn't changed. TODO: if * ever duplicates are added to the source hash table, this logic * won't suffice to avoid loops. See testing/regtest.cc's * TestNonBlockingProgress test! */ if (srcpos != 0 && srcpos == stream->match_last_srcpos) { IF_DEBUG2(DP(RINT "[match_setup] looping failure\n")); goto bad; } /* Implement src->max_winsize, which prevents the encoder from seeking * back further than the LRU cache maintaining FIFO discipline, (to * avoid seeking). */ if (srcpos < stream->srcwin_cksum_pos && stream->srcwin_cksum_pos - srcpos > src->max_winsize) { IF_DEBUG2(DP(RINT "[match_setup] rejected due to src->max_winsize " "distance eof=%"Q"u srcpos=%"Q"u max_winsz=%"Q"u\n", xd3_source_eof (src), srcpos, src->max_winsize)); goto bad; } /* There are cases where the above test does not reject a match that * will experience XD3_TOOFARBACK at the first xd3_getblk call * because the input may have advanced up to one block beyond the * actual EOF. */ IF_DEBUG2(DP(RINT "[match_setup] %"Q"u srcpos %"Q"u, " "src->max_winsize %"Q"u\n", stream->total_in + stream->input_position, srcpos, src->max_winsize)); /* Going backwards, the 1.5-pass algorithm allows some * already-matched input may be covered by a longer source match. * The greedy algorithm does not allow this. * TODO: Measure this. */ if (stream->flags & XD3_BEGREEDY) { /* The greedy algorithm allows backward matching to the last * matched position. */ greedy_or_not = xd3_iopt_last_matched (stream); } else { /* The 1.5-pass algorithm allows backward matching to go back as * far as the unencoded offset, which is updated as instructions * pass out of the iopt buffer. If this (default) is chosen, it * means xd3_iopt_erase may be called to eliminate instructions * when a covering source match is found. */ greedy_or_not = stream->unencoded_offset; } /* Backward target match limit. */ XD3_ASSERT (stream->input_position >= greedy_or_not); stream->match_maxback = stream->input_position - greedy_or_not; /* Forward target match limit. */ XD3_ASSERT (stream->avail_in > stream->input_position); stream->match_maxfwd = stream->avail_in - stream->input_position; /* Now we take the source position into account. It depends whether * the srclen/srcbase have been decided yet. */ if (stream->srcwin_decided == 0) { /* Unrestricted case: the match can cover the entire source, * 0--src->size. We compare the usize_t * match_maxfwd/match_maxback against the xoff_t * src->size/srcpos values and take the min. */ /* TODO #if XD3_USE_LARGESIZET ? */ if (srcpos < stream->match_maxback) { stream->match_maxback = (usize_t) srcpos; } if (src->eof_known) { xoff_t srcavail = xd3_source_eof (src) - srcpos; if (srcavail < stream->match_maxfwd) { stream->match_maxfwd = (usize_t) srcavail; } } IF_DEBUG2(DP(RINT "[match_setup] srcpos %"Q"u (tgtpos %"Q"u) " "unrestricted maxback %"W"u maxfwd %"W"u\n", srcpos, stream->total_in + stream->input_position, stream->match_maxback, stream->match_maxfwd)); goto good; } /* Decided some source window. */ XD3_ASSERT (src->srclen > 0); /* Restricted case: fail if the srcpos lies outside the source window */ if ((srcpos < src->srcbase) || (srcpos > (src->srcbase + src->srclen))) { IF_DEBUG1(DP(RINT "[match_setup] restricted source window failure\n")); goto bad; } else { usize_t srcavail; srcavail = (usize_t) (srcpos - src->srcbase); if (srcavail < stream->match_maxback) { stream->match_maxback = srcavail; } srcavail = src->srcbase + src->srclen - srcpos; if (srcavail < stream->match_maxfwd) { stream->match_maxfwd = srcavail; } IF_DEBUG2(DP(RINT "[match_setup] srcpos %"Q"u (tgtpos %"Q"u) " "restricted maxback %"W"u maxfwd %"W"u\n", srcpos, stream->total_in + stream->input_position, stream->match_maxback, stream->match_maxfwd)); goto good; } good: stream->match_state = MATCH_BACKWARD; stream->match_srcpos = srcpos; stream->match_last_srcpos = srcpos; return 0; bad: stream->match_state = MATCH_SEARCHING; stream->match_last_srcpos = srcpos; return 1; } static inline usize_t xd3_forward_match(const uint8_t *s1c, const uint8_t *s2c, usize_t n) { usize_t i = 0; #if UNALIGNED_OK usize_t nint = n / sizeof(int); if (nint >> 3) { usize_t j = 0; const int *s1 = (const int*)s1c; const int *s2 = (const int*)s2c; usize_t nint_8 = nint - 8; while (i <= nint_8 && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++] && s1[i++] == s2[j++]) { } i = (i - 1) * sizeof(int); } #endif while (i < n && s1c[i] == s2c[i]) { i++; } return i; } /* This function expands the source match backward and forward. It is * reentrant, since xd3_getblk may return XD3_GETSRCBLK, so most * variables are kept in xd3_stream. There are two callers of this * function, the string_matching routine when a checksum match is * discovered, and xd3_encode_input whenever a continuing (or initial) * match is suspected. The two callers do different things with the * input_position, thus this function leaves that variable untouched. * If a match is taken the resulting stream->match_fwd is left * non-zero. */ static int xd3_source_extend_match (xd3_stream *stream) { int ret; xd3_source *const src = stream->src; xoff_t matchoff; /* matchoff is the current right/left-boundary of the source match being tested. */ usize_t streamoff; /* streamoff is the current right/left-boundary of the input match being tested. */ xoff_t tryblk; /* tryblk, tryoff are the block, offset position of matchoff */ usize_t tryoff; usize_t tryrem; /* tryrem is the number of matchable bytes */ usize_t matched; IF_DEBUG2(DP(RINT "[extend match] srcpos %"Q"u\n", stream->match_srcpos)); XD3_ASSERT (src != NULL); /* Does it make sense to compute backward match AFTER forward match? */ if (stream->match_state == MATCH_BACKWARD) { /* Note: this code is practically duplicated below, substituting * match_fwd/match_back and direction. */ matchoff = stream->match_srcpos - stream->match_back; streamoff = stream->input_position - stream->match_back; xd3_blksize_div (matchoff, src, &tryblk, &tryoff); /* this loops backward over source blocks */ while (stream->match_back < stream->match_maxback) { /* see if we're backing across a source block boundary */ if (tryoff == 0) { tryoff = src->blksize; tryblk -= 1; } if ((ret = xd3_getblk (stream, tryblk))) { if (ret == XD3_TOOFARBACK) { IF_DEBUG2(DP(RINT "[maxback] %"Q"u TOOFARBACK: %"W"u INP %"Q"u CKSUM %"Q"u\n", tryblk, stream->match_back, stream->total_in + stream->input_position, stream->srcwin_cksum_pos)); /* the starting position is too far back. */ if (stream->match_back == 0) { XD3_ASSERT(stream->match_fwd == 0); goto donefwd; } /* search went too far back, continue forward. */ goto doneback; } /* could be a XD3_GETSRCBLK failure. */ return ret; } tryrem = xd3_min (tryoff, stream->match_maxback - stream->match_back); IF_DEBUG2(DP(RINT "[maxback] maxback %"W"u trysrc %"Q"u/%"W"u tgt %"W"u tryrem %"W"u\n", stream->match_maxback, tryblk, tryoff, streamoff, tryrem)); /* TODO: This code can be optimized similar to xd3_match_forward() */ for (; tryrem != 0; tryrem -= 1, stream->match_back += 1) { if (src->curblk[tryoff-1] != stream->next_in[streamoff-1]) { goto doneback; } tryoff -= 1; streamoff -= 1; } } doneback: stream->match_state = MATCH_FORWARD; } XD3_ASSERT (stream->match_state == MATCH_FORWARD); matchoff = stream->match_srcpos + stream->match_fwd; streamoff = stream->input_position + stream->match_fwd; xd3_blksize_div (matchoff, src, & tryblk, & tryoff); /* Note: practically the same code as backwards case above: same comments */ while (stream->match_fwd < stream->match_maxfwd) { if (tryoff == src->blksize) { tryoff = 0; tryblk += 1; } if ((ret = xd3_getblk (stream, tryblk))) { if (ret == XD3_TOOFARBACK) { IF_DEBUG2(DP(RINT "[maxfwd] %"Q"u TOOFARBACK: %"W"u INP %"Q"u CKSUM %"Q"u\n", tryblk, stream->match_fwd, stream->total_in + stream->input_position, stream->srcwin_cksum_pos)); goto donefwd; } /* could be a XD3_GETSRCBLK failure. */ return ret; } tryrem = xd3_min(stream->match_maxfwd - stream->match_fwd, src->onblk - tryoff); if (tryrem == 0) { /* Generally, this means we have a power-of-two size source * and we just found the end-of-file, in this case it's an * empty block. */ XD3_ASSERT (src->onblk < src->blksize); break; } matched = xd3_forward_match(src->curblk + tryoff, stream->next_in + streamoff, tryrem); tryoff += matched; streamoff += matched; stream->match_fwd += matched; if (tryrem != matched) { break; } } donefwd: stream->match_state = MATCH_SEARCHING; IF_DEBUG2(DP(RINT "[extend match] input %"Q"u srcpos %"Q"u len %"W"u\n", stream->input_position + stream->total_in, stream->match_srcpos, stream->match_fwd)); /* If the match ends short of the last instruction end, we probably * don't want it. There is the possibility that a copy ends short * of the last copy but also goes further back, in which case we * might want it. This code does not implement such: if so we would * need more complicated xd3_iopt_erase logic. */ if (stream->match_fwd < stream->min_match) { stream->match_fwd = 0; } else { usize_t total = stream->match_fwd + stream->match_back; /* Correct the variables to remove match_back from the equation. */ usize_t target_position = stream->input_position - stream->match_back; usize_t match_length = stream->match_back + stream->match_fwd; xoff_t match_position = stream->match_srcpos - stream->match_back; xoff_t match_end = stream->match_srcpos + stream->match_fwd; /* At this point we may have to erase any iopt-buffer * instructions that are fully covered by a backward-extending * copy. */ if (stream->match_back > 0) { xd3_iopt_erase (stream, target_position, total); } stream->match_back = 0; /* Update ranges. The first source match occurs with both values set to 0. */ if (stream->match_maxaddr == 0 || match_position < stream->match_minaddr) { stream->match_minaddr = match_position; } if (match_end > stream->match_maxaddr) { /* Note: per-window */ stream->match_maxaddr = match_end; } if (match_end > stream->maxsrcaddr) { /* Note: across windows */ stream->maxsrcaddr = match_end; } IF_DEBUG2 ({ static int x = 0; DP(RINT "[source match:%d] length %"W"u (%s)\n", x++, match_length, stream->total_in + target_position, stream->total_in + target_position + match_length, match_position, match_position + match_length, (stream->total_in + target_position == match_position) ? "same" : "diff"); }); if ((ret = xd3_found_match (stream, /* decoder position */ target_position, /* length */ match_length, /* address */ match_position, /* is_source */ 1))) { return ret; } /* If the match ends with the available input: */ if (target_position + match_length == stream->avail_in) { /* Setup continuing match for the next window. */ stream->match_state = MATCH_TARGET; stream->match_srcpos = match_end; } } return 0; } /* Update the small hash. Values in the small_table are offset by * HASH_CKOFFSET (1) to distinguish empty buckets from real offsets. */ static void xd3_scksum_insert (xd3_stream *stream, usize_t inx, usize_t scksum, usize_t pos) { /* If we are maintaining previous duplicates. */ if (stream->small_prev) { usize_t last_pos = stream->small_table[inx]; xd3_slist *pos_list = & stream->small_prev[pos & stream->sprevmask]; /* Note last_pos is offset by HASH_CKOFFSET. */ pos_list->last_pos = last_pos; } /* Enter the new position into the hash bucket. */ stream->small_table[inx] = pos + HASH_CKOFFSET; } #if XD3_DEBUG static int xd3_check_smatch (const uint8_t *ref0, const uint8_t *inp0, const uint8_t *inp_max, usize_t cmp_len) { usize_t i; for (i = 0; i < cmp_len; i += 1) { XD3_ASSERT (ref0[i] == inp0[i]); } if (inp0 + cmp_len < inp_max) { XD3_ASSERT (inp0[i] != ref0[i]); } return 1; } #endif /* XD3_DEBUG */ /* When the hash table indicates a possible small string match, it * calls this routine to find the best match. The first matching * position is taken from the small_table, HASH_CKOFFSET is subtracted * to get the actual position. After checking that match, if previous * linked lists are in use (because stream->smatcher.small_chain > 1), * previous matches are tested searching for the longest match. If * (stream->min_match > MIN_MATCH) then a lazy match is in effect. */ static usize_t xd3_smatch (xd3_stream *stream, usize_t base, usize_t scksum, usize_t *match_offset) { usize_t cmp_len; usize_t match_length = 0; usize_t chain = (stream->min_match == MIN_MATCH ? stream->smatcher.small_chain : stream->smatcher.small_lchain); const uint8_t *inp_max = stream->next_in + stream->avail_in; const uint8_t *inp; const uint8_t *ref; SMALL_HASH_DEBUG1 (stream, stream->next_in + stream->input_position); XD3_ASSERT (stream->min_match + stream->input_position <= stream->avail_in); base -= HASH_CKOFFSET; again: IF_DEBUG2 (DP(RINT "smatch at base=%"W"u inp=%"W"u cksum=%"W"u\n", base, stream->input_position, scksum)); /* For small matches, we can always go to the end-of-input because * the matching position must be less than the input position. */ XD3_ASSERT (base < stream->input_position); ref = stream->next_in + base; inp = stream->next_in + stream->input_position; SMALL_HASH_DEBUG2 (stream, ref); /* Expand potential match forward. */ while (inp < inp_max && *inp == *ref) { ++inp; ++ref; } cmp_len = (usize_t)(inp - (stream->next_in + stream->input_position)); /* Verify correctness */ XD3_ASSERT (xd3_check_smatch (stream->next_in + base, stream->next_in + stream->input_position, inp_max, cmp_len)); /* Update longest match */ if (cmp_len > match_length) { ( match_length) = cmp_len; (*match_offset) = base; /* Stop if we match the entire input or have a long_enough match. */ if (inp == inp_max || cmp_len >= stream->smatcher.long_enough) { goto done; } } /* If we have not reached the chain limit, see if there is another previous position. */ while (--chain != 0) { /* Calculate the previous offset. */ usize_t prev_pos = stream->small_prev[base & stream->sprevmask].last_pos; usize_t diff_pos; if (prev_pos == 0) { break; } prev_pos -= HASH_CKOFFSET; if (prev_pos > base) { break; } base = prev_pos; XD3_ASSERT (stream->input_position > base); diff_pos = stream->input_position - base; /* Stop searching if we go beyond sprevsz, since those entries * are for unrelated checksum entries. */ if (diff_pos & ~stream->sprevmask) { break; } goto again; } done: /* Crude efficiency test: if the match is very short and very far back, it's * unlikely to help, but the exact calculation requires knowing the state of * the address cache and adjacent instructions, which we can't do here. * Rather than encode a probably inefficient copy here and check it later * (which complicates the code a lot), do this: */ if (match_length == 4 && stream->input_position - (*match_offset) >= 1<<14) { /* It probably takes >2 bytes to encode an address >= 2^14 from here */ return 0; } if (match_length == 5 && stream->input_position - (*match_offset) >= 1<<21) { /* It probably takes >3 bytes to encode an address >= 2^21 from here */ return 0; } /* It's unlikely that a window is large enough for the (match_length == 6 && * address >= 2^28) check */ return match_length; } #if XD3_DEBUG static void xd3_verify_small_state (xd3_stream *stream, const uint8_t *inp, uint32_t x_cksum) { uint32_t state; uint32_t cksum = xd3_scksum (&state, inp, stream->smatcher.small_look); XD3_ASSERT (cksum == x_cksum); } static void xd3_verify_large_state (xd3_stream *stream, const uint8_t *inp, usize_t x_cksum) { usize_t cksum = xd3_large_cksum (&stream->large_hash, inp, stream->smatcher.large_look); XD3_ASSERT (cksum == x_cksum); } static void xd3_verify_run_state (xd3_stream *stream, const uint8_t *inp, usize_t x_run_l, uint8_t *x_run_c) { usize_t slook = stream->smatcher.small_look; uint8_t run_c; usize_t run_l = xd3_comprun (inp, slook, &run_c); XD3_ASSERT (run_l == 0 || run_c == *x_run_c); XD3_ASSERT (x_run_l > slook || run_l == x_run_l); } #endif /* XD3_DEBUG */ /* This function computes more source checksums to advance the window. * Called at every entrance to the string-match loop and each time * stream->input_position reaches the value returned as * *next_move_point. NB: this is one of the most expensive functions * in this code and also the most critical for good compression. */ static int xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) { /* the source file is indexed until this point */ xoff_t target_cksum_pos; /* the absolute target file input position */ xoff_t absolute_input_pos; if (stream->src->eof_known) { xoff_t source_size = xd3_source_eof (stream->src); XD3_ASSERT(stream->srcwin_cksum_pos <= source_size); if (stream->srcwin_cksum_pos == source_size) { *next_move_point = USIZE_T_MAX; return 0; } } absolute_input_pos = stream->total_in + stream->input_position; /* Immediately read the entire window. * * Note: this reverses a long held policy, at this point in the * code, of advancing relatively slowly as the input is read, which * results in better compression for very-similar inputs, but worse * compression where data is deleted near the beginning of the file. * * The new policy is simpler, somewhat slower and can benefit, or * slightly worsen, compression performance. */ if (absolute_input_pos < stream->src->max_winsize / 2) { target_cksum_pos = stream->src->max_winsize; } else { /* TODO: The addition of 2 blocks here is arbitrary. Do a * better job of stream alignment based on observed source copy * addresses, and when both input sizes are known, the * difference in size. */ target_cksum_pos = absolute_input_pos + stream->src->max_winsize / 2 + stream->src->blksize * 2; target_cksum_pos &= ~stream->src->maskby; } /* A long match may have extended past srcwin_cksum_pos. Don't * start checksumming already-matched source data. */ if (stream->maxsrcaddr > stream->srcwin_cksum_pos) { stream->srcwin_cksum_pos = stream->maxsrcaddr; } if (target_cksum_pos < stream->srcwin_cksum_pos) { target_cksum_pos = stream->srcwin_cksum_pos; } while (stream->srcwin_cksum_pos < target_cksum_pos && (!stream->src->eof_known || stream->srcwin_cksum_pos < xd3_source_eof (stream->src))) { xoff_t blkno; xoff_t blkbaseoffset; usize_t blkrem; ssize_t oldpos; /* Using ssize_t because of a */ ssize_t blkpos; /* do { blkpos-- } while (blkpos >= oldpos); */ int ret; xd3_blksize_div (stream->srcwin_cksum_pos, stream->src, &blkno, &blkrem); oldpos = blkrem; if ((ret = xd3_getblk (stream, blkno))) { /* TOOFARBACK should never occur here, since we read forward. */ if (ret == XD3_TOOFARBACK) { ret = XD3_INTERNAL; } IF_DEBUG1 (DP(RINT "[srcwin_move_point] async getblk return for %"Q"u: %s\n", blkno, xd3_strerror (ret))); return ret; } IF_DEBUG1 (DP(RINT "[srcwin_move_point] block %"Q"u T=%"Q"u S=%"Q"u L=%"Q"u EOF=%"Q"u %s\n", blkno, stream->total_in + stream->input_position, stream->srcwin_cksum_pos, target_cksum_pos, xd3_source_eof (stream->src), stream->src->eof_known ? "known" : "unknown")); blkpos = xd3_bytes_on_srcblk (stream->src, blkno); if (blkpos < (ssize_t) stream->smatcher.large_look) { stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize; IF_DEBUG2 (DP(RINT "[srcwin_move_point] continue (end-of-block): %"Z"d\n", blkpos)); continue; } /* This inserts checksums for the entire block, in reverse, * starting from the end of the block. This logic does not test * stream->srcwin_cksum_pos because it always advances it to the * start of the next block. * * oldpos is the srcwin_cksum_pos within this block. blkpos is * the number of bytes available. Each iteration inspects * large_look bytes then steps back large_step bytes. The * if-stmt above ensures at least one large_look of data. */ blkpos -= stream->smatcher.large_look; blkbaseoffset = stream->src->blksize * blkno; do { /* TODO: This would be significantly faster if the compiler * knew stream->smatcher.large_look (which the template for * xd3_string_match_* allows). */ usize_t cksum = xd3_large_cksum (&stream->large_hash, stream->src->curblk + blkpos, stream->smatcher.large_look); usize_t hval = xd3_checksum_hash (& stream->large_hash, cksum); stream->large_table[hval] = (usize_t) (blkbaseoffset + (xoff_t)(blkpos + HASH_CKOFFSET)); IF_DEBUG (stream->large_ckcnt += 1); blkpos -= stream->smatcher.large_step; } while (blkpos >= oldpos); stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize; } IF_DEBUG1 (DP(RINT "[srcwin_move_point] exited loop T=%"Q"u " "S=%"Q"u EOF=%"Q"u %s\n", stream->total_in + stream->input_position, stream->srcwin_cksum_pos, xd3_source_eof (stream->src), stream->src->eof_known ? "known" : "unknown")); if (stream->src->eof_known) { xoff_t source_size = xd3_source_eof (stream->src); if (stream->srcwin_cksum_pos >= source_size) { /* This invariant is needed for xd3_source_cksum_offset() */ stream->srcwin_cksum_pos = source_size; *next_move_point = USIZE_T_MAX; IF_DEBUG1 (DP(RINT "[srcwin_move_point] finished with source input\n")); return 0; } } /* How long until this function should be called again. */ XD3_ASSERT(stream->srcwin_cksum_pos >= target_cksum_pos); *next_move_point = stream->input_position + stream->src->blksize - ((stream->srcwin_cksum_pos - target_cksum_pos) & stream->src->maskby); IF_DEBUG2 (DP(RINT "[srcwin_move_point] finished T=%"Q"u " "S=%"Q"u L=%"Q"u EOF=%"Q"u %s again in %"W"u\n", stream->total_in + stream->input_position, stream->srcwin_cksum_pos, target_cksum_pos, xd3_source_eof (stream->src), stream->src->eof_known ? "known" : "unknown", *next_move_point - stream->input_position)); return 0; } #endif /* XD3_ENCODER */ /******************************************************************** TEMPLATE pass *********************************************************************/ #endif /* __XDELTA3_C_INLINE_PASS__ */ #ifdef __XDELTA3_C_TEMPLATE_PASS__ #if XD3_ENCODER /******************************************************************** Templates *******************************************************************/ /* Template macros */ #define XD3_TEMPLATE(x) XD3_TEMPLATE2(x,TEMPLATE) #define XD3_TEMPLATE2(x,n) XD3_TEMPLATE3(x,n) #define XD3_TEMPLATE3(x,n) x ## n #define XD3_STRINGIFY(x) XD3_STRINGIFY2(x) #define XD3_STRINGIFY2(x) #x static int XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream); static const xd3_smatcher XD3_TEMPLATE(__smatcher_) = { XD3_STRINGIFY(TEMPLATE), XD3_TEMPLATE(xd3_string_match_), #if SOFTCFG == 1 0, 0, 0, 0, 0, 0, 0 #else LLOOK, LSTEP, SLOOK, SCHAIN, SLCHAIN, MAXLAZY, LONGENOUGH #endif }; static int XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream) { const int DO_SMALL = ! (stream->flags & XD3_NOCOMPRESS); const int DO_LARGE = (stream->src != NULL); const int DO_RUN = (1); const uint8_t *inp; uint32_t scksum = 0; uint32_t scksum_state = 0; usize_t lcksum = 0; usize_t sinx; usize_t linx; uint8_t run_c; usize_t run_l; int ret; usize_t match_length; usize_t match_offset = 0; usize_t next_move_point = 0; IF_DEBUG2(DP(RINT "[string_match] initial entry %"W"u\n", stream->input_position)); /* If there will be no compression due to settings or short input, * skip it entirely. */ if (! (DO_SMALL || DO_LARGE || DO_RUN) || stream->input_position + SLOOK > stream->avail_in) { goto loopnomore; } if ((ret = xd3_string_match_init (stream))) { return ret; } /* The restartloop label is reached when the incremental loop state * needs to be reset. */ restartloop: IF_DEBUG2(DP(RINT "[string_match] restartloop %"W"u\n", stream->input_position)); /* If there is not enough input remaining for any kind of match, skip it. */ if (stream->input_position + SLOOK > stream->avail_in) { goto loopnomore; } /* Now reset the incremental loop state: */ /* The min_match variable is updated to avoid matching the same lazy * match over and over again. For example, if you find a (small) * match of length 9 at one position, you will likely find a match * of length 8 at the next position. */ if (xd3_iopt_last_matched (stream) > stream->input_position) { stream->min_match = xd3_max (MIN_MATCH, 1 + xd3_iopt_last_matched(stream) - stream->input_position); } else { stream->min_match = MIN_MATCH; } /* The current input byte. */ inp = stream->next_in + stream->input_position; /* Small match state. */ if (DO_SMALL) { scksum = xd3_scksum (&scksum_state, inp, SLOOK); } /* Run state. */ if (DO_RUN) { run_l = xd3_comprun (inp, SLOOK, & run_c); } /* Large match state. We continue the loop even after not enough * bytes for LLOOK remain, so always check stream->input_position in * DO_LARGE code. */ if (DO_LARGE && (stream->input_position + LLOOK <= stream->avail_in)) { /* Source window: next_move_point is the point that * stream->input_position must reach before computing more * source checksum. Note: this is called unconditionally * the first time after reentry, subsequent calls will be * avoided if next_move_point is > input_position */ if ((ret = xd3_srcwin_move_point (stream, & next_move_point))) { return ret; } lcksum = xd3_large_cksum (&stream->large_hash, inp, LLOOK); } /* TRYLAZYLEN: True if a certain length match should be followed by * lazy search. This checks that LEN is shorter than MAXLAZY and * that there is enough leftover data to consider lazy matching. * "Enough" is set to 2 since the next match will start at the next * offset, it must match two extra characters. */ #define TRYLAZYLEN(LEN,POS,MAX) ((MAXLAZY) > 0 && (LEN) < (MAXLAZY) \ && (POS) + (LEN) <= (MAX) - 2) /* HANDLELAZY: This statement is called each time an instruciton is * emitted (three cases). If the instruction is large enough, the * loop is restarted, otherwise lazy matching may ensue. */ #define HANDLELAZY(mlen) \ if (TRYLAZYLEN ((mlen), (stream->input_position), (stream->avail_in))) \ { stream->min_match = (mlen) + LEAST_MATCH_INCR; goto updateone; } \ else \ { stream->input_position += (mlen); goto restartloop; } /* Now loop over one input byte at a time until a match is found... */ for (;; inp += 1, stream->input_position += 1) { /* Now we try three kinds of string match in order of expense: * run, large match, small match. */ /* Expand the start of a RUN. The test for (run_l == SLOOK) * avoids repeating this check when we pass through a run area * performing lazy matching. The run is only expanded once when * the min_match is first reached. If lazy matching is * performed, the run_l variable will remain inconsistent until * the first non-running input character is reached, at which * time the run_l may then again grow to SLOOK. */ if (DO_RUN && run_l == SLOOK) { usize_t max_len = stream->avail_in - stream->input_position; IF_DEBUG (xd3_verify_run_state (stream, inp, run_l, &run_c)); while (run_l < max_len && inp[run_l] == run_c) { run_l += 1; } /* Output a RUN instruction. */ if (run_l >= stream->min_match && run_l >= MIN_RUN) { if ((ret = xd3_emit_run (stream, stream->input_position, run_l, &run_c))) { return ret; } HANDLELAZY (run_l); } } /* If there is enough input remaining. */ if (DO_LARGE && (stream->input_position + LLOOK <= stream->avail_in)) { if ((stream->input_position >= next_move_point) && (ret = xd3_srcwin_move_point (stream, & next_move_point))) { return ret; } linx = xd3_checksum_hash (& stream->large_hash, lcksum); IF_DEBUG (xd3_verify_large_state (stream, inp, lcksum)); if (stream->large_table[linx] != 0) { /* the match_setup will fail if the source window has * been decided and the match lies outside it. * OPT: Consider forcing a window at this point to * permit a new source window. */ xoff_t adj_offset = xd3_source_cksum_offset(stream, stream->large_table[linx] - HASH_CKOFFSET); if (xd3_source_match_setup (stream, adj_offset) == 0) { if ((ret = xd3_source_extend_match (stream))) { return ret; } /* Update stream position. match_fwd is zero if no * match. */ if (stream->match_fwd > 0) { HANDLELAZY (stream->match_fwd); } } } } /* Small matches. */ if (DO_SMALL) { sinx = xd3_checksum_hash (& stream->small_hash, scksum); /* Verify incremental state in debugging mode. */ IF_DEBUG (xd3_verify_small_state (stream, inp, scksum)); /* Search for the longest match */ if (stream->small_table[sinx] != 0) { match_length = xd3_smatch (stream, stream->small_table[sinx], scksum, & match_offset); } else { match_length = 0; } /* Insert a hash for this string. */ xd3_scksum_insert (stream, sinx, scksum, stream->input_position); /* Maybe output a COPY instruction */ if (match_length >= stream->min_match) { IF_DEBUG2 ({ static int x = 0; DP(RINT "[target match:%d] " "(-%"W"d) [ %"W"u bytes ]\n", x++, stream->input_position, stream->input_position + match_length, match_offset, match_offset + match_length, stream->input_position - match_offset, match_length); }); if ((ret = xd3_found_match (stream, /* decoder position */ stream->input_position, /* length */ match_length, /* address */ (xoff_t) match_offset, /* is_source */ 0))) { return ret; } /* Copy instruction. */ HANDLELAZY (match_length); } } /* The logic above prevents excess work during lazy matching by * increasing min_match to avoid smaller matches. Each time we * advance stream->input_position by one, the minimum match * shortens as well. */ if (stream->min_match > MIN_MATCH) { stream->min_match -= 1; } updateone: /* See if there are no more incremental cksums to compute. */ if (stream->input_position + SLOOK == stream->avail_in) { goto loopnomore; } /* Compute next RUN, CKSUM */ if (DO_RUN) { NEXTRUN (inp[SLOOK]); } if (DO_SMALL) { scksum = xd3_small_cksum_update (&scksum_state, inp, SLOOK); } if (DO_LARGE && (stream->input_position + LLOOK < stream->avail_in)) { lcksum = xd3_large_cksum_update (&stream->large_hash, lcksum, inp, LLOOK); } } loopnomore: return 0; } #endif /* XD3_ENCODER */ #endif /* __XDELTA3_C_TEMPLATE_PASS__ */ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3.h ================================================ /* xdelta3 - delta compression tools and library Copyright 2016 Joshua MacDonald Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* To learn more about Xdelta, start by reading xdelta3.c. If you are * ready to use the API, continue reading here. There are two * interfaces -- xd3_encode_input and xd3_decode_input -- plus a dozen * or so related calls. This interface is styled after Zlib. */ #ifndef _XDELTA3_H_ #define _XDELTA3_H_ #define _POSIX_SOURCE 200112L #define _ISOC99_SOURCE #define _C99_SOURCE #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include /****************************************************************/ /* Default configured value of stream->winsize. If the program * supplies xd3_encode_input() with data smaller than winsize the * stream will automatically buffer the input, otherwise the input * buffer is used directly. */ #ifndef XD3_DEFAULT_WINSIZE #define XD3_DEFAULT_WINSIZE (1U << 23) #endif /* Default total size of the source window used in xdelta3-main.h */ #ifndef XD3_DEFAULT_SRCWINSZ #define XD3_DEFAULT_SRCWINSZ (1U << 26) #endif /* When Xdelta requests a memory allocation for certain buffers, it * rounds up to units of at least this size. The code assumes (and * asserts) that this is a power-of-two. */ #ifndef XD3_ALLOCSIZE #define XD3_ALLOCSIZE (1U<<14) #endif /* The XD3_HARDMAXWINSIZE parameter is a safety mechanism to protect * decoders against malicious files. The decoder will never decode a * window larger than this. If the file specifies VCD_TARGET the * decoder may require two buffers of this size. * * 8-16MB is reasonable, probably don't need to go larger. */ #ifndef XD3_HARDMAXWINSIZE #define XD3_HARDMAXWINSIZE (1U<<26) #endif /* The IOPT_SIZE value sets the size of a buffer used to batch * overlapping copy instructions before they are optimized by picking * the best non-overlapping ranges. The larger this buffer, the * longer a forced xd3_srcwin_setup() decision is held off. Setting * this value to 0 causes an unlimited buffer to be used. */ #ifndef XD3_DEFAULT_IOPT_SIZE #define XD3_DEFAULT_IOPT_SIZE (1U<<15) #endif /* The maximum distance backward to search for small matches */ #ifndef XD3_DEFAULT_SPREVSZ #define XD3_DEFAULT_SPREVSZ (1U<<18) #endif /* The default compression level */ #ifndef XD3_DEFAULT_LEVEL #define XD3_DEFAULT_LEVEL 3 #endif #ifndef XD3_DEFAULT_SECONDARY_LEVEL #define XD3_DEFAULT_SECONDARY_LEVEL 6 #endif #ifndef XD3_USE_LARGEFILE64 #define XD3_USE_LARGEFILE64 1 #endif /* The source window size is limited to 2GB unless * XD3_USE_LARGESIZET is defined to 1. */ #ifndef XD3_USE_LARGESIZET #define XD3_USE_LARGESIZET 1 #endif /* Sizes and addresses within VCDIFF windows are represented as usize_t * * For source-file offsets and total file sizes, total input and * output counts, the xoff_t type is used. The decoder and encoder * generally check for overflow of the xoff_t size (this is tested at * the 32bit boundary [xdelta3-test.h]). */ #ifndef _WIN32 #define __STDC_FORMAT_MACROS #include #include #else /* WIN32 case */ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifndef WINVER #if XD3_USE_LARGEFILE64 /* 64 bit file offsets: uses GetFileSizeEx and SetFilePointerEx. */ #define WINVER 0x0500 #define _WIN32_WINNT 0x0500 #else /* xoff_t is 32bit */ /* 32 bit file offsets: uses GetFileSize and SetFilePointer. */ #define WINVER 0x0400 #define _WIN32_WINNT 0x0400 #endif /* if XD3_USE_LARGEFILE64 */ #endif /* ifndef WINVER */ #include /* _MSV_VER is defined by Microsoft tools, not by Mingw32 */ #ifdef _MSC_VER typedef signed int ssize_t; typedef int pid_t; #if _MSC_VER < 1600 typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; typedef ULONGLONG uint64_t; #else /* _MSC_VER >= 1600 */ /* For MSVC10 and above */ #include #define inline __inline #endif /* _MSC_VER < 1600 */ #else /* _MSC_VER not defined */ /* Mingw32 */ #include #endif /* _MSC_VER defined */ #endif /* _WIN32 defined */ /* Settings based on the size of xoff_t (32 vs 64 file offsets) */ #if XD3_USE_LARGEFILE64 /* xoff_t is a 64-bit type */ #define __USE_FILE_OFFSET64 1 /* GLIBC: for 64bit fileops. */ #ifndef _LARGEFILE_SOURCE #define _LARGEFILE_SOURCE #endif #ifndef _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 #endif static_assert(SIZEOF_SIZE_T == sizeof(size_t), "SIZEOF_SIZE_T not correctly set"); static_assert(SIZEOF_UNSIGNED_LONG_LONG == sizeof(unsigned long long), "SIZEOF_UNSIGNED_LONG_LONG not correctly set"); /* Set a xoff_t typedef and the "Q" printf insert. */ #if defined(_WIN32) typedef uint64_t xoff_t; #define Q "I64" #elif SIZEOF_UNSIGNED_LONG == 8 typedef unsigned long xoff_t; #define Q "l" #elif SIZEOF_SIZE_T == 8 typedef size_t xoff_t; #define Q "z" #elif SIZEOF_UNSIGNED_LONG_LONG == 8 typedef unsigned long long xoff_t; #define Q "ll" #endif /* typedef and #define Q */ #define SIZEOF_XOFF_T 8 #else /* XD3_USE_LARGEFILE64 == 0 */ #if SIZEOF_UNSIGNED_INT == 4 typedef unsigned int xoff_t; #elif SIZEOF_UNSIGNED_LONG == 4 typedef unsigned long xoff_t; #else typedef uint32_t xoff_t; #endif /* xoff_t is 32 bits */ #define SIZEOF_XOFF_T 4 #define Q #endif /* 64 vs 32 bit xoff_t */ /* Settings based on the size of usize_t (32 and 64 bit window size) */ #if XD3_USE_LARGESIZET /* Set a usize_ttypedef and the "W" printf insert. */ #if defined(_WIN32) typedef uint64_t usize_t; #define W "I64" #elif SIZEOF_UNSIGNED_LONG == 8 typedef unsigned long usize_t; #define W "l" #elif SIZEOF_SIZE_T == 8 typedef size_t usize_t; #define W "z" #elif SIZEOF_UNSIGNED_LONG_LONG == 8 typedef unsigned long long usize_t; #define W "ll" #endif /* typedef and #define W */ #define SIZEOF_USIZE_T 8 #else /* XD3_USE_LARGESIZET == 0 */ #if SIZEOF_UNSIGNED_INT == 4 typedef unsigned int usize_t; #elif SIZEOF_UNSIGNED_LONG == 4 typedef unsigned long usize_t; #else typedef uint32_t usize_t; #endif /* usize_t is 32 bits */ #define SIZEOF_USIZE_T 4 #define W #endif /* 64 vs 32 bit usize_t */ /* Settings based on the size of size_t (the system-provided, * usually-but-maybe-not an unsigned type) */ #if SIZEOF_SIZE_T == 4 #define Z "z" #elif SIZEOF_SIZE_T == 8 #ifdef _WIN32 #define Z "I64" #else /* !_WIN32 */ #define Z "z" #endif /* Windows or not */ #else #error Bad configure script #endif /* size_t printf flags */ #define USE_UINT32 (SIZEOF_USIZE_T == 4 || \ SIZEOF_XOFF_T == 4 || REGRESSION_TEST) #define USE_UINT64 (SIZEOF_USIZE_T == 8 || \ SIZEOF_XOFF_T == 8 || REGRESSION_TEST) #ifndef UNALIGNED_OK #ifdef HAVE_ALIGNED_ACCESS_REQUIRED #define UNALIGNED_OK 0 #else /* This generally includes all Windows builds. */ #define UNALIGNED_OK 1 #endif #endif /**********************************************************************/ /* Whether to build the encoder, otherwise only build the decoder. */ #ifndef XD3_ENCODER #define XD3_ENCODER 1 #endif /* The code returned when main() fails, also defined in system includes. */ #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif /* REGRESSION TEST enables the "xdelta3 test" command, which runs a series of self-tests. */ #ifndef REGRESSION_TEST #define REGRESSION_TEST 0 #endif /* XD3_DEBUG=1 enables assertions and various statistics. Levels > 1 * enable some additional output only useful during development and * debugging. */ #ifndef XD3_DEBUG #define XD3_DEBUG 0 #endif #ifndef PYTHON_MODULE #define PYTHON_MODULE 0 #endif #ifndef SWIG_MODULE #define SWIG_MODULE 0 #endif #ifndef NOT_MAIN #define NOT_MAIN 0 #endif /* There are three string matching functions supplied: one fast, one * slow (default), and one soft-configurable. To disable any of * these, use the following definitions. */ #ifndef XD3_BUILD_SLOW #define XD3_BUILD_SLOW 1 #endif #ifndef XD3_BUILD_FAST #define XD3_BUILD_FAST 1 #endif #ifndef XD3_BUILD_FASTER #define XD3_BUILD_FASTER 1 #endif #ifndef XD3_BUILD_FASTEST #define XD3_BUILD_FASTEST 1 #endif #ifndef XD3_BUILD_SOFT #define XD3_BUILD_SOFT 1 #endif #ifndef XD3_BUILD_DEFAULT #define XD3_BUILD_DEFAULT 1 #endif #if XD3_DEBUG #include #endif typedef struct _xd3_stream xd3_stream; typedef struct _xd3_source xd3_source; typedef struct _xd3_hash_cfg xd3_hash_cfg; typedef struct _xd3_smatcher xd3_smatcher; typedef struct _xd3_rinst xd3_rinst; typedef struct _xd3_dinst xd3_dinst; typedef struct _xd3_hinst xd3_hinst; typedef struct _xd3_winst xd3_winst; typedef struct _xd3_rpage xd3_rpage; typedef struct _xd3_addr_cache xd3_addr_cache; typedef struct _xd3_output xd3_output; typedef struct _xd3_desect xd3_desect; typedef struct _xd3_iopt_buflist xd3_iopt_buflist; typedef struct _xd3_rlist xd3_rlist; typedef struct _xd3_sec_type xd3_sec_type; typedef struct _xd3_sec_cfg xd3_sec_cfg; typedef struct _xd3_sec_stream xd3_sec_stream; typedef struct _xd3_config xd3_config; typedef struct _xd3_code_table_desc xd3_code_table_desc; typedef struct _xd3_code_table_sizes xd3_code_table_sizes; typedef struct _xd3_slist xd3_slist; typedef struct _xd3_whole_state xd3_whole_state; typedef struct _xd3_wininfo xd3_wininfo; /* The stream configuration has three callbacks functions, all of * which may be supplied with NULL values. If config->getblk is * provided as NULL, the stream returns XD3_GETSRCBLK. */ typedef void* (xd3_alloc_func) (void *opaque, size_t items, usize_t size); typedef void (xd3_free_func) (void *opaque, void *address); typedef int (xd3_getblk_func) (xd3_stream *stream, xd3_source *source, xoff_t blkno); typedef const xd3_dinst* (xd3_code_table_func) (void); #ifdef _WIN32 #define vsnprintf_func _vsnprintf #define snprintf_func _snprintf #else #define vsnprintf_func vsnprintf #define snprintf_func snprintf #endif #define short_sprintf(sb,fmt,...) \ snprintf_func((sb).buf,sizeof((sb).buf),fmt,__VA_ARGS__) /* Type used for short snprintf calls. */ typedef struct { char buf[48]; } shortbuf; #ifndef PRINTF_ATTRIBUTE #ifdef __GNUC__ #define PRINTF_ATTRIBUTE(x,y) __attribute__ ((__format__ (__printf__, x, y))) #else #define PRINTF_ATTRIBUTE(x,y) #endif #endif /* Underlying xprintf() */ int xsnprintf_func (char *str, size_t n, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); /* XPR(NT "", ...) (used by main) prefixes an "xdelta3: " to the output. */ void xprintf(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); #define XPR xprintf #define NT "xdelta3: " #define NTR "" /* DP(RINT ...) */ #define DP xprintf #define RINT "" #if XD3_DEBUG #define XD3_ASSERT(x) \ do { \ if (! (x)) { \ DP(RINT "%s:%d: XD3 assertion failed: %s\n", \ __FILE__, __LINE__, #x); \ abort (); } } while (0) #else #define XD3_ASSERT(x) (void)0 #endif /* XD3_DEBUG */ #define xd3_max(x,y) ((x) < (y) ? (y) : (x)) #define xd3_min(x,y) ((x) < (y) ? (x) : (y)) /**************************************************************** PUBLIC ENUMS ******************************************************************/ /* These are the five ordinary status codes returned by the * xd3_encode_input() and xd3_decode_input() state machines. */ typedef enum { /* An application must be prepared to handle these five return * values from either xd3_encode_input or xd3_decode_input, except * in the case of no-source compression, in which case XD3_GETSRCBLK * is never returned. More detailed comments for these are given in * xd3_encode_input and xd3_decode_input comments, below. */ XD3_INPUT = -17703, /* need input */ XD3_OUTPUT = -17704, /* have output */ XD3_GETSRCBLK = -17705, /* need a block of source input (with no * xd3_getblk function), a chance to do * non-blocking read. */ XD3_GOTHEADER = -17706, /* (decode-only) after the initial VCDIFF & first window header */ XD3_WINSTART = -17707, /* notification: returned before a window is * processed, giving a chance to * XD3_SKIP_WINDOW or not XD3_SKIP_EMIT that * window. */ XD3_WINFINISH = -17708, /* notification: returned after encode/decode & output for a window */ XD3_TOOFARBACK = -17709, /* (encoder only) may be returned by getblk() if the block is too old */ XD3_INTERNAL = -17710, /* internal error */ XD3_INVALID = -17711, /* invalid config */ XD3_INVALID_INPUT = -17712, /* invalid input/decoder error */ XD3_NOSECOND = -17713, /* when secondary compression finds no improvement. */ XD3_UNIMPLEMENTED = -17714 /* currently VCD_TARGET, VCD_CODETABLE */ } xd3_rvalues; /* special values in config->flags */ typedef enum { XD3_JUST_HDR = (1 << 1), /* used by VCDIFF tools, see xdelta3-main.h. */ XD3_SKIP_WINDOW = (1 << 2), /* used by VCDIFF tools, see xdelta3-main.h. */ XD3_SKIP_EMIT = (1 << 3), /* used by VCDIFF tools, see xdelta3-main.h. */ XD3_FLUSH = (1 << 4), /* flush the stream buffer to prepare for xd3_stream_close(). */ XD3_SEC_DJW = (1 << 5), /* use DJW static huffman */ XD3_SEC_FGK = (1 << 6), /* use FGK adaptive huffman */ XD3_SEC_LZMA = (1 << 24), /* use LZMA secondary */ XD3_SEC_TYPE = (XD3_SEC_DJW | XD3_SEC_FGK | XD3_SEC_LZMA), XD3_SEC_NODATA = (1 << 7), /* disable secondary compression of the data section. */ XD3_SEC_NOINST = (1 << 8), /* disable secondary compression of the inst section. */ XD3_SEC_NOADDR = (1 << 9), /* disable secondary compression of the addr section. */ XD3_SEC_NOALL = (XD3_SEC_NODATA | XD3_SEC_NOINST | XD3_SEC_NOADDR), XD3_ADLER32 = (1 << 10), /* enable checksum computation in the encoder. */ XD3_ADLER32_NOVER = (1 << 11), /* disable checksum verification in the decoder. */ XD3_NOCOMPRESS = (1 << 13), /* disable ordinary data * compression feature, only search * the source, not the target. */ XD3_BEGREEDY = (1 << 14), /* disable the "1.5-pass * algorithm", instead use greedy * matching. Greedy is off by * default. */ XD3_ADLER32_RECODE = (1 << 15), /* used by "recode". */ /* 4 bits to set the compression level the same as the command-line * setting -1 through -9 (-0 corresponds to the XD3_NOCOMPRESS flag, * and is independent of compression level). This is for * convenience, especially with xd3_encode_memory(). */ XD3_COMPLEVEL_SHIFT = 20, /* 20 - 23 */ XD3_COMPLEVEL_MASK = (0xF << XD3_COMPLEVEL_SHIFT), XD3_COMPLEVEL_1 = (1 << XD3_COMPLEVEL_SHIFT), XD3_COMPLEVEL_2 = (2 << XD3_COMPLEVEL_SHIFT), XD3_COMPLEVEL_3 = (3 << XD3_COMPLEVEL_SHIFT), XD3_COMPLEVEL_6 = (6 << XD3_COMPLEVEL_SHIFT), XD3_COMPLEVEL_9 = (9 << XD3_COMPLEVEL_SHIFT) } xd3_flags; /* The values of this enumeration are set in xd3_config using the * smatch_cfg variable. It can be set to default, slow, fast, etc., * and soft. */ typedef enum { XD3_SMATCH_DEFAULT = 0, /* Flags may contain XD3_COMPLEVEL bits, else default. */ XD3_SMATCH_SLOW = 1, XD3_SMATCH_FAST = 2, XD3_SMATCH_FASTER = 3, XD3_SMATCH_FASTEST = 4, XD3_SMATCH_SOFT = 5 } xd3_smatch_cfg; /********************************************************************* PRIVATE ENUMS **********************************************************************/ /* stream->match_state is part of the xd3_encode_input state machine * for source matching: * * 1. the XD3_GETSRCBLK block-read mechanism means reentrant matching * 2. this state spans encoder windows: a match and end-of-window * will continue in the next 3. the initial target byte and source * byte are a presumed match, to avoid some computation in case the * inputs are identical. */ typedef enum { MATCH_TARGET = 0, /* in this state, attempt to match the start of * the target with the previously set source * address (initially 0). */ MATCH_BACKWARD = 1, /* currently expanding a match backward in the source/target. */ MATCH_FORWARD = 2, /* currently expanding a match forward in the source/target. */ MATCH_SEARCHING = 3 /* currently searching for a match. */ } xd3_match_state; /* The xd3_encode_input state machine steps through these states in * the following order. The matcher is reentrant and returns * XD3_INPUT whenever it requires more data. After receiving * XD3_INPUT, if the application reads EOF it should call * xd3_stream_close(). */ typedef enum { ENC_INIT = 0, /* xd3_encode_input has never been called. */ ENC_INPUT = 1, /* waiting for xd3_avail_input () to be called. */ ENC_SEARCH = 2, /* currently searching for matches. */ ENC_INSTR = 3, /* currently formatting output. */ ENC_FLUSH = 4, /* currently emitting output. */ ENC_POSTOUT = 5, /* after an output section. */ ENC_POSTWIN = 6, /* after all output sections. */ ENC_ABORTED = 7 /* abort. */ } xd3_encode_state; /* The xd3_decode_input state machine steps through these states in * the following order. The matcher is reentrant and returns * XD3_INPUT whenever it requires more data. After receiving * XD3_INPUT, if the application reads EOF it should call * xd3_stream_close(). * * 0-8: the VCDIFF header * 9-18: the VCDIFF window header * 19-21: the three primary sections: data, inst, addr * 22: producing output: returns XD3_OUTPUT, possibly XD3_GETSRCBLK, * 23: return XD3_WINFINISH, set state=9 to decode more input */ typedef enum { DEC_VCHEAD = 0, /* VCDIFF header */ DEC_HDRIND = 1, /* header indicator */ DEC_SECONDID = 2, /* secondary compressor ID */ DEC_TABLEN = 3, /* code table length */ DEC_NEAR = 4, /* code table near */ DEC_SAME = 5, /* code table same */ DEC_TABDAT = 6, /* code table data */ DEC_APPLEN = 7, /* application data length */ DEC_APPDAT = 8, /* application data */ DEC_WININD = 9, /* window indicator */ DEC_CPYLEN = 10, /* copy window length */ DEC_CPYOFF = 11, /* copy window offset */ DEC_ENCLEN = 12, /* length of delta encoding */ DEC_TGTLEN = 13, /* length of target window */ DEC_DELIND = 14, /* delta indicator */ DEC_DATALEN = 15, /* length of ADD+RUN data */ DEC_INSTLEN = 16, /* length of instruction data */ DEC_ADDRLEN = 17, /* length of address data */ DEC_CKSUM = 18, /* window checksum */ DEC_DATA = 19, /* data section */ DEC_INST = 20, /* instruction section */ DEC_ADDR = 21, /* address section */ DEC_EMIT = 22, /* producing data */ DEC_FINISH = 23, /* window finished */ DEC_ABORTED = 24 /* xd3_abort_stream */ } xd3_decode_state; /************************************************************ internal types ************************************************************/ /* instruction lists used in the IOPT buffer */ struct _xd3_rlist { xd3_rlist *next; xd3_rlist *prev; }; /* the raw encoding of an instruction used in the IOPT buffer */ struct _xd3_rinst { uint8_t type; uint8_t xtra; uint8_t code1; uint8_t code2; usize_t pos; usize_t size; xoff_t addr; xd3_rlist link; }; /* the code-table form of an single- or double-instruction */ struct _xd3_dinst { uint8_t type1; uint8_t size1; uint8_t type2; uint8_t size2; }; /* the decoded form of a single (half) instruction. */ struct _xd3_hinst { uint8_t type; usize_t size; usize_t addr; }; /* the form of a whole-file instruction */ struct _xd3_winst { uint8_t type; /* RUN, ADD, COPY */ uint8_t mode; /* 0, VCD_SOURCE, VCD_TARGET */ usize_t size; xoff_t addr; xoff_t position; /* absolute position of this inst */ }; /* used by the encoder to buffer output in sections. list of blocks. */ struct _xd3_output { uint8_t *base; usize_t next; usize_t avail; xd3_output *next_page; }; /* used by the decoder to buffer input in sections. */ struct _xd3_desect { const uint8_t *buf; const uint8_t *buf_max; usize_t size; usize_t pos; /* used in xdelta3-decode.h */ uint8_t *copied1; usize_t alloc1; /* used in xdelta3-second.h */ uint8_t *copied2; usize_t alloc2; }; /* the VCDIFF address cache, see the RFC */ struct _xd3_addr_cache { usize_t s_near; usize_t s_same; usize_t next_slot; /* the circular index for near */ usize_t *near_array; /* array of size s_near */ usize_t *same_array; /* array of size s_same*256 */ }; /* the IOPT buffer list is just a list of buffers, which may be allocated * during encode when using an unlimited buffer. */ struct _xd3_iopt_buflist { xd3_rinst *buffer; xd3_iopt_buflist *next; }; /* This is the record of a pre-compiled configuration, a subset of xd3_config. */ struct _xd3_smatcher { const char *name; int (*string_match) (xd3_stream *stream); usize_t large_look; usize_t large_step; usize_t small_look; usize_t small_chain; usize_t small_lchain; usize_t max_lazy; usize_t long_enough; }; /* hash table size & power-of-two hash function. */ struct _xd3_hash_cfg { usize_t size; // Number of buckets usize_t shift; usize_t mask; usize_t look; // How wide is this checksum usize_t multiplier; // K * powers[0] usize_t *powers; // Array of [0,look) where powers[look-1] == 1 // and powers[N] = powers[N+1]*K (Rabin-Karp) }; /* the sprev list */ struct _xd3_slist { usize_t last_pos; }; /* window info (for whole state) */ struct _xd3_wininfo { xoff_t offset; usize_t length; uint32_t adler32; }; /* whole state for, e.g., merge */ struct _xd3_whole_state { usize_t addslen; uint8_t *adds; usize_t adds_alloc; usize_t instlen; xd3_winst *inst; usize_t inst_alloc; usize_t wininfolen; xd3_wininfo *wininfo; usize_t wininfo_alloc; xoff_t length; }; /******************************************************************** public types *******************************************************************/ /* Settings for the secondary compressor. */ struct _xd3_sec_cfg { int data_type; /* Which section. (set automatically) */ usize_t ngroups; /* Number of DJW Huffman groups. */ usize_t sector_size; /* Sector size. */ int inefficient; /* If true, ignore efficiency check [avoid XD3_NOSECOND]. */ }; /* This is the user-visible stream configuration. */ struct _xd3_config { usize_t winsize; /* The encoder window size. */ usize_t sprevsz; /* How far back small string matching goes */ usize_t iopt_size; /* entries in the instruction-optimizing buffer */ xd3_getblk_func *getblk; /* The three callbacks. */ xd3_alloc_func *alloc; xd3_free_func *freef; void *opaque; /* Not used. */ uint32_t flags; /* stream->flags are initialized * from xd3_config & never * modified by the library. Use * xd3_set_flags to modify flags * settings mid-stream. */ xd3_sec_cfg sec_data; /* Secondary compressor config: data */ xd3_sec_cfg sec_inst; /* Secondary compressor config: inst */ xd3_sec_cfg sec_addr; /* Secondary compressor config: addr */ xd3_smatch_cfg smatch_cfg; /* See enum: use fields below for soft config */ xd3_smatcher smatcher_soft; }; /* The primary source file object. You create one of these objects and * initialize the first four fields. This library maintains the next * 5 fields. The configured getblk implementation is responsible for * setting the final 3 fields when called (and/or when XD3_GETSRCBLK * is returned). */ struct _xd3_source { /* you set */ usize_t blksize; /* block size */ const char *name; /* its name, for debug/print purposes */ void *ioh; /* opaque handle */ xoff_t max_winsize; /* maximum visible buffer */ /* getblk sets */ xoff_t curblkno; /* current block number: client sets after getblk request */ usize_t onblk; /* number of bytes on current block: client sets, must be >= 0 and <= blksize */ const uint8_t *curblk; /* current block array: client sets after getblk request */ /* xd3 sets */ usize_t srclen; /* length of this source window */ xoff_t srcbase; /* offset of this source window in the source itself */ usize_t shiftby; /* for power-of-two blocksizes */ usize_t maskby; /* for power-of-two blocksizes */ xoff_t cpyoff_blocks; /* offset of dec_cpyoff in blocks */ usize_t cpyoff_blkoff; /* offset of copy window in blocks, remainder */ xoff_t getblkno; /* request block number: xd3 sets current getblk request */ /* See xd3_getblk() */ xoff_t max_blkno; /* Maximum block, if eof is known, * otherwise, equals frontier_blkno * (initially 0). */ usize_t onlastblk; /* Number of bytes on max_blkno */ int eof_known; /* Set to true when the first * partial block is read. */ }; /* The primary xd3_stream object, used for encoding and decoding. You * may access only two fields: avail_out, next_out. Use the methods * above to operate on xd3_stream. */ struct _xd3_stream { /* input state */ const uint8_t *next_in; /* next input byte */ usize_t avail_in; /* number of bytes available at next_in */ xoff_t total_in; /* how many bytes in */ /* output state */ uint8_t *next_out; /* next output byte */ usize_t avail_out; /* number of bytes available at next_out */ usize_t space_out; /* total out space */ xoff_t current_window; /* number of windows encoded/decoded */ xoff_t total_out; /* how many bytes out */ /* to indicate an error, xd3 sets */ const char *msg; /* last error message, NULL if no error */ /* source configuration */ xd3_source *src; /* source array */ /* encoder memory configuration */ usize_t winsize; /* suggested window size */ usize_t sprevsz; /* small string, previous window size (power of 2) */ usize_t sprevmask; /* small string, previous window size mask */ usize_t iopt_size; usize_t iopt_unlimited; /* general configuration */ xd3_getblk_func *getblk; /* set nxtblk, nxtblkno to scanblkno */ xd3_alloc_func *alloc; /* malloc function */ xd3_free_func *free; /* free function */ void* opaque; /* private data object passed to alloc, free, and getblk */ uint32_t flags; /* various options */ /* secondary compressor configuration */ xd3_sec_cfg sec_data; /* Secondary compressor config: data */ xd3_sec_cfg sec_inst; /* Secondary compressor config: inst */ xd3_sec_cfg sec_addr; /* Secondary compressor config: addr */ xd3_smatcher smatcher; usize_t *large_table; /* table of large checksums */ xd3_hash_cfg large_hash; /* large hash config */ usize_t *small_table; /* table of small checksums */ xd3_slist *small_prev; /* table of previous offsets, circular linked list */ int small_reset; /* true if small table should be reset */ xd3_hash_cfg small_hash; /* small hash config */ xd3_addr_cache acache; /* the vcdiff address cache */ xd3_encode_state enc_state; /* state of the encoder */ usize_t taroff; /* base offset of the target input */ usize_t input_position; /* current input position */ usize_t min_match; /* current minimum match length, avoids redundent matches */ usize_t unencoded_offset; /* current input, first * unencoded offset. this value * is <= the first instruction's * position in the iopt buffer, * if there is at least one * match in the buffer. */ /* SRCWIN */ int srcwin_decided; /* boolean: true if srclen and srcbase have been decided. */ int srcwin_decided_early; /* boolean: true if srclen and srcbase were decided early. */ xoff_t srcwin_cksum_pos; /* Source checksum position */ /* MATCH */ xd3_match_state match_state; /* encoder match state */ xoff_t match_srcpos; /* current match source position relative to srcbase */ xoff_t match_last_srcpos; /* previously attempted * srcpos, to avoid loops. */ xoff_t match_minaddr; /* smallest matching address to * set window params (reset each * window xd3_encode_reset) */ xoff_t match_maxaddr; /* largest matching address to * set window params (reset each * window xd3_encode_reset) */ usize_t match_back; /* match extends back so far */ usize_t match_maxback; /* match extends back maximum */ usize_t match_fwd; /* match extends forward so far */ usize_t match_maxfwd; /* match extends forward maximum */ xoff_t maxsrcaddr; /* address of the last source match (across windows) */ uint8_t *buf_in; /* for saving buffered input */ usize_t buf_avail; /* amount of saved input */ const uint8_t *buf_leftover; /* leftover content of next_in (i.e., user's buffer) */ usize_t buf_leftavail; /* amount of leftover content */ xd3_output *enc_current; /* current output buffer */ xd3_output *enc_free; /* free output buffers */ xd3_output *enc_heads[4]; /* array of encoded outputs: head of chain */ xd3_output *enc_tails[4]; /* array of encoded outputs: tail of chain */ uint32_t recode_adler32; /* set the adler32 checksum * during "recode". */ xd3_rlist iopt_used; /* instruction optimizing buffer */ xd3_rlist iopt_free; xd3_rinst *iout; /* next single instruction */ xd3_iopt_buflist *iopt_alloc; const uint8_t *enc_appheader; /* application header to encode */ usize_t enc_appheadsz; /* application header size */ /* decoder stuff */ xd3_decode_state dec_state; /* current DEC_XXX value */ usize_t dec_hdr_ind; /* VCDIFF header indicator */ usize_t dec_win_ind; /* VCDIFF window indicator */ usize_t dec_del_ind; /* VCDIFF delta indicator */ uint8_t dec_magic[4]; /* First four bytes */ usize_t dec_magicbytes; /* Magic position. */ usize_t dec_secondid; /* Optional secondary compressor ID. */ usize_t dec_codetblsz; /* Optional code table: length. */ uint8_t *dec_codetbl; /* Optional code table: storage. */ usize_t dec_codetblbytes; /* Optional code table: position. */ usize_t dec_appheadsz; /* Optional application header: size. */ uint8_t *dec_appheader; /* Optional application header: storage */ usize_t dec_appheadbytes; /* Optional application header: position. */ usize_t dec_cksumbytes; /* Optional checksum: position. */ uint8_t dec_cksum[4]; /* Optional checksum: storage. */ uint32_t dec_adler32; /* Optional checksum: value. */ usize_t dec_cpylen; /* length of copy window (VCD_SOURCE or VCD_TARGET) */ xoff_t dec_cpyoff; /* offset of copy window (VCD_SOURCE or VCD_TARGET) */ usize_t dec_enclen; /* length of delta encoding */ usize_t dec_tgtlen; /* length of target window */ #if USE_UINT64 uint64_t dec_64part; /* part of a decoded uint64_t */ #endif #if USE_UINT32 uint32_t dec_32part; /* part of a decoded uint32_t */ #endif xoff_t dec_winstart; /* offset of the start of current target window */ xoff_t dec_window_count; /* == current_window + 1 in DEC_FINISH */ usize_t dec_winbytes; /* bytes of the three sections so far consumed */ usize_t dec_hdrsize; /* VCDIFF + app header size */ const uint8_t *dec_tgtaddrbase; /* Base of decoded target addresses (addr >= dec_cpylen). */ const uint8_t *dec_cpyaddrbase; /* Base of decoded copy addresses (addr < dec_cpylen). */ usize_t dec_position; /* current decoder position counting the cpylen offset */ usize_t dec_maxpos; /* maximum decoder position counting the cpylen offset */ xd3_hinst dec_current1; /* current instruction */ xd3_hinst dec_current2; /* current instruction */ uint8_t *dec_buffer; /* Decode buffer */ uint8_t *dec_lastwin; /* In case of VCD_TARGET, the last target window. */ usize_t dec_lastlen; /* length of the last target window */ xoff_t dec_laststart; /* offset of the start of last target window */ usize_t dec_lastspace; /* allocated space of last target window, for reuse */ xd3_desect inst_sect; /* staging area for decoding window sections */ xd3_desect addr_sect; xd3_desect data_sect; xd3_code_table_func *code_table_func; const xd3_dinst *code_table; const xd3_code_table_desc *code_table_desc; xd3_dinst *code_table_alloc; /* secondary compression */ const xd3_sec_type *sec_type; xd3_sec_stream *sec_stream_d; xd3_sec_stream *sec_stream_i; xd3_sec_stream *sec_stream_a; /* state for reconstructing whole files (e.g., for merge), this only * supports loading USIZE_T_MAX instructions, adds, etc. */ xd3_whole_state whole_target; /* statistics */ xoff_t n_scpy; xoff_t n_tcpy; xoff_t n_add; xoff_t n_run; xoff_t l_scpy; xoff_t l_tcpy; xoff_t l_add; xoff_t l_run; usize_t i_slots_used; #if XD3_DEBUG usize_t large_ckcnt; /* memory usage */ usize_t alloc_cnt; usize_t free_cnt; #endif }; /************************************************************************** PUBLIC FUNCTIONS **************************************************************************/ #ifdef __cplusplus extern "C" { #endif // __cplusplus /* This function configures an xd3_stream using the provided in-memory * input buffer, source buffer, output buffer, and flags. The output * array must be large enough or else ENOSPC will be returned. This * is the simplest in-memory encoding interface. */ int xd3_encode_memory (const uint8_t *input, usize_t input_size, const uint8_t *source, usize_t source_size, uint8_t *output_buffer, usize_t *output_size, usize_t avail_output, int flags); /* The reverse of xd3_encode_memory. */ int xd3_decode_memory (const uint8_t *input, usize_t input_size, const uint8_t *source, usize_t source_size, uint8_t *output_buf, usize_t *output_size, usize_t avail_output, int flags); /* This function encodes an in-memory input using a pre-configured * xd3_stream. This allows the caller to set a variety of options * which are not available in the xd3_encode/decode_memory() * functions. * * The output array must be large enough to hold the output or else * ENOSPC is returned. The source (if any) should be set using * xd3_set_source_and_size() with a single-block xd3_source. This * calls the underlying non-blocking interfaces, * xd3_encode/decode_input(), handling the necessary input/output * states. This method may be considered a reference for any * application using xd3_encode_input() directly. * * xd3_stream stream; * xd3_config config; * xd3_source src; * * memset (& src, 0, sizeof (src)); * memset (& stream, 0, sizeof (stream)); * memset (& config, 0, sizeof (config)); * * if (source != NULL) * { * src.size = source_size; * src.blksize = source_size; * src.curblkno = 0; * src.onblk = source_size; * src.curblk = source; * src.max_winsize = source_size; * xd3_set_source(&stream, &src); * } * * config.flags = flags; * config.winsize = input_size; * * ... set smatcher, appheader, encoding-table, compression-level, etc. * * xd3_config_stream(&stream, &config); * xd3_encode_stream(&stream, ...); * xd3_free_stream(&stream); */ int xd3_encode_stream (xd3_stream *stream, const uint8_t *input, usize_t input_size, uint8_t *output, usize_t *output_size, usize_t avail_output); /* The reverse of xd3_encode_stream. */ int xd3_decode_stream (xd3_stream *stream, const uint8_t *input, usize_t input_size, uint8_t *output, usize_t *output_size, usize_t avail_size); /* This is the non-blocking interface. * * Handling input and output states is the same for encoding or * decoding using the xd3_avail_input() and xd3_consume_output() * routines, inlined below. * * Return values: * * XD3_INPUT: the process requires more input: call * xd3_avail_input() then repeat * * XD3_OUTPUT: the process has more output: read stream->next_out, * stream->avail_out, then call xd3_consume_output(), * then repeat * * XD3_GOTHEADER: (decoder-only) notification returned following the * VCDIFF header and first window header. the decoder * may use the header to configure itself. * * XD3_WINSTART: a general notification returned once for each * window except the 0-th window, which is implied by * XD3_GOTHEADER. It is recommended to use a * switch-stmt such as: * * ... * again: * switch ((ret = xd3_decode_input (stream))) { * case XD3_GOTHEADER: { * assert(stream->current_window == 0); * stuff; * } * // fallthrough * case XD3_WINSTART: { * something(stream->current_window); * goto again; * } * ... * * XD3_WINFINISH: a general notification, following the complete * input & output of a window. at this point, * stream->total_in and stream->total_out are consistent * for either encoding or decoding. * * XD3_GETSRCBLK: If the xd3_getblk() callback is NULL, this value * is returned to initiate a non-blocking source read. */ int xd3_decode_input (xd3_stream *stream); int xd3_encode_input (xd3_stream *stream); /* The xd3_config structure is used to initialize a stream - all data * is copied into stream so config may be a temporary variable. See * the [documentation] or comments on the xd3_config structure. */ int xd3_config_stream (xd3_stream *stream, xd3_config *config); /* Since Xdelta3 doesn't open any files, xd3_close_stream is just an * error check that the stream is in a proper state to be closed: this * means the encoder is flushed and the decoder is at a window * boundary. The application is responsible for freeing any of the * resources it supplied. */ int xd3_close_stream (xd3_stream *stream); /* This arranges for closes the stream to succeed. Does not free the * stream.*/ void xd3_abort_stream (xd3_stream *stream); /* xd3_free_stream frees all memory allocated for the stream. The * application is responsible for freeing any of the resources it * supplied. */ void xd3_free_stream (xd3_stream *stream); /* This function informs the encoder or decoder that source matching * (i.e., delta-compression) is possible. For encoding, this should * be called before the first xd3_encode_input. A NULL source is * ignored. For decoding, this should be called before the first * window is decoded, but the appheader may be read first * (XD3_GOTHEADER). After decoding the header, call xd3_set_source() * if you have a source file. Note: if (stream->dec_win_ind & VCD_SOURCE) * is true, it means the first window expects there to be a source file. */ int xd3_set_source (xd3_stream *stream, xd3_source *source); /* If the source size is known, call this instead of xd3_set_source(). * to avoid having stream->getblk called (and/or to avoid XD3_GETSRCBLK). * * Follow these steps: xd3_source source; memset(&source, 0, sizeof(source)); source.blksize = size; source.onblk = size; source.curblk = buf; source.curblkno = 0; int ret = xd3_set_source_and_size(&stream, &source, size); ... */ int xd3_set_source_and_size (xd3_stream *stream, xd3_source *source, xoff_t source_size); /* This should be called before the first call to xd3_encode_input() * to include application-specific data in the VCDIFF header. */ void xd3_set_appheader (xd3_stream *stream, const uint8_t *data, usize_t size); /* xd3_get_appheader may be called in the decoder after XD3_GOTHEADER. * For convenience, the decoder always adds a single byte padding to * the end of the application header, which is set to zero in case the * application header is a string. */ int xd3_get_appheader (xd3_stream *stream, uint8_t **data, usize_t *size); /* To generate a VCDIFF encoded delta with xd3_encode_init() from * another format, use: * * xd3_encode_init_partial() -- initialze encoder state (w/o hash tables) * xd3_init_cache() -- reset VCDIFF address cache * xd3_found_match() -- to report a copy instruction * * set stream->enc_state to ENC_INSTR and call xd3_encode_input as usual. */ int xd3_encode_init_partial (xd3_stream *stream); void xd3_init_cache (xd3_addr_cache* acache); int xd3_found_match (xd3_stream *stream, usize_t pos, usize_t size, xoff_t addr, int is_source); /* Gives an error string for xdelta3-speficic errors, returns NULL for system errors */ const char* xd3_strerror (int ret); /* For convenience, zero & initialize the xd3_config structure with specified flags. */ static inline void xd3_init_config (xd3_config *config, uint32_t flags) { memset (config, 0, sizeof (*config)); config->flags = flags; } /* This supplies some input to the stream. * * For encoding, if the input is larger than the configured window * size (xd3_config.winsize), the entire input will be consumed and * encoded anyway. If you wish to strictly limit the window size, * limit the buffer passed to xd3_avail_input to the window size. * * For encoding, if the input is smaller than the configured window * size (xd3_config.winsize), the library will create a window-sized * buffer and accumulate input until a full-sized window can be * encoded. XD3_INPUT will be returned. The input must remain valid * until the next time xd3_encode_input() returns XD3_INPUT. * * For decoding, the input will be consumed entirely before XD3_INPUT * is returned again. */ static inline void xd3_avail_input (xd3_stream *stream, const uint8_t *idata, usize_t isize) { /* Even if isize is zero, the code expects a non-NULL idata. Why? * It uses this value to determine whether xd3_avail_input has ever * been called. If xd3_encode_input is called before * xd3_avail_input it will return XD3_INPUT right away without * allocating a stream->winsize buffer. This is to avoid an * unwanted allocation. */ XD3_ASSERT (idata != NULL || isize == 0); stream->next_in = idata; stream->avail_in = isize; } /* This acknowledges receipt of output data, must be called after any * XD3_OUTPUT return. */ static inline void xd3_consume_output (xd3_stream *stream) { stream->avail_out = 0; } /* These are set for each XD3_WINFINISH return. */ static inline int xd3_encoder_used_source (xd3_stream *stream) { return stream->src != NULL && stream->src->srclen > 0; } static inline xoff_t xd3_encoder_srcbase (xd3_stream *stream) { return stream->src->srcbase; } static inline usize_t xd3_encoder_srclen (xd3_stream *stream) { return stream->src->srclen; } /* Checks for legal flag changes. */ static inline void xd3_set_flags (xd3_stream *stream, uint32_t flags) { /* The bitwise difference should contain only XD3_FLUSH or XD3_SKIP_WINDOW */ XD3_ASSERT(((flags ^ stream->flags) & ~(XD3_FLUSH | XD3_SKIP_WINDOW)) == 0); stream->flags = flags; } /* Gives some extra information about the latest library error, if any * is known. */ static inline const char* xd3_errstring (xd3_stream *stream) { return stream->msg ? stream->msg : ""; } /* 64-bit divisions are expensive, which is why we require a * power-of-two source->blksize. To relax this restriction is * relatively easy, see the history for xd3_blksize_div(). */ static inline void xd3_blksize_div (const xoff_t offset, const xd3_source *source, xoff_t *blkno, usize_t *blkoff) { *blkno = offset >> source->shiftby; *blkoff = offset & source->maskby; XD3_ASSERT (*blkoff < source->blksize); } static inline void xd3_blksize_add (xoff_t *blkno, usize_t *blkoff, const xd3_source *source, const usize_t add) { usize_t blkdiff; /* Does not check for overflow, checked in xdelta3-decode.h. */ *blkoff += add; blkdiff = *blkoff >> source->shiftby; if (blkdiff) { *blkno += blkdiff; *blkoff &= source->maskby; } XD3_ASSERT (*blkoff < source->blksize); } #ifdef __cplusplus } // extern "C" #endif #define XD3_NOOP 0U #define XD3_ADD 1U #define XD3_RUN 2U #define XD3_CPY 3U /* XD3_CPY rtypes are represented as (XD3_CPY + * copy-mode value) */ #if XD3_DEBUG #define IF_DEBUG(x) x #else #define IF_DEBUG(x) #endif #if XD3_DEBUG > 1 #define IF_DEBUG1(x) x #else #define IF_DEBUG1(x) #endif #if XD3_DEBUG > 2 #define IF_DEBUG2(x) x #else #define IF_DEBUG2(x) #endif #define SIZEOF_ARRAY(x) (sizeof(x) / sizeof(x[0])) #endif /* _XDELTA3_H_ */ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3.i ================================================ %module xdelta3 %import cstring.i %import argcargv.i %{ #include "xdelta3.h" int xd3_main_cmdline (int ARGC, char **ARGV); %} %cstring_input_binary(const char *input, unsigned int input_size); %cstring_input_binary(const char *source, unsigned int source_size); %define %max_output_withsize(TYPEMAP, SIZE, MAXSIZE) %typemap(in) MAXSIZE (unsigned int alloc_size) { $1 = alloc_size = PyInt_AsLong(obj2); } %typemap(in,numinputs=0) (TYPEMAP, SIZE) { } %typemap(check) (TYPEMAP, SIZE) { // alloc_size input is #7th position in xd3_xxcode_memory() $1 = malloc(alloc_size7); $2 = &alloc_size7; } %typemap(argout,fragment="t_output_helper") (TYPEMAP, SIZE) { if (result == 0) { PyObject *o; // alloc_size7 now carries actual size o = PyString_FromStringAndSize($1,alloc_size7); $result = t_output_helper($result,o); } else { $result = t_output_helper($result,Py_None); } free($1); } %typemap(default) int flags { $1 = 0; } %enddef %max_output_withsize(char *output_buf, unsigned int *output_size, unsigned int max_output); int xd3_encode_memory (const uint8_t *input, usize_t input_size, const uint8_t *source, usize_t source_size, uint8_t *output_buffer, usize_t *output_size, usize_t avail_output, int flags); int xd3_decode_memory (const uint8_t *input, usize_t input_size, const uint8_t *source, usize_t source_size, uint8_t *output_buf, usize_t *output_size, usize_t avail_output, int flags); int xd3_main_cmdline (int ARGC, char **ARGV); /* Is this the right way? */ enum { /*XD3_JUST_HDR,*/ /*XD3_SKIP_WINDOW,*/ /*XD3_SKIP_EMIT,*/ /*XD3_FLUSH,*/ XD3_SEC_DJW, XD3_SEC_FGK, /*XD3_SEC_TYPE,*/ XD3_SEC_NODATA, XD3_SEC_NOINST, XD3_SEC_NOADDR, /*XD3_SEC_OTHER,*/ XD3_ADLER32, XD3_ADLER32_NOVER, XD3_NOCOMPRESS, XD3_BEGREEDY, XD3_COMPLEVEL_SHIFT, XD3_COMPLEVEL_MASK, XD3_COMPLEVEL_1, XD3_COMPLEVEL_3, XD3_COMPLEVEL_6, XD3_COMPLEVEL_9, }; ================================================ FILE: source-code/dependencies/xdelta3/xdelta3.vcxproj ================================================  Debug Itanium Debug Win32 Debug x64 Release Itanium Release Win32 Release x64 xdelta3-64 Itanium xdelta3-64 Win32 xdelta3-64 x64 %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(PreprocessorDefinitions) /DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions) /DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions) /DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions) /DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions) /DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions) /DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0;%(PreprocessorDefinitions) {8F9D37B5-B78E-4816-BE61-AEF679DBF3BC} Win32Proj xdelta3 Application true MultiByte v120 Application true MultiByte Application true MultiByte v120 Application false true MultiByte v120 Application false true MultiByte Application false true MultiByte v120 Application false true MultiByte v120 Application false true MultiByte Application false true MultiByte v120 true true true false false false $(WindowsSdkDir)\include;$(VCInstallDir)include;..\xz\include $(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64;..\xz\bin_x86-64 false false false NotUsing Level3 Disabled WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;SECONDARY_LZMA=0;LZMA_API_STATIC;SIZEOF_SIZE_T=4;SIZEOF_UNSIGNED_LONG_LONG=8;%(PreprocessorDefinitions) MultiThreaded ../xz/include Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) NotUsing Level3 Disabled WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreaded Console true NotUsing Level3 Disabled WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreaded Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;..\..\..\..\src\xz\bin_x86-64\liblzma_static.lib;%(AdditionalDependencies) Level3 NotUsing MaxSpeed true true WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;SECONDARY_LZMA=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;LZMA_API_STATIC;%(PreprocessorDefinitions) MultiThreaded ..\..\..\..\src\xz\include Console true true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;..\..\..\..\src\xz\bin_i486\liblzma_static.lib;%(AdditionalDependencies) Level3 NotUsing MaxSpeed true true WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreaded Console true true true Level3 NotUsing MaxSpeed true true WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;SECONDARY_LZMA=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;LZMA_API_STATIC;%(PreprocessorDefinitions) MultiThreaded ..\..\..\..\src\xz\include Console true true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);..\..\..\..\src\xz\bin_x86-64\liblzma_static.lib Level3 NotUsing MaxSpeed true true WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreaded Console true true true Level3 NotUsing MaxSpeed true true WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreaded Console true true true Level3 NotUsing MaxSpeed true true WIN32;XD3_MAIN=1;XD3_DEBUG=0;XD3_USE_LARGEFILE64=1;REGRESSION_TEST=1;SECONDARY_DJW=1;SECONDARY_FGK=1;XD3_WIN32=1;EXTERNAL_COMPRESSION=0;SHELL_TESTS=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreaded Console true true true ================================================ FILE: source-code/dependencies/xdelta3/xdelta3.wxi ================================================ ================================================ FILE: source-code/dependencies/xdelta3/xdelta3.wxs ================================================ ================================================ FILE: source-code/source/PD-Loader/ModuleList.h ================================================ #pragma once #include #include #include #include #include std::wstring GetModuleFileNameW(HMODULE hModule) { static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH; static constexpr auto MAX_ITERATIONS = 7; std::wstring ret; auto bufferSize = INITIAL_BUFFER_SIZE; for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations) { ret.resize(bufferSize); auto charsReturned = GetModuleFileNameW(hModule, &ret[0], bufferSize); if (charsReturned < ret.length()) { ret.resize(charsReturned); return ret; } else { bufferSize *= 2; } } return L""; } auto starts_with = [](const std::wstring& big_str, const std::wstring& small_str) -> auto { return big_str.compare(0, small_str.length(), small_str) == 0; }; // Stores a list of loaded modules with their names, WITHOUT extension class ModuleList { public: enum class SearchLocation { All, LocalOnly, SystemOnly, }; // Initializes module list // Needs to be called before any calls to Get or GetAll void Enumerate(SearchLocation location = SearchLocation::All) { constexpr size_t INITIAL_SIZE = sizeof(HMODULE) * 256; HMODULE* modules = static_cast(malloc(INITIAL_SIZE)); if (modules != nullptr) { typedef BOOL(WINAPI * Func)(HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded); HMODULE hLib = LoadLibrary(TEXT("kernel32")); assert(hLib != nullptr); // If this fails then everything is probably broken anyway Func pEnumProcessModules = reinterpret_cast(GetProcAddress(hLib, "K32EnumProcessModules")); if (pEnumProcessModules == nullptr) { // Try psapi FreeLibrary(hLib); hLib = LoadLibrary(TEXT("psapi")); if (hLib != nullptr) { pEnumProcessModules = reinterpret_cast(GetProcAddress(hLib, "EnumProcessModules")); } } if (pEnumProcessModules != nullptr) { const HANDLE currentProcess = GetCurrentProcess(); DWORD cbNeeded = 0; if (pEnumProcessModules(currentProcess, modules, INITIAL_SIZE, &cbNeeded) != 0) { if (cbNeeded > INITIAL_SIZE) { HMODULE* newModules = static_cast(realloc(modules, cbNeeded)); if (newModules != nullptr) { modules = newModules; if (pEnumProcessModules(currentProcess, modules, cbNeeded, &cbNeeded) != 0) { EnumerateInternal(modules, location, cbNeeded / sizeof(HMODULE)); } } } else { EnumerateInternal(modules, location, cbNeeded / sizeof(HMODULE)); } } } if (hLib != nullptr) { FreeLibrary(hLib); } free(modules); } } // Recreates module list void ReEnumerate(SearchLocation location = SearchLocation::All) { Clear(); Enumerate(location); } // Clears module list void Clear() { m_moduleList.clear(); } // Gets handle of a loaded module with given name, NULL otherwise HMODULE Get(const wchar_t* moduleName) const { // If vector is empty then we're trying to call it without calling Enumerate first assert(m_moduleList.size() != 0); auto it = std::find_if(m_moduleList.begin(), m_moduleList.end(), [&](const auto& e) { return _wcsicmp(moduleName, std::get<1>(e).c_str()) == 0; }); return it != m_moduleList.end() ? std::get<0>(*it) : nullptr; } // Gets handles to all loaded modules with given name std::vector GetAll(const wchar_t* moduleName) const { // If vector is empty then we're trying to call it without calling Enumerate first assert(m_moduleList.size() != 0); std::vector results; for (auto& e : m_moduleList) { if (_wcsicmp(moduleName, std::get<1>(e).c_str()) == 0) { results.push_back(std::get<0>(e)); } } return results; } private: void EnumerateInternal(HMODULE* modules, SearchLocation location, size_t numModules) { const auto exeModulePath = GetModuleFileNameW(NULL).substr(0, GetModuleFileNameW(NULL).find_last_of(L"/\\")); m_moduleList.reserve(numModules); for (size_t i = 0; i < numModules; i++) { // Obtain module name, with resizing if necessary auto moduleName = GetModuleFileNameW(*modules); if (!moduleName.empty()) { const wchar_t* nameBegin = wcsrchr(moduleName.c_str(), '\\') + 1; const wchar_t* dotPos = wcsrchr(nameBegin, '.'); bool isLocal = starts_with(std::wstring(moduleName), exeModulePath); if ((isLocal && location != SearchLocation::SystemOnly) || (!isLocal && location != SearchLocation::LocalOnly)) { if (dotPos != nullptr) { m_moduleList.emplace_back(*modules, std::wstring(nameBegin, dotPos), isLocal); } else { m_moduleList.emplace_back(*modules, nameBegin, isLocal); } } } modules++; } } public: std::vector< std::tuple > m_moduleList; }; ================================================ FILE: source-code/source/PD-Loader/PD-Loader.vcxproj ================================================  Debug x64 Release x64 16.0 {CA479467-D518-46A2-AC86-3098ADA99FE5} Win32Proj PDLoader 10.0 DynamicLibrary true v142 Unicode DynamicLibrary false v142 true Unicode false true dinput8 false dnsapi NotUsing Level3 Disabled true _CRT_SECURE_NO_WARNINGS;_DEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true pch.h ..\dependencies\MemoryModule;%(AdditionalIncludeDirectories) stdcpp17 -d2FH4- %(AdditionalOptions) Windows true false x64.def -d2:-FH4- %(AdditionalOptions) NotUsing Level3 MaxSpeed true true true _CRT_SECURE_NO_WARNINGS;NDEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true pch.h ..\dependencies\MemoryModule;%(AdditionalIncludeDirectories) stdcpp17 MultiThreadedDLL -d2FH4- %(AdditionalOptions) Windows true true true false x64.def -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/PD-Loader/PD-Loader.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Source Files Source Files Source Files ================================================ FILE: source-code/source/PD-Loader/dllmain.cpp ================================================ #include "framework.h" #include "exception.hpp" #include #include #pragma comment(lib, "Shlwapi.lib") #include #include #include #pragma comment(linker,"\"/manifestdependency:type='win32' \ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") HMODULE hm; std::vector iniPaths; bool iequals(std::wstring_view s1, std::wstring_view s2) { std::wstring str1(std::move(s1)); std::wstring str2(std::move(s2)); std::transform(str1.begin(), str1.end(), str1.begin(), [](wchar_t c) { return ::towlower(c); }); std::transform(str2.begin(), str2.end(), str2.begin(), [](wchar_t c) { return ::towlower(c); }); return (str1 == str2); } std::wstring to_wstring(std::string_view cstr) { std::string str(std::move(cstr)); auto charsReturned = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); std::wstring wstrTo(charsReturned, 0); MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], charsReturned); return wstrTo; } std::wstring SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken) { std::wstring r; WCHAR* szSystemPath = nullptr; if (SUCCEEDED(SHGetKnownFolderPath(rfid, dwFlags, hToken, &szSystemPath))) { r = szSystemPath; } CoTaskMemFree(szSystemPath); return r; }; HMODULE LoadLibraryW(const std::wstring& lpLibFileName) { return LoadLibraryW(lpLibFileName.c_str()); } std::wstring GetCurrentDirectoryW() { static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH; static constexpr auto MAX_ITERATIONS = 7; std::wstring ret; auto bufferSize = INITIAL_BUFFER_SIZE; for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations) { ret.resize(bufferSize); auto charsReturned = GetCurrentDirectoryW(bufferSize, &ret[0]); if (charsReturned < ret.length()) { ret.resize(charsReturned); return ret; } else { bufferSize *= 2; } } return L""; } UINT GetPrivateProfileIntW(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, const std::vector& fileNames) { for (const auto& file : fileNames) { nDefault = GetPrivateProfileIntW(lpAppName, lpKeyName, nDefault, file.c_str()); } return nDefault; } std::wstring GetSelfName() { const std::wstring moduleFileName = GetModuleFileNameW(hm); return moduleFileName.substr(moduleFileName.find_last_of(L"/\\") + 1); } template void GetSections(T&& h, Args... args) { const std::set< std::string_view, std::less<> > s = { args... }; size_t dwLoadOffset = (size_t)GetModuleHandle(NULL); BYTE* pImageBase = reinterpret_cast(dwLoadOffset); PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast(dwLoadOffset); PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast(pImageBase + pDosHeader->e_lfanew); PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeader); for (int iSection = 0; iSection < pNtHeader->FileHeader.NumberOfSections; ++iSection, ++pSection) { auto pszSectionName = reinterpret_cast(pSection->Name); if (s.find(pszSectionName) != s.end()) { DWORD dwPhysSize = (pSection->Misc.VirtualSize + 4095) & ~4095; std::forward(h)(pSection, dwLoadOffset, dwPhysSize); } } } enum Kernel32ExportsNames { eGetStartupInfoA, eGetStartupInfoW, eGetModuleHandleA, eGetModuleHandleW, eGetProcAddress, eGetShortPathNameA, eFindNextFileA, eFindNextFileW, eLoadLibraryA, eLoadLibraryW, eFreeLibrary, eCreateEventA, eCreateEventW, eGetSystemInfo, eInterlockedCompareExchange, eSleep, Kernel32ExportsNamesCount }; enum Kernel32ExportsData { IATPtr, ProcAddress, Kernel32ExportsDataCount }; size_t Kernel32Data[Kernel32ExportsNamesCount][Kernel32ExportsDataCount]; static LONG OriginalLibraryLoaded = 0; void LoadOriginalLibrary() { if (_InterlockedCompareExchange(&OriginalLibraryLoaded, 1, 0) != 0) return; auto szSelfName = GetSelfName(); auto szSystemPath = SHGetKnownFolderPath(FOLDERID_System, 0, nullptr) + L'\\' + szSelfName; auto szLocalPath = GetModuleFileNameW(hm); szLocalPath = szLocalPath.substr(0, szLocalPath.find_last_of(L"/\\") + 1); if (iequals(szSelfName, L"dinput8.dll")) { dinput8.LoadOriginalLibrary(LoadLibraryW(szSystemPath)); } else if (iequals(szSelfName, L"dnsapi.dll")) { dnsapi.LoadOriginalLibrary(LoadLibraryW(szSystemPath)); } } void LoadDVA(std::wstring &path, LPCWSTR dir, LPCWSTR fileName) { if (GetModuleHandle(path.c_str()) == NULL) { auto h = LoadLibraryW(path); SetCurrentDirectoryW(dir); //in case dva switched it if (h == NULL) { auto e = GetLastError(); if (e != ERROR_DLL_INIT_FAILED) // in case dllmain returns false { std::wstring msg = L"Unable to load " + std::wstring(fileName) + L". Error: " + std::to_wstring(e); LPVOID err_msg; if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPWSTR)&err_msg, 1, NULL) != 0) { msg += L"\n"; msg += (LPWSTR)err_msg; } switch (e) { case 126: msg.append(L"\n\nIs the Microsoft Visual C++ Redistributable for Visual Studio 2019 (x64) installed?"); break; case 998: msg.append(L"\n\nPossible causes:\n- a dependency is not installed; or\n- GPU detection failed (select the GPU Type manually/force Novidia in its Config)."); break; default: msg.append(L"\n\nAre all dependencies installed?"); } msg.append(L"\nPlease refer to the quick start guide or the wiki.\n\nAlso, please note that 3rd-party plugins may require additional libraries."); MessageBoxW(0, msg.c_str(), L"PD Loader", MB_ICONERROR); } } else { auto procedure = (void(*)())GetProcAddress(h, "InitializeDVA"); if (procedure != NULL) { procedure(); } } } } void FindFiles(WIN32_FIND_DATAW* fd) { auto dir = GetCurrentDirectoryW(); HANDLE dvaFile = FindFirstFileW(L"*.dva", fd); if (dvaFile != INVALID_HANDLE_VALUE) { do { if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (fd->cFileName[0] == '.' && fd->cFileName[1] == '_') continue; // exclude macOS metadata auto pos = wcslen(fd->cFileName); if (fd->cFileName[pos - 4] == '.' && (fd->cFileName[pos - 3] == 'd' || fd->cFileName[pos - 3] == 'D') && (fd->cFileName[pos - 2] == 'v' || fd->cFileName[pos - 2] == 'V') && (fd->cFileName[pos - 1] == 'a' || fd->cFileName[pos - 1] == 'A') && GetPrivateProfileIntW(L"plugins", fd->cFileName, TRUE, iniPaths)) { auto path = dir + L'\\' + fd->cFileName; LoadDVA(path, dir.c_str(), fd->cFileName); } } } while (FindNextFileW(dvaFile, fd)); FindClose(dvaFile); } } void LoadPlugins() { auto oldDir = GetCurrentDirectoryW(); // store the current directory auto szSelfPath = GetModuleFileNameW(hm).substr(0, GetModuleFileNameW(hm).find_last_of(L"/\\") + 1); SetCurrentDirectoryW(szSelfPath.c_str()); auto nWantsToLoadPlugins = GetPrivateProfileIntW(L"global", L"enable", TRUE, iniPaths); if (nWantsToLoadPlugins) { if (SetCurrentDirectoryW(szSelfPath.c_str())) { WIN32_FIND_DATAW dh; HANDLE divaHook = FindFirstFileW(L"divahook.dll", &dh); if (divaHook != INVALID_HANDLE_VALUE && !(dh.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { printf("[PD Loader] Loading divahook.dll\n"); auto path = szSelfPath + L'\\' + dh.cFileName; LoadDVA(path, szSelfPath.c_str(), dh.cFileName); } if (SetCurrentDirectoryW(L"plugins\\")) { WIN32_FIND_DATAW fd; FindFiles(&fd); } } } SetCurrentDirectoryW(oldDir.c_str()); // Reset the current directory } static LONG LoadedPluginsYet = 0; void LoadEverything() { if (_InterlockedCompareExchange(&LoadedPluginsYet, 1, 0) != 0) return; LoadOriginalLibrary(); LoadPlugins(); } static LONG RestoredOnce = 0; void LoadPluginsAndRestoreIAT(uintptr_t retaddr) { bool calledFromBind = false; //steam drm check GetSections([&](PIMAGE_SECTION_HEADER pSection, size_t dwLoadOffset, DWORD dwPhysSize) { auto dwStart = static_cast(dwLoadOffset + pSection->VirtualAddress); auto dwEnd = dwStart + dwPhysSize; if (retaddr >= dwStart && retaddr <= dwEnd) calledFromBind = true; }, ".bind"); if (calledFromBind) return; if (_InterlockedCompareExchange(&RestoredOnce, 1, 0) != 0) return; LoadEverything(); for (size_t i = 0; i < Kernel32ExportsNamesCount; i++) { if (Kernel32Data[i][IATPtr] && Kernel32Data[i][ProcAddress]) { auto ptr = (size_t*)Kernel32Data[i][IATPtr]; DWORD dwProtect[2]; VirtualProtect(ptr, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]); *ptr = Kernel32Data[i][ProcAddress]; VirtualProtect(ptr, sizeof(size_t), dwProtect[0], &dwProtect[1]); } } } void WINAPI CustomGetStartupInfoA(LPSTARTUPINFOA lpStartupInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetStartupInfoA(lpStartupInfo); } void WINAPI CustomGetStartupInfoW(LPSTARTUPINFOW lpStartupInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetStartupInfoW(lpStartupInfo); } HMODULE WINAPI CustomGetModuleHandleA(LPCSTR lpModuleName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetModuleHandleA(lpModuleName); } HMODULE WINAPI CustomGetModuleHandleW(LPCWSTR lpModuleName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetModuleHandleW(lpModuleName); } FARPROC WINAPI CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetProcAddress(hModule, lpProcName); } DWORD WINAPI CustomGetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetShortPathNameA(lpszLongPath, lpszShortPath, cchBuffer); } BOOL WINAPI CustomFindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return FindNextFileA(hFindFile, lpFindFileData); } BOOL WINAPI CustomFindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return FindNextFileW(hFindFile, lpFindFileData); } HMODULE WINAPI CustomLoadLibraryA(LPCSTR lpLibFileName) { LoadOriginalLibrary(); return LoadLibraryA(lpLibFileName); } HMODULE WINAPI CustomLoadLibraryW(LPCWSTR lpLibFileName) { LoadOriginalLibrary(); return LoadLibraryW(lpLibFileName); } BOOL WINAPI CustomFreeLibrary(HMODULE hLibModule) { if (hLibModule != hm) return FreeLibrary(hLibModule); else return !NULL; } HANDLE WINAPI CustomCreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return CreateEventA(lpEventAttributes, bManualReset, bInitialState, lpName); } HANDLE WINAPI CustomCreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName); } void WINAPI CustomGetSystemInfo(LPSYSTEM_INFO lpSystemInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetSystemInfo(lpSystemInfo); } LONG WINAPI CustomInterlockedCompareExchange(LONG volatile* Destination, LONG ExChange, LONG Comperand) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return _InterlockedCompareExchange(Destination, ExChange, Comperand); } void WINAPI CustomSleep(DWORD dwMilliseconds) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return Sleep(dwMilliseconds); } bool HookKernel32IAT(HMODULE mod, bool exe) { auto hExecutableInstance = (size_t)mod; IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hExecutableInstance + ((IMAGE_DOS_HEADER*)hExecutableInstance)->e_lfanew); IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hExecutableInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1; if (exe) { Kernel32Data[eGetStartupInfoA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoA"); Kernel32Data[eGetStartupInfoW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoW"); Kernel32Data[eGetModuleHandleA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleA"); Kernel32Data[eGetModuleHandleW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleW"); Kernel32Data[eGetProcAddress][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetProcAddress"); Kernel32Data[eGetShortPathNameA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetShortPathNameA"); Kernel32Data[eFindNextFileA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileA"); Kernel32Data[eFindNextFileW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileW"); Kernel32Data[eLoadLibraryA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryA"); Kernel32Data[eLoadLibraryW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryW"); Kernel32Data[eFreeLibrary][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FreeLibrary"); Kernel32Data[eCreateEventA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventA"); Kernel32Data[eCreateEventW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventW"); Kernel32Data[eGetSystemInfo][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetSystemInfo"); Kernel32Data[eInterlockedCompareExchange][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "InterlockedCompareExchange"); Kernel32Data[eSleep][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "Sleep"); } uint32_t matchedImports = 0; auto PatchIAT = [&](size_t start, size_t end, size_t exe_end) { for (size_t i = 0; i < nNumImports; i++) { if (hExecutableInstance + (pImports + i)->FirstThunk > start && !(end && hExecutableInstance + (pImports + i)->FirstThunk > end)) end = hExecutableInstance + (pImports + i)->FirstThunk; } if (!end) { end = start + 0x100; } if (end > exe_end) //for very broken exes { start = hExecutableInstance; end = exe_end; } for (auto i = start; i < end; i += sizeof(size_t)) { DWORD dwProtect[2]; VirtualProtect((size_t*)i, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]); auto ptr = *(size_t*)i; if (!ptr) continue; if (ptr == Kernel32Data[eGetStartupInfoA][ProcAddress]) { if (exe) Kernel32Data[eGetStartupInfoA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetStartupInfoA; matchedImports++; } else if (ptr == Kernel32Data[eGetStartupInfoW][ProcAddress]) { if (exe) Kernel32Data[eGetStartupInfoW][IATPtr] = i; *(size_t*)i = (size_t)CustomGetStartupInfoW; matchedImports++; } else if (ptr == Kernel32Data[eGetModuleHandleA][ProcAddress]) { if (exe) Kernel32Data[eGetModuleHandleA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetModuleHandleA; matchedImports++; } else if (ptr == Kernel32Data[eGetModuleHandleW][ProcAddress]) { if (exe) Kernel32Data[eGetModuleHandleW][IATPtr] = i; *(size_t*)i = (size_t)CustomGetModuleHandleW; matchedImports++; } else if (ptr == Kernel32Data[eGetProcAddress][ProcAddress]) { if (exe) Kernel32Data[eGetProcAddress][IATPtr] = i; *(size_t*)i = (size_t)CustomGetProcAddress; matchedImports++; } else if (ptr == Kernel32Data[eGetShortPathNameA][ProcAddress]) { if (exe) Kernel32Data[eGetShortPathNameA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetShortPathNameA; matchedImports++; } else if (ptr == Kernel32Data[eFindNextFileA][ProcAddress]) { if (exe) Kernel32Data[eFindNextFileA][IATPtr] = i; *(size_t*)i = (size_t)CustomFindNextFileA; matchedImports++; } else if (ptr == Kernel32Data[eFindNextFileW][ProcAddress]) { if (exe) Kernel32Data[eFindNextFileW][IATPtr] = i; *(size_t*)i = (size_t)CustomFindNextFileW; matchedImports++; } else if (ptr == Kernel32Data[eLoadLibraryA][ProcAddress]) { if (exe) Kernel32Data[eLoadLibraryA][IATPtr] = i; *(size_t*)i = (size_t)CustomLoadLibraryA; matchedImports++; } else if (ptr == Kernel32Data[eLoadLibraryW][ProcAddress]) { if (exe) Kernel32Data[eLoadLibraryW][IATPtr] = i; *(size_t*)i = (size_t)CustomLoadLibraryW; matchedImports++; } else if (ptr == Kernel32Data[eFreeLibrary][ProcAddress]) { if (exe) Kernel32Data[eFreeLibrary][IATPtr] = i; *(size_t*)i = (size_t)CustomFreeLibrary; matchedImports++; } else if (ptr == Kernel32Data[eCreateEventA][ProcAddress]) { if (exe) Kernel32Data[eCreateEventA][IATPtr] = i; *(size_t*)i = (size_t)CustomCreateEventA; matchedImports++; } else if (ptr == Kernel32Data[eCreateEventW][ProcAddress]) { if (exe) Kernel32Data[eCreateEventW][IATPtr] = i; *(size_t*)i = (size_t)CustomCreateEventW; matchedImports++; } else if (ptr == Kernel32Data[eGetSystemInfo][ProcAddress]) { if (exe) Kernel32Data[eGetSystemInfo][IATPtr] = i; *(size_t*)i = (size_t)CustomGetSystemInfo; matchedImports++; } else if (ptr == Kernel32Data[eInterlockedCompareExchange][ProcAddress]) { if (exe) Kernel32Data[eInterlockedCompareExchange][IATPtr] = i; *(size_t*)i = (size_t)CustomInterlockedCompareExchange; matchedImports++; } else if (ptr == Kernel32Data[eSleep][ProcAddress]) { if (exe) Kernel32Data[eSleep][IATPtr] = i; *(size_t*)i = (size_t)CustomSleep; matchedImports++; } VirtualProtect((size_t*)i, sizeof(size_t), dwProtect[0], &dwProtect[1]); } }; static auto getSection = [](const PIMAGE_NT_HEADERS nt_headers, unsigned section) -> PIMAGE_SECTION_HEADER { return reinterpret_cast( (UCHAR*)nt_headers->OptionalHeader.DataDirectory + nt_headers->OptionalHeader.NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY) + section * sizeof(IMAGE_SECTION_HEADER)); }; static auto getSectionEnd = [](IMAGE_NT_HEADERS* ntHeader, size_t inst) -> auto { auto sec = getSection(ntHeader, ntHeader->FileHeader.NumberOfSections - 1); auto secSize = max(sec->SizeOfRawData, sec->Misc.VirtualSize); auto end = inst + max(sec->PointerToRawData, sec->VirtualAddress) + secSize; return end; }; auto hExecutableInstance_end = getSectionEnd(ntHeader, hExecutableInstance); // Find kernel32.dll for (size_t i = 0; i < nNumImports; i++) { if ((size_t)(hExecutableInstance + (pImports + i)->Name) < hExecutableInstance_end) { if (!_stricmp((const char*)(hExecutableInstance + (pImports + i)->Name), "KERNEL32.DLL")) PatchIAT(hExecutableInstance + (pImports + i)->FirstThunk, 0, hExecutableInstance_end); } } // Fixing ordinals auto szSelfName = GetSelfName(); static auto PatchOrdinals = [&szSelfName](size_t hInstance) { IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hInstance + ((IMAGE_DOS_HEADER*)hInstance)->e_lfanew); IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1; for (size_t i = 0; i < nNumImports; i++) { if ((size_t)(hInstance + (pImports + i)->Name) < getSectionEnd(ntHeader, (size_t)hInstance)) { if (iequals(szSelfName, (to_wstring((const char*)(hInstance + (pImports + i)->Name))))) { PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(hInstance + (pImports + i)->OriginalFirstThunk); size_t j = 0; while (thunk->u1.Function) { if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) { PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)(hInstance + thunk->u1.AddressOfData); void** p = (void**)(hInstance + (pImports + i)->FirstThunk); if (iequals(szSelfName, L"dinput8.dll")) { DWORD Protect; VirtualProtect(&p[j], 4, PAGE_EXECUTE_READWRITE, &Protect); if ((IMAGE_ORDINAL(thunk->u1.Ordinal)) == 1) p[j] = _DirectInput8Create; } } ++thunk; } } } } }; ModuleList dlls; dlls.Enumerate(ModuleList::SearchLocation::LocalOnly); for (auto& e : dlls.m_moduleList) { PatchOrdinals((size_t)std::get(e)); } return matchedImports > 0; } LONG WINAPI CustomUnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) { // step 1: write minidump wchar_t modulename[MAX_PATH]; wchar_t filename[MAX_PATH]; wchar_t timestamp[128]; __time64_t time; struct tm ltime; HANDLE hFile; HWND hWnd; wchar_t* modulenameptr = NULL; if (GetModuleFileNameW(GetModuleHandle(NULL), modulename, _countof(modulename)) != 0) { modulenameptr = wcsrchr(modulename, '\\'); *modulenameptr = L'\0'; modulenameptr += 1; } else { *modulenameptr = L'err.err'; } _time64(&time); _localtime64_s(<ime, &time); wcsftime(timestamp, _countof(timestamp), L"%Y%m%d%H%M%S", <ime); swprintf_s(filename, L"%s\\%s\\%s.%s.dmp", modulename, L"logs", modulenameptr, timestamp); hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION ex; memset(&ex, 0, sizeof(ex)); ex.ThreadId = GetCurrentThreadId(); ex.ExceptionPointers = ExceptionInfo; ex.ClientPointers = TRUE; if (FAILED(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithDataSegs, &ex, NULL, NULL))) { } CloseHandle(hFile); } // step 2: write log // Logs exception into buffer and writes to file swprintf_s(filename, L"%s\\%s\\%s.%s.log", modulename, L"logs", modulenameptr, timestamp); hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { auto Log = [ExceptionInfo, hFile](char* buffer, size_t size, bool reg, bool stack, bool trace) { if (LogException(buffer, size, (LPEXCEPTION_POINTERS)ExceptionInfo, reg, stack, trace)) { DWORD NumberOfBytesWritten = 0; WriteFile(hFile, buffer, strlen(buffer), &NumberOfBytesWritten, NULL); } }; // Try to make a very descriptive exception, for that we need to malloc a huge buffer... if (auto buffer = (char*)malloc(max_logsize_ever)) { Log(buffer, max_logsize_ever, true, true, true); free(buffer); } else { // Use a static buffer, no need for any allocation static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump; static char static_buf[size]; static_assert(size <= max_static_buffer, "Static buffer is too big"); Log(buffer = static_buf, sizeof(static_buf), true, true, false); } CloseHandle(hFile); } // step 3: exit the application ShowCursor(TRUE); hWnd = FindWindowW(0, L""); SetForegroundWindow(hWnd); return EXCEPTION_CONTINUE_SEARCH; } void Init() { SetProcessDPIAware(); auto dir = GetModuleFileNameW(hm).substr(0, GetModuleFileNameW(hm).find_last_of(L"/\\") + 1); SetCurrentDirectoryW(dir.c_str()); std::wstring modulePath = GetModuleFileNameW(hm); std::wstring moduleName = modulePath.substr(modulePath.find_last_of(L"/\\") + 1); moduleName.resize(moduleName.find_last_of(L'.')); modulePath.resize(modulePath.find_last_of(L"/\\") + 1); iniPaths.emplace_back(modulePath + moduleName + L".ini"); const auto CONFIG_FILE = L"plugins\\config.ini"; const auto CONFIG_FILE_TEMPLATE = L"plugins\\config_template.bin"; iniPaths.emplace_back(modulePath + CONFIG_FILE); // initialize configuration files. CopyFileW(CONFIG_FILE_TEMPLATE, CONFIG_FILE, true); const auto COMPONENTS_TEMPLATE = L"plugins\\components_template.bin"; const auto COMPONENTS = L"plugins\\components.ini"; CopyFileW(COMPONENTS_TEMPLATE, COMPONENTS, true); const auto KEYCONFIG_TEMPLATE = L"plugins\\keyconfig_template.bin"; const auto KEYCONFIG = L"plugins\\keyconfig.ini"; CopyFileW(KEYCONFIG_TEMPLATE, KEYCONFIG, true); const auto PLAYERDATA_TEMPLATE = L"plugins\\playerdata_template.bin"; const auto PLAYERDATA = L"plugins\\playerdata.ini"; CopyFileW(PLAYERDATA_TEMPLATE, PLAYERDATA, true); const auto DIVASOUND_TEMPLATE = L"plugins\\DivaSound_template.bin"; const auto DIVASOUND = L"plugins\\DivaSound.ini"; CopyFileW(DIVASOUND_TEMPLATE, DIVASOUND, true); const auto SHADERPATCH_TEMPLATE = L"plugins\\ShaderPatch_template.bin"; const auto SHADERPATCH = L"plugins\\ShaderPatch.ini"; CopyFileW(SHADERPATCH_TEMPLATE, SHADERPATCH, true); const auto SHADERPATCHCONFIG_TEMPLATE = L"plugins\\ShaderPatchConfig_template.bin"; const auto SHADERPATCHCONFIG = L"plugins\\ShaderPatchConfig.ini"; CopyFileW(SHADERPATCHCONFIG_TEMPLATE, SHADERPATCHCONFIG, true); if ((PathFileExistsW(CONFIG_FILE_TEMPLATE) && !PathFileExistsW(CONFIG_FILE)) || (PathFileExistsW(COMPONENTS_TEMPLATE) && !PathFileExistsW(COMPONENTS)) || (PathFileExistsW(KEYCONFIG_TEMPLATE) && !PathFileExistsW(KEYCONFIG)) || (PathFileExistsW(PLAYERDATA_TEMPLATE) && !PathFileExistsW(PLAYERDATA)) || (PathFileExistsW(DIVASOUND_TEMPLATE) && !PathFileExistsW(DIVASOUND)) || (PathFileExistsW(SHADERPATCH_TEMPLATE) && !PathFileExistsW(SHADERPATCH)) || (PathFileExistsW(SHADERPATCHCONFIG_TEMPLATE) && !PathFileExistsW(SHADERPATCHCONFIG)) ) MessageBoxW(0, L"Could not install configuration files. Possible causes:\n\n- PD Loader was not installed correctly\n- The game is on a read-only drive\n- No privileges to write in the folder", L"PD Loader", MB_ICONWARNING); CreateDirectoryW(L"plugins\\pv_equip", NULL); const auto eq_modules = L"plugins\\pv_equip\\modules.ini"; if (!PathFileExistsW(eq_modules)) { std::ofstream stream(eq_modules); stream << "[modules]\n# Manual editing is NOT recommended as the game will save here during gameplay"; stream.close(); } const auto eq_sfx = L"plugins\\pv_equip\\sfx.ini"; if (!PathFileExistsW(eq_sfx)) { std::ofstream stream(eq_sfx); stream << "[SFX]\n# INI Format = ' pv.xxx.btn = sfx id (ex. 5) '\n# pv.001.btn=2 for example\n# pv.xxx.btn, pv.xxx.chain, pv.xxx.slide & pv.xxx.touch can all be assigned using the format"; stream.close(); } const auto eq_skins = L"plugins\\pv_equip\\skins.ini"; if (!PathFileExistsW(eq_skins)) { std::ofstream stream(eq_skins); stream << "[skins]\n# INI Format = ' pv.xxx.skin = skin ID (ex. 123) '\n# pv.001.skin=100 for example"; stream.close(); } const std::filesystem::path databank_template = L"ram\\databank_template_v2"; const std::filesystem::path databank = L"ram\\databank"; if (!std::filesystem::exists(databank)&&std::filesystem::exists(databank_template)) { try { std::filesystem::create_directories(databank); std::filesystem::copy(databank_template, databank, std::filesystem::copy_options::recursive); } catch (std::exception& e) { std::cout << "[PD Loader] databank copy exception: " << e.what() << std::endl; MessageBoxW(0, L"Could not install databank files. Is the game in a read-only folder?\n\n", L"PD Loader", MB_ICONWARNING); } } std::wstring m = GetModuleFileNameW(NULL); m = m.substr(0, m.find_last_of(L"/\\") + 1) + L"logs"; auto FolderExists = [](LPCWSTR szPath) -> BOOL { DWORD dwAttrib = GetFileAttributes(szPath); return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); }; if (FolderExists(m.c_str())) { SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter); // Now stub out CustomUnhandledExceptionFilter so NO ONE ELSE can set it! uint32_t ret = 0x909090C3; //ret DWORD protect[2]; VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), PAGE_EXECUTE_READWRITE, &protect[0]); memcpy(&SetUnhandledExceptionFilter, &ret, sizeof(ret)); VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), protect[0], &protect[1]); } DeleteFileW(L"~dinput8.dll"); std::wstring szSelfName = GetSelfName(); if (iequals(szSelfName, L"DINPUT8.dll")) { WIN32_FIND_DATAW fd; HANDLE dnsloader = FindFirstFileW(L"dnsapi.dll", &fd); if (dnsloader != INVALID_HANDLE_VALUE) { MessageBoxW(0, L"PD Loader was loaded from \"dinput8.dll\", but \"dnsapi.dll\" was found. Aborting.\nPlease refer to the quick start guide or the wiki.", L"PD Loader", MB_ICONERROR); exit(1); } } else if (iequals(szSelfName, L"DNSAPI.dll")) { WIN32_FIND_DATAW fd; HANDLE dnsloader = FindFirstFileW(L"dinput8.dll", &fd); if (dnsloader != INVALID_HANDLE_VALUE) { auto dinput_handle = GetModuleHandleW(L"DINPUT8.dll"); if (dinput_handle&&!FreeLibrary(dinput_handle)) { MessageBoxW(0, L"PD Loader was loaded from \"dnsapi.dll\", but \"dinput8.dll\" was found and PD Loader could not unload it. Please delete \"dinput8.dll\".", L"PD Loader", MB_ICONERROR); exit(1); } else if (!MoveFileExW(L"dinput8.dll", L"~dinput8.dll", MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { MessageBoxW(0, L"PD Loader was loaded from \"dnsapi.dll\", but \"dinput8.dll\" was found and PD Loader could not delete it automatically\nIs it read-only?", L"PD Loader", MB_ICONERROR); exit(1); } } if(IsWindows8OrGreater()) { if (MoveFileExW(L"dnsapi.dll", L"dinput8.dll", MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { WCHAR DIVA_EXECUTABLE[MAX_PATH]; GetModuleFileNameW(NULL, DIVA_EXECUTABLE, MAX_PATH); LPWSTR DIVA_COMMAND_LINE = GetCommandLineW(); STARTUPINFOW si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); CreateProcessW(DIVA_EXECUTABLE, DIVA_COMMAND_LINE, NULL, NULL, false, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); exit(0); } else MessageBoxW(0, L"It is highly recommended to rename \"dnsapi.dll\" \"dinput8.dll\" on Windows 8/8.1/10 to avoid issues, but PD Loader could not rename the file automatically.\nIs it read-only?", L"PD Loader", MB_ICONWARNING); } } else { MessageBoxW(0, L"Supported file names:\n\"dnsapi.dll\" (Windows Vista/7)\n\"dinput8.dll\"", L"PD Loader", MB_ICONERROR); exit(1); } LoadEverything(); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID /*lpReserved*/) { if (reason == DLL_PROCESS_ATTACH) { hm = hModule; Init(); } return TRUE; } ================================================ FILE: source-code/source/PD-Loader/exception.hpp ================================================ #pragma once /* * Unhandled Exception Tracer * by LINK/2012 * * This source code is offered for use in the public domain. You may * use, modify or distribute it freely. * * This code is distributed in the hope that it will be useful but * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY * DISCLAIMED. This includes but is not limited to warranties of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #include #include #include #include #include #include #pragma comment(lib, "Dbghelp.lib") /* * Special Note: * Try not to allocate any memory in this file! * Allocation after a exception may not be a good idea... */ #define LODWORD(_qw) ((DWORD)(_qw)) #define HIDWORD(_qw) ((DWORD)(((_qw) >> 32) & 0xffffffff)) // General constants static const int sizeof_word = sizeof(void*); // Size of a CPU word (4 bytes on x86) static const int max_chars_per_print = MAX_PATH + 256; // Max characters per Print() call static const int symbol_max = 256; // Max size of a symbol (func symbol, var symbol, etc) static const int max_static_buffer = 4096; // Max static buffer for logging // Stackdump constants static const int stackdump_max_words = 60; // max number of CPU words that the stackdump should dump static const int stackdump_words_per_line = 6; // max CPU words in a single line static const int stackdump_line_count = (stackdump_max_words / stackdump_words_per_line) + 1; // Backtrace constants static const int max_backtrace_ever = 100; static const int max_backtrace = 20; // Maximum log size constants static const int max_logsize_basic = (MAX_PATH + 200); // module path + other text static const int max_logsize_regs = 32 + (4 * 4 * 28); // info + (regsPerLine * numLines * charsPerReg) static const int max_logsize_stackdump = 32 + 80 + (stackdump_line_count * 32) + (10 * stackdump_words_per_line * stackdump_line_count); static const int max_logsize_backtrace = 32 + max_backtrace_ever * (MAX_PATH + symbol_max + 90); static const int max_logsize_ever = 32 + max_logsize_basic + max_logsize_regs + max_logsize_stackdump + max_logsize_backtrace; // Internal class ExceptionTracer; class StackTrace; static HMODULE GetModuleFromAddress(LPVOID address); static const char* GetExceptionCodeString(unsigned int code); static const char* FindModuleName(HMODULE module, char* output, DWORD size); static int LogException(char* buffer, size_t max, LPEXCEPTION_POINTERS pException, bool bLogRegisters, bool bLogStack, bool bLogBacktrace); static LPTOP_LEVEL_EXCEPTION_FILTER PrevFilter = nullptr; static void(*ExceptionCallback)(const char* buffer) = nullptr; // Exportable int InstallExceptionCatcher(void(*OnException)(const char* log)); /* * ExceptionTrace * This class is responssible for tracing all possible informations about an LPEXCEPTION_POINTER */ class ExceptionTracer { public: ExceptionTracer(char* buffer, size_t max, LPEXCEPTION_POINTERS pException); void PrintUnhandledException(); void PrintRegisters(); void PrintStackdump(); void PrintBacktrace(); void EnterScope(); void LeaveScope(); void Print(const char* fmt, ...); void NewLine() { Print("\n%s", spc); } protected: EXCEPTION_POINTERS& exception; EXCEPTION_RECORD& record; CONTEXT& context; HMODULE module; char* buffer; // Logging buffer size_t len; // Logged length size_t max; // Maximum we can log in that buffer char spc[(10 * 4) + 1]; // Scope/spacing buffer, 4 spaces per scope, max 10 scopes size_t nspc; // Number spaces used up there }; /* * StackTracer * Responssible for backtracing an stack from a context */ class StackTracer { public: struct Trace { // The following values may be null (any) HMODULE module; // The module the func related to this frame is located void* pc; // Program counter at func related to this frame (EIP) void* ret; // Return address for the frame void* frame; // The frame address (EBP) void* stack; // The stack pointer at the frame (ESP) }; StackTracer(const CONTEXT& context); Trace* Walk(); private: Trace trace; DWORD old_options; CONTEXT context; STACKFRAME64 frame; }; /* * TheUnhandledExceptionFilter * Logs an unhandled exception */ static LONG CALLBACK TheUnhandledExceptionFilter(LPEXCEPTION_POINTERS pException) { // Logs exception into buffer and calls the callback auto Log = [pException](char* buffer, size_t size, bool reg, bool stack, bool trace) { if (LogException(buffer, size, (LPEXCEPTION_POINTERS)pException, reg, stack, trace)) ExceptionCallback(buffer); }; // Try to make a very descriptive exception, for that we need to malloc a huge buffer... if (auto buffer = (char*)malloc(max_logsize_ever)) { Log(buffer, max_logsize_ever, true, true, true); free(buffer); } else { // Use a static buffer, no need for any allocation static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump; static char static_buf[size]; static_assert(size <= max_static_buffer, "Static buffer is too big"); Log(buffer = static_buf, sizeof(static_buf), true, true, false); } // Continue exception propagation return (PrevFilter ? PrevFilter(pException) : EXCEPTION_CONTINUE_SEARCH); // I'm not really sure about this return } /* * InstallExceptionCatcher * Installs a exception handler to call the specified callback when it happens with human readalbe information. */ int InstallExceptionCatcher(void(*cb)(const char* log)) { PrevFilter = SetUnhandledExceptionFilter(TheUnhandledExceptionFilter); ExceptionCallback = cb; return 1; } /* * LogException * Takes an LPEXCEPTION_POINTERS and transforms in a string that is put in the logging steam */ static int LogException(char* buffer, size_t max, LPEXCEPTION_POINTERS pException, bool bLogRegisters, bool bLogStack, bool bLogBacktrace) { ExceptionTracer trace(buffer, max, pException); trace.PrintUnhandledException(); trace.EnterScope(); if (bLogRegisters) trace.PrintRegisters(); if (bLogStack) trace.PrintStackdump(); if (bLogBacktrace) trace.PrintBacktrace(); trace.LeaveScope(); return 1; } /* * ExceptionTracer * Contructs a exception trace object, responssible for tracing informations about an exception */ ExceptionTracer::ExceptionTracer(char* buffer, size_t max, LPEXCEPTION_POINTERS pException) : buffer(buffer), exception(*pException), record(*pException->ExceptionRecord), context(*pException->ContextRecord) { this->buffer = buffer; this->buffer[this->len = 0] = 0; this->spc[this->nspc = 0] = 0; this->max = max; // Acquiere common information that we'll access this->module = GetModuleFromAddress(record.ExceptionAddress); } /* * Print * Prints some formated text into the logging buffer */ void ExceptionTracer::Print(const char* fmt, ...) { va_list va; va_start(va, fmt); if ((this->max - this->len) > max_chars_per_print) this->len += vsprintf(&this->buffer[len], fmt, va); va_end(va); } /* * EnterScope * Enters a new scope in the logging buffer (scope is related to indentation) * This also prints a new line */ void ExceptionTracer::EnterScope() { nspc += 4; spc[nspc - 4] = ' '; spc[nspc - 3] = ' '; spc[nspc - 2] = ' '; spc[nspc - 1] = ' '; spc[nspc - 0] = 0; NewLine(); } /* * LeaveScope * Leaves the scope */ void ExceptionTracer::LeaveScope() { assert(nspc > 0); nspc -= 4; spc[nspc] = 0; NewLine(); } /* * PrintUnhandledException * Prints the well known "Unhandled exception at ..." into the logging buffer */ void ExceptionTracer::PrintUnhandledException() { char module_name[MAX_PATH]; auto dwExceptionCode = record.ExceptionCode; uintptr_t address = (uintptr_t)record.ExceptionAddress; // Find out our module name for logging if (!this->module || !GetModuleFileNameA(this->module, module_name, sizeof(module_name))) strcpy(module_name, "unknown"); // Log the exception in a similar format similar to debuggers format Print("Unhandled exception at 0x%p in %s", address, FindModuleName(module, module_name, sizeof(module_name))); if (module) Print(" (+0x%x)", address - (uintptr_t)(module)); Print(": 0x%X: %s", dwExceptionCode, GetExceptionCodeString(dwExceptionCode)); // If exception is IN_PAGE_ERROR or ACCESS_VIOLATION, we have additional information such as an address if (dwExceptionCode == EXCEPTION_IN_PAGE_ERROR || dwExceptionCode == EXCEPTION_ACCESS_VIOLATION) { auto rw = (DWORD)record.ExceptionInformation[0]; // read or write? auto addr = (ULONG_PTR)record.ExceptionInformation[1]; // which address? Print(" %s 0x%p", rw == 0 ? "reading location" : rw == 1 ? "writing location" : rw == 8 ? "DEP at" : "", addr); // IN_PAGE_ERROR have another information... if (dwExceptionCode == EXCEPTION_IN_PAGE_ERROR) { NewLine(); Print("Underlying NTSTATUS code that resulted in the exception is 0x%p", record.ExceptionInformation[2]); } } Print("."); } /* * PrintRegisters * Prints the content of the assembly registers into the logging buffer */ void ExceptionTracer::PrintRegisters() { int regs_in_line = 0; // Amount of registers currently printed on this line // Prints a register, followed by spaces auto PrintRegister = [this, ®s_in_line](const char* reg_name, size_t reg_value, const char* spaces) { Print("%s: 0x%p%s", reg_name, reg_value, spaces); if (++regs_in_line >= 4) { this->NewLine(); regs_in_line = 0; } }; auto PrintFloatRegister = [this, ®s_in_line](const char* reg_name, int reg_num, uint32_t reg_value1, uint32_t reg_value2, uint32_t reg_value3, uint32_t reg_value4) { Print("%s%02d: 0x%08X 0x%08X 0x%08X 0x%08X [ %f %f %f %f ]", reg_name, reg_num, reg_value1, reg_value2, reg_value3, reg_value4, *(float*)& reg_value1, *(float*)& reg_value2, *(float*)& reg_value3, *(float*)& reg_value4); if (++regs_in_line >= 1) { this->NewLine(); regs_in_line = 0; } }; // Prints a general purposes register auto PrintIntRegister = [PrintRegister](const char* reg_name, size_t reg_value) { PrintRegister(reg_name, reg_value, " "); }; // Prints a segment register auto PrintSegRegister = [PrintRegister](const char* reg_name, size_t reg_value) { PrintRegister(reg_name, reg_value, " "); }; Print("Register dump:"); EnterScope(); { // Print main general purposes registers if (context.ContextFlags & CONTEXT_INTEGER) { #if !_M_X64 PrintIntRegister("EAX", context.Eax); PrintIntRegister("EBX", context.Ebx); PrintIntRegister("ECX", context.Ecx); PrintIntRegister("EDX", context.Edx); PrintIntRegister("EDI", context.Edi); PrintIntRegister("ESI", context.Esi); #else PrintIntRegister("RAX", context.Rax); PrintIntRegister("RCX", context.Rcx); PrintIntRegister("RDX", context.Rdx); PrintIntRegister("RBX", context.Rbx); PrintIntRegister("RBP", context.Rbp); PrintIntRegister("RSI", context.Rsi); PrintIntRegister("RDI", context.Rdi); PrintIntRegister("R08", context.R8); PrintIntRegister("R09", context.R9); PrintIntRegister("R10", context.R10); PrintIntRegister("R11", context.R11); PrintIntRegister("R12", context.R12); PrintIntRegister("R13", context.R13); PrintIntRegister("R14", context.R14); PrintIntRegister("R15", context.R15); #endif } // Print control registers if (context.ContextFlags & CONTEXT_CONTROL) { #if !_M_X64 PrintIntRegister("EBP", context.Ebp); PrintIntRegister("EIP", context.Eip); PrintIntRegister("ESP", context.Esp); PrintIntRegister("EFL", context.EFlags); this->NewLine(); this->NewLine(); regs_in_line = 0; PrintSegRegister("CS", context.SegCs); PrintSegRegister("SS", context.SegSs); #else PrintIntRegister("RIP", context.Rip); PrintIntRegister("RSP", context.Rsp); PrintIntRegister("EFL", context.EFlags); this->NewLine(); this->NewLine(); regs_in_line = 0; PrintSegRegister("CS", context.SegCs); PrintSegRegister("SS", context.SegSs); #endif } this->NewLine(); regs_in_line = 0; // Print segment registers if (context.ContextFlags & CONTEXT_SEGMENTS) { PrintSegRegister("GS", context.SegGs); PrintSegRegister("FS", context.SegFs); this->NewLine(); regs_in_line = 0; PrintSegRegister("ES", context.SegEs); PrintSegRegister("DS", context.SegDs); } this->NewLine(); this->NewLine(); regs_in_line = 0; // Print floating point registers if (context.ContextFlags & CONTEXT_FLOATING_POINT) { for (int i = 0; i < 8; i++) { #if !_M_X64 auto f = *(M128A*) & (context.FloatSave.RegisterArea[i * 10]); PrintFloatRegister("ST", i, LODWORD(f.Low), HIDWORD(f.Low), LODWORD(f.High), HIDWORD(f.High)); #else PrintFloatRegister("ST", i, LODWORD(context.FltSave.FloatRegisters[i].Low), HIDWORD(context.FltSave.FloatRegisters[i].Low), LODWORD(context.FltSave.FloatRegisters[i].High), HIDWORD(context.FltSave.FloatRegisters[i].High)); #endif } this->NewLine(); for (int i = 0; i < 16; i++) { #if !_M_X64 auto f = *(M128A*) & (context.ExtendedRegisters[(i + 10) * 16]); PrintFloatRegister("XMM", i, LODWORD(f.Low), HIDWORD(f.Low), LODWORD(f.High), HIDWORD(f.High)); if (i >= 7) break; #else PrintFloatRegister("XMM", i, LODWORD(context.FltSave.XmmRegisters[i].Low), HIDWORD(context.FltSave.XmmRegisters[i].Low), LODWORD(context.FltSave.XmmRegisters[i].High), HIDWORD(context.FltSave.XmmRegisters[i].High)); #endif } } } LeaveScope(); } /* * PrintStackdump * Prints the content of the stack into the logging buffer */ void ExceptionTracer::PrintStackdump() { // We need the ESP of the exception context to execute a stack dump, make sure we have access to it if ((context.ContextFlags & CONTEXT_CONTROL) == 0) return; static const auto align = sizeof_word; // Stack aligment static const auto max_words_in_line_magic = stackdump_words_per_line + 10; MEMORY_BASIC_INFORMATION mbi; #if !_M_X64 uintptr_t base, bottom, top = (uintptr_t)context.Esp; #else uintptr_t base, bottom, top = (uintptr_t)context.Rsp; #endif auto words_in_line = max_words_in_line_magic; // Finds the bottom of the stack from it's base pointer // Note: mbi will get overriden on this function auto GetStackBottom = [&mbi](uintptr_t base) { VirtualQuery((void*)base, &mbi, sizeof(mbi)); // Find uncommited region of the stack VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find guard page VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find commited region of the stack auto last = (uintptr_t)mbi.BaseAddress; return (base + (last - base) + mbi.RegionSize); // base + distanceToLastRegion + lastRegionSize }; // Prints an CPU word at the specified stack address auto PrintWord = [this, &words_in_line](uintptr_t addr) { if (words_in_line++ >= stackdump_words_per_line) { // Print new line only if it's not the first time we enter here (i.e. words_in_line has magical value) if (words_in_line != max_words_in_line_magic + 1) NewLine(); words_in_line = 1; Print("0x%p: ", addr); } Print(" %p", *(size_t*)addr); }; Print("Stack dump:"); EnterScope(); { // Makes sure the pointer at top (ESP) is valid and readable memory if (VirtualQuery((void*)(top), &mbi, sizeof(mbi)) && (mbi.State & MEM_COMMIT) && (mbi.Protect & (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_READONLY)) != 0) { base = (uintptr_t)mbi.AllocationBase; // Base of the stack (uncommited) bottom = GetStackBottom(base); // Bottom of the stack (commited) // Align the stack top (esp) in a 4 bytes boundary auto remainder = top % align; uintptr_t current = remainder ? top + (align - remainder) : top; // on x86 stack grows downward! (i.e. from bottom to base) for (int n = 0; n < stackdump_max_words && current < bottom; ++n, current += align) PrintWord(current); NewLine(); Print("base: 0x%p top: 0x%p bottom: 0x%p", base, top, bottom); NewLine(); } } LeaveScope(); } /* * PrintBacktrace * Prints a call backtrace into the logging buffer */ void ExceptionTracer::PrintBacktrace() { StackTracer tracer(this->context); char module_name[MAX_PATH]; char sym_buffer[sizeof(SYMBOL_INFO) + symbol_max]; int backtrace_count = 0; // Num of frames traced bool has_symbol_api = false; // True if we have the symbol API available for use DWORD old_options; // Saves old symbol API options SYMBOL_INFO& symbol = *(SYMBOL_INFO*)sym_buffer; symbol.SizeOfStruct = sizeof(SYMBOL_INFO); symbol.MaxNameLen = symbol_max; // Tries to get the symbol api if (SymInitialize(GetCurrentProcess(), 0, TRUE)) { has_symbol_api = true; old_options = SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_NO_PROMPTS | SYMOPT_FAIL_CRITICAL_ERRORS); } Print("Backtrace (may be wrong):"); EnterScope(); { // Walks on the stack until there's no frame to trace or we traced 'max_backtrace' frames while (auto trace = tracer.Walk()) { if (++backtrace_count >= max_backtrace) break; bool has_sym = false; // This EIP has a symbol associated with it? DWORD64 displacement; // EIP displacement relative to symbol // If we have access to the symbol api, try to get symbol name from pc (eip) if (has_symbol_api) has_sym = trace->pc ? !!SymFromAddr(GetCurrentProcess(), (DWORD64)trace->pc, &displacement, &symbol) : false; // Print everything up, this.... Ew, this looks awful! Print(backtrace_count == 1 ? "=>" : " "); // First line should have '=>' to specify where it crashed Print("0x%p ", trace->pc); // Print EIP at frame if (has_sym) Print("%s+0x%x ", symbol.Name, (DWORD)displacement); // Print frame func symbol Print("in %s (+0x%x) ", // Print module trace->module ? FindModuleName(trace->module, module_name, sizeof(module_name)) : "unknown", (uintptr_t)(trace->pc) - (uintptr_t)(trace->module) // Module displacement ); if (trace->frame) Print("(0x%p) ", trace->frame); // Print frame pointer NewLine(); } } LeaveScope(); // Cleanup the symbol api if (has_symbol_api) { SymSetOptions(old_options); SymCleanup(GetCurrentProcess()); } } /* * GetExceptionCodeString * Returns an description by an exception code */ static const char* GetExceptionCodeString(unsigned int code) { switch (code) { case EXCEPTION_ACCESS_VIOLATION: return "Access violation"; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "Array bounds exceeded"; case EXCEPTION_BREAKPOINT: return "Breakpoint exception"; case EXCEPTION_DATATYPE_MISALIGNMENT: return "Data type misalignment exception"; case EXCEPTION_FLT_DENORMAL_OPERAND: return "Denormal float operand"; case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "Floating-point division by zero"; case EXCEPTION_FLT_INEXACT_RESULT: return "Floating-point inexact result"; case EXCEPTION_FLT_INVALID_OPERATION: return "Floating-point invalid operation"; case EXCEPTION_FLT_OVERFLOW: return "Floating-point overflow"; case EXCEPTION_FLT_STACK_CHECK: return "Floating-point stack check"; case EXCEPTION_FLT_UNDERFLOW: return "Floating-point underflow"; case EXCEPTION_ILLEGAL_INSTRUCTION: return "Illegal instruction."; case EXCEPTION_IN_PAGE_ERROR: return "In page error"; case EXCEPTION_INT_DIVIDE_BY_ZERO: return "Integer division by zero"; case EXCEPTION_INT_OVERFLOW: return "Integer overflow"; case EXCEPTION_INVALID_DISPOSITION: return "Invalid disposition"; case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "Non-continuable exception"; case EXCEPTION_PRIV_INSTRUCTION: return "Privileged instruction"; case EXCEPTION_SINGLE_STEP: return "Single step exception"; case EXCEPTION_STACK_OVERFLOW: return "Stack overflow"; default: return "NO_DESCRIPTION"; } } /* * FindModuleName * Finds module filename or "unknown" */ static const char* FindModuleName(HMODULE module, char* output, DWORD maxsize) { if (GetModuleFileNameA(module, output, maxsize)) { // Finds the filename part in the output string char* filename = strrchr(output, '\\'); if (!filename) filename = strrchr(output, '/'); // If filename found (i.e. output isn't already a filename but full path), make output be filename if (filename) { size_t size = strlen(++filename); memmove(output, filename, size); output[size] = 0; } } else { // Unknown module strcpy(output, "unknown"); } return output; } /* * GetModuleFromAddress * Finds module handle from some address inside it */ static HMODULE GetModuleFromAddress(LPVOID address) { HMODULE module; if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (char*)address, &module)) return module; return nullptr; } /* * StackTracer * Constructs the tracer, we basically need to initialize the symbol api */ StackTracer::StackTracer(const CONTEXT& context) { // Initialise basic values memset(&this->frame, 0, sizeof(frame)); memcpy(&this->context, &context, sizeof(context)); // Setup the initial frame context #if !_M_X64 frame.AddrPC.Mode = AddrModeFlat; frame.AddrPC.Offset = context.Eip; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Ebp; frame.AddrStack.Mode = AddrModeFlat; frame.AddrStack.Offset = context.Esp; #else frame.AddrPC.Mode = AddrModeFlat; frame.AddrPC.Offset = context.Rip; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Rbp; frame.AddrStack.Mode = AddrModeFlat; frame.AddrStack.Offset = context.Rsp; #endif } /* * StackTracer::Walk * Walks on the stack, each walk is one frame of backtrace * Returns a frame or null if the walk on the park is not possible anymore */ StackTracer::Trace* StackTracer::Walk() { if (StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &frame, &context, NULL, NULL, NULL, NULL)) { trace.module = GetModuleFromAddress((void*)frame.AddrPC.Offset); trace.frame = (void*)frame.AddrFrame.Offset; trace.stack = (void*)frame.AddrStack.Offset; trace.pc = (void*)frame.AddrPC.Offset; trace.ret = (void*)frame.AddrReturn.Offset; return &trace; } return nullptr; } ================================================ FILE: source-code/source/PD-Loader/framework.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include #pragma once #include #include #include #include "ModuleList.h" #include #pragma intrinsic(_ReturnAddress) struct shared { FARPROC DllCanUnloadNow; FARPROC DllGetClassObject; FARPROC DllRegisterServer; FARPROC DllUnregisterServer; FARPROC DebugSetMute; void LoadOriginalLibrary(HMODULE dll) { DllCanUnloadNow = GetProcAddress(dll, "DllCanUnloadNow"); DllGetClassObject = GetProcAddress(dll, "DllGetClassObject"); DllRegisterServer = GetProcAddress(dll, "DllRegisterServer"); DllUnregisterServer = GetProcAddress(dll, "DllUnregisterServer"); DebugSetMute = GetProcAddress(dll, "DebugSetMute"); } } shared; struct dnsapi_dll { HMODULE dll; // generated using windows 7 dnsapi.dll // functions not in vista are commented out manually // needed windows 8+ have been manually added so they can be stubbed FARPROC BreakRecordsIntoBlob; FARPROC CombineRecordsInBlob; FARPROC DnsAcquireContextHandle_A; FARPROC DnsAcquireContextHandle_W; FARPROC DnsAllocateRecord; FARPROC DnsApiAlloc; FARPROC DnsApiAllocZero; FARPROC DnsApiFree; FARPROC DnsApiHeapReset; FARPROC DnsApiRealloc; FARPROC DnsApiSetDebugGlobals; FARPROC DnsAsyncRegisterHostAddrs; FARPROC DnsAsyncRegisterInit; FARPROC DnsAsyncRegisterTerm; FARPROC DnsCancelQuery; FARPROC DnsCopyStringEx; FARPROC DnsCreateReverseNameStringForIpAddress; FARPROC DnsCreateStandardDnsNameCopy; FARPROC DnsCreateStringCopy; FARPROC DnsDhcpRegisterAddrs; FARPROC DnsDhcpRegisterHostAddrs; FARPROC DnsDhcpRegisterInit; FARPROC DnsDhcpRegisterTerm; FARPROC DnsDhcpRemoveRegistrations; FARPROC DnsDhcpSrvRegisterHostAddr; //FARPROC DnsDhcpSrvRegisterHostAddrEx; FARPROC DnsDhcpSrvRegisterHostName; //FARPROC DnsDhcpSrvRegisterHostNameEx; FARPROC DnsDhcpSrvRegisterInit; FARPROC DnsDhcpSrvRegisterInitialize; FARPROC DnsDhcpSrvRegisterTerm; FARPROC DnsDowncaseDnsNameLabel; FARPROC DnsExtractRecordsFromMessage_UTF8; FARPROC DnsExtractRecordsFromMessage_W; FARPROC DnsFindAuthoritativeZone; FARPROC DnsFlushResolverCache; FARPROC DnsFlushResolverCacheEntry_A; FARPROC DnsFlushResolverCacheEntry_UTF8; FARPROC DnsFlushResolverCacheEntry_W; FARPROC DnsFree; FARPROC DnsFreeConfigStructure; //FARPROC DnsFreePolicyConfig; //FARPROC DnsFreeProxyName; FARPROC DnsGetBufferLengthForStringCopy; FARPROC DnsGetCacheDataTable; FARPROC DnsGetDnsServerList; FARPROC DnsGetDomainName; FARPROC DnsGetLastFailedUpdateInfo; //FARPROC DnsGetPolicyTableInfo; //FARPROC DnsGetPolicyTableInfoPrivate; FARPROC DnsGetPrimaryDomainName_A; //FARPROC DnsGetProxyInfoPrivate; //FARPROC DnsGetProxyInformation; FARPROC DnsGlobals; FARPROC DnsIpv6AddressToString; FARPROC DnsIpv6StringToAddress; FARPROC DnsIsAMailboxType; FARPROC DnsIsStatusRcode; FARPROC DnsIsStringCountValidForTextType; FARPROC DnsLogEvent; FARPROC DnsLogIn; FARPROC DnsLogInit; FARPROC DnsLogIt; FARPROC DnsLogOut; FARPROC DnsLogTime; FARPROC DnsMapRcodeToStatus; FARPROC DnsModifyRecordsInSet_A; FARPROC DnsModifyRecordsInSet_UTF8; FARPROC DnsModifyRecordsInSet_W; FARPROC DnsNameCompareEx_A; FARPROC DnsNameCompareEx_UTF8; FARPROC DnsNameCompareEx_W; FARPROC DnsNameCompare_A; FARPROC DnsNameCompare_UTF8; FARPROC DnsNameCompare_W; FARPROC DnsNameCopy; FARPROC DnsNameCopyAllocate; FARPROC DnsNetworkInfo_CreateFromFAZ; FARPROC DnsNetworkInformation_CreateFromFAZ; FARPROC DnsNotifyResolver; FARPROC DnsNotifyResolverClusterIp; FARPROC DnsNotifyResolverEx; FARPROC DnsQueryConfig; FARPROC DnsQueryConfigAllocEx; FARPROC DnsQueryConfigDword; FARPROC DnsQueryEx; FARPROC DnsQueryExA; FARPROC DnsQueryExUTF8; FARPROC DnsQueryExW; FARPROC DnsQuery_A; FARPROC DnsQuery_UTF8; FARPROC DnsQuery_W; FARPROC DnsRecordBuild_UTF8; FARPROC DnsRecordBuild_W; FARPROC DnsRecordCompare; FARPROC DnsRecordCopyEx; FARPROC DnsRecordListFree; FARPROC DnsRecordSetCompare; FARPROC DnsRecordSetCopyEx; FARPROC DnsRecordSetDetach; FARPROC DnsRecordStringForType; FARPROC DnsRecordStringForWritableType; FARPROC DnsRecordTypeForName; FARPROC DnsRegisterClusterAddress; FARPROC DnsReleaseContextHandle; FARPROC DnsRemoveRegistrations; FARPROC DnsReplaceRecordSetA; FARPROC DnsReplaceRecordSetUTF8; FARPROC DnsReplaceRecordSetW; FARPROC DnsResolverOp; FARPROC DnsScreenLocalAddrsForRegistration; FARPROC DnsSetConfigDword; FARPROC DnsStatusString; FARPROC DnsStringCopyAllocateEx; //FARPROC DnsTraceServerConfig; FARPROC DnsUnicodeToUtf8; FARPROC DnsUpdate; //FARPROC DnsUpdateMachinePresence; FARPROC DnsUpdateTest_A; FARPROC DnsUpdateTest_UTF8; FARPROC DnsUpdateTest_W; FARPROC DnsUtf8ToUnicode; FARPROC DnsValidateNameOrIp_TempW; FARPROC DnsValidateName_A; FARPROC DnsValidateName_UTF8; FARPROC DnsValidateName_W; //FARPROC DnsValidateServerArray_A; // available in vista sp2 //FARPROC DnsValidateServerArray_W; // available in vista sp2 //FARPROC DnsValidateServerStatus; //FARPROC DnsValidateServer_A; // available in vista sp2 //FARPROC DnsValidateServer_W; // available in vista sp2 FARPROC DnsValidateUtf8Byte; FARPROC DnsWriteQuestionToBuffer_UTF8; FARPROC DnsWriteQuestionToBuffer_W; FARPROC DnsWriteReverseNameStringForIpAddress; FARPROC Dns_AddRecordsToMessage; FARPROC Dns_AllocateMsgBuf; FARPROC Dns_BuildPacket; FARPROC Dns_CleanupWinsock; FARPROC Dns_CloseConnection; FARPROC Dns_CloseSocket; FARPROC Dns_CreateMulticastSocket; FARPROC Dns_CreateSocket; FARPROC Dns_CreateSocketEx; FARPROC Dns_ExtractRecordsFromMessage; FARPROC Dns_FindAuthoritativeZoneLib; FARPROC Dns_FreeMsgBuf; FARPROC Dns_GetRandomXid; FARPROC Dns_InitializeMsgBuf; FARPROC Dns_InitializeMsgRemoteSockaddr; FARPROC Dns_InitializeWinsock; FARPROC Dns_OpenTcpConnectionAndSend; FARPROC Dns_ParseMessage; FARPROC Dns_ParsePacketRecord; FARPROC Dns_PingAdapterServers; FARPROC Dns_ReadPacketName; FARPROC Dns_ReadPacketNameAllocate; FARPROC Dns_ReadRecordStructureFromPacket; FARPROC Dns_RecvTcp; FARPROC Dns_ResetNetworkInfo; FARPROC Dns_SendAndRecvUdp; FARPROC Dns_SendEx; FARPROC Dns_SetRecordDatalength; FARPROC Dns_SetRecordsSection; FARPROC Dns_SetRecordsTtl; FARPROC Dns_SkipPacketName; FARPROC Dns_SkipToRecord; FARPROC Dns_UpdateLib; FARPROC Dns_UpdateLibEx; FARPROC Dns_WriteDottedNameToPacket; FARPROC Dns_WriteQuestionToMessage; FARPROC Dns_WriteRecordStructureToPacketEx; FARPROC ExtraInfo_Init; FARPROC Faz_AreServerListsInSameNameSpace; //FARPROC FlushDnsPolicyUnreachableStatus; FARPROC GetCurrentTimeInSeconds; FARPROC HostsFile_Close; FARPROC HostsFile_Open; FARPROC HostsFile_ReadLine; FARPROC IpHelp_IsAddrOnLink; FARPROC Local_GetRecordsForLocalName; FARPROC Local_GetRecordsForLocalNameEx; FARPROC NetInfo_Build; FARPROC NetInfo_Clean; FARPROC NetInfo_Copy; FARPROC NetInfo_Free; FARPROC NetInfo_GetAdapterByAddress; FARPROC NetInfo_GetAdapterByInterfaceIndex; FARPROC NetInfo_GetAdapterByName; FARPROC NetInfo_IsAddrConfig; FARPROC NetInfo_IsForUpdate; FARPROC NetInfo_ResetServerPriorities; //FARPROC NetInfo_UpdateServerReachability; FARPROC QueryDirectEx; FARPROC Query_Main; FARPROC Reg_FreeUpdateInfo; FARPROC Reg_GetValueEx; FARPROC Reg_ReadGlobalsEx; FARPROC Reg_ReadUpdateInfo; FARPROC Security_ContextListTimeout; FARPROC Send_AndRecvUdpWithParam; FARPROC Send_MessagePrivate; FARPROC Send_OpenTcpConnectionAndSend; FARPROC Socket_CacheCleanup; FARPROC Socket_CacheInit; FARPROC Socket_CleanupWinsock; FARPROC Socket_ClearMessageSockets; FARPROC Socket_CloseEx; FARPROC Socket_CloseMessageSockets; FARPROC Socket_Create; FARPROC Socket_CreateMulticast; FARPROC Socket_InitWinsock; FARPROC Socket_JoinMulticast; FARPROC Socket_RecvFrom; FARPROC Socket_SetMulticastInterface; FARPROC Socket_SetMulticastLoopBack; FARPROC Socket_SetTtl; FARPROC Socket_TcpListen; //FARPROC Trace_Reset; FARPROC Update_ReplaceAddressRecordsW; FARPROC Util_IsIp6Running; // DnsQueryEx and DnsCancelQuery are only present on win 8+ so they need stubs for older versions // they both take pointers to structs as parameters // (three for DnsQueryEx and one for DnsCancelQuery) // fortunately they should fit in registers so the stack doesn't matter static LONG WINAPI DnsQueryExStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } static LONG WINAPI DnsCancelQueryStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } void LoadOriginalLibrary(HMODULE module) { dll = module; shared.LoadOriginalLibrary(dll); BreakRecordsIntoBlob = GetProcAddress(dll, "BreakRecordsIntoBlob"); CombineRecordsInBlob = GetProcAddress(dll, "CombineRecordsInBlob"); DnsAcquireContextHandle_A = GetProcAddress(dll, "DnsAcquireContextHandle_A"); DnsAcquireContextHandle_W = GetProcAddress(dll, "DnsAcquireContextHandle_W"); DnsAllocateRecord = GetProcAddress(dll, "DnsAllocateRecord"); DnsApiAlloc = GetProcAddress(dll, "DnsApiAlloc"); DnsApiAllocZero = GetProcAddress(dll, "DnsApiAllocZero"); DnsApiFree = GetProcAddress(dll, "DnsApiFree"); DnsApiHeapReset = GetProcAddress(dll, "DnsApiHeapReset"); DnsApiRealloc = GetProcAddress(dll, "DnsApiRealloc"); DnsApiSetDebugGlobals = GetProcAddress(dll, "DnsApiSetDebugGlobals"); DnsAsyncRegisterHostAddrs = GetProcAddress(dll, "DnsAsyncRegisterHostAddrs"); DnsAsyncRegisterInit = GetProcAddress(dll, "DnsAsyncRegisterInit"); DnsAsyncRegisterTerm = GetProcAddress(dll, "DnsAsyncRegisterTerm"); DnsCancelQuery = GetProcAddress(dll, "DnsCancelQuery"); DnsCopyStringEx = GetProcAddress(dll, "DnsCopyStringEx"); DnsCreateReverseNameStringForIpAddress = GetProcAddress(dll, "DnsCreateReverseNameStringForIpAddress"); DnsCreateStandardDnsNameCopy = GetProcAddress(dll, "DnsCreateStandardDnsNameCopy"); DnsCreateStringCopy = GetProcAddress(dll, "DnsCreateStringCopy"); DnsDhcpRegisterAddrs = GetProcAddress(dll, "DnsDhcpRegisterAddrs"); DnsDhcpRegisterHostAddrs = GetProcAddress(dll, "DnsDhcpRegisterHostAddrs"); DnsDhcpRegisterInit = GetProcAddress(dll, "DnsDhcpRegisterInit"); DnsDhcpRegisterTerm = GetProcAddress(dll, "DnsDhcpRegisterTerm"); DnsDhcpRemoveRegistrations = GetProcAddress(dll, "DnsDhcpRemoveRegistrations"); DnsDhcpSrvRegisterHostAddr = GetProcAddress(dll, "DnsDhcpSrvRegisterHostAddr"); //DnsDhcpSrvRegisterHostAddrEx = GetProcAddress(dll, "DnsDhcpSrvRegisterHostAddrEx"); DnsDhcpSrvRegisterHostName = GetProcAddress(dll, "DnsDhcpSrvRegisterHostName"); //DnsDhcpSrvRegisterHostNameEx = GetProcAddress(dll, "DnsDhcpSrvRegisterHostNameEx"); DnsDhcpSrvRegisterInit = GetProcAddress(dll, "DnsDhcpSrvRegisterInit"); DnsDhcpSrvRegisterInitialize = GetProcAddress(dll, "DnsDhcpSrvRegisterInitialize"); DnsDhcpSrvRegisterTerm = GetProcAddress(dll, "DnsDhcpSrvRegisterTerm"); DnsDowncaseDnsNameLabel = GetProcAddress(dll, "DnsDowncaseDnsNameLabel"); DnsExtractRecordsFromMessage_UTF8 = GetProcAddress(dll, "DnsExtractRecordsFromMessage_UTF8"); DnsExtractRecordsFromMessage_W = GetProcAddress(dll, "DnsExtractRecordsFromMessage_W"); DnsFindAuthoritativeZone = GetProcAddress(dll, "DnsFindAuthoritativeZone"); DnsFlushResolverCache = GetProcAddress(dll, "DnsFlushResolverCache"); DnsFlushResolverCacheEntry_A = GetProcAddress(dll, "DnsFlushResolverCacheEntry_A"); DnsFlushResolverCacheEntry_UTF8 = GetProcAddress(dll, "DnsFlushResolverCacheEntry_UTF8"); DnsFlushResolverCacheEntry_W = GetProcAddress(dll, "DnsFlushResolverCacheEntry_W"); DnsFree = GetProcAddress(dll, "DnsFree"); DnsFreeConfigStructure = GetProcAddress(dll, "DnsFreeConfigStructure"); //DnsFreePolicyConfig = GetProcAddress(dll, "DnsFreePolicyConfig"); //DnsFreeProxyName = GetProcAddress(dll, "DnsFreeProxyName"); DnsGetBufferLengthForStringCopy = GetProcAddress(dll, "DnsGetBufferLengthForStringCopy"); DnsGetCacheDataTable = GetProcAddress(dll, "DnsGetCacheDataTable"); DnsGetDnsServerList = GetProcAddress(dll, "DnsGetDnsServerList"); DnsGetDomainName = GetProcAddress(dll, "DnsGetDomainName"); DnsGetLastFailedUpdateInfo = GetProcAddress(dll, "DnsGetLastFailedUpdateInfo"); //DnsGetPolicyTableInfo = GetProcAddress(dll, "DnsGetPolicyTableInfo"); //DnsGetPolicyTableInfoPrivate = GetProcAddress(dll, "DnsGetPolicyTableInfoPrivate"); DnsGetPrimaryDomainName_A = GetProcAddress(dll, "DnsGetPrimaryDomainName_A"); //DnsGetProxyInfoPrivate = GetProcAddress(dll, "DnsGetProxyInfoPrivate"); //DnsGetProxyInformation = GetProcAddress(dll, "DnsGetProxyInformation"); DnsGlobals = GetProcAddress(dll, "DnsGlobals"); DnsIpv6AddressToString = GetProcAddress(dll, "DnsIpv6AddressToString"); DnsIpv6StringToAddress = GetProcAddress(dll, "DnsIpv6StringToAddress"); DnsIsAMailboxType = GetProcAddress(dll, "DnsIsAMailboxType"); DnsIsStatusRcode = GetProcAddress(dll, "DnsIsStatusRcode"); DnsIsStringCountValidForTextType = GetProcAddress(dll, "DnsIsStringCountValidForTextType"); DnsLogEvent = GetProcAddress(dll, "DnsLogEvent"); DnsLogIn = GetProcAddress(dll, "DnsLogIn"); DnsLogInit = GetProcAddress(dll, "DnsLogInit"); DnsLogIt = GetProcAddress(dll, "DnsLogIt"); DnsLogOut = GetProcAddress(dll, "DnsLogOut"); DnsLogTime = GetProcAddress(dll, "DnsLogTime"); DnsMapRcodeToStatus = GetProcAddress(dll, "DnsMapRcodeToStatus"); DnsModifyRecordsInSet_A = GetProcAddress(dll, "DnsModifyRecordsInSet_A"); DnsModifyRecordsInSet_UTF8 = GetProcAddress(dll, "DnsModifyRecordsInSet_UTF8"); DnsModifyRecordsInSet_W = GetProcAddress(dll, "DnsModifyRecordsInSet_W"); DnsNameCompareEx_A = GetProcAddress(dll, "DnsNameCompareEx_A"); DnsNameCompareEx_UTF8 = GetProcAddress(dll, "DnsNameCompareEx_UTF8"); DnsNameCompareEx_W = GetProcAddress(dll, "DnsNameCompareEx_W"); DnsNameCompare_A = GetProcAddress(dll, "DnsNameCompare_A"); DnsNameCompare_UTF8 = GetProcAddress(dll, "DnsNameCompare_UTF8"); DnsNameCompare_W = GetProcAddress(dll, "DnsNameCompare_W"); DnsNameCopy = GetProcAddress(dll, "DnsNameCopy"); DnsNameCopyAllocate = GetProcAddress(dll, "DnsNameCopyAllocate"); DnsNetworkInfo_CreateFromFAZ = GetProcAddress(dll, "DnsNetworkInfo_CreateFromFAZ"); DnsNetworkInformation_CreateFromFAZ = GetProcAddress(dll, "DnsNetworkInformation_CreateFromFAZ"); DnsNotifyResolver = GetProcAddress(dll, "DnsNotifyResolver"); DnsNotifyResolverClusterIp = GetProcAddress(dll, "DnsNotifyResolverClusterIp"); DnsNotifyResolverEx = GetProcAddress(dll, "DnsNotifyResolverEx"); DnsQueryConfig = GetProcAddress(dll, "DnsQueryConfig"); DnsQueryConfigAllocEx = GetProcAddress(dll, "DnsQueryConfigAllocEx"); DnsQueryConfigDword = GetProcAddress(dll, "DnsQueryConfigDword"); DnsQueryEx = GetProcAddress(dll, "DnsQueryEx"); DnsQueryExA = GetProcAddress(dll, "DnsQueryExA"); DnsQueryExUTF8 = GetProcAddress(dll, "DnsQueryExUTF8"); DnsQueryExW = GetProcAddress(dll, "DnsQueryExW"); DnsQuery_A = GetProcAddress(dll, "DnsQuery_A"); DnsQuery_UTF8 = GetProcAddress(dll, "DnsQuery_UTF8"); DnsQuery_W = GetProcAddress(dll, "DnsQuery_W"); DnsRecordBuild_UTF8 = GetProcAddress(dll, "DnsRecordBuild_UTF8"); DnsRecordBuild_W = GetProcAddress(dll, "DnsRecordBuild_W"); DnsRecordCompare = GetProcAddress(dll, "DnsRecordCompare"); DnsRecordCopyEx = GetProcAddress(dll, "DnsRecordCopyEx"); DnsRecordListFree = GetProcAddress(dll, "DnsRecordListFree"); DnsRecordSetCompare = GetProcAddress(dll, "DnsRecordSetCompare"); DnsRecordSetCopyEx = GetProcAddress(dll, "DnsRecordSetCopyEx"); DnsRecordSetDetach = GetProcAddress(dll, "DnsRecordSetDetach"); DnsRecordStringForType = GetProcAddress(dll, "DnsRecordStringForType"); DnsRecordStringForWritableType = GetProcAddress(dll, "DnsRecordStringForWritableType"); DnsRecordTypeForName = GetProcAddress(dll, "DnsRecordTypeForName"); DnsRegisterClusterAddress = GetProcAddress(dll, "DnsRegisterClusterAddress"); DnsReleaseContextHandle = GetProcAddress(dll, "DnsReleaseContextHandle"); DnsRemoveRegistrations = GetProcAddress(dll, "DnsRemoveRegistrations"); DnsReplaceRecordSetA = GetProcAddress(dll, "DnsReplaceRecordSetA"); DnsReplaceRecordSetUTF8 = GetProcAddress(dll, "DnsReplaceRecordSetUTF8"); DnsReplaceRecordSetW = GetProcAddress(dll, "DnsReplaceRecordSetW"); DnsResolverOp = GetProcAddress(dll, "DnsResolverOp"); DnsScreenLocalAddrsForRegistration = GetProcAddress(dll, "DnsScreenLocalAddrsForRegistration"); DnsSetConfigDword = GetProcAddress(dll, "DnsSetConfigDword"); DnsStatusString = GetProcAddress(dll, "DnsStatusString"); DnsStringCopyAllocateEx = GetProcAddress(dll, "DnsStringCopyAllocateEx"); //DnsTraceServerConfig = GetProcAddress(dll, "DnsTraceServerConfig"); DnsUnicodeToUtf8 = GetProcAddress(dll, "DnsUnicodeToUtf8"); DnsUpdate = GetProcAddress(dll, "DnsUpdate"); //DnsUpdateMachinePresence = GetProcAddress(dll, "DnsUpdateMachinePresence"); DnsUpdateTest_A = GetProcAddress(dll, "DnsUpdateTest_A"); DnsUpdateTest_UTF8 = GetProcAddress(dll, "DnsUpdateTest_UTF8"); DnsUpdateTest_W = GetProcAddress(dll, "DnsUpdateTest_W"); DnsUtf8ToUnicode = GetProcAddress(dll, "DnsUtf8ToUnicode"); DnsValidateNameOrIp_TempW = GetProcAddress(dll, "DnsValidateNameOrIp_TempW"); DnsValidateName_A = GetProcAddress(dll, "DnsValidateName_A"); DnsValidateName_UTF8 = GetProcAddress(dll, "DnsValidateName_UTF8"); DnsValidateName_W = GetProcAddress(dll, "DnsValidateName_W"); //DnsValidateServerArray_A = GetProcAddress(dll, "DnsValidateServerArray_A"); //DnsValidateServerArray_W = GetProcAddress(dll, "DnsValidateServerArray_W"); //DnsValidateServerStatus = GetProcAddress(dll, "DnsValidateServerStatus"); //DnsValidateServer_A = GetProcAddress(dll, "DnsValidateServer_A"); //DnsValidateServer_W = GetProcAddress(dll, "DnsValidateServer_W"); DnsValidateUtf8Byte = GetProcAddress(dll, "DnsValidateUtf8Byte"); DnsWriteQuestionToBuffer_UTF8 = GetProcAddress(dll, "DnsWriteQuestionToBuffer_UTF8"); DnsWriteQuestionToBuffer_W = GetProcAddress(dll, "DnsWriteQuestionToBuffer_W"); DnsWriteReverseNameStringForIpAddress = GetProcAddress(dll, "DnsWriteReverseNameStringForIpAddress"); Dns_AddRecordsToMessage = GetProcAddress(dll, "Dns_AddRecordsToMessage"); Dns_AllocateMsgBuf = GetProcAddress(dll, "Dns_AllocateMsgBuf"); Dns_BuildPacket = GetProcAddress(dll, "Dns_BuildPacket"); Dns_CleanupWinsock = GetProcAddress(dll, "Dns_CleanupWinsock"); Dns_CloseConnection = GetProcAddress(dll, "Dns_CloseConnection"); Dns_CloseSocket = GetProcAddress(dll, "Dns_CloseSocket"); Dns_CreateMulticastSocket = GetProcAddress(dll, "Dns_CreateMulticastSocket"); Dns_CreateSocket = GetProcAddress(dll, "Dns_CreateSocket"); Dns_CreateSocketEx = GetProcAddress(dll, "Dns_CreateSocketEx"); Dns_ExtractRecordsFromMessage = GetProcAddress(dll, "Dns_ExtractRecordsFromMessage"); Dns_FindAuthoritativeZoneLib = GetProcAddress(dll, "Dns_FindAuthoritativeZoneLib"); Dns_FreeMsgBuf = GetProcAddress(dll, "Dns_FreeMsgBuf"); Dns_GetRandomXid = GetProcAddress(dll, "Dns_GetRandomXid"); Dns_InitializeMsgBuf = GetProcAddress(dll, "Dns_InitializeMsgBuf"); Dns_InitializeMsgRemoteSockaddr = GetProcAddress(dll, "Dns_InitializeMsgRemoteSockaddr"); Dns_InitializeWinsock = GetProcAddress(dll, "Dns_InitializeWinsock"); Dns_OpenTcpConnectionAndSend = GetProcAddress(dll, "Dns_OpenTcpConnectionAndSend"); Dns_ParseMessage = GetProcAddress(dll, "Dns_ParseMessage"); Dns_ParsePacketRecord = GetProcAddress(dll, "Dns_ParsePacketRecord"); Dns_PingAdapterServers = GetProcAddress(dll, "Dns_PingAdapterServers"); Dns_ReadPacketName = GetProcAddress(dll, "Dns_ReadPacketName"); Dns_ReadPacketNameAllocate = GetProcAddress(dll, "Dns_ReadPacketNameAllocate"); Dns_ReadRecordStructureFromPacket = GetProcAddress(dll, "Dns_ReadRecordStructureFromPacket"); Dns_RecvTcp = GetProcAddress(dll, "Dns_RecvTcp"); Dns_ResetNetworkInfo = GetProcAddress(dll, "Dns_ResetNetworkInfo"); Dns_SendAndRecvUdp = GetProcAddress(dll, "Dns_SendAndRecvUdp"); Dns_SendEx = GetProcAddress(dll, "Dns_SendEx"); Dns_SetRecordDatalength = GetProcAddress(dll, "Dns_SetRecordDatalength"); Dns_SetRecordsSection = GetProcAddress(dll, "Dns_SetRecordsSection"); Dns_SetRecordsTtl = GetProcAddress(dll, "Dns_SetRecordsTtl"); Dns_SkipPacketName = GetProcAddress(dll, "Dns_SkipPacketName"); Dns_SkipToRecord = GetProcAddress(dll, "Dns_SkipToRecord"); Dns_UpdateLib = GetProcAddress(dll, "Dns_UpdateLib"); Dns_UpdateLibEx = GetProcAddress(dll, "Dns_UpdateLibEx"); Dns_WriteDottedNameToPacket = GetProcAddress(dll, "Dns_WriteDottedNameToPacket"); Dns_WriteQuestionToMessage = GetProcAddress(dll, "Dns_WriteQuestionToMessage"); Dns_WriteRecordStructureToPacketEx = GetProcAddress(dll, "Dns_WriteRecordStructureToPacketEx"); ExtraInfo_Init = GetProcAddress(dll, "ExtraInfo_Init"); Faz_AreServerListsInSameNameSpace = GetProcAddress(dll, "Faz_AreServerListsInSameNameSpace"); //FlushDnsPolicyUnreachableStatus = GetProcAddress(dll, "FlushDnsPolicyUnreachableStatus"); GetCurrentTimeInSeconds = GetProcAddress(dll, "GetCurrentTimeInSeconds"); HostsFile_Close = GetProcAddress(dll, "HostsFile_Close"); HostsFile_Open = GetProcAddress(dll, "HostsFile_Open"); HostsFile_ReadLine = GetProcAddress(dll, "HostsFile_ReadLine"); IpHelp_IsAddrOnLink = GetProcAddress(dll, "IpHelp_IsAddrOnLink"); Local_GetRecordsForLocalName = GetProcAddress(dll, "Local_GetRecordsForLocalName"); Local_GetRecordsForLocalNameEx = GetProcAddress(dll, "Local_GetRecordsForLocalNameEx"); NetInfo_Build = GetProcAddress(dll, "NetInfo_Build"); NetInfo_Clean = GetProcAddress(dll, "NetInfo_Clean"); NetInfo_Copy = GetProcAddress(dll, "NetInfo_Copy"); NetInfo_Free = GetProcAddress(dll, "NetInfo_Free"); NetInfo_GetAdapterByAddress = GetProcAddress(dll, "NetInfo_GetAdapterByAddress"); NetInfo_GetAdapterByInterfaceIndex = GetProcAddress(dll, "NetInfo_GetAdapterByInterfaceIndex"); NetInfo_GetAdapterByName = GetProcAddress(dll, "NetInfo_GetAdapterByName"); NetInfo_IsAddrConfig = GetProcAddress(dll, "NetInfo_IsAddrConfig"); NetInfo_IsForUpdate = GetProcAddress(dll, "NetInfo_IsForUpdate"); NetInfo_ResetServerPriorities = GetProcAddress(dll, "NetInfo_ResetServerPriorities"); //NetInfo_UpdateServerReachability = GetProcAddress(dll, "NetInfo_UpdateServerReachability"); QueryDirectEx = GetProcAddress(dll, "QueryDirectEx"); Query_Main = GetProcAddress(dll, "Query_Main"); Reg_FreeUpdateInfo = GetProcAddress(dll, "Reg_FreeUpdateInfo"); Reg_GetValueEx = GetProcAddress(dll, "Reg_GetValueEx"); Reg_ReadGlobalsEx = GetProcAddress(dll, "Reg_ReadGlobalsEx"); Reg_ReadUpdateInfo = GetProcAddress(dll, "Reg_ReadUpdateInfo"); Security_ContextListTimeout = GetProcAddress(dll, "Security_ContextListTimeout"); Send_AndRecvUdpWithParam = GetProcAddress(dll, "Send_AndRecvUdpWithParam"); Send_MessagePrivate = GetProcAddress(dll, "Send_MessagePrivate"); Send_OpenTcpConnectionAndSend = GetProcAddress(dll, "Send_OpenTcpConnectionAndSend"); Socket_CacheCleanup = GetProcAddress(dll, "Socket_CacheCleanup"); Socket_CacheInit = GetProcAddress(dll, "Socket_CacheInit"); Socket_CleanupWinsock = GetProcAddress(dll, "Socket_CleanupWinsock"); Socket_ClearMessageSockets = GetProcAddress(dll, "Socket_ClearMessageSockets"); Socket_CloseEx = GetProcAddress(dll, "Socket_CloseEx"); Socket_CloseMessageSockets = GetProcAddress(dll, "Socket_CloseMessageSockets"); Socket_Create = GetProcAddress(dll, "Socket_Create"); Socket_CreateMulticast = GetProcAddress(dll, "Socket_CreateMulticast"); Socket_InitWinsock = GetProcAddress(dll, "Socket_InitWinsock"); Socket_JoinMulticast = GetProcAddress(dll, "Socket_JoinMulticast"); Socket_RecvFrom = GetProcAddress(dll, "Socket_RecvFrom"); Socket_SetMulticastInterface = GetProcAddress(dll, "Socket_SetMulticastInterface"); Socket_SetMulticastLoopBack = GetProcAddress(dll, "Socket_SetMulticastLoopBack"); Socket_SetTtl = GetProcAddress(dll, "Socket_SetTtl"); Socket_TcpListen = GetProcAddress(dll, "Socket_TcpListen"); //Trace_Reset = GetProcAddress(dll, "Trace_Reset"); Update_ReplaceAddressRecordsW = GetProcAddress(dll, "Update_ReplaceAddressRecordsW"); Util_IsIp6Running = GetProcAddress(dll, "Util_IsIp6Running"); // if entry points aren't found, GetProcAddress should return null if (DnsQueryEx == NULL) { DnsQueryEx = (FARPROC)& DnsQueryExStub; }; if (DnsCancelQuery == NULL) { DnsCancelQuery = (FARPROC)& DnsCancelQueryStub; }; } } dnsapi; struct dinput8_dll { HMODULE dll; FARPROC DirectInput8Create; void LoadOriginalLibrary(HMODULE module) { dll = module; shared.LoadOriginalLibrary(dll); DirectInput8Create = GetProcAddress(dll, "DirectInput8Create"); } } dinput8; #pragma runtime_checks( "", off ) #ifdef _DEBUG #pragma message ("You are compiling the code in Debug - be warned that wrappers for export functions may not have correct code generated") #endif // not sure if these all work -- there's a very real possibility some of these will need more full definitions to not break stack parameters // (see https://github.com/ThirteenAG/Ultimate-ASI-Loader/blob/master/source/dllmain.h#L2870 for reference) void _BreakRecordsIntoBlob() { dnsapi.BreakRecordsIntoBlob(); } void _CombineRecordsInBlob() { dnsapi.CombineRecordsInBlob(); } void _DnsAcquireContextHandle_A() { dnsapi.DnsAcquireContextHandle_A(); } void _DnsAcquireContextHandle_W() { dnsapi.DnsAcquireContextHandle_W(); } void _DnsAllocateRecord() { dnsapi.DnsAllocateRecord(); } void _DnsApiAlloc() { dnsapi.DnsApiAlloc(); } void _DnsApiAllocZero() { dnsapi.DnsApiAllocZero(); } void _DnsApiFree() { dnsapi.DnsApiFree(); } void _DnsApiHeapReset() { dnsapi.DnsApiHeapReset(); } void _DnsApiRealloc() { dnsapi.DnsApiRealloc(); } void _DnsApiSetDebugGlobals() { dnsapi.DnsApiSetDebugGlobals(); } void _DnsAsyncRegisterHostAddrs() { dnsapi.DnsAsyncRegisterHostAddrs(); } void _DnsAsyncRegisterInit() { dnsapi.DnsAsyncRegisterInit(); } void _DnsAsyncRegisterTerm() { dnsapi.DnsAsyncRegisterTerm(); } void _DnsCancelQuery() { dnsapi.DnsCancelQuery(); } void _DnsCopyStringEx() { dnsapi.DnsCopyStringEx(); } void _DnsCreateReverseNameStringForIpAddress() { dnsapi.DnsCreateReverseNameStringForIpAddress(); } void _DnsCreateStandardDnsNameCopy() { dnsapi.DnsCreateStandardDnsNameCopy(); } void _DnsCreateStringCopy() { dnsapi.DnsCreateStringCopy(); } void _DnsDhcpRegisterAddrs() { dnsapi.DnsDhcpRegisterAddrs(); } void _DnsDhcpRegisterHostAddrs() { dnsapi.DnsDhcpRegisterHostAddrs(); } void _DnsDhcpRegisterInit() { dnsapi.DnsDhcpRegisterInit(); } void _DnsDhcpRegisterTerm() { dnsapi.DnsDhcpRegisterTerm(); } void _DnsDhcpRemoveRegistrations() { dnsapi.DnsDhcpRemoveRegistrations(); } void _DnsDhcpSrvRegisterHostAddr() { dnsapi.DnsDhcpSrvRegisterHostAddr(); } //void _DnsDhcpSrvRegisterHostAddrEx() { dnsapi.DnsDhcpSrvRegisterHostAddrEx(); } void _DnsDhcpSrvRegisterHostName() { dnsapi.DnsDhcpSrvRegisterHostName(); } //void _DnsDhcpSrvRegisterHostNameEx() { dnsapi.DnsDhcpSrvRegisterHostNameEx(); } void _DnsDhcpSrvRegisterInit() { dnsapi.DnsDhcpSrvRegisterInit(); } void _DnsDhcpSrvRegisterInitialize() { dnsapi.DnsDhcpSrvRegisterInitialize(); } void _DnsDhcpSrvRegisterTerm() { dnsapi.DnsDhcpSrvRegisterTerm(); } void _DnsDowncaseDnsNameLabel() { dnsapi.DnsDowncaseDnsNameLabel(); } void _DnsExtractRecordsFromMessage_UTF8() { dnsapi.DnsExtractRecordsFromMessage_UTF8(); } void _DnsExtractRecordsFromMessage_W() { dnsapi.DnsExtractRecordsFromMessage_W(); } void _DnsFindAuthoritativeZone() { dnsapi.DnsFindAuthoritativeZone(); } void _DnsFlushResolverCache() { dnsapi.DnsFlushResolverCache(); } void _DnsFlushResolverCacheEntry_A() { dnsapi.DnsFlushResolverCacheEntry_A(); } void _DnsFlushResolverCacheEntry_UTF8() { dnsapi.DnsFlushResolverCacheEntry_UTF8(); } void _DnsFlushResolverCacheEntry_W() { dnsapi.DnsFlushResolverCacheEntry_W(); } void _DnsFree() { dnsapi.DnsFree(); } void _DnsFreeConfigStructure() { dnsapi.DnsFreeConfigStructure(); } //void _DnsFreePolicyConfig() { dnsapi.DnsFreePolicyConfig(); } //void _DnsFreeProxyName() { dnsapi.DnsFreeProxyName(); } void _DnsGetBufferLengthForStringCopy() { dnsapi.DnsGetBufferLengthForStringCopy(); } void _DnsGetCacheDataTable() { dnsapi.DnsGetCacheDataTable(); } void _DnsGetDnsServerList() { dnsapi.DnsGetDnsServerList(); } void _DnsGetDomainName() { dnsapi.DnsGetDomainName(); } void _DnsGetLastFailedUpdateInfo() { dnsapi.DnsGetLastFailedUpdateInfo(); } //void _DnsGetPolicyTableInfo() { dnsapi.DnsGetPolicyTableInfo(); } //void _DnsGetPolicyTableInfoPrivate() { dnsapi.DnsGetPolicyTableInfoPrivate(); } void _DnsGetPrimaryDomainName_A() { dnsapi.DnsGetPrimaryDomainName_A(); } //void _DnsGetProxyInfoPrivate() { dnsapi.DnsGetProxyInfoPrivate(); } //void _DnsGetProxyInformation() { dnsapi.DnsGetProxyInformation(); } void _DnsGlobals() { dnsapi.DnsGlobals(); } void _DnsIpv6AddressToString() { dnsapi.DnsIpv6AddressToString(); } void _DnsIpv6StringToAddress() { dnsapi.DnsIpv6StringToAddress(); } void _DnsIsAMailboxType() { dnsapi.DnsIsAMailboxType(); } void _DnsIsStatusRcode() { dnsapi.DnsIsStatusRcode(); } void _DnsIsStringCountValidForTextType() { dnsapi.DnsIsStringCountValidForTextType(); } void _DnsLogEvent() { dnsapi.DnsLogEvent(); } void _DnsLogIn() { dnsapi.DnsLogIn(); } void _DnsLogInit() { dnsapi.DnsLogInit(); } void _DnsLogIt() { dnsapi.DnsLogIt(); } void _DnsLogOut() { dnsapi.DnsLogOut(); } void _DnsLogTime() { dnsapi.DnsLogTime(); } void _DnsMapRcodeToStatus() { dnsapi.DnsMapRcodeToStatus(); } void _DnsModifyRecordsInSet_A() { dnsapi.DnsModifyRecordsInSet_A(); } void _DnsModifyRecordsInSet_UTF8() { dnsapi.DnsModifyRecordsInSet_UTF8(); } void _DnsModifyRecordsInSet_W() { dnsapi.DnsModifyRecordsInSet_W(); } void _DnsNameCompareEx_A() { dnsapi.DnsNameCompareEx_A(); } void _DnsNameCompareEx_UTF8() { dnsapi.DnsNameCompareEx_UTF8(); } void _DnsNameCompareEx_W() { dnsapi.DnsNameCompareEx_W(); } void _DnsNameCompare_A() { dnsapi.DnsNameCompare_A(); } void _DnsNameCompare_UTF8() { dnsapi.DnsNameCompare_UTF8(); } void _DnsNameCompare_W() { dnsapi.DnsNameCompare_W(); } void _DnsNameCopy() { dnsapi.DnsNameCopy(); } void _DnsNameCopyAllocate() { dnsapi.DnsNameCopyAllocate(); } void _DnsNetworkInfo_CreateFromFAZ() { dnsapi.DnsNetworkInfo_CreateFromFAZ(); } void _DnsNetworkInformation_CreateFromFAZ() { dnsapi.DnsNetworkInformation_CreateFromFAZ(); } void _DnsNotifyResolver() { dnsapi.DnsNotifyResolver(); } void _DnsNotifyResolverClusterIp() { dnsapi.DnsNotifyResolverClusterIp(); } void _DnsNotifyResolverEx() { dnsapi.DnsNotifyResolverEx(); } void _DnsQueryConfig() { dnsapi.DnsQueryConfig(); } void _DnsQueryConfigAllocEx() { dnsapi.DnsQueryConfigAllocEx(); } void _DnsQueryConfigDword() { dnsapi.DnsQueryConfigDword(); } void _DnsQueryEx() { dnsapi.DnsQueryEx(); } void _DnsQueryExA() { dnsapi.DnsQueryExA(); } void _DnsQueryExUTF8() { dnsapi.DnsQueryExUTF8(); } void _DnsQueryExW() { dnsapi.DnsQueryExW(); } void _DnsQuery_A() { dnsapi.DnsQuery_A(); } void _DnsQuery_UTF8() { dnsapi.DnsQuery_UTF8(); } void _DnsQuery_W() { dnsapi.DnsQuery_W(); } void _DnsRecordBuild_UTF8() { dnsapi.DnsRecordBuild_UTF8(); } void _DnsRecordBuild_W() { dnsapi.DnsRecordBuild_W(); } void _DnsRecordCompare() { dnsapi.DnsRecordCompare(); } void _DnsRecordCopyEx() { dnsapi.DnsRecordCopyEx(); } void _DnsRecordListFree() { dnsapi.DnsRecordListFree(); } void _DnsRecordSetCompare() { dnsapi.DnsRecordSetCompare(); } void _DnsRecordSetCopyEx() { dnsapi.DnsRecordSetCopyEx(); } void _DnsRecordSetDetach() { dnsapi.DnsRecordSetDetach(); } void _DnsRecordStringForType() { dnsapi.DnsRecordStringForType(); } void _DnsRecordStringForWritableType() { dnsapi.DnsRecordStringForWritableType(); } void _DnsRecordTypeForName() { dnsapi.DnsRecordTypeForName(); } void _DnsRegisterClusterAddress() { dnsapi.DnsRegisterClusterAddress(); } void _DnsReleaseContextHandle() { dnsapi.DnsReleaseContextHandle(); } void _DnsRemoveRegistrations() { dnsapi.DnsRemoveRegistrations(); } void _DnsReplaceRecordSetA() { dnsapi.DnsReplaceRecordSetA(); } void _DnsReplaceRecordSetUTF8() { dnsapi.DnsReplaceRecordSetUTF8(); } void _DnsReplaceRecordSetW() { dnsapi.DnsReplaceRecordSetW(); } void _DnsResolverOp() { dnsapi.DnsResolverOp(); } void _DnsScreenLocalAddrsForRegistration() { dnsapi.DnsScreenLocalAddrsForRegistration(); } void _DnsSetConfigDword() { dnsapi.DnsSetConfigDword(); } void _DnsStatusString() { dnsapi.DnsStatusString(); } void _DnsStringCopyAllocateEx() { dnsapi.DnsStringCopyAllocateEx(); } //void _DnsTraceServerConfig() { dnsapi.DnsTraceServerConfig(); } void _DnsUnicodeToUtf8() { dnsapi.DnsUnicodeToUtf8(); } void _DnsUpdate() { dnsapi.DnsUpdate(); } //void _DnsUpdateMachinePresence() { dnsapi.DnsUpdateMachinePresence(); } void _DnsUpdateTest_A() { dnsapi.DnsUpdateTest_A(); } void _DnsUpdateTest_UTF8() { dnsapi.DnsUpdateTest_UTF8(); } void _DnsUpdateTest_W() { dnsapi.DnsUpdateTest_W(); } void _DnsUtf8ToUnicode() { dnsapi.DnsUtf8ToUnicode(); } void _DnsValidateNameOrIp_TempW() { dnsapi.DnsValidateNameOrIp_TempW(); } void _DnsValidateName_A() { dnsapi.DnsValidateName_A(); } void _DnsValidateName_UTF8() { dnsapi.DnsValidateName_UTF8(); } void _DnsValidateName_W() { dnsapi.DnsValidateName_W(); } //void _DnsValidateServerArray_A() { dnsapi.DnsValidateServerArray_A(); } //void _DnsValidateServerArray_W() { dnsapi.DnsValidateServerArray_W(); } //void _DnsValidateServerStatus() { dnsapi.DnsValidateServerStatus(); } //void _DnsValidateServer_A() { dnsapi.DnsValidateServer_A(); } //void _DnsValidateServer_W() { dnsapi.DnsValidateServer_W(); } void _DnsValidateUtf8Byte() { dnsapi.DnsValidateUtf8Byte(); } void _DnsWriteQuestionToBuffer_UTF8() { dnsapi.DnsWriteQuestionToBuffer_UTF8(); } void _DnsWriteQuestionToBuffer_W() { dnsapi.DnsWriteQuestionToBuffer_W(); } void _DnsWriteReverseNameStringForIpAddress() { dnsapi.DnsWriteReverseNameStringForIpAddress(); } void _Dns_AddRecordsToMessage() { dnsapi.Dns_AddRecordsToMessage(); } void _Dns_AllocateMsgBuf() { dnsapi.Dns_AllocateMsgBuf(); } void _Dns_BuildPacket() { dnsapi.Dns_BuildPacket(); } void _Dns_CleanupWinsock() { dnsapi.Dns_CleanupWinsock(); } void _Dns_CloseConnection() { dnsapi.Dns_CloseConnection(); } void _Dns_CloseSocket() { dnsapi.Dns_CloseSocket(); } void _Dns_CreateMulticastSocket() { dnsapi.Dns_CreateMulticastSocket(); } void _Dns_CreateSocket() { dnsapi.Dns_CreateSocket(); } void _Dns_CreateSocketEx() { dnsapi.Dns_CreateSocketEx(); } void _Dns_ExtractRecordsFromMessage() { dnsapi.Dns_ExtractRecordsFromMessage(); } void _Dns_FindAuthoritativeZoneLib() { dnsapi.Dns_FindAuthoritativeZoneLib(); } void _Dns_FreeMsgBuf() { dnsapi.Dns_FreeMsgBuf(); } void _Dns_GetRandomXid() { dnsapi.Dns_GetRandomXid(); } void _Dns_InitializeMsgBuf() { dnsapi.Dns_InitializeMsgBuf(); } void _Dns_InitializeMsgRemoteSockaddr() { dnsapi.Dns_InitializeMsgRemoteSockaddr(); } void _Dns_InitializeWinsock() { dnsapi.Dns_InitializeWinsock(); } void _Dns_OpenTcpConnectionAndSend() { dnsapi.Dns_OpenTcpConnectionAndSend(); } void _Dns_ParseMessage() { dnsapi.Dns_ParseMessage(); } void _Dns_ParsePacketRecord() { dnsapi.Dns_ParsePacketRecord(); } void _Dns_PingAdapterServers() { dnsapi.Dns_PingAdapterServers(); } void _Dns_ReadPacketName() { dnsapi.Dns_ReadPacketName(); } void _Dns_ReadPacketNameAllocate() { dnsapi.Dns_ReadPacketNameAllocate(); } void _Dns_ReadRecordStructureFromPacket() { dnsapi.Dns_ReadRecordStructureFromPacket(); } void _Dns_RecvTcp() { dnsapi.Dns_RecvTcp(); } void _Dns_ResetNetworkInfo() { dnsapi.Dns_ResetNetworkInfo(); } void _Dns_SendAndRecvUdp() { dnsapi.Dns_SendAndRecvUdp(); } void _Dns_SendEx() { dnsapi.Dns_SendEx(); } void _Dns_SetRecordDatalength() { dnsapi.Dns_SetRecordDatalength(); } void _Dns_SetRecordsSection() { dnsapi.Dns_SetRecordsSection(); } void _Dns_SetRecordsTtl() { dnsapi.Dns_SetRecordsTtl(); } void _Dns_SkipPacketName() { dnsapi.Dns_SkipPacketName(); } void _Dns_SkipToRecord() { dnsapi.Dns_SkipToRecord(); } void _Dns_UpdateLib() { dnsapi.Dns_UpdateLib(); } void _Dns_UpdateLibEx() { dnsapi.Dns_UpdateLibEx(); } void _Dns_WriteDottedNameToPacket() { dnsapi.Dns_WriteDottedNameToPacket(); } void _Dns_WriteQuestionToMessage() { dnsapi.Dns_WriteQuestionToMessage(); } void _Dns_WriteRecordStructureToPacketEx() { dnsapi.Dns_WriteRecordStructureToPacketEx(); } void _ExtraInfo_Init() { dnsapi.ExtraInfo_Init(); } void _Faz_AreServerListsInSameNameSpace() { dnsapi.Faz_AreServerListsInSameNameSpace(); } //void _FlushDnsPolicyUnreachableStatus() { dnsapi.FlushDnsPolicyUnreachableStatus(); } void _GetCurrentTimeInSeconds() { dnsapi.GetCurrentTimeInSeconds(); } void _HostsFile_Close() { dnsapi.HostsFile_Close(); } void _HostsFile_Open() { dnsapi.HostsFile_Open(); } void _HostsFile_ReadLine() { dnsapi.HostsFile_ReadLine(); } void _IpHelp_IsAddrOnLink() { dnsapi.IpHelp_IsAddrOnLink(); } void _Local_GetRecordsForLocalName() { dnsapi.Local_GetRecordsForLocalName(); } void _Local_GetRecordsForLocalNameEx() { dnsapi.Local_GetRecordsForLocalNameEx(); } void _NetInfo_Build() { dnsapi.NetInfo_Build(); } void _NetInfo_Clean() { dnsapi.NetInfo_Clean(); } void _NetInfo_Copy() { dnsapi.NetInfo_Copy(); } void _NetInfo_Free() { dnsapi.NetInfo_Free(); } void _NetInfo_GetAdapterByAddress() { dnsapi.NetInfo_GetAdapterByAddress(); } void _NetInfo_GetAdapterByInterfaceIndex() { dnsapi.NetInfo_GetAdapterByInterfaceIndex(); } void _NetInfo_GetAdapterByName() { dnsapi.NetInfo_GetAdapterByName(); } void _NetInfo_IsAddrConfig() { dnsapi.NetInfo_IsAddrConfig(); } void _NetInfo_IsForUpdate() { dnsapi.NetInfo_IsForUpdate(); } void _NetInfo_ResetServerPriorities() { dnsapi.NetInfo_ResetServerPriorities(); } //void _NetInfo_UpdateServerReachability() { dnsapi.NetInfo_UpdateServerReachability(); } void _QueryDirectEx() { dnsapi.QueryDirectEx(); } void _Query_Main() { dnsapi.Query_Main(); } void _Reg_FreeUpdateInfo() { dnsapi.Reg_FreeUpdateInfo(); } void _Reg_GetValueEx() { dnsapi.Reg_GetValueEx(); } void _Reg_ReadGlobalsEx() { dnsapi.Reg_ReadGlobalsEx(); } void _Reg_ReadUpdateInfo() { dnsapi.Reg_ReadUpdateInfo(); } void _Security_ContextListTimeout() { dnsapi.Security_ContextListTimeout(); } void _Send_AndRecvUdpWithParam() { dnsapi.Send_AndRecvUdpWithParam(); } void _Send_MessagePrivate() { dnsapi.Send_MessagePrivate(); } void _Send_OpenTcpConnectionAndSend() { dnsapi.Send_OpenTcpConnectionAndSend(); } void _Socket_CacheCleanup() { dnsapi.Socket_CacheCleanup(); } void _Socket_CacheInit() { dnsapi.Socket_CacheInit(); } void _Socket_CleanupWinsock() { dnsapi.Socket_CleanupWinsock(); } void _Socket_ClearMessageSockets() { dnsapi.Socket_ClearMessageSockets(); } void _Socket_CloseEx() { dnsapi.Socket_CloseEx(); } void _Socket_CloseMessageSockets() { dnsapi.Socket_CloseMessageSockets(); } void _Socket_Create() { dnsapi.Socket_Create(); } void _Socket_CreateMulticast() { dnsapi.Socket_CreateMulticast(); } void _Socket_InitWinsock() { dnsapi.Socket_InitWinsock(); } void _Socket_JoinMulticast() { dnsapi.Socket_JoinMulticast(); } void _Socket_RecvFrom() { dnsapi.Socket_RecvFrom(); } void _Socket_SetMulticastInterface() { dnsapi.Socket_SetMulticastInterface(); } void _Socket_SetMulticastLoopBack() { dnsapi.Socket_SetMulticastLoopBack(); } void _Socket_SetTtl() { dnsapi.Socket_SetTtl(); } void _Socket_TcpListen() { dnsapi.Socket_TcpListen(); } //void _Trace_Reset() { dnsapi.Trace_Reset(); } void _Update_ReplaceAddressRecordsW() { dnsapi.Update_ReplaceAddressRecordsW(); } void _Util_IsIp6Running() { dnsapi.Util_IsIp6Running(); } typedef HRESULT(*fn_DirectInput8Create)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, LPUNKNOWN punkOuter); void _DirectInput8Create() { (fn_DirectInput8Create)dinput8.DirectInput8Create(); } void _DllRegisterServer() { shared.DllRegisterServer(); } void _DllUnregisterServer() { shared.DllUnregisterServer(); } void _DllCanUnloadNow() { shared.DllCanUnloadNow(); } void _DllGetClassObject() { shared.DllGetClassObject(); } #pragma runtime_checks( "", restore ) ================================================ FILE: source-code/source/PD-Loader/x64.def ================================================ LIBRARY "dinput8" EXPORTS DirectInput8Create = _DirectInput8Create DllCanUnloadNow = _DllCanUnloadNow PRIVATE DllGetClassObject = _DllGetClassObject PRIVATE DllRegisterServer = _DllRegisterServer PRIVATE DllUnregisterServer = _DllUnregisterServer PRIVATE LIBRARY "dnsapi" EXPORTS BreakRecordsIntoBlob = _BreakRecordsIntoBlob CombineRecordsInBlob = _CombineRecordsInBlob DnsAcquireContextHandle_A = _DnsAcquireContextHandle_A DnsAcquireContextHandle_W = _DnsAcquireContextHandle_W DnsAllocateRecord = _DnsAllocateRecord DnsApiAlloc = _DnsApiAlloc DnsApiAllocZero = _DnsApiAllocZero DnsApiFree = _DnsApiFree DnsApiHeapReset = _DnsApiHeapReset DnsApiRealloc = _DnsApiRealloc DnsApiSetDebugGlobals = _DnsApiSetDebugGlobals DnsAsyncRegisterHostAddrs = _DnsAsyncRegisterHostAddrs DnsAsyncRegisterInit = _DnsAsyncRegisterInit DnsAsyncRegisterTerm = _DnsAsyncRegisterTerm DnsCancelQuery = _DnsCancelQuery DnsCopyStringEx = _DnsCopyStringEx DnsCreateReverseNameStringForIpAddress = _DnsCreateReverseNameStringForIpAddress DnsCreateStandardDnsNameCopy = _DnsCreateStandardDnsNameCopy DnsCreateStringCopy = _DnsCreateStringCopy DnsDhcpRegisterAddrs = _DnsDhcpRegisterAddrs DnsDhcpRegisterHostAddrs = _DnsDhcpRegisterHostAddrs DnsDhcpRegisterInit = _DnsDhcpRegisterInit DnsDhcpRegisterTerm = _DnsDhcpRegisterTerm DnsDhcpRemoveRegistrations = _DnsDhcpRemoveRegistrations DnsDhcpSrvRegisterHostAddr = _DnsDhcpSrvRegisterHostAddr ;DnsDhcpSrvRegisterHostAddrEx = _DnsDhcpSrvRegisterHostAddrEx DnsDhcpSrvRegisterHostName = _DnsDhcpSrvRegisterHostName ;DnsDhcpSrvRegisterHostNameEx = _DnsDhcpSrvRegisterHostNameEx DnsDhcpSrvRegisterInit = _DnsDhcpSrvRegisterInit DnsDhcpSrvRegisterInitialize = _DnsDhcpSrvRegisterInitialize DnsDhcpSrvRegisterTerm = _DnsDhcpSrvRegisterTerm DnsDowncaseDnsNameLabel = _DnsDowncaseDnsNameLabel DnsExtractRecordsFromMessage_UTF8 = _DnsExtractRecordsFromMessage_UTF8 DnsExtractRecordsFromMessage_W = _DnsExtractRecordsFromMessage_W DnsFindAuthoritativeZone = _DnsFindAuthoritativeZone DnsFlushResolverCache = _DnsFlushResolverCache DnsFlushResolverCacheEntry_A = _DnsFlushResolverCacheEntry_A DnsFlushResolverCacheEntry_UTF8 = _DnsFlushResolverCacheEntry_UTF8 DnsFlushResolverCacheEntry_W = _DnsFlushResolverCacheEntry_W DnsFree = _DnsFree DnsFreeConfigStructure = _DnsFreeConfigStructure ;DnsFreePolicyConfig = _DnsFreePolicyConfig ;DnsFreeProxyName = _DnsFreeProxyName DnsGetBufferLengthForStringCopy = _DnsGetBufferLengthForStringCopy DnsGetCacheDataTable = _DnsGetCacheDataTable DnsGetDnsServerList = _DnsGetDnsServerList DnsGetDomainName = _DnsGetDomainName DnsGetLastFailedUpdateInfo = _DnsGetLastFailedUpdateInfo ;DnsGetPolicyTableInfo = _DnsGetPolicyTableInfo ;DnsGetPolicyTableInfoPrivate = _DnsGetPolicyTableInfoPrivate DnsGetPrimaryDomainName_A = _DnsGetPrimaryDomainName_A ;DnsGetProxyInfoPrivate = _DnsGetProxyInfoPrivate ;DnsGetProxyInformation = _DnsGetProxyInformation DnsGlobals = _DnsGlobals DnsIpv6AddressToString = _DnsIpv6AddressToString DnsIpv6StringToAddress = _DnsIpv6StringToAddress DnsIsAMailboxType = _DnsIsAMailboxType DnsIsStatusRcode = _DnsIsStatusRcode DnsIsStringCountValidForTextType = _DnsIsStringCountValidForTextType DnsLogEvent = _DnsLogEvent DnsLogIn = _DnsLogIn DnsLogInit = _DnsLogInit DnsLogIt = _DnsLogIt DnsLogOut = _DnsLogOut DnsLogTime = _DnsLogTime DnsMapRcodeToStatus = _DnsMapRcodeToStatus DnsModifyRecordsInSet_A = _DnsModifyRecordsInSet_A DnsModifyRecordsInSet_UTF8 = _DnsModifyRecordsInSet_UTF8 DnsModifyRecordsInSet_W = _DnsModifyRecordsInSet_W DnsNameCompareEx_A = _DnsNameCompareEx_A DnsNameCompareEx_UTF8 = _DnsNameCompareEx_UTF8 DnsNameCompareEx_W = _DnsNameCompareEx_W DnsNameCompare_A = _DnsNameCompare_A DnsNameCompare_UTF8 = _DnsNameCompare_UTF8 DnsNameCompare_W = _DnsNameCompare_W DnsNameCopy = _DnsNameCopy DnsNameCopyAllocate = _DnsNameCopyAllocate DnsNetworkInfo_CreateFromFAZ = _DnsNetworkInfo_CreateFromFAZ DnsNetworkInformation_CreateFromFAZ = _DnsNetworkInformation_CreateFromFAZ DnsNotifyResolver = _DnsNotifyResolver DnsNotifyResolverClusterIp = _DnsNotifyResolverClusterIp DnsNotifyResolverEx = _DnsNotifyResolverEx DnsQueryConfig = _DnsQueryConfig DnsQueryConfigAllocEx = _DnsQueryConfigAllocEx DnsQueryConfigDword = _DnsQueryConfigDword DnsQueryEx = _DnsQueryEx DnsQueryExA = _DnsQueryExA DnsQueryExUTF8 = _DnsQueryExUTF8 DnsQueryExW = _DnsQueryExW DnsQuery_A = _DnsQuery_A DnsQuery_UTF8 = _DnsQuery_UTF8 DnsQuery_W = _DnsQuery_W DnsRecordBuild_UTF8 = _DnsRecordBuild_UTF8 DnsRecordBuild_W = _DnsRecordBuild_W DnsRecordCompare = _DnsRecordCompare DnsRecordCopyEx = _DnsRecordCopyEx DnsRecordListFree = _DnsRecordListFree DnsRecordSetCompare = _DnsRecordSetCompare DnsRecordSetCopyEx = _DnsRecordSetCopyEx DnsRecordSetDetach = _DnsRecordSetDetach DnsRecordStringForType = _DnsRecordStringForType DnsRecordStringForWritableType = _DnsRecordStringForWritableType DnsRecordTypeForName = _DnsRecordTypeForName DnsRegisterClusterAddress = _DnsRegisterClusterAddress DnsReleaseContextHandle = _DnsReleaseContextHandle DnsRemoveRegistrations = _DnsRemoveRegistrations DnsReplaceRecordSetA = _DnsReplaceRecordSetA DnsReplaceRecordSetUTF8 = _DnsReplaceRecordSetUTF8 DnsReplaceRecordSetW = _DnsReplaceRecordSetW DnsResolverOp = _DnsResolverOp DnsScreenLocalAddrsForRegistration = _DnsScreenLocalAddrsForRegistration DnsSetConfigDword = _DnsSetConfigDword DnsStatusString = _DnsStatusString DnsStringCopyAllocateEx = _DnsStringCopyAllocateEx ;DnsTraceServerConfig = _DnsTraceServerConfig DnsUnicodeToUtf8 = _DnsUnicodeToUtf8 DnsUpdate = _DnsUpdate ;DnsUpdateMachinePresence = _DnsUpdateMachinePresence DnsUpdateTest_A = _DnsUpdateTest_A DnsUpdateTest_UTF8 = _DnsUpdateTest_UTF8 DnsUpdateTest_W = _DnsUpdateTest_W DnsUtf8ToUnicode = _DnsUtf8ToUnicode DnsValidateNameOrIp_TempW = _DnsValidateNameOrIp_TempW DnsValidateName_A = _DnsValidateName_A DnsValidateName_UTF8 = _DnsValidateName_UTF8 DnsValidateName_W = _DnsValidateName_W ;DnsValidateServerArray_A = _DnsValidateServerArray_A ;DnsValidateServerArray_W = _DnsValidateServerArray_W ;DnsValidateServerStatus = _DnsValidateServerStatus ;DnsValidateServer_A = _DnsValidateServer_A ;DnsValidateServer_W = _DnsValidateServer_W DnsValidateUtf8Byte = _DnsValidateUtf8Byte DnsWriteQuestionToBuffer_UTF8 = _DnsWriteQuestionToBuffer_UTF8 DnsWriteQuestionToBuffer_W = _DnsWriteQuestionToBuffer_W DnsWriteReverseNameStringForIpAddress = _DnsWriteReverseNameStringForIpAddress Dns_AddRecordsToMessage = _Dns_AddRecordsToMessage Dns_AllocateMsgBuf = _Dns_AllocateMsgBuf Dns_BuildPacket = _Dns_BuildPacket Dns_CleanupWinsock = _Dns_CleanupWinsock Dns_CloseConnection = _Dns_CloseConnection Dns_CloseSocket = _Dns_CloseSocket Dns_CreateMulticastSocket = _Dns_CreateMulticastSocket Dns_CreateSocket = _Dns_CreateSocket Dns_CreateSocketEx = _Dns_CreateSocketEx Dns_ExtractRecordsFromMessage = _Dns_ExtractRecordsFromMessage Dns_FindAuthoritativeZoneLib = _Dns_FindAuthoritativeZoneLib Dns_FreeMsgBuf = _Dns_FreeMsgBuf Dns_GetRandomXid = _Dns_GetRandomXid Dns_InitializeMsgBuf = _Dns_InitializeMsgBuf Dns_InitializeMsgRemoteSockaddr = _Dns_InitializeMsgRemoteSockaddr Dns_InitializeWinsock = _Dns_InitializeWinsock Dns_OpenTcpConnectionAndSend = _Dns_OpenTcpConnectionAndSend Dns_ParseMessage = _Dns_ParseMessage Dns_ParsePacketRecord = _Dns_ParsePacketRecord Dns_PingAdapterServers = _Dns_PingAdapterServers Dns_ReadPacketName = _Dns_ReadPacketName Dns_ReadPacketNameAllocate = _Dns_ReadPacketNameAllocate Dns_ReadRecordStructureFromPacket = _Dns_ReadRecordStructureFromPacket Dns_RecvTcp = _Dns_RecvTcp Dns_ResetNetworkInfo = _Dns_ResetNetworkInfo Dns_SendAndRecvUdp = _Dns_SendAndRecvUdp Dns_SendEx = _Dns_SendEx Dns_SetRecordDatalength = _Dns_SetRecordDatalength Dns_SetRecordsSection = _Dns_SetRecordsSection Dns_SetRecordsTtl = _Dns_SetRecordsTtl Dns_SkipPacketName = _Dns_SkipPacketName Dns_SkipToRecord = _Dns_SkipToRecord Dns_UpdateLib = _Dns_UpdateLib Dns_UpdateLibEx = _Dns_UpdateLibEx Dns_WriteDottedNameToPacket = _Dns_WriteDottedNameToPacket Dns_WriteQuestionToMessage = _Dns_WriteQuestionToMessage Dns_WriteRecordStructureToPacketEx = _Dns_WriteRecordStructureToPacketEx ExtraInfo_Init = _ExtraInfo_Init Faz_AreServerListsInSameNameSpace = _Faz_AreServerListsInSameNameSpace ;FlushDnsPolicyUnreachableStatus = _FlushDnsPolicyUnreachableStatus GetCurrentTimeInSeconds = _GetCurrentTimeInSeconds HostsFile_Close = _HostsFile_Close HostsFile_Open = _HostsFile_Open HostsFile_ReadLine = _HostsFile_ReadLine IpHelp_IsAddrOnLink = _IpHelp_IsAddrOnLink Local_GetRecordsForLocalName = _Local_GetRecordsForLocalName Local_GetRecordsForLocalNameEx = _Local_GetRecordsForLocalNameEx NetInfo_Build = _NetInfo_Build NetInfo_Clean = _NetInfo_Clean NetInfo_Copy = _NetInfo_Copy NetInfo_Free = _NetInfo_Free NetInfo_GetAdapterByAddress = _NetInfo_GetAdapterByAddress NetInfo_GetAdapterByInterfaceIndex = _NetInfo_GetAdapterByInterfaceIndex NetInfo_GetAdapterByName = _NetInfo_GetAdapterByName NetInfo_IsAddrConfig = _NetInfo_IsAddrConfig NetInfo_IsForUpdate = _NetInfo_IsForUpdate NetInfo_ResetServerPriorities = _NetInfo_ResetServerPriorities ;NetInfo_UpdateServerReachability = _NetInfo_UpdateServerReachability QueryDirectEx = _QueryDirectEx Query_Main = _Query_Main Reg_FreeUpdateInfo = _Reg_FreeUpdateInfo Reg_GetValueEx = _Reg_GetValueEx Reg_ReadGlobalsEx = _Reg_ReadGlobalsEx Reg_ReadUpdateInfo = _Reg_ReadUpdateInfo Security_ContextListTimeout = _Security_ContextListTimeout Send_AndRecvUdpWithParam = _Send_AndRecvUdpWithParam Send_MessagePrivate = _Send_MessagePrivate Send_OpenTcpConnectionAndSend = _Send_OpenTcpConnectionAndSend Socket_CacheCleanup = _Socket_CacheCleanup Socket_CacheInit = _Socket_CacheInit Socket_CleanupWinsock = _Socket_CleanupWinsock Socket_ClearMessageSockets = _Socket_ClearMessageSockets Socket_CloseEx = _Socket_CloseEx Socket_CloseMessageSockets = _Socket_CloseMessageSockets Socket_Create = _Socket_Create Socket_CreateMulticast = _Socket_CreateMulticast Socket_InitWinsock = _Socket_InitWinsock Socket_JoinMulticast = _Socket_JoinMulticast Socket_RecvFrom = _Socket_RecvFrom Socket_SetMulticastInterface = _Socket_SetMulticastInterface Socket_SetMulticastLoopBack = _Socket_SetMulticastLoopBack Socket_SetTtl = _Socket_SetTtl Socket_TcpListen = _Socket_TcpListen ;Trace_Reset = _Trace_Reset Update_ReplaceAddressRecordsW = _Update_ReplaceAddressRecordsW Util_IsIp6Running = _Util_IsIp6Running DllCanUnloadNow = _DllCanUnloadNow PRIVATE DllGetClassObject = _DllGetClassObject PRIVATE DllRegisterServer = _DllRegisterServer PRIVATE DllUnregisterServer = _DllUnregisterServer PRIVATE ================================================ FILE: source-code/source/fakedll/ModuleList.h ================================================ #pragma once #include #include #include #include #include std::wstring GetModuleFileNameW(HMODULE hModule) { static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH; static constexpr auto MAX_ITERATIONS = 7; std::wstring ret; auto bufferSize = INITIAL_BUFFER_SIZE; for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations) { ret.resize(bufferSize); auto charsReturned = GetModuleFileNameW(hModule, &ret[0], bufferSize); if (charsReturned < ret.length()) { ret.resize(charsReturned); return ret; } else { bufferSize *= 2; } } return L""; } auto starts_with = [](const std::wstring& big_str, const std::wstring& small_str) -> auto { return big_str.compare(0, small_str.length(), small_str) == 0; }; // Stores a list of loaded modules with their names, WITHOUT extension class ModuleList { public: enum class SearchLocation { All, LocalOnly, SystemOnly, }; // Initializes module list // Needs to be called before any calls to Get or GetAll void Enumerate(SearchLocation location = SearchLocation::All) { constexpr size_t INITIAL_SIZE = sizeof(HMODULE) * 256; HMODULE* modules = static_cast(malloc(INITIAL_SIZE)); if (modules != nullptr) { typedef BOOL(WINAPI * Func)(HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded); HMODULE hLib = LoadLibrary(TEXT("kernel32")); assert(hLib != nullptr); // If this fails then everything is probably broken anyway Func pEnumProcessModules = reinterpret_cast(GetProcAddress(hLib, "K32EnumProcessModules")); if (pEnumProcessModules == nullptr) { // Try psapi FreeLibrary(hLib); hLib = LoadLibrary(TEXT("psapi")); if (hLib != nullptr) { pEnumProcessModules = reinterpret_cast(GetProcAddress(hLib, "EnumProcessModules")); } } if (pEnumProcessModules != nullptr) { const HANDLE currentProcess = GetCurrentProcess(); DWORD cbNeeded = 0; if (pEnumProcessModules(currentProcess, modules, INITIAL_SIZE, &cbNeeded) != 0) { if (cbNeeded > INITIAL_SIZE) { HMODULE* newModules = static_cast(realloc(modules, cbNeeded)); if (newModules != nullptr) { modules = newModules; if (pEnumProcessModules(currentProcess, modules, cbNeeded, &cbNeeded) != 0) { EnumerateInternal(modules, location, cbNeeded / sizeof(HMODULE)); } } } else { EnumerateInternal(modules, location, cbNeeded / sizeof(HMODULE)); } } } if (hLib != nullptr) { FreeLibrary(hLib); } free(modules); } } // Recreates module list void ReEnumerate(SearchLocation location = SearchLocation::All) { Clear(); Enumerate(location); } // Clears module list void Clear() { m_moduleList.clear(); } // Gets handle of a loaded module with given name, NULL otherwise HMODULE Get(const wchar_t* moduleName) const { // If vector is empty then we're trying to call it without calling Enumerate first assert(m_moduleList.size() != 0); auto it = std::find_if(m_moduleList.begin(), m_moduleList.end(), [&](const auto& e) { return _wcsicmp(moduleName, std::get<1>(e).c_str()) == 0; }); return it != m_moduleList.end() ? std::get<0>(*it) : nullptr; } // Gets handles to all loaded modules with given name std::vector GetAll(const wchar_t* moduleName) const { // If vector is empty then we're trying to call it without calling Enumerate first assert(m_moduleList.size() != 0); std::vector results; for (auto& e : m_moduleList) { if (_wcsicmp(moduleName, std::get<1>(e).c_str()) == 0) { results.push_back(std::get<0>(e)); } } return results; } private: void EnumerateInternal(HMODULE* modules, SearchLocation location, size_t numModules) { const auto exeModulePath = GetModuleFileNameW(NULL).substr(0, GetModuleFileNameW(NULL).find_last_of(L"/\\")); m_moduleList.reserve(numModules); for (size_t i = 0; i < numModules; i++) { // Obtain module name, with resizing if necessary auto moduleName = GetModuleFileNameW(*modules); if (!moduleName.empty()) { const wchar_t* nameBegin = wcsrchr(moduleName.c_str(), '\\') + 1; const wchar_t* dotPos = wcsrchr(nameBegin, '.'); bool isLocal = starts_with(std::wstring(moduleName), exeModulePath); if ((isLocal && location != SearchLocation::SystemOnly) || (!isLocal && location != SearchLocation::LocalOnly)) { if (dotPos != nullptr) { m_moduleList.emplace_back(*modules, std::wstring(nameBegin, dotPos), isLocal); } else { m_moduleList.emplace_back(*modules, nameBegin, isLocal); } } } modules++; } } public: std::vector< std::tuple > m_moduleList; }; ================================================ FILE: source-code/source/fakedll/dllmain.cpp ================================================ #include "framework.h" #include "exception.hpp" HMODULE hm; std::vector iniPaths; bool iequals(std::wstring_view s1, std::wstring_view s2) { std::wstring str1(std::move(s1)); std::wstring str2(std::move(s2)); std::transform(str1.begin(), str1.end(), str1.begin(), [](wchar_t c) { return ::towlower(c); }); std::transform(str2.begin(), str2.end(), str2.begin(), [](wchar_t c) { return ::towlower(c); }); return (str1 == str2); } std::wstring to_wstring(std::string_view cstr) { std::string str(std::move(cstr)); auto charsReturned = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); std::wstring wstrTo(charsReturned, 0); MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], charsReturned); return wstrTo; } std::wstring SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken) { std::wstring r; WCHAR* szSystemPath = nullptr; if (SUCCEEDED(SHGetKnownFolderPath(rfid, dwFlags, hToken, &szSystemPath))) { r = szSystemPath; } CoTaskMemFree(szSystemPath); return r; }; HMODULE LoadLibraryW(const std::wstring& lpLibFileName) { return LoadLibraryW(lpLibFileName.c_str()); } std::wstring GetCurrentDirectoryW() { static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH; static constexpr auto MAX_ITERATIONS = 7; std::wstring ret; auto bufferSize = INITIAL_BUFFER_SIZE; for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations) { ret.resize(bufferSize); auto charsReturned = GetCurrentDirectoryW(bufferSize, &ret[0]); if (charsReturned < ret.length()) { ret.resize(charsReturned); return ret; } else { bufferSize *= 2; } } return L""; } UINT GetPrivateProfileIntW(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, const std::vector& fileNames) { for (const auto& file : fileNames) { nDefault = GetPrivateProfileIntW(lpAppName, lpKeyName, nDefault, file.c_str()); } return nDefault; } std::wstring GetSelfName() { const std::wstring moduleFileName = GetModuleFileNameW(hm); return moduleFileName.substr(moduleFileName.find_last_of(L"/\\") + 1); } template void GetSections(T&& h, Args... args) { const std::set< std::string_view, std::less<> > s = { args... }; size_t dwLoadOffset = (size_t)GetModuleHandle(NULL); BYTE* pImageBase = reinterpret_cast(dwLoadOffset); PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast(dwLoadOffset); PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast(pImageBase + pDosHeader->e_lfanew); PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeader); for (int iSection = 0; iSection < pNtHeader->FileHeader.NumberOfSections; ++iSection, ++pSection) { auto pszSectionName = reinterpret_cast(pSection->Name); if (s.find(pszSectionName) != s.end()) { DWORD dwPhysSize = (pSection->Misc.VirtualSize + 4095) & ~4095; std::forward(h)(pSection, dwLoadOffset, dwPhysSize); } } } enum Kernel32ExportsNames { eGetStartupInfoA, eGetStartupInfoW, eGetModuleHandleA, eGetModuleHandleW, eGetProcAddress, eGetShortPathNameA, eFindNextFileA, eFindNextFileW, eLoadLibraryA, eLoadLibraryW, eFreeLibrary, eCreateEventA, eCreateEventW, eGetSystemInfo, eInterlockedCompareExchange, eSleep, Kernel32ExportsNamesCount }; enum Kernel32ExportsData { IATPtr, ProcAddress, Kernel32ExportsDataCount }; size_t Kernel32Data[Kernel32ExportsNamesCount][Kernel32ExportsDataCount]; static LONG OriginalLibraryLoaded = 0; void LoadOriginalLibrary() { if (_InterlockedCompareExchange(&OriginalLibraryLoaded, 1, 0) != 0) return; auto szSelfName = GetSelfName(); auto szSystemPath = SHGetKnownFolderPath(FOLDERID_System, 0, nullptr) + L'\\' + szSelfName; auto szLocalPath = GetModuleFileNameW(hm); szLocalPath = szLocalPath.substr(0, szLocalPath.find_last_of(L"/\\") + 1); if (iequals(szSelfName, L"dnsapi.dll")) { dnsapi.LoadOriginalLibrary(LoadLibraryW(szSystemPath)); } } void FindFiles(WIN32_FIND_DATAW* fd) { auto dir = GetCurrentDirectoryW(); HANDLE dvaFile = FindFirstFileW(L"*.dva", fd); if (dvaFile != INVALID_HANDLE_VALUE) { do { if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { auto pos = wcslen(fd->cFileName); if (fd->cFileName[pos - 4] == '.' && (fd->cFileName[pos - 3] == 'd' || fd->cFileName[pos - 3] == 'D') && (fd->cFileName[pos - 2] == 'v' || fd->cFileName[pos - 2] == 'V') && (fd->cFileName[pos - 1] == 'a' || fd->cFileName[pos - 1] == 'A')) { auto path = dir + L'\\' + fd->cFileName; if (GetModuleHandle(path.c_str()) == NULL) { auto h = LoadLibraryW(path); SetCurrentDirectoryW(dir.c_str()); //in case dva switched it if (h == NULL) { auto e = GetLastError(); if (e != ERROR_DLL_INIT_FAILED) // in case dllmain returns false { std::wstring msg = L"Unable to load " + std::wstring(fd->cFileName) + L". Error: " + std::to_wstring(e); MessageBoxW(0, msg.c_str(), L"PD Loader", MB_ICONERROR); } } else { auto procedure = (void(*)())GetProcAddress(h, "InitializeDVA"); if (procedure != NULL) { procedure(); } } } } } } while (FindNextFileW(dvaFile, fd)); FindClose(dvaFile); } } void LoadPlugins() { auto oldDir = GetCurrentDirectoryW(); // store the current directory auto szSelfPath = GetModuleFileNameW(hm).substr(0, GetModuleFileNameW(hm).find_last_of(L"/\\") + 1); SetCurrentDirectoryW(szSelfPath.c_str()); auto nWantsToLoadPlugins = GetPrivateProfileIntW(L"global", L"enable", TRUE, iniPaths); if (nWantsToLoadPlugins) { WIN32_FIND_DATAW fd; SetCurrentDirectoryW(szSelfPath.c_str()); if (SetCurrentDirectoryW(L"plugins\\")) FindFiles(&fd); } SetCurrentDirectoryW(oldDir.c_str()); // Reset the current directory } void InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } static LONG LoadedPluginsYet = 0; void LoadEverything() { if (_InterlockedCompareExchange(&LoadedPluginsYet, 1, 0) != 0) return; LoadOriginalLibrary(); //LoadPlugins(); InjectCode((void*)0x00000001409FF58E, { 0x52, 0x54, 0x46, 0x4D }); InjectCode((void*)0x00000001409FF730, { 0x53, 0x65, 0x65, 0x20, 0x52, 0x45, 0x41, 0x44, 0x4D, 0x45, 0x2E, 0x74, 0x78, 0x74, 0x2E, 0x00, 0x00 }); } static LONG RestoredOnce = 0; void LoadPluginsAndRestoreIAT(uintptr_t retaddr) { bool calledFromBind = false; //steam drm check GetSections([&](PIMAGE_SECTION_HEADER pSection, size_t dwLoadOffset, DWORD dwPhysSize) { auto dwStart = static_cast(dwLoadOffset + pSection->VirtualAddress); auto dwEnd = dwStart + dwPhysSize; if (retaddr >= dwStart && retaddr <= dwEnd) calledFromBind = true; }, ".bind"); if (calledFromBind) return; if (_InterlockedCompareExchange(&RestoredOnce, 1, 0) != 0) return; LoadEverything(); for (size_t i = 0; i < Kernel32ExportsNamesCount; i++) { if (Kernel32Data[i][IATPtr] && Kernel32Data[i][ProcAddress]) { auto ptr = (size_t*)Kernel32Data[i][IATPtr]; DWORD dwProtect[2]; VirtualProtect(ptr, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]); *ptr = Kernel32Data[i][ProcAddress]; VirtualProtect(ptr, sizeof(size_t), dwProtect[0], &dwProtect[1]); } } } void WINAPI CustomGetStartupInfoA(LPSTARTUPINFOA lpStartupInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetStartupInfoA(lpStartupInfo); } void WINAPI CustomGetStartupInfoW(LPSTARTUPINFOW lpStartupInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetStartupInfoW(lpStartupInfo); } HMODULE WINAPI CustomGetModuleHandleA(LPCSTR lpModuleName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetModuleHandleA(lpModuleName); } HMODULE WINAPI CustomGetModuleHandleW(LPCWSTR lpModuleName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetModuleHandleW(lpModuleName); } FARPROC WINAPI CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetProcAddress(hModule, lpProcName); } DWORD WINAPI CustomGetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetShortPathNameA(lpszLongPath, lpszShortPath, cchBuffer); } BOOL WINAPI CustomFindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return FindNextFileA(hFindFile, lpFindFileData); } BOOL WINAPI CustomFindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return FindNextFileW(hFindFile, lpFindFileData); } HMODULE WINAPI CustomLoadLibraryA(LPCSTR lpLibFileName) { LoadOriginalLibrary(); return LoadLibraryA(lpLibFileName); } HMODULE WINAPI CustomLoadLibraryW(LPCWSTR lpLibFileName) { LoadOriginalLibrary(); return LoadLibraryW(lpLibFileName); } BOOL WINAPI CustomFreeLibrary(HMODULE hLibModule) { if (hLibModule != hm) return FreeLibrary(hLibModule); else return !NULL; } HANDLE WINAPI CustomCreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return CreateEventA(lpEventAttributes, bManualReset, bInitialState, lpName); } HANDLE WINAPI CustomCreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName); } void WINAPI CustomGetSystemInfo(LPSYSTEM_INFO lpSystemInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetSystemInfo(lpSystemInfo); } LONG WINAPI CustomInterlockedCompareExchange(LONG volatile* Destination, LONG ExChange, LONG Comperand) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return _InterlockedCompareExchange(Destination, ExChange, Comperand); } void WINAPI CustomSleep(DWORD dwMilliseconds) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return Sleep(dwMilliseconds); } bool HookKernel32IAT(HMODULE mod, bool exe) { auto hExecutableInstance = (size_t)mod; IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hExecutableInstance + ((IMAGE_DOS_HEADER*)hExecutableInstance)->e_lfanew); IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hExecutableInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1; if (exe) { Kernel32Data[eGetStartupInfoA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoA"); Kernel32Data[eGetStartupInfoW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoW"); Kernel32Data[eGetModuleHandleA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleA"); Kernel32Data[eGetModuleHandleW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleW"); Kernel32Data[eGetProcAddress][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetProcAddress"); Kernel32Data[eGetShortPathNameA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetShortPathNameA"); Kernel32Data[eFindNextFileA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileA"); Kernel32Data[eFindNextFileW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileW"); Kernel32Data[eLoadLibraryA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryA"); Kernel32Data[eLoadLibraryW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryW"); Kernel32Data[eFreeLibrary][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FreeLibrary"); Kernel32Data[eCreateEventA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventA"); Kernel32Data[eCreateEventW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventW"); Kernel32Data[eGetSystemInfo][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetSystemInfo"); Kernel32Data[eInterlockedCompareExchange][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "InterlockedCompareExchange"); Kernel32Data[eSleep][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "Sleep"); } uint32_t matchedImports = 0; auto PatchIAT = [&](size_t start, size_t end, size_t exe_end) { for (size_t i = 0; i < nNumImports; i++) { if (hExecutableInstance + (pImports + i)->FirstThunk > start && !(end && hExecutableInstance + (pImports + i)->FirstThunk > end)) end = hExecutableInstance + (pImports + i)->FirstThunk; } if (!end) { end = start + 0x100; } if (end > exe_end) //for very broken exes { start = hExecutableInstance; end = exe_end; } for (auto i = start; i < end; i += sizeof(size_t)) { DWORD dwProtect[2]; VirtualProtect((size_t*)i, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]); auto ptr = *(size_t*)i; if (!ptr) continue; if (ptr == Kernel32Data[eGetStartupInfoA][ProcAddress]) { if (exe) Kernel32Data[eGetStartupInfoA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetStartupInfoA; matchedImports++; } else if (ptr == Kernel32Data[eGetStartupInfoW][ProcAddress]) { if (exe) Kernel32Data[eGetStartupInfoW][IATPtr] = i; *(size_t*)i = (size_t)CustomGetStartupInfoW; matchedImports++; } else if (ptr == Kernel32Data[eGetModuleHandleA][ProcAddress]) { if (exe) Kernel32Data[eGetModuleHandleA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetModuleHandleA; matchedImports++; } else if (ptr == Kernel32Data[eGetModuleHandleW][ProcAddress]) { if (exe) Kernel32Data[eGetModuleHandleW][IATPtr] = i; *(size_t*)i = (size_t)CustomGetModuleHandleW; matchedImports++; } else if (ptr == Kernel32Data[eGetProcAddress][ProcAddress]) { if (exe) Kernel32Data[eGetProcAddress][IATPtr] = i; *(size_t*)i = (size_t)CustomGetProcAddress; matchedImports++; } else if (ptr == Kernel32Data[eGetShortPathNameA][ProcAddress]) { if (exe) Kernel32Data[eGetShortPathNameA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetShortPathNameA; matchedImports++; } else if (ptr == Kernel32Data[eFindNextFileA][ProcAddress]) { if (exe) Kernel32Data[eFindNextFileA][IATPtr] = i; *(size_t*)i = (size_t)CustomFindNextFileA; matchedImports++; } else if (ptr == Kernel32Data[eFindNextFileW][ProcAddress]) { if (exe) Kernel32Data[eFindNextFileW][IATPtr] = i; *(size_t*)i = (size_t)CustomFindNextFileW; matchedImports++; } else if (ptr == Kernel32Data[eLoadLibraryA][ProcAddress]) { if (exe) Kernel32Data[eLoadLibraryA][IATPtr] = i; *(size_t*)i = (size_t)CustomLoadLibraryA; matchedImports++; } else if (ptr == Kernel32Data[eLoadLibraryW][ProcAddress]) { if (exe) Kernel32Data[eLoadLibraryW][IATPtr] = i; *(size_t*)i = (size_t)CustomLoadLibraryW; matchedImports++; } else if (ptr == Kernel32Data[eFreeLibrary][ProcAddress]) { if (exe) Kernel32Data[eFreeLibrary][IATPtr] = i; *(size_t*)i = (size_t)CustomFreeLibrary; matchedImports++; } else if (ptr == Kernel32Data[eCreateEventA][ProcAddress]) { if (exe) Kernel32Data[eCreateEventA][IATPtr] = i; *(size_t*)i = (size_t)CustomCreateEventA; matchedImports++; } else if (ptr == Kernel32Data[eCreateEventW][ProcAddress]) { if (exe) Kernel32Data[eCreateEventW][IATPtr] = i; *(size_t*)i = (size_t)CustomCreateEventW; matchedImports++; } else if (ptr == Kernel32Data[eGetSystemInfo][ProcAddress]) { if (exe) Kernel32Data[eGetSystemInfo][IATPtr] = i; *(size_t*)i = (size_t)CustomGetSystemInfo; matchedImports++; } else if (ptr == Kernel32Data[eInterlockedCompareExchange][ProcAddress]) { if (exe) Kernel32Data[eInterlockedCompareExchange][IATPtr] = i; *(size_t*)i = (size_t)CustomInterlockedCompareExchange; matchedImports++; } else if (ptr == Kernel32Data[eSleep][ProcAddress]) { if (exe) Kernel32Data[eSleep][IATPtr] = i; *(size_t*)i = (size_t)CustomSleep; matchedImports++; } VirtualProtect((size_t*)i, sizeof(size_t), dwProtect[0], &dwProtect[1]); } }; static auto getSection = [](const PIMAGE_NT_HEADERS nt_headers, unsigned section) -> PIMAGE_SECTION_HEADER { return reinterpret_cast( (UCHAR*)nt_headers->OptionalHeader.DataDirectory + nt_headers->OptionalHeader.NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY) + section * sizeof(IMAGE_SECTION_HEADER)); }; static auto getSectionEnd = [](IMAGE_NT_HEADERS* ntHeader, size_t inst) -> auto { auto sec = getSection(ntHeader, ntHeader->FileHeader.NumberOfSections - 1); auto secSize = max(sec->SizeOfRawData, sec->Misc.VirtualSize); auto end = inst + max(sec->PointerToRawData, sec->VirtualAddress) + secSize; return end; }; auto hExecutableInstance_end = getSectionEnd(ntHeader, hExecutableInstance); // Find kernel32.dll for (size_t i = 0; i < nNumImports; i++) { if ((size_t)(hExecutableInstance + (pImports + i)->Name) < hExecutableInstance_end) { if (!_stricmp((const char*)(hExecutableInstance + (pImports + i)->Name), "KERNEL32.DLL")) PatchIAT(hExecutableInstance + (pImports + i)->FirstThunk, 0, hExecutableInstance_end); } } // Fixing ordinals auto szSelfName = GetSelfName(); static auto PatchOrdinals = [&szSelfName](size_t hInstance) { IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hInstance + ((IMAGE_DOS_HEADER*)hInstance)->e_lfanew); IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1; for (size_t i = 0; i < nNumImports; i++) { if ((size_t)(hInstance + (pImports + i)->Name) < getSectionEnd(ntHeader, (size_t)hInstance)) { if (iequals(szSelfName, (to_wstring((const char*)(hInstance + (pImports + i)->Name))))) { PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(hInstance + (pImports + i)->OriginalFirstThunk); size_t j = 0; while (thunk->u1.Function) { if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) { PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)(hInstance + thunk->u1.AddressOfData); void** p = (void**)(hInstance + (pImports + i)->FirstThunk); } ++thunk; } } } } }; ModuleList dlls; dlls.Enumerate(ModuleList::SearchLocation::LocalOnly); for (auto& e : dlls.m_moduleList) { PatchOrdinals((size_t)std::get(e)); } return matchedImports > 0; } LONG WINAPI CustomUnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) { // step 1: write minidump wchar_t modulename[MAX_PATH]; wchar_t filename[MAX_PATH]; wchar_t timestamp[128]; __time64_t time; struct tm ltime; HANDLE hFile; HWND hWnd; wchar_t* modulenameptr = NULL; if (GetModuleFileNameW(GetModuleHandle(NULL), modulename, _countof(modulename)) != 0) { modulenameptr = wcsrchr(modulename, '\\'); *modulenameptr = L'\0'; modulenameptr += 1; } else { *modulenameptr = L'err.err'; } _time64(&time); _localtime64_s(<ime, &time); wcsftime(timestamp, _countof(timestamp), L"%Y%m%d%H%M%S", <ime); swprintf_s(filename, L"%s\\%s\\%s.%s.dmp", modulename, L"logs", modulenameptr, timestamp); hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION ex; memset(&ex, 0, sizeof(ex)); ex.ThreadId = GetCurrentThreadId(); ex.ExceptionPointers = ExceptionInfo; ex.ClientPointers = TRUE; if (FAILED(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithDataSegs, &ex, NULL, NULL))) { } CloseHandle(hFile); } // step 2: write log // Logs exception into buffer and writes to file swprintf_s(filename, L"%s\\%s\\%s.%s.log", modulename, L"logs", modulenameptr, timestamp); hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { auto Log = [ExceptionInfo, hFile](char* buffer, size_t size, bool reg, bool stack, bool trace) { if (LogException(buffer, size, (LPEXCEPTION_POINTERS)ExceptionInfo, reg, stack, trace)) { DWORD NumberOfBytesWritten = 0; WriteFile(hFile, buffer, strlen(buffer), &NumberOfBytesWritten, NULL); } }; // Try to make a very descriptive exception, for that we need to malloc a huge buffer... if (auto buffer = (char*)malloc(max_logsize_ever)) { Log(buffer, max_logsize_ever, true, true, true); free(buffer); } else { // Use a static buffer, no need for any allocation static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump; static char static_buf[size]; static_assert(size <= max_static_buffer, "Static buffer is too big"); Log(buffer = static_buf, sizeof(static_buf), true, true, false); } CloseHandle(hFile); } // step 3: exit the application ShowCursor(TRUE); hWnd = FindWindowW(0, L""); SetForegroundWindow(hWnd); return EXCEPTION_CONTINUE_SEARCH; } void Init() { std::wstring modulePath = GetModuleFileNameW(hm); std::wstring moduleName = modulePath.substr(modulePath.find_last_of(L"/\\") + 1); moduleName.resize(moduleName.find_last_of(L'.')); modulePath.resize(modulePath.find_last_of(L"/\\") + 1); iniPaths.emplace_back(modulePath + moduleName + L".ini"); iniPaths.emplace_back(modulePath + L"plugins\\config.ini"); std::wstring m = GetModuleFileNameW(NULL); m = m.substr(0, m.find_last_of(L"/\\") + 1) + L"logs"; auto FolderExists = [](LPCWSTR szPath) -> BOOL { DWORD dwAttrib = GetFileAttributes(szPath); return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); }; if (FolderExists(m.c_str())) { SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter); // Now stub out CustomUnhandledExceptionFilter so NO ONE ELSE can set it! uint32_t ret = 0x909090C3; //ret DWORD protect[2]; VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), PAGE_EXECUTE_READWRITE, &protect[0]); memcpy(&SetUnhandledExceptionFilter, &ret, sizeof(ret)); VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), protect[0], &protect[1]); } LoadEverything(); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID /*lpReserved*/) { if (reason == DLL_PROCESS_ATTACH) { hm = hModule; Init(); } return TRUE; } ================================================ FILE: source-code/source/fakedll/exception.hpp ================================================ #pragma once /* * Unhandled Exception Tracer * by LINK/2012 * * This source code is offered for use in the public domain. You may * use, modify or distribute it freely. * * This code is distributed in the hope that it will be useful but * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY * DISCLAIMED. This includes but is not limited to warranties of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #include #include #include #include #include #include #pragma comment(lib, "Dbghelp.lib") /* * Special Note: * Try not to allocate any memory in this file! * Allocation after a exception may not be a good idea... */ #define LODWORD(_qw) ((DWORD)(_qw)) #define HIDWORD(_qw) ((DWORD)(((_qw) >> 32) & 0xffffffff)) // General constants static const int sizeof_word = sizeof(void*); // Size of a CPU word (4 bytes on x86) static const int max_chars_per_print = MAX_PATH + 256; // Max characters per Print() call static const int symbol_max = 256; // Max size of a symbol (func symbol, var symbol, etc) static const int max_static_buffer = 4096; // Max static buffer for logging // Stackdump constants static const int stackdump_max_words = 60; // max number of CPU words that the stackdump should dump static const int stackdump_words_per_line = 6; // max CPU words in a single line static const int stackdump_line_count = (stackdump_max_words / stackdump_words_per_line) + 1; // Backtrace constants static const int max_backtrace_ever = 100; static const int max_backtrace = 20; // Maximum log size constants static const int max_logsize_basic = (MAX_PATH + 200); // module path + other text static const int max_logsize_regs = 32 + (4 * 4 * 28); // info + (regsPerLine * numLines * charsPerReg) static const int max_logsize_stackdump = 32 + 80 + (stackdump_line_count * 32) + (10 * stackdump_words_per_line * stackdump_line_count); static const int max_logsize_backtrace = 32 + max_backtrace_ever * (MAX_PATH + symbol_max + 90); static const int max_logsize_ever = 32 + max_logsize_basic + max_logsize_regs + max_logsize_stackdump + max_logsize_backtrace; // Internal class ExceptionTracer; class StackTrace; static HMODULE GetModuleFromAddress(LPVOID address); static const char* GetExceptionCodeString(unsigned int code); static const char* FindModuleName(HMODULE module, char* output, DWORD size); static int LogException(char* buffer, size_t max, LPEXCEPTION_POINTERS pException, bool bLogRegisters, bool bLogStack, bool bLogBacktrace); static LPTOP_LEVEL_EXCEPTION_FILTER PrevFilter = nullptr; static void(*ExceptionCallback)(const char* buffer) = nullptr; // Exportable int InstallExceptionCatcher(void(*OnException)(const char* log)); /* * ExceptionTrace * This class is responssible for tracing all possible informations about an LPEXCEPTION_POINTER */ class ExceptionTracer { public: ExceptionTracer(char* buffer, size_t max, LPEXCEPTION_POINTERS pException); void PrintUnhandledException(); void PrintRegisters(); void PrintStackdump(); void PrintBacktrace(); void EnterScope(); void LeaveScope(); void Print(const char* fmt, ...); void NewLine() { Print("\n%s", spc); } protected: EXCEPTION_POINTERS& exception; EXCEPTION_RECORD& record; CONTEXT& context; HMODULE module; char* buffer; // Logging buffer size_t len; // Logged length size_t max; // Maximum we can log in that buffer char spc[(10 * 4) + 1]; // Scope/spacing buffer, 4 spaces per scope, max 10 scopes size_t nspc; // Number spaces used up there }; /* * StackTracer * Responssible for backtracing an stack from a context */ class StackTracer { public: struct Trace { // The following values may be null (any) HMODULE module; // The module the func related to this frame is located void* pc; // Program counter at func related to this frame (EIP) void* ret; // Return address for the frame void* frame; // The frame address (EBP) void* stack; // The stack pointer at the frame (ESP) }; StackTracer(const CONTEXT& context); Trace* Walk(); private: Trace trace; DWORD old_options; CONTEXT context; STACKFRAME64 frame; }; /* * TheUnhandledExceptionFilter * Logs an unhandled exception */ static LONG CALLBACK TheUnhandledExceptionFilter(LPEXCEPTION_POINTERS pException) { // Logs exception into buffer and calls the callback auto Log = [pException](char* buffer, size_t size, bool reg, bool stack, bool trace) { if (LogException(buffer, size, (LPEXCEPTION_POINTERS)pException, reg, stack, trace)) ExceptionCallback(buffer); }; // Try to make a very descriptive exception, for that we need to malloc a huge buffer... if (auto buffer = (char*)malloc(max_logsize_ever)) { Log(buffer, max_logsize_ever, true, true, true); free(buffer); } else { // Use a static buffer, no need for any allocation static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump; static char static_buf[size]; static_assert(size <= max_static_buffer, "Static buffer is too big"); Log(buffer = static_buf, sizeof(static_buf), true, true, false); } // Continue exception propagation return (PrevFilter ? PrevFilter(pException) : EXCEPTION_CONTINUE_SEARCH); // I'm not really sure about this return } /* * InstallExceptionCatcher * Installs a exception handler to call the specified callback when it happens with human readalbe information. */ int InstallExceptionCatcher(void(*cb)(const char* log)) { PrevFilter = SetUnhandledExceptionFilter(TheUnhandledExceptionFilter); ExceptionCallback = cb; return 1; } /* * LogException * Takes an LPEXCEPTION_POINTERS and transforms in a string that is put in the logging steam */ static int LogException(char* buffer, size_t max, LPEXCEPTION_POINTERS pException, bool bLogRegisters, bool bLogStack, bool bLogBacktrace) { ExceptionTracer trace(buffer, max, pException); trace.PrintUnhandledException(); trace.EnterScope(); if (bLogRegisters) trace.PrintRegisters(); if (bLogStack) trace.PrintStackdump(); if (bLogBacktrace) trace.PrintBacktrace(); trace.LeaveScope(); return 1; } /* * ExceptionTracer * Contructs a exception trace object, responssible for tracing informations about an exception */ ExceptionTracer::ExceptionTracer(char* buffer, size_t max, LPEXCEPTION_POINTERS pException) : buffer(buffer), exception(*pException), record(*pException->ExceptionRecord), context(*pException->ContextRecord) { this->buffer = buffer; this->buffer[this->len = 0] = 0; this->spc[this->nspc = 0] = 0; this->max = max; // Acquiere common information that we'll access this->module = GetModuleFromAddress(record.ExceptionAddress); } /* * Print * Prints some formated text into the logging buffer */ void ExceptionTracer::Print(const char* fmt, ...) { va_list va; va_start(va, fmt); if ((this->max - this->len) > max_chars_per_print) this->len += vsprintf(&this->buffer[len], fmt, va); va_end(va); } /* * EnterScope * Enters a new scope in the logging buffer (scope is related to indentation) * This also prints a new line */ void ExceptionTracer::EnterScope() { nspc += 4; spc[nspc - 4] = ' '; spc[nspc - 3] = ' '; spc[nspc - 2] = ' '; spc[nspc - 1] = ' '; spc[nspc - 0] = 0; NewLine(); } /* * LeaveScope * Leaves the scope */ void ExceptionTracer::LeaveScope() { assert(nspc > 0); nspc -= 4; spc[nspc] = 0; NewLine(); } /* * PrintUnhandledException * Prints the well known "Unhandled exception at ..." into the logging buffer */ void ExceptionTracer::PrintUnhandledException() { char module_name[MAX_PATH]; auto dwExceptionCode = record.ExceptionCode; uintptr_t address = (uintptr_t)record.ExceptionAddress; // Find out our module name for logging if (!this->module || !GetModuleFileNameA(this->module, module_name, sizeof(module_name))) strcpy(module_name, "unknown"); // Log the exception in a similar format similar to debuggers format Print("Unhandled exception at 0x%p in %s", address, FindModuleName(module, module_name, sizeof(module_name))); if (module) Print(" (+0x%x)", address - (uintptr_t)(module)); Print(": 0x%X: %s", dwExceptionCode, GetExceptionCodeString(dwExceptionCode)); // If exception is IN_PAGE_ERROR or ACCESS_VIOLATION, we have additional information such as an address if (dwExceptionCode == EXCEPTION_IN_PAGE_ERROR || dwExceptionCode == EXCEPTION_ACCESS_VIOLATION) { auto rw = (DWORD)record.ExceptionInformation[0]; // read or write? auto addr = (ULONG_PTR)record.ExceptionInformation[1]; // which address? Print(" %s 0x%p", rw == 0 ? "reading location" : rw == 1 ? "writing location" : rw == 8 ? "DEP at" : "", addr); // IN_PAGE_ERROR have another information... if (dwExceptionCode == EXCEPTION_IN_PAGE_ERROR) { NewLine(); Print("Underlying NTSTATUS code that resulted in the exception is 0x%p", record.ExceptionInformation[2]); } } Print("."); } /* * PrintRegisters * Prints the content of the assembly registers into the logging buffer */ void ExceptionTracer::PrintRegisters() { int regs_in_line = 0; // Amount of registers currently printed on this line // Prints a register, followed by spaces auto PrintRegister = [this, ®s_in_line](const char* reg_name, size_t reg_value, const char* spaces) { Print("%s: 0x%p%s", reg_name, reg_value, spaces); if (++regs_in_line >= 4) { this->NewLine(); regs_in_line = 0; } }; auto PrintFloatRegister = [this, ®s_in_line](const char* reg_name, int reg_num, uint32_t reg_value1, uint32_t reg_value2, uint32_t reg_value3, uint32_t reg_value4) { Print("%s%02d: 0x%08X 0x%08X 0x%08X 0x%08X [ %f %f %f %f ]", reg_name, reg_num, reg_value1, reg_value2, reg_value3, reg_value4, *(float*)& reg_value1, *(float*)& reg_value2, *(float*)& reg_value3, *(float*)& reg_value4); if (++regs_in_line >= 1) { this->NewLine(); regs_in_line = 0; } }; // Prints a general purposes register auto PrintIntRegister = [PrintRegister](const char* reg_name, size_t reg_value) { PrintRegister(reg_name, reg_value, " "); }; // Prints a segment register auto PrintSegRegister = [PrintRegister](const char* reg_name, size_t reg_value) { PrintRegister(reg_name, reg_value, " "); }; Print("Register dump:"); EnterScope(); { // Print main general purposes registers if (context.ContextFlags & CONTEXT_INTEGER) { #if !_M_X64 PrintIntRegister("EAX", context.Eax); PrintIntRegister("EBX", context.Ebx); PrintIntRegister("ECX", context.Ecx); PrintIntRegister("EDX", context.Edx); PrintIntRegister("EDI", context.Edi); PrintIntRegister("ESI", context.Esi); #else PrintIntRegister("RAX", context.Rax); PrintIntRegister("RCX", context.Rcx); PrintIntRegister("RDX", context.Rdx); PrintIntRegister("RBX", context.Rbx); PrintIntRegister("RBP", context.Rbp); PrintIntRegister("RSI", context.Rsi); PrintIntRegister("RDI", context.Rdi); PrintIntRegister("R08", context.R8); PrintIntRegister("R09", context.R9); PrintIntRegister("R10", context.R10); PrintIntRegister("R11", context.R11); PrintIntRegister("R12", context.R12); PrintIntRegister("R13", context.R13); PrintIntRegister("R14", context.R14); PrintIntRegister("R15", context.R15); #endif } // Print control registers if (context.ContextFlags & CONTEXT_CONTROL) { #if !_M_X64 PrintIntRegister("EBP", context.Ebp); PrintIntRegister("EIP", context.Eip); PrintIntRegister("ESP", context.Esp); PrintIntRegister("EFL", context.EFlags); this->NewLine(); this->NewLine(); regs_in_line = 0; PrintSegRegister("CS", context.SegCs); PrintSegRegister("SS", context.SegSs); #else PrintIntRegister("RIP", context.Rip); PrintIntRegister("RSP", context.Rsp); PrintIntRegister("EFL", context.EFlags); this->NewLine(); this->NewLine(); regs_in_line = 0; PrintSegRegister("CS", context.SegCs); PrintSegRegister("SS", context.SegSs); #endif } this->NewLine(); regs_in_line = 0; // Print segment registers if (context.ContextFlags & CONTEXT_SEGMENTS) { PrintSegRegister("GS", context.SegGs); PrintSegRegister("FS", context.SegFs); this->NewLine(); regs_in_line = 0; PrintSegRegister("ES", context.SegEs); PrintSegRegister("DS", context.SegDs); } this->NewLine(); this->NewLine(); regs_in_line = 0; // Print floating point registers if (context.ContextFlags & CONTEXT_FLOATING_POINT) { for (int i = 0; i < 8; i++) { #if !_M_X64 auto f = *(M128A*) & (context.FloatSave.RegisterArea[i * 10]); PrintFloatRegister("ST", i, LODWORD(f.Low), HIDWORD(f.Low), LODWORD(f.High), HIDWORD(f.High)); #else PrintFloatRegister("ST", i, LODWORD(context.FltSave.FloatRegisters[i].Low), HIDWORD(context.FltSave.FloatRegisters[i].Low), LODWORD(context.FltSave.FloatRegisters[i].High), HIDWORD(context.FltSave.FloatRegisters[i].High)); #endif } this->NewLine(); for (int i = 0; i < 16; i++) { #if !_M_X64 auto f = *(M128A*) & (context.ExtendedRegisters[(i + 10) * 16]); PrintFloatRegister("XMM", i, LODWORD(f.Low), HIDWORD(f.Low), LODWORD(f.High), HIDWORD(f.High)); if (i >= 7) break; #else PrintFloatRegister("XMM", i, LODWORD(context.FltSave.XmmRegisters[i].Low), HIDWORD(context.FltSave.XmmRegisters[i].Low), LODWORD(context.FltSave.XmmRegisters[i].High), HIDWORD(context.FltSave.XmmRegisters[i].High)); #endif } } } LeaveScope(); } /* * PrintStackdump * Prints the content of the stack into the logging buffer */ void ExceptionTracer::PrintStackdump() { // We need the ESP of the exception context to execute a stack dump, make sure we have access to it if ((context.ContextFlags & CONTEXT_CONTROL) == 0) return; static const auto align = sizeof_word; // Stack aligment static const auto max_words_in_line_magic = stackdump_words_per_line + 10; MEMORY_BASIC_INFORMATION mbi; #if !_M_X64 uintptr_t base, bottom, top = (uintptr_t)context.Esp; #else uintptr_t base, bottom, top = (uintptr_t)context.Rsp; #endif auto words_in_line = max_words_in_line_magic; // Finds the bottom of the stack from it's base pointer // Note: mbi will get overriden on this function auto GetStackBottom = [&mbi](uintptr_t base) { VirtualQuery((void*)base, &mbi, sizeof(mbi)); // Find uncommited region of the stack VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find guard page VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find commited region of the stack auto last = (uintptr_t)mbi.BaseAddress; return (base + (last - base) + mbi.RegionSize); // base + distanceToLastRegion + lastRegionSize }; // Prints an CPU word at the specified stack address auto PrintWord = [this, &words_in_line](uintptr_t addr) { if (words_in_line++ >= stackdump_words_per_line) { // Print new line only if it's not the first time we enter here (i.e. words_in_line has magical value) if (words_in_line != max_words_in_line_magic + 1) NewLine(); words_in_line = 1; Print("0x%p: ", addr); } Print(" %p", *(size_t*)addr); }; Print("Stack dump:"); EnterScope(); { // Makes sure the pointer at top (ESP) is valid and readable memory if (VirtualQuery((void*)(top), &mbi, sizeof(mbi)) && (mbi.State & MEM_COMMIT) && (mbi.Protect & (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_READONLY)) != 0) { base = (uintptr_t)mbi.AllocationBase; // Base of the stack (uncommited) bottom = GetStackBottom(base); // Bottom of the stack (commited) // Align the stack top (esp) in a 4 bytes boundary auto remainder = top % align; uintptr_t current = remainder ? top + (align - remainder) : top; // on x86 stack grows downward! (i.e. from bottom to base) for (int n = 0; n < stackdump_max_words && current < bottom; ++n, current += align) PrintWord(current); NewLine(); Print("base: 0x%p top: 0x%p bottom: 0x%p", base, top, bottom); NewLine(); } } LeaveScope(); } /* * PrintBacktrace * Prints a call backtrace into the logging buffer */ void ExceptionTracer::PrintBacktrace() { StackTracer tracer(this->context); char module_name[MAX_PATH]; char sym_buffer[sizeof(SYMBOL_INFO) + symbol_max]; int backtrace_count = 0; // Num of frames traced bool has_symbol_api = false; // True if we have the symbol API available for use DWORD old_options; // Saves old symbol API options SYMBOL_INFO& symbol = *(SYMBOL_INFO*)sym_buffer; symbol.SizeOfStruct = sizeof(SYMBOL_INFO); symbol.MaxNameLen = symbol_max; // Tries to get the symbol api if (SymInitialize(GetCurrentProcess(), 0, TRUE)) { has_symbol_api = true; old_options = SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_NO_PROMPTS | SYMOPT_FAIL_CRITICAL_ERRORS); } Print("Backtrace (may be wrong):"); EnterScope(); { // Walks on the stack until there's no frame to trace or we traced 'max_backtrace' frames while (auto trace = tracer.Walk()) { if (++backtrace_count >= max_backtrace) break; bool has_sym = false; // This EIP has a symbol associated with it? DWORD64 displacement; // EIP displacement relative to symbol // If we have access to the symbol api, try to get symbol name from pc (eip) if (has_symbol_api) has_sym = trace->pc ? !!SymFromAddr(GetCurrentProcess(), (DWORD64)trace->pc, &displacement, &symbol) : false; // Print everything up, this.... Ew, this looks awful! Print(backtrace_count == 1 ? "=>" : " "); // First line should have '=>' to specify where it crashed Print("0x%p ", trace->pc); // Print EIP at frame if (has_sym) Print("%s+0x%x ", symbol.Name, (DWORD)displacement); // Print frame func symbol Print("in %s (+0x%x) ", // Print module trace->module ? FindModuleName(trace->module, module_name, sizeof(module_name)) : "unknown", (uintptr_t)(trace->pc) - (uintptr_t)(trace->module) // Module displacement ); if (trace->frame) Print("(0x%p) ", trace->frame); // Print frame pointer NewLine(); } } LeaveScope(); // Cleanup the symbol api if (has_symbol_api) { SymSetOptions(old_options); SymCleanup(GetCurrentProcess()); } } /* * GetExceptionCodeString * Returns an description by an exception code */ static const char* GetExceptionCodeString(unsigned int code) { switch (code) { case EXCEPTION_ACCESS_VIOLATION: return "Access violation"; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "Array bounds exceeded"; case EXCEPTION_BREAKPOINT: return "Breakpoint exception"; case EXCEPTION_DATATYPE_MISALIGNMENT: return "Data type misalignment exception"; case EXCEPTION_FLT_DENORMAL_OPERAND: return "Denormal float operand"; case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "Floating-point division by zero"; case EXCEPTION_FLT_INEXACT_RESULT: return "Floating-point inexact result"; case EXCEPTION_FLT_INVALID_OPERATION: return "Floating-point invalid operation"; case EXCEPTION_FLT_OVERFLOW: return "Floating-point overflow"; case EXCEPTION_FLT_STACK_CHECK: return "Floating-point stack check"; case EXCEPTION_FLT_UNDERFLOW: return "Floating-point underflow"; case EXCEPTION_ILLEGAL_INSTRUCTION: return "Illegal instruction."; case EXCEPTION_IN_PAGE_ERROR: return "In page error"; case EXCEPTION_INT_DIVIDE_BY_ZERO: return "Integer division by zero"; case EXCEPTION_INT_OVERFLOW: return "Integer overflow"; case EXCEPTION_INVALID_DISPOSITION: return "Invalid disposition"; case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "Non-continuable exception"; case EXCEPTION_PRIV_INSTRUCTION: return "Privileged instruction"; case EXCEPTION_SINGLE_STEP: return "Single step exception"; case EXCEPTION_STACK_OVERFLOW: return "Stack overflow"; default: return "NO_DESCRIPTION"; } } /* * FindModuleName * Finds module filename or "unknown" */ static const char* FindModuleName(HMODULE module, char* output, DWORD maxsize) { if (GetModuleFileNameA(module, output, maxsize)) { // Finds the filename part in the output string char* filename = strrchr(output, '\\'); if (!filename) filename = strrchr(output, '/'); // If filename found (i.e. output isn't already a filename but full path), make output be filename if (filename) { size_t size = strlen(++filename); memmove(output, filename, size); output[size] = 0; } } else { // Unknown module strcpy(output, "unknown"); } return output; } /* * GetModuleFromAddress * Finds module handle from some address inside it */ static HMODULE GetModuleFromAddress(LPVOID address) { HMODULE module; if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (char*)address, &module)) return module; return nullptr; } /* * StackTracer * Constructs the tracer, we basically need to initialize the symbol api */ StackTracer::StackTracer(const CONTEXT& context) { // Initialise basic values memset(&this->frame, 0, sizeof(frame)); memcpy(&this->context, &context, sizeof(context)); // Setup the initial frame context #if !_M_X64 frame.AddrPC.Mode = AddrModeFlat; frame.AddrPC.Offset = context.Eip; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Ebp; frame.AddrStack.Mode = AddrModeFlat; frame.AddrStack.Offset = context.Esp; #else frame.AddrPC.Mode = AddrModeFlat; frame.AddrPC.Offset = context.Rip; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Rbp; frame.AddrStack.Mode = AddrModeFlat; frame.AddrStack.Offset = context.Rsp; #endif } /* * StackTracer::Walk * Walks on the stack, each walk is one frame of backtrace * Returns a frame or null if the walk on the park is not possible anymore */ StackTracer::Trace* StackTracer::Walk() { if (StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &frame, &context, NULL, NULL, NULL, NULL)) { trace.module = GetModuleFromAddress((void*)frame.AddrPC.Offset); trace.frame = (void*)frame.AddrFrame.Offset; trace.stack = (void*)frame.AddrStack.Offset; trace.pc = (void*)frame.AddrPC.Offset; trace.ret = (void*)frame.AddrReturn.Offset; return &trace; } return nullptr; } ================================================ FILE: source-code/source/fakedll/fakedll.vcxproj ================================================  Debug x64 Release x64 16.0 {B49C6ABE-931C-4F91-9A94-21A41A305FEE} Win32Proj fakedll 10.0 DynamicLibrary true v142 Unicode DynamicLibrary false v142 true Unicode false true fakednsapi false fakednsapi NotUsing Level3 Disabled true _CRT_SECURE_NO_WARNINGS;_DEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true pch.h ..\dependencies\MemoryModule;%(AdditionalIncludeDirectories) stdcpp17 -d2FH4- %(AdditionalOptions) Windows true false x64.def -d2:-FH4- %(AdditionalOptions) NotUsing Level3 MaxSpeed true true true _CRT_SECURE_NO_WARNINGS;NDEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true pch.h ..\dependencies\MemoryModule;%(AdditionalIncludeDirectories) stdcpp17 MultiThreadedDLL -d2FH4- %(AdditionalOptions) Windows true true true false x64.def -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/fakedll/fakedll.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Source Files Source Files Source Files ================================================ FILE: source-code/source/fakedll/framework.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include #pragma once #include #include #include #include "ModuleList.h" #include #pragma intrinsic(_ReturnAddress) struct shared { FARPROC DllCanUnloadNow; FARPROC DllGetClassObject; FARPROC DllRegisterServer; FARPROC DllUnregisterServer; FARPROC DebugSetMute; void LoadOriginalLibrary(HMODULE dll) { DllCanUnloadNow = GetProcAddress(dll, "DllCanUnloadNow"); DllGetClassObject = GetProcAddress(dll, "DllGetClassObject"); DllRegisterServer = GetProcAddress(dll, "DllRegisterServer"); DllUnregisterServer = GetProcAddress(dll, "DllUnregisterServer"); DebugSetMute = GetProcAddress(dll, "DebugSetMute"); } } shared; struct dnsapi_dll { HMODULE dll; // only some functions are implemented. // PDAFT doesn't use many, so this should hopefully be fine FARPROC DnsFree; FARPROC DnsQuery_A; FARPROC DnsQueryEx; FARPROC DnsCancelQuery; FARPROC DnsDhcpRegisterTerm; FARPROC DnsNotifyResolver; FARPROC DnsDhcpRegisterHostAddrs; FARPROC DnsQueryConfigDword; FARPROC DnsDhcpRemoveRegistrations; FARPROC DnsDhcpRegisterInit; FARPROC DnsDhcpRegisterAddrs; // DnsQueryEx and DnsCancelQuery take pointers to structs as parameters // (three for DnsQueryEx and one for DnsCancelQuery) // fortunately they should fit in registers so the stack doesn't matter // hopefully this works fine... I have no clue what I'm doing static LONG WINAPI DnsQueryExStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } static LONG WINAPI DnsCancelQueryStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } /*static LONG WINAPI DnsDhcpRegisterTermStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } static LONG WINAPI DnsNotifyResolverStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } static LONG WINAPI DnsDhcpRegisterHostAddrsStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } static LONG WINAPI DnsQueryConfigDwordStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } static LONG WINAPI DnsDhcpRemoveRegistrationsStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } static LONG WINAPI DnsDhcpRegisterInitStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED } static LONG WINAPI DnsDhcpRegisterAddrsStub() { return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED }*/ void LoadOriginalLibrary(HMODULE module) { dll = module; shared.LoadOriginalLibrary(dll); DnsFree = GetProcAddress(dll, "DnsFree"); DnsQuery_A = GetProcAddress(dll, "DnsQuery_A"); DnsQueryEx = GetProcAddress(dll, "DnsQueryEx"); DnsCancelQuery = GetProcAddress(dll, "DnsCancelQuery"); DnsDhcpRegisterTerm = GetProcAddress(dll, "DnsDhcpRegisterTerm"); DnsNotifyResolver = GetProcAddress(dll, "DnsNotifyResolver"); DnsDhcpRegisterHostAddrs = GetProcAddress(dll, "DnsDhcpRegisterHostAddrs"); DnsQueryConfigDword = GetProcAddress(dll, "DnsQueryConfigDword"); DnsDhcpRemoveRegistrations = GetProcAddress(dll, "DnsDhcpRemoveRegistrations"); DnsDhcpRegisterInit = GetProcAddress(dll, "DnsDhcpRegisterInit"); DnsDhcpRegisterAddrs = GetProcAddress(dll, "DnsDhcpRegisterAddrs"); // if entry points aren't found, GetProcAddress should return null // I hope this is correct // Thanks to somewhatlurker if (DnsQueryEx == NULL) { DnsQueryEx = (FARPROC)& DnsQueryExStub; }; if (DnsCancelQuery == NULL) { DnsCancelQuery = (FARPROC)& DnsCancelQueryStub; }; /*if (DnsDhcpRegisterTerm == NULL) { DnsDhcpRegisterTerm = (FARPROC)& DnsDhcpRegisterTermStub; }; if (DnsNotifyResolver == NULL) { DnsNotifyResolver = (FARPROC)& DnsNotifyResolverStub; }; if (DnsDhcpRegisterHostAddrs == NULL) { DnsDhcpRegisterHostAddrs = (FARPROC)& DnsDhcpRegisterHostAddrsStub; }; if (DnsQueryConfigDword == NULL) { DnsQueryConfigDword = (FARPROC)& DnsQueryConfigDwordStub; }; if (DnsDhcpRemoveRegistrations == NULL) { DnsDhcpRemoveRegistrations = (FARPROC)& DnsDhcpRemoveRegistrationsStub; }; if (DnsDhcpRegisterInit == NULL) { DnsDhcpRegisterInit = (FARPROC)& DnsDhcpRegisterInitStub; }; if (DnsDhcpRegisterAddrs == NULL) { DnsDhcpRegisterAddrs = (FARPROC)& DnsDhcpRegisterAddrsStub; };*/ } } dnsapi; void _DnsFree() { dnsapi.DnsFree(); } void _DnsQuery_A() { dnsapi.DnsQuery_A(); } void _DnsQueryEx() { dnsapi.DnsQueryEx(); } void _DnsCancelQuery() { dnsapi.DnsCancelQuery(); } void _DnsDhcpRegisterTerm() { dnsapi.DnsDhcpRegisterTerm(); } void _DnsNotifyResolver() { dnsapi.DnsNotifyResolver(); } void _DnsDhcpRegisterHostAddrs() { dnsapi.DnsDhcpRegisterHostAddrs(); } void _DnsQueryConfigDword() { dnsapi.DnsQueryConfigDword(); } void _DnsDhcpRemoveRegistrations() { dnsapi.DnsDhcpRemoveRegistrations(); } void _DnsDhcpRegisterInit() { dnsapi.DnsDhcpRegisterInit(); } void _DnsDhcpRegisterAddrs() { dnsapi.DnsDhcpRegisterAddrs(); } #pragma runtime_checks( "", off ) #ifdef _DEBUG #pragma message ("You are compiling the code in Debug - be warned that wrappers for export functions may not have correct code generated") #endif void _DllRegisterServer() { shared.DllRegisterServer(); } void _DllUnregisterServer() { shared.DllUnregisterServer(); } void _DllCanUnloadNow() { shared.DllCanUnloadNow(); } void _DllGetClassObject() { shared.DllGetClassObject(); } #pragma runtime_checks( "", restore ) ================================================ FILE: source-code/source/fakedll/x64.def ================================================ LIBRARY "dnsapi" EXPORTS DnsFree = _DnsFree DnsQuery_A = _DnsQuery_A DnsQueryEx = _DnsQueryEx DnsCancelQuery = _DnsCancelQuery DnsDhcpRegisterTerm = _DnsDhcpRegisterTerm DnsNotifyResolver = _DnsNotifyResolver DnsDhcpRegisterHostAddrs = _DnsDhcpRegisterHostAddrs DnsQueryConfigDword = _DnsQueryConfigDword DnsDhcpRemoveRegistrations = _DnsDhcpRemoveRegistrations DnsDhcpRegisterInit = _DnsDhcpRegisterInit DnsDhcpRegisterAddrs = _DnsDhcpRegisterAddrs DllCanUnloadNow = _DllCanUnloadNow PRIVATE DllGetClassObject = _DllGetClassObject PRIVATE DllRegisterServer = _DllRegisterServer PRIVATE DllUnregisterServer = _DllUnregisterServer PRIVATE ================================================ FILE: source-code/source/plugins/DSCRemote/DSCRemote.vcxproj ================================================  Debug x64 Release x64 16.0 {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A} DSCRemote 10.0 DynamicLibrary true v142 MultiByte DynamicLibrary false v142 true MultiByte .dva .dva Level3 Disabled true true ..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) -d2FH4- %(AdditionalOptions) Console ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) detours.lib;evr.lib;mfplat.lib;mfuuid.lib;strmiids.lib;syelog.lib;%(AdditionalDependencies) -d2:-FH4- %(AdditionalOptions) Level3 MaxSpeed true true true true ..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) MultiThreaded -d2FH4- %(AdditionalOptions) Console true true detours.lib;evr.lib;mfplat.lib;mfuuid.lib;syelog.lib;%(AdditionalDependencies) ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/plugins/DSCRemote/DSCRemote.vcxproj.filters ================================================  ================================================ FILE: source-code/source/plugins/DSCRemote/PluginConfigApi.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include // resolution class to store and sort the width and height easily class resolution { public: unsigned int width; unsigned int height; resolution() { width = 0; height = 0; } resolution(unsigned int width, unsigned int height) { resolution::width = width; resolution::height = height; } bool operator ==(const resolution &res2) { return width == res2.width && height == res2.height; } // in comparisons width takes priority because it's usually displayed first bool operator <(const resolution &res2) { if (width == res2.width) return height < res2.height; else return width < res2.width; } bool operator >(const resolution &res2) { if (width == res2.width) return height > res2.height; else return width > res2.width; } }; namespace PluginConfig { #pragma pack(push, 1) enum ConfigType { CONFIG_BOOLEAN, CONFIG_NUMERIC, CONFIG_STRING, CONFIG_DROPDOWN_INDEX, CONFIG_DROPDOWN_TEXT, CONFIG_DROPDOWN_NUMBER, CONFIG_RESOLUTION, CONFIG_GROUP_START, CONFIG_GROUP_END, CONFIG_BUTTON, CONFIG_SPACER }; struct PluginConfigBooleanData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; bool defaultVal; bool saveAsString; }; struct PluginConfigNumericData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; int minVal; int maxVal; }; struct PluginConfigStringData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; LPCWSTR defaultVal; bool useUtf8; }; struct PluginConfigDropdownIndexData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; std::vector valueStrings; }; struct PluginConfigDropdownTextData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; LPCWSTR defaultVal; std::vector valueStrings; bool editable; bool useUtf8; }; struct PluginConfigDropdownNumberData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; std::vector valueInts; bool editable; }; struct PluginConfigResolutionData { LPCWSTR iniVarName; LPCWSTR iniVarName2; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; resolution defaultVal; std::vector valueResolutions; bool editable; }; struct PluginConfigGroupData { LPCWSTR name; int height; }; struct PluginConfigButtonData { LPCWSTR friendlyName; LPCWSTR description; void(*func)(); }; struct PluginConfigSpacerData { int height; }; struct PluginConfigOption { ConfigType cfgType; void* data; }; struct PluginConfigArray { int len; PluginConfigOption* options; }; #pragma pack(pop) } ================================================ FILE: source-code/source/plugins/DSCRemote/dllmain.cpp ================================================ #include #pragma comment(lib, "Ws2_32.lib") #include #include #include #include "framework.h" #include "PluginConfigApi.h" #include bool(__cdecl* DSC_EXECUTE_COMMAND)(__int64 dsc_address, float delta_time, __int64 start_time, void* wait_timer, int* a5, int a6, int a7) = (bool(__cdecl*)(__int64 dsc_address, float delta_time, __int64 start_time, void* wait_timer, int* a5, int a6, int a7)) 0x14011CBA0; bool hookedDSC_EXECUTE_COMMAND(__int64 dsc_address, float delta_time, __int64 start_time, void* wait_timer, int* a5, int a6, int a7); void serve(); bool debug = false; unsigned short port = 8139; void loadConfig() { port = GetPrivateProfileIntW(L"general", L"port", 8139, CONFIG_FILE); debug = GetPrivateProfileIntW(L"general", L"debug", 0, CONFIG_FILE) > 0; return; } float last_delta_time = 0.0; __int64 last_start_time = 0i64; void* last_wait_timer = nullptr; int* last_a5 = nullptr; int last_a6 = 0; int last_a7 = 0; bool hookedDSC_EXECUTE_COMMAND(__int64 dsc_address, float delta_time, __int64 start_time, void* wait_timer, int* a5, int a6, int a7) { last_delta_time = delta_time; last_start_time = start_time; last_wait_timer = wait_timer; last_a5 = a5; last_a6 = a6; last_a7 = a7; return DSC_EXECUTE_COMMAND(dsc_address, delta_time, start_time, wait_timer, a5, a6, a7); } void serve() { using namespace std; cout << "[DSCRemote] Staring server..." << endl; WSADATA wsadata; int result = WSAStartup(MAKEWORD(2, 2), &wsadata); if (result) // error { cout << "[DSCRemote] E: WSAStartup error " << result << '.' << endl; return; } SOCKET sock; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (result == INVALID_SOCKET) { cout << "[DSCRemote] E: Invalid socket." << endl; WSACleanup(); return; } sockaddr_in saddrin; saddrin.sin_family = AF_INET; saddrin.sin_addr.s_addr = 0; saddrin.sin_port = htons(port); result = ::bind(sock, (sockaddr*)&saddrin, sizeof(sockaddr_in)); if (result) // error { cout << "[DSCRemote] E: Couldn't bind port " << port << '.' << endl; closesocket(sock); WSACleanup(); return; } result = listen(sock, 1); if (result) // error { cout << "[DSCRemote] E: Couldn't listen." << endl; closesocket(sock); WSACleanup(); return; } while (true) { cout << "[DSCRemote] Waiting for client..." << endl; SOCKET client_sock; client_sock = accept(sock, NULL, NULL); cout << "[DSCRemote] Client accepted." << endl; char buff_recv[64]; vector cmdStack; do { result = recv(client_sock, buff_recv, sizeof(buff_recv), 0); if (result > 0) { if (debug) cout << "[DSCRemote] D: Received: " << buff_recv << endl; if (buff_recv[0] != 'i') { long stack = stol(buff_recv); for (int i = 0; i < sizeof(buff_recv); i++) buff_recv[i] = '\0'; cmdStack.push_back(stack); const char buff_out[] = "Stacking command/parameter. Send 'i' to inject."; send(client_sock, buff_out, sizeof(buff_out), 0); continue; } for (int i = 0; i < sizeof(buff_recv); i++) buff_recv[i] = '\0'; const char buff_out[] = "Injecting stack."; send(client_sock, buff_out, sizeof(buff_out), 0); const int64_t dscbaseaddr = 0x140CDD978i64; int* currentpos = (int*)(dscbaseaddr + 0x2bf2c); int* command = (int*)(dscbaseaddr + 0xc); int posbk = *currentpos; vector cmdbk; for (int i=0; i 0); closesocket(client_sock); cout << "[DSCRemote] Restarting..." << endl; } cout << "[DSCRemote] Bye!" << endl; closesocket(sock); WSACleanup(); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { using namespace std; loadConfig(); DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); cout << "[DSCRemote] Hooking functions..." << endl; DetourAttach(&(PVOID&)DSC_EXECUTE_COMMAND, (PVOID)hookedDSC_EXECUTE_COMMAND); cout << "[DSCRemote] Functions hooked." << endl; DetourTransactionCommit(); thread* server_thread = new thread(serve); } return TRUE; } PluginConfig::PluginConfigOption config[] = { { PluginConfig::CONFIG_NUMERIC, new PluginConfig::PluginConfigNumericData{ L"port", L"general", CONFIG_FILE, L"Port", L"TCP/IP port.", 8139, 1, USHRT_MAX } }, { PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"debug", L"general", CONFIG_FILE, L"Debug", L"Print extra information.", false } }, }; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"DSCRemote"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"Allows external applications to send DSC commands via TCP/IP."; } extern "C" __declspec(dllexport) PluginConfig::PluginConfigArray GetPluginOptions(void) { return PluginConfig::PluginConfigArray{ _countof(config), config }; } ================================================ FILE: source-code/source/plugins/DSCRemote/framework.h ================================================ #include #include std::wstring ExePath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); return std::wstring(buffer); } std::wstring DirPath() { std::wstring exepath = ExePath(); std::wstring::size_type pos = exepath.find_last_of(L"\\/"); return exepath.substr(0, pos); } std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\DSCRemote.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); ================================================ FILE: source-code/source/plugins/DivaMovie/DivaMovie.vcxproj ================================================  Debug x64 Release x64 16.0 {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A} DivaMovie 10.0 DynamicLibrary true v142 MultiByte DynamicLibrary false v142 true MultiByte .dva .dva Level3 Disabled true true ..\..\..\dependencies\simpleini;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) -d2FH4- %(AdditionalOptions) Console ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) detours.lib;evr.lib;mfplat.lib;mfuuid.lib;strmiids.lib;syelog.lib;%(AdditionalDependencies) -d2:-FH4- %(AdditionalOptions) Level3 MaxSpeed true true true true ..\..\..\dependencies\simpleini;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) MultiThreadedDLL -d2FH4- %(AdditionalOptions) Console true true detours.lib;evr.lib;mfplat.lib;mfuuid.lib;syelog.lib;%(AdditionalDependencies) ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/plugins/DivaMovie/DivaMovie.vcxproj.filters ================================================  ================================================ FILE: source-code/source/plugins/DivaMovie/PluginConfigApi.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include // resolution class to store and sort the width and height easily class resolution { public: unsigned int width; unsigned int height; resolution() { width = 0; height = 0; } resolution(unsigned int width, unsigned int height) { resolution::width = width; resolution::height = height; } bool operator ==(const resolution &res2) { return width == res2.width && height == res2.height; } // in comparisons width takes priority because it's usually displayed first bool operator <(const resolution &res2) { if (width == res2.width) return height < res2.height; else return width < res2.width; } bool operator >(const resolution &res2) { if (width == res2.width) return height > res2.height; else return width > res2.width; } }; namespace PluginConfig { #pragma pack(push, 1) enum ConfigType { CONFIG_BOOLEAN, CONFIG_NUMERIC, CONFIG_STRING, CONFIG_DROPDOWN_INDEX, CONFIG_DROPDOWN_TEXT, CONFIG_DROPDOWN_NUMBER, CONFIG_RESOLUTION, CONFIG_GROUP_START, CONFIG_GROUP_END, CONFIG_BUTTON, CONFIG_SPACER }; struct PluginConfigBooleanData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; bool defaultVal; bool saveAsString; }; struct PluginConfigNumericData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; int minVal; int maxVal; }; struct PluginConfigStringData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; LPCWSTR defaultVal; bool useUtf8; }; struct PluginConfigDropdownIndexData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; std::vector valueStrings; }; struct PluginConfigDropdownTextData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; LPCWSTR defaultVal; std::vector valueStrings; bool editable; bool useUtf8; }; struct PluginConfigDropdownNumberData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; std::vector valueInts; bool editable; }; struct PluginConfigResolutionData { LPCWSTR iniVarName; LPCWSTR iniVarName2; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; resolution defaultVal; std::vector valueResolutions; bool editable; }; struct PluginConfigGroupData { LPCWSTR name; int height; }; struct PluginConfigButtonData { LPCWSTR friendlyName; LPCWSTR description; void(*func)(); }; struct PluginConfigSpacerData { int height; }; struct PluginConfigOption { ConfigType cfgType; void* data; }; struct PluginConfigArray { int len; PluginConfigOption* options; }; #pragma pack(pop) } ================================================ FILE: source-code/source/plugins/DivaMovie/dllmain.cpp ================================================ #include "framework.h" #include "PluginConfigApi.h" #include #include #include #include #include #include #include #include bool forceSoftwareDecoding = false, forceHybridDecoding = false, debug = false; IDirect3DDeviceManager9* deviceManager; IMFTransform* mfTransform; int width; int height; unsigned long samplesize; unsigned long subtype; IMFSample* dstSample; IDirect3DSurface9* dstSurface; IMFSample* srcSample; IMFMediaBuffer* srcBuffer; HRESULT initialize(IMFTransform* transform) { HRESULT result = S_OK; IMFMediaType* type = NULL; IMFMediaBuffer* buffer = NULL; HANDLE hDevice = NULL; IDirectXVideoAccelerationService* service = NULL; AM_MEDIA_TYPE* format = NULL; VIDEOINFOHEADER2* header = NULL; // Release what we already had beforehand SAFE_RELEASE(mfTransform); SAFE_RELEASE(dstSample); SAFE_RELEASE(dstSurface); SAFE_RELEASE(srcSample); SAFE_RELEASE(srcBuffer); ASSERT(transform->GetOutputCurrentType(0, &type)); ASSERT(type->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&format)); header = (VIDEOINFOHEADER2*)format->pbFormat; width = header->bmiHeader.biWidth; height = header->bmiHeader.biHeight; samplesize = format->lSampleSize; subtype = format->subtype.Data1; // System memory sample ASSERT(MFCreateSample(&srcSample)); ASSERT(MFCreateMemoryBuffer(format->lSampleSize, &buffer)); ASSERT(srcSample->AddBuffer(buffer)); ASSERT(buffer->QueryInterface(&srcBuffer)); // Video memory sample ASSERT(deviceManager->OpenDeviceHandle(&hDevice)); ASSERT(deviceManager->GetVideoService(hDevice, __uuidof(IDirectXVideoAccelerationService), (void**)& service)); ASSERT(service->CreateSurface(width, height, 0, (D3DFORMAT)subtype, D3DPOOL_DEFAULT, 0, DXVA2_VideoSoftwareRenderTarget, &dstSurface, NULL)); ASSERT(MFCreateVideoSampleFromSurface(dstSurface, &dstSample)); ASSERT(deviceManager->CloseDeviceHandle(hDevice)); mfTransform = transform; mfTransform->AddRef(); end: if (format) type->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, format); SAFE_RELEASE(service); SAFE_RELEASE(buffer); SAFE_RELEASE(type); return result; } VTABLE_HOOK(HRESULT, IMFTransform, ProcessOutput, DWORD dwFlags, DWORD cOutputBufferCount, MFT_OUTPUT_DATA_BUFFER* pOutputSamples, DWORD* pdwStatus) { if (pOutputSamples->pSample != NULL || deviceManager == NULL || cOutputBufferCount != 1) return originalProcessOutput(This, dwFlags, cOutputBufferCount, pOutputSamples, pdwStatus); HRESULT result = S_OK; if (mfTransform != This) ASSERT(initialize(This)); pOutputSamples->pSample = srcSample; pOutputSamples->pSample->AddRef(); ASSERT(originalProcessOutput(This, dwFlags, cOutputBufferCount, pOutputSamples, pdwStatus)); D3DLOCKED_RECT rect; BYTE* buf; ASSERT(srcBuffer->Lock(&buf, NULL, NULL)); ASSERT(dstSurface->LockRect(&rect, NULL, NULL)); ASSERT(MFCopyImage((BYTE*)rect.pBits, rect.Pitch, buf, samplesize, samplesize, 1)); ASSERT(dstSurface->UnlockRect()); ASSERT(srcBuffer->Unlock()); LONGLONG duration; ASSERT(srcSample->GetSampleDuration(&duration)); ASSERT(dstSample->SetSampleDuration(duration)); LONGLONG time; ASSERT(srcSample->GetSampleTime(&time)); ASSERT(dstSample->SetSampleTime(time)); DWORD flags; ASSERT(srcSample->GetSampleFlags(&flags)); ASSERT(dstSample->SetSampleFlags(flags)); pOutputSamples->pSample->Release(); pOutputSamples->pSample = dstSample; pOutputSamples->pSample->AddRef(); end: return result; } VTABLE_HOOK(HRESULT, IMFTransform, ProcessMessage, MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) { if (forceSoftwareDecoding) { if (eMessage == MFT_MESSAGE_SET_D3D_MANAGER) { PRINT("[DivaMovie] Force Software Decoding enabled\n"); INSTALL_VTABLE_HOOK(This, ProcessOutput, 25); return S_OK; } return originalProcessMessage(This, eMessage, ulParam); } else { HRESULT result = originalProcessMessage(This, eMessage, ulParam); if (eMessage == MFT_MESSAGE_SET_D3D_MANAGER && result == MF_E_UNSUPPORTED_D3D_TYPE) { PRINT("[DivaMovie] This system does not support DXVA hardware decoding\n"); result = originalProcessMessage(This, eMessage, NULL); if (SUCCEEDED(result)) INSTALL_VTABLE_HOOK(This, ProcessOutput, 25); } else if (!forceHybridDecoding && eMessage == MFT_MESSAGE_SET_D3D_MANAGER && result == 0) { static bool warn = false; if (!warn) { MessageBoxW(0, L"Your system supports DXVA hardware decoding and Force Hybrid Decoding is disabled.\nDivaMovie will be disabled.\n\nIt is HIGHLY recommended to restart the game now.", L"DivaMovie", MB_ICONINFORMATION); CSimpleIniW ini_reader; ini_reader.SetUnicode(false); ini_reader.LoadFile(MASTER_CONFIG_FILE); ini_reader.SetValue(L"plugins", L"DivaMovie.dva", L"0"); ini_reader.SaveFile(MASTER_CONFIG_FILE); warn = true; } } return result; } } HOOK(void*, IMFTransformInitializer, 0x140420B90, void* a1, void* a2, IMFTransform** transform) { void* result = originalIMFTransformInitializer(a1, a2, transform); INSTALL_VTABLE_HOOK(*transform, ProcessMessage, 23); return result; } HOOK(HRESULT, DXVA2CreateDirect3DDeviceManager, PROC_ADDRESS("dxva2.dll", "DXVA2CreateDirect3DDeviceManager9"), UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager) { HRESULT result = originalDXVA2CreateDirect3DDeviceManager(pResetToken, ppDeviceManager); if (FAILED(result)) return result; if (deviceManager) deviceManager->Release(); deviceManager = *ppDeviceManager; deviceManager->AddRef(); return result; } void loadConfig() { forceSoftwareDecoding = GetPrivateProfileIntW(L"general", L"force_software_decoding", 0, CONFIG_FILE) > 0 ? true : false; forceHybridDecoding = GetPrivateProfileIntW(L"general", L"force_hybrid_decoding", 0, CONFIG_FILE) > 0 ? true : false; debug = GetPrivateProfileIntW(L"general", L"debug", 0, CONFIG_FILE) > 0 ? true : false; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { loadConfig(); INSTALL_HOOK(DXVA2CreateDirect3DDeviceManager); INSTALL_HOOK(IMFTransformInitializer); } return TRUE; } PluginConfig::PluginConfigOption config[] = { { PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"force_software_decoding", L"general", CONFIG_FILE, L"Force Software Decoding", L"Use software decoding even on systems that support DXVA hardware decoding.", false } }, { PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"force_hybrid_decoding", L"general", CONFIG_FILE, L"Force Hybrid Decoding", L"Do not disable DivaMovie on systems that support DXVA hardware decoding.\nCan cause issues on recent drivers.", false } }, { PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"debug", L"general", CONFIG_FILE, L"Debug (slow!)", L"Enable PRINT (possibly at the cost of performance).", false } }, }; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"DivaMovie"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"DivaMovie Plugin by Skyth\n\nDivaMovie enables movies on systems that do not support DXVA hardware decoding."; } extern "C" __declspec(dllexport) PluginConfig::PluginConfigArray GetPluginOptions(void) { return PluginConfig::PluginConfigArray{ _countof(config), config }; } ================================================ FILE: source-code/source/plugins/DivaMovie/framework.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN #include #include #include #include std::wstring ExePath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); return std::wstring(buffer); } std::wstring DirPath() { std::wstring exepath = ExePath(); std::wstring::size_type pos = exepath.find_last_of(L"\\/"); return exepath.substr(0, pos); } std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\DivaMovie.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); std::wstring MASTER_CONFIG_FILE_STRING = DirPath() + L"\\plugins\\config.ini"; LPCWSTR MASTER_CONFIG_FILE = MASTER_CONFIG_FILE_STRING.c_str(); #define PRINT(value, ...) if (debug) printf(value, __VA_ARGS__); #define PROC_ADDRESS(libraryName, procName) \ GetProcAddress(LoadLibrary(TEXT(libraryName)), procName) #define SAFE_RELEASE(object) if (object) { object->Release(); object = NULL; } #define VTABLE_HOOK(returnType, className, functionName, ...) \ typedef returnType functionName(className* This, __VA_ARGS__); \ functionName* original##functionName; \ returnType implOf##functionName(className* This, __VA_ARGS__) #define INSTALL_VTABLE_HOOK(object, functionName, functionIndex) \ { \ void** addr = &(*(void***)object)[functionIndex]; \ if (*addr != implOf##functionName) \ { \ PRINT("[DivaMovie] Installing %s hook...\n", #functionName); \ original##functionName = (functionName*)*addr; \ DWORD oldProtect; \ VirtualProtect(addr, sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProtect); \ *addr = implOf##functionName; \ VirtualProtect(addr, sizeof(void*), oldProtect, NULL); \ } \ } #define HOOK(returnType, function, location, ...) \ typedef returnType function(__VA_ARGS__); \ function* original##function = (function*)location; \ returnType implOf##function(__VA_ARGS__) #define INSTALL_HOOK(functionName) \ { \ PRINT("[DivaMovie] Installing %s hook...\n", #functionName); \ DetourTransactionBegin(); \ DetourUpdateThread(GetCurrentThread()); \ DetourAttach((void**)&original##functionName, implOf##functionName); \ DetourTransactionCommit(); \ } #define ASSERT(function) \ if (FAILED(result = (function))) \ { \ PRINT("[DivaMovie] %s failed (error code: 0x%08x)\n", #function, (unsigned int)result); \ goto end; \ } /*\ else \ { \ PRINT("[DivaMovie] %s succeeded\n", #function); \ }*/ ================================================ FILE: source-code/source/plugins/DivaSound/DivaSound.vcxproj ================================================  Debug x64 Release x64 {EE1A551A-49A0-40F2-8C2E-862D0AE55B43} DivaSound DivaSound 10.0 DynamicLibrary true v142 MultiByte DynamicLibrary false true MultiByte v142 .dva .dva Level3 Disabled true ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\detours\include;miniaudio;bassasio -d2FH4- %(AdditionalOptions) detours.lib;syelog.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) ..\..\..\dependencies\detours\lib;bassasio -d2:-FH4- %(AdditionalOptions) Level3 MaxSpeed true true true stdcpp17 ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\detours\include;miniaudio;bassasio MultiThreadedDLL -d2FH4- %(AdditionalOptions) true true detours.lib;syelog.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) ..\..\..\dependencies\detours\lib;bassasio -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/plugins/DivaSound/DivaSound.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Header Files ================================================ FILE: source-code/source/plugins/DivaSound/bassasio/bassasio.h ================================================ /* BASSASIO 1.4 C/C++ header file Copyright (c) 2005-2019 Un4seen Developments Ltd. See the BASSASIO.CHM file for more detailed documentation */ /* DivaSound version -- loads the required functions at runtime */ #ifndef BASSASIO_H #define BASSASIO_H #include #ifdef __cplusplus extern "C" { #endif #ifndef BASSASIODEF #define BASSASIODEF(f) WINAPI f #endif #define BASSASIOVERSION 0x104 // API version // error codes returned by BASS_ASIO_ErrorGetCode #define BASS_OK 0 // all is OK #define BASS_ERROR_FILEOPEN 2 // can't open the file #define BASS_ERROR_DRIVER 3 // can't find a free/valid driver #define BASS_ERROR_HANDLE 5 // invalid handle #define BASS_ERROR_FORMAT 6 // unsupported sample format #define BASS_ERROR_INIT 8 // BASS_ASIO_Init has not been successfully called #define BASS_ERROR_START 9 // BASS_ASIO_Start has/hasn't been called #define BASS_ERROR_ALREADY 14 // already initialized/started #define BASS_ERROR_NOCHAN 18 // no channels are enabled #define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified #define BASS_ERROR_DEVICE 23 // illegal device number #define BASS_ERROR_NOTAVAIL 37 // not available #define BASS_ERROR_UNKNOWN -1 // some other mystery error // BASS_ASIO_Init flags #define BASS_ASIO_THREAD 1 // host driver in dedicated thread #define BASS_ASIO_JOINORDER 2 // order joined channels by when they were joined // device info structure typedef struct { const char *name; // description const char *driver; // driver } BASS_ASIO_DEVICEINFO; typedef struct { char name[32]; // driver name DWORD version; // driver version DWORD inputs; // number of inputs DWORD outputs; // number of outputs DWORD bufmin; // minimum buffer length DWORD bufmax; // maximum buffer length DWORD bufpref; // preferred/default buffer length int bufgran; // buffer length granularity DWORD initflags; // BASS_ASIO_Init "flags" parameter } BASS_ASIO_INFO; typedef struct { DWORD group; DWORD format; // sample format (BASS_ASIO_FORMAT_xxx) char name[32]; // channel name } BASS_ASIO_CHANNELINFO; // sample formats #define BASS_ASIO_FORMAT_16BIT 16 // 16-bit integer #define BASS_ASIO_FORMAT_24BIT 17 // 24-bit integer #define BASS_ASIO_FORMAT_32BIT 18 // 32-bit integer #define BASS_ASIO_FORMAT_FLOAT 19 // 32-bit floating-point #define BASS_ASIO_FORMAT_DSD_LSB 32 // DSD (LSB 1st) #define BASS_ASIO_FORMAT_DSD_MSB 33 // DSD (MSB 1st) #define BASS_ASIO_FORMAT_DITHER 0x100 // flag: apply dither when converting from floating-point to integer // BASS_ASIO_ChannelReset flags #define BASS_ASIO_RESET_ENABLE 1 // disable channel #define BASS_ASIO_RESET_JOIN 2 // unjoin channel #define BASS_ASIO_RESET_PAUSE 4 // unpause channel #define BASS_ASIO_RESET_FORMAT 8 // reset sample format to native format #define BASS_ASIO_RESET_RATE 16 // reset sample rate to device rate #define BASS_ASIO_RESET_VOLUME 32 // reset volume to 1.0 #define BASS_ASIO_RESET_JOINED 0x10000 // apply to joined channels too // BASS_ASIO_ChannelIsActive return values #define BASS_ASIO_ACTIVE_DISABLED 0 #define BASS_ASIO_ACTIVE_ENABLED 1 #define BASS_ASIO_ACTIVE_PAUSED 2 typedef DWORD (CALLBACK ASIOPROC)(BOOL input, DWORD channel, void *buffer, DWORD length, void *user); /* ASIO channel callback function. input : Input? else output channel: Channel number buffer : Buffer containing the sample data length : Number of bytes user : The 'user' parameter given when calling BASS_ASIO_ChannelEnable RETURN : The number of bytes written (ignored with input channels) */ typedef void (CALLBACK ASIONOTIFYPROC)(DWORD notify, void *user); /* Driver notification callback function. notify : The notification (BASS_ASIO_NOTIFY_xxx) user : The 'user' parameter given when calling BASS_ASIO_SetNotify */ // driver notifications #define BASS_ASIO_NOTIFY_RATE 1 // sample rate change #define BASS_ASIO_NOTIFY_RESET 2 // reset (reinitialization) request // BASS_ASIO_ChannelGetLevel flags #define BASS_ASIO_LEVEL_RMS 0x1000000 HMODULE bassAsioModule = LoadLibraryW(L"bassasio.dll"); DWORD(WINAPI* BASS_ASIO_GetVersion)() = (DWORD(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_GetVersion"); BOOL(WINAPI* BASS_ASIO_SetUnicode)(BOOL unicode) = (BOOL(WINAPI*)(BOOL unicode))GetProcAddress(bassAsioModule, "BASS_ASIO_SetUnicode"); // DWORD BASSASIODEF(BASS_ASIO_ErrorGetCode)(); BOOL(WINAPI* BASS_ASIO_GetDeviceInfo)(DWORD device, BASS_ASIO_DEVICEINFO *info) = (BOOL(WINAPI*)(DWORD device, BASS_ASIO_DEVICEINFO *info))GetProcAddress(bassAsioModule, "BASS_ASIO_GetDeviceInfo"); // DWORD BASSASIODEF(BASS_ASIO_AddDevice)(const GUID *clsid, const char *driver, const char *name); // BOOL BASSASIODEF(BASS_ASIO_SetDevice)(DWORD device); // DWORD BASSASIODEF(BASS_ASIO_GetDevice)(); BOOL(WINAPI* BASS_ASIO_Init)(int device, DWORD flags) = (BOOL(WINAPI*)(int device, DWORD flags))GetProcAddress(bassAsioModule, "BASS_ASIO_Init"); BOOL(WINAPI* BASS_ASIO_Free)() = (BOOL(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_Free"); // BOOL BASSASIODEF(BASS_ASIO_Lock)(BOOL lock); BOOL(WINAPI* BASS_ASIO_SetNotify)(ASIONOTIFYPROC *proc, void *user) = (BOOL(WINAPI*)(ASIONOTIFYPROC *proc, void *user))GetProcAddress(bassAsioModule, "BASS_ASIO_SetNotify"); BOOL(WINAPI* BASS_ASIO_ControlPanel)() = (BOOL(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_ControlPanel"); BOOL(WINAPI* BASS_ASIO_GetInfo)(BASS_ASIO_INFO *info) = (BOOL(WINAPI*)(BASS_ASIO_INFO *info))GetProcAddress(bassAsioModule, "BASS_ASIO_GetInfo"); BOOL(WINAPI* BASS_ASIO_CheckRate)(double rate) = (BOOL(WINAPI*)(double rate))GetProcAddress(bassAsioModule, "BASS_ASIO_CheckRate"); BOOL(WINAPI* BASS_ASIO_SetRate)(double rate) = (BOOL(WINAPI*)(double rate))GetProcAddress(bassAsioModule, "BASS_ASIO_SetRate"); double(WINAPI* BASS_ASIO_GetRate)() = (double(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_GetRate"); BOOL(WINAPI* BASS_ASIO_Start)(DWORD buflen, DWORD threads) = (BOOL(WINAPI*)(DWORD buflen, DWORD threads))GetProcAddress(bassAsioModule, "BASS_ASIO_Start"); BOOL(WINAPI* BASS_ASIO_Stop)() = (BOOL(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_Stop"); BOOL(WINAPI* BASS_ASIO_IsStarted)() = (BOOL(WINAPI*)())GetProcAddress(bassAsioModule, "BASS_ASIO_IsStarted"); // DWORD BASSASIODEF(BASS_ASIO_GetLatency)(BOOL input); // float BASSASIODEF(BASS_ASIO_GetCPU)(); // BOOL BASSASIODEF(BASS_ASIO_Monitor)(int input, DWORD output, DWORD gain, DWORD state, DWORD pan); // BOOL BASSASIODEF(BASS_ASIO_SetDSD)(BOOL dsd); // BOOL BASSASIODEF(BASS_ASIO_Future)(DWORD selector, void *param); // BOOL BASSASIODEF(BASS_ASIO_ChannelGetInfo)(BOOL input, DWORD channel, BASS_ASIO_CHANNELINFO *info); // BOOL BASSASIODEF(BASS_ASIO_ChannelReset)(BOOL input, int channel, DWORD flags); BOOL(WINAPI* BASS_ASIO_ChannelEnable)(BOOL input, DWORD channel, ASIOPROC *proc, void *user) = (BOOL(WINAPI*)(BOOL input, DWORD channel, ASIOPROC *proc, void *user))GetProcAddress(bassAsioModule, "BASS_ASIO_ChannelEnable"); // BOOL BASSASIODEF(BASS_ASIO_ChannelEnableMirror)(DWORD channel, BOOL input2, DWORD channel2); // BOOL BASSASIODEF(BASS_ASIO_ChannelEnableBASS)(BOOL input, DWORD channel, DWORD handle, BOOL join); BOOL(WINAPI* BASS_ASIO_ChannelJoin)(BOOL input, DWORD channel, int channel2) = (BOOL(WINAPI*)(BOOL input, DWORD channel, int channel2))GetProcAddress(bassAsioModule, "BASS_ASIO_ChannelJoin"); // BOOL BASSASIODEF(BASS_ASIO_ChannelPause)(BOOL input, DWORD channel); // DWORD BASSASIODEF(BASS_ASIO_ChannelIsActive)(BOOL input, DWORD channel); BOOL(WINAPI* BASS_ASIO_ChannelSetFormat)(BOOL input, DWORD channel, DWORD format) = (BOOL(WINAPI*)(BOOL input, DWORD channel, DWORD format))GetProcAddress(bassAsioModule, "BASS_ASIO_ChannelSetFormat"); // DWORD BASSASIODEF(BASS_ASIO_ChannelGetFormat)(BOOL input, DWORD channel); BOOL(WINAPI* BASS_ASIO_ChannelSetRate)(BOOL input, DWORD channel, double rate) = (BOOL(WINAPI*)(BOOL input, DWORD channel, double rate))GetProcAddress(bassAsioModule, "BASS_ASIO_ChannelSetRate"); // double BASSASIODEF(BASS_ASIO_ChannelGetRate)(BOOL input, DWORD channel); // BOOL BASSASIODEF(BASS_ASIO_ChannelSetVolume)(BOOL input, int channel, float volume); // float BASSASIODEF(BASS_ASIO_ChannelGetVolume)(BOOL input, int channel); // float BASSASIODEF(BASS_ASIO_ChannelGetLevel)(BOOL input, DWORD channel); #ifdef __cplusplus } #endif #endif ================================================ FILE: source-code/source/plugins/DivaSound/miniaudio/miniaudio.h ================================================ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. miniaudio (formerly mini_al) - v0.9.5 - 2019-05-21 David Reid - davidreidsoftware@gmail.com */ /* MAJOR CHANGES IN VERSION 0.9 ============================ Version 0.9 includes major API changes, centered mostly around full-duplex and the rebrand to "miniaudio". Before I go into detail about the major changes I would like to apologize. I know it's annoying dealing with breaking API changes, but I think it's best to get these changes out of the way now while the library is still relatively young and unknown. There's been a lot of refactoring with this release so there's a good chance a few bugs have been introduced. I apologize in advance for this. You may want to hold off on upgrading for the short term if you're worried. If mini_al v0.8.14 works for you, and you don't need full-duplex support, you can avoid upgrading (though you won't be getting future bug fixes). Rebranding to "miniaudio" ------------------------- The decision was made to rename mini_al to miniaudio. Don't worry, it's the same project. The reason for this is simple: 1) Having the word "audio" in the title makes it immediately clear that the library is related to audio; and 2) I don't like the look of the underscore. This rebrand has necessitated a change in namespace from "mal" to "ma". I know this is annoying, and I apologize, but it's better to get this out of the road now rather than later. Also, since there are necessary API changes for full-duplex support I think it's better to just get the namespace change over and done with at the same time as the full-duplex changes. I'm hoping this will be the last of the major API changes. Fingers crossed! The implementation define is now "#define MINIAUDIO_IMPLEMENTATION". You can also use "#define MA_IMPLEMENTATION" if that's your preference. Full-Duplex Support ------------------- The major feature added to version 0.9 is full-duplex. This has necessitated a few API changes. 1) The data callback has now changed. Previously there was one type of callback for playback and another for capture. I wanted to avoid a third callback just for full-duplex so the decision was made to break this API and unify the callbacks. Now, there is just one callback which is the same for all three modes (playback, capture, duplex). The new callback looks like the following: void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); This callback allows you to move data straight out of the input buffer and into the output buffer in full-duplex mode. In playback-only mode, pInput will be null. Likewise, pOutput will be null in capture-only mode. The sample count is no longer returned from the callback since it's not necessary for miniaudio anymore. 2) The device config needed to change in order to support full-duplex. Full-duplex requires the ability to allow the client to choose a different PCM format for the playback and capture sides. The old ma_device_config object simply did not allow this and needed to change. With these changes you now specify the device ID, format, channels, channel map and share mode on a per-playback and per-capture basis (see example below). The sample rate must be the same for playback and capture. Since the device config API has changed I have also decided to take the opportunity to simplify device initialization. Now, the device ID, device type and callback user data are set in the config. ma_device_init() is now simplified down to taking just the context, device config and a pointer to the device object being initialized. The rationale for this change is that it just makes more sense to me that these are set as part of the config like everything else. Example device initialization: ma_device_config config = ma_device_config_init(ma_device_type_duplex); // Or ma_device_type_playback or ma_device_type_capture. config.playback.pDeviceID = &myPlaybackDeviceID; // Or NULL for the default playback device. config.playback.format = ma_format_f32; config.playback.channels = 2; config.capture.pDeviceID = &myCaptureDeviceID; // Or NULL for the default capture device. config.capture.format = ma_format_s16; config.capture.channels = 1; config.sampleRate = 44100; config.dataCallback = data_callback; config.pUserData = &myUserData; result = ma_device_init(&myContext, &config, &device); if (result != MA_SUCCESS) { ... handle error ... } Note that the "onDataCallback" member of ma_device_config has been renamed to "dataCallback". Also, "onStopCallback" has been renamed to "stopCallback". This is the first pass for full-duplex and there is a known bug. You will hear crackling on the following backends when sample rate conversion is required for the playback device: - Core Audio - JACK - AAudio - OpenSL - WebAudio In addition to the above, not all platforms have been absolutely thoroughly tested simply because I lack the hardware for such thorough testing. If you experience a bug, an issue report on GitHub or an email would be greatly appreciated (and a sample program that reproduces the issue if possible). Other API Changes ----------------- In addition to the above, the following API changes have been made: - The log callback is no longer passed to ma_context_config_init(). Instead you need to set it manually after initialization. - The onLogCallback member of ma_context_config has been renamed to "logCallback". - The log callback now takes a logLevel parameter. The new callback looks like: void log_callback(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) - You can use ma_log_level_to_string() to convert the logLevel to human readable text if you want to log it. - Some APIs have been renamed: - mal_decoder_read() -> ma_decoder_read_pcm_frames() - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame() - mal_sine_wave_read() -> ma_sine_wave_read_f32() - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex() - Some APIs have been removed: - mal_device_get_buffer_size_in_bytes() - mal_device_set_recv_callback() - mal_device_set_send_callback() - mal_src_set_input_sample_rate() - mal_src_set_output_sample_rate() - Error codes have been rearranged. If you're a binding maintainer you will need to update. - The ma_backend enums have been rearranged to priority order. The rationale for this is to simplify automatic backend selection and to make it easier to see the priority. If you're a binding maintainer you will need to update. - ma_dsp has been renamed to ma_pcm_converter. The rationale for this change is that I'm expecting "ma_dsp" to conflict with some future planned high-level APIs. - For functions that take a pointer/count combo, such as ma_decoder_read_pcm_frames(), the parameter order has changed so that the pointer comes before the count. The rationale for this is to keep it consistent with things like memcpy(). Miscellaneous Changes --------------------- The following miscellaneous changes have also been made. - The AAudio backend has been added for Android 8 and above. This is Android's new "High-Performance Audio" API. (For the record, this is one of the nicest audio APIs out there, just behind the BSD audio APIs). - The WebAudio backend has been added. This is based on ScriptProcessorNode. This removes the need for SDL. - The SDL and OpenAL backends have been removed. These were originally implemented to add support for platforms for which miniaudio was not explicitly supported. These are no longer needed and have therefore been removed. - Device initialization now fails if the requested share mode is not supported. If you ask for exclusive mode, you either get an exclusive mode device, or an error. The rationale for this change is to give the client more control over how to handle cases when the desired shared mode is unavailable. - A lock-free ring buffer API has been added. There are two varients of this. "ma_rb" operates on bytes, whereas "ma_pcm_rb" operates on PCM frames. - The library is now licensed as a choice of Public Domain (Unlicense) _or_ MIT-0 (No Attribution) which is the same as MIT, but removes the attribution requirement. The rationale for this is to support countries that don't recognize public domain. */ /* ABOUT ===== miniaudio is a single file library for audio playback and capture. It's written in C (compilable as C++) and released into the public domain. Supported Backends: - WASAPI - DirectSound - WinMM - Core Audio (Apple) - ALSA - PulseAudio - JACK - sndio (OpenBSD) - audio(4) (NetBSD and OpenBSD) - OSS (FreeBSD) - AAudio (Android 8.0+) - OpenSL|ES (Android only) - Web Audio (Emscripten) - Null (Silence) Supported Formats: - Unsigned 8-bit PCM - Signed 16-bit PCM - Signed 24-bit PCM (tightly packed) - Signed 32-bit PCM - IEEE 32-bit floating point PCM USAGE ===== miniaudio is a single-file library. To use it, do something like the following in one .c file. #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" You can then #include this file in other parts of the program as you would with any other header file. miniaudio uses an asynchronous, callback based API. You initialize a device with a configuration (sample rate, channel count, etc.) which includes the callback you want to use to handle data transmission to/from the device. In the callback you either read from a data pointer in the case of playback or write to it in the case of capture. Playback Example ---------------- void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { ma_decoder* pDecoder = (ma_decoder*)pDevice->pUserData; if (pDecoder == NULL) { return; } ma_decoder_read_pcm_frames(pDecoder, frameCount, pOutput); } ... ma_device_config config = ma_device_config_init(ma_device_type_playback); config.playback.format = decoder.outputFormat; config.playback.channels = decoder.outputChannels; config.sampleRate = decoder.outputSampleRate; config.dataCallback = data_callback; config.pUserData = &decoder; ma_device device; if (ma_device_init(NULL, &config, &device) != MA_SUCCESS) { ... An error occurred ... } ma_device_start(&device); // The device is sleeping by default so you'll need to start it manually. ... ma_device_uninit(&device); // This will stop the device so no need to do that manually. BUILDING ======== miniaudio should Just Work by adding it to your project's source tree. You do not need to download or install any dependencies. See below for platform-specific details. If you want to disable a specific backend, #define the appropriate MA_NO_* option before the implementation. Note that GCC and Clang requires "-msse2", "-mavx2", etc. for SIMD optimizations. Building for Windows -------------------- The Windows build should compile clean on all popular compilers without the need to configure any include paths nor link to any libraries. Building for macOS and iOS -------------------------- The macOS build should compile clean without the need to download any dependencies or link to any libraries or frameworks. The iOS build needs to be compiled as Objective-C (sorry) and will need to link the relevant frameworks but should Just Work with Xcode. Building for Linux ------------------ The Linux build only requires linking to -ldl, -lpthread and -lm. You do not need any development packages. Building for BSD ---------------- The BSD build only requires linking to -ldl, -lpthread and -lm. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS. Building for Android -------------------- AAudio is the highest priority backend on Android. This should work out out of the box without needing any kind of compiler configuration. Support for AAudio starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+. Building for Emscripten ----------------------- The Emscripten build emits Web Audio JavaScript directly and should Just Work without any configuration. NOTES ===== - This library uses an asynchronous API for delivering and requesting audio data. Each device will have it's own worker thread which is managed by the library. - If ma_device_init() is called with a device that's not aligned to the platform's natural alignment boundary (4 bytes on 32-bit, 8 bytes on 64-bit), it will _not_ be thread-safe. The reason for this is that it depends on members of ma_device being correctly aligned for atomic assignments. - Sample data is always native-endian and interleaved. For example, ma_format_s16 means signed 16-bit integer samples, interleaved. Let me know if you need non-interleaved and I'll look into it. - The sndio backend is currently only enabled on OpenBSD builds. - The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can use it. - Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as PulseAudio may naturally support it, though not all have been tested. BACKEND NUANCES =============== PulseAudio ---------- - If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki: https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling Alternatively, consider using a different backend such as ALSA. Android ------- - To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: - With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES. - With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration API (devices are enumerated through Java). You can however perform your own device enumeration through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it to ma_device_init(). - The backend API will perform resampling where possible. The reason for this as opposed to using miniaudio's built-in resampler is to take advantage of any potential device-specific optimizations the driver may implement. UWP --- - UWP only supports default playback and capture devices. - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest): ... Web Audio / Emscripten ---------------------- - The first time a context is initialized it will create a global object called "mal" whose primary purpose is to act as a factory for device objects. - Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as they've been deprecated. - Google is implementing a policy in their browsers that prevent automatic media output without first receiving some kind of user input. See here for details: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device may fail if you try to start playback without first handling some kind of user input. OPTIONS ======= #define these options before including this file. #define MA_NO_WASAPI Disables the WASAPI backend. #define MA_NO_DSOUND Disables the DirectSound backend. #define MA_NO_WINMM Disables the WinMM backend. #define MA_NO_ALSA Disables the ALSA backend. #define MA_NO_PULSEAUDIO Disables the PulseAudio backend. #define MA_NO_JACK Disables the JACK backend. #define MA_NO_COREAUDIO Disables the Core Audio backend. #define MA_NO_SNDIO Disables the sndio backend. #define MA_NO_AUDIO4 Disables the audio(4) backend. #define MA_NO_OSS Disables the OSS backend. #define MA_NO_AAUDIO Disables the AAudio backend. #define MA_NO_OPENSL Disables the OpenSL|ES backend. #define MA_NO_WEBAUDIO Disables the Web Audio backend. #define MA_NO_NULL Disables the null backend. #define MA_DEFAULT_PERIODS When a period count of 0 is specified when a device is initialized, it will default to this. #define MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY #define MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE When a buffer size of 0 is specified when a device is initialized it will default to a buffer of this size, depending on the chosen performance profile. These can be increased or decreased depending on your specific requirements. #define MA_NO_DECODING Disables the decoding APIs. #define MA_NO_DEVICE_IO Disables playback and recording. This will disable ma_context and ma_device APIs. This is useful if you only want to use miniaudio's data conversion and/or decoding APIs. #define MA_NO_STDIO Disables file IO APIs. #define MA_NO_SSE2 Disables SSE2 optimizations. #define MA_NO_AVX2 Disables AVX2 optimizations. #define MA_NO_AVX512 Disables AVX-512 optimizations. #define MA_NO_NEON Disables NEON optimizations. #define MA_LOG_LEVEL Sets the logging level. Set level to one of the following: MA_LOG_LEVEL_VERBOSE MA_LOG_LEVEL_INFO MA_LOG_LEVEL_WARNING MA_LOG_LEVEL_ERROR #define MA_DEBUG_OUTPUT Enable printf() debug output. #define MA_COINIT_VALUE Windows only. The value to pass to internal calls to CoInitializeEx(). Defaults to COINIT_MULTITHREADED. DEFINITIONS =========== This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity in the use of terms throughout the audio space, so this section is intended to clarify how miniaudio uses each term. Sample ------ A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit floating point number. Frame / PCM Frame ----------------- A frame is a groups of samples equal to the number of channels. For a stereo stream a frame is 2 samples, a mono frame is 1 sample, a 5.1 surround sound frame is 6 samples, etc. The terms "frame" and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. If ever miniaudio needs to refer to a compressed frame, such as a FLAC frame, it will always clarify what it's referring to with something like "FLAC frame" or whatnot. Channel ------- A stream of monaural audio that is emitted from an individual speaker in a speaker system, or received from an individual microphone in a microphone system. A stereo stream has two channels (a left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio systems refer to a channel as a complex audio stream that's mixed with other channels to produce the final mix - this is completely different to miniaudio's use of the term "channel" and should not be confused. Sample Rate ----------- The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number of PCM frames that are processed per second. Formats ------- Throughout miniaudio you will see references to different sample formats: u8 - Unsigned 8-bit integer s16 - Signed 16-bit integer s24 - Signed 24-bit integer (tightly packed). s32 - Signed 32-bit integer f32 - 32-bit floating point */ #ifndef miniaudio_h #define miniaudio_h #ifdef __cplusplus extern "C" { #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */ #pragma warning(disable:4324) /* structure was padded due to alignment specifier */ #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */ #endif /* Platform/backend detection. */ #ifdef _WIN32 #define MA_WIN32 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) #define MA_WIN32_UWP #else #define MA_WIN32_DESKTOP #endif #else #define MA_POSIX #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ #ifdef __unix__ #define MA_UNIX #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #define MA_BSD #endif #endif #ifdef __linux__ #define MA_LINUX #endif #ifdef __APPLE__ #define MA_APPLE #endif #ifdef __ANDROID__ #define MA_ANDROID #endif #ifdef __EMSCRIPTEN__ #define MA_EMSCRIPTEN #endif #endif #include /* For size_t. */ /* Sized types. Prefer built-in types. Fall back to stdint. */ #ifdef _MSC_VER #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wlanguage-extension-token" #pragma GCC diagnostic ignored "-Wc++11-long-long" #endif typedef signed __int8 ma_int8; typedef unsigned __int8 ma_uint8; typedef signed __int16 ma_int16; typedef unsigned __int16 ma_uint16; typedef signed __int32 ma_int32; typedef unsigned __int32 ma_uint32; typedef signed __int64 ma_int64; typedef unsigned __int64 ma_uint64; #if defined(__clang__) #pragma GCC diagnostic pop #endif #else #define MA_HAS_STDINT #include typedef int8_t ma_int8; typedef uint8_t ma_uint8; typedef int16_t ma_int16; typedef uint16_t ma_uint16; typedef int32_t ma_int32; typedef uint32_t ma_uint32; typedef int64_t ma_int64; typedef uint64_t ma_uint64; #endif #ifdef MA_HAS_STDINT typedef uintptr_t ma_uintptr; #else #if defined(_WIN32) #if defined(_WIN64) typedef ma_uint64 ma_uintptr; #else typedef ma_uint32 ma_uintptr; #endif #elif defined(__GNUC__) #if defined(__LP64__) typedef ma_uint64 ma_uintptr; #else typedef ma_uint32 ma_uintptr; #endif #else typedef ma_uint64 ma_uintptr; /* Fallback. */ #endif #endif typedef ma_uint8 ma_bool8; typedef ma_uint32 ma_bool32; #define MA_TRUE 1 #define MA_FALSE 0 typedef void* ma_handle; typedef void* ma_ptr; typedef void (* ma_proc)(void); #if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) typedef ma_uint16 wchar_t; #endif /* Define NULL for some compilers. */ #ifndef NULL #define NULL 0 #endif #if defined(SIZE_MAX) #define MA_SIZE_MAX SIZE_MAX #else #define MA_SIZE_MAX 0xFFFFFFFF /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */ #endif #ifdef _MSC_VER #define MA_INLINE __forceinline #else #ifdef __GNUC__ #define MA_INLINE __inline__ __attribute__((always_inline)) #else #define MA_INLINE #endif #endif #if defined(_MSC_VER) #if _MSC_VER >= 1400 #define MA_ALIGN(alignment) __declspec(align(alignment)) #endif #elif !defined(__DMC__) #define MA_ALIGN(alignment) __attribute__((aligned(alignment))) #endif #ifndef MA_ALIGN #define MA_ALIGN(alignment) #endif #ifdef _MSC_VER #define MA_ALIGNED_STRUCT(alignment) MA_ALIGN(alignment) struct #else #define MA_ALIGNED_STRUCT(alignment) struct MA_ALIGN(alignment) #endif /* SIMD alignment in bytes. Currently set to 64 bytes in preparation for future AVX-512 optimizations. */ #define MA_SIMD_ALIGNMENT 64 /* Logging levels */ #define MA_LOG_LEVEL_VERBOSE 4 #define MA_LOG_LEVEL_INFO 3 #define MA_LOG_LEVEL_WARNING 2 #define MA_LOG_LEVEL_ERROR 1 #ifndef MA_LOG_LEVEL #define MA_LOG_LEVEL MA_LOG_LEVEL_ERROR #endif typedef struct ma_context ma_context; typedef struct ma_device ma_device; typedef ma_uint8 ma_channel; #define MA_CHANNEL_NONE 0 #define MA_CHANNEL_MONO 1 #define MA_CHANNEL_FRONT_LEFT 2 #define MA_CHANNEL_FRONT_RIGHT 3 #define MA_CHANNEL_FRONT_CENTER 4 #define MA_CHANNEL_LFE 5 #define MA_CHANNEL_BACK_LEFT 6 #define MA_CHANNEL_BACK_RIGHT 7 #define MA_CHANNEL_FRONT_LEFT_CENTER 8 #define MA_CHANNEL_FRONT_RIGHT_CENTER 9 #define MA_CHANNEL_BACK_CENTER 10 #define MA_CHANNEL_SIDE_LEFT 11 #define MA_CHANNEL_SIDE_RIGHT 12 #define MA_CHANNEL_TOP_CENTER 13 #define MA_CHANNEL_TOP_FRONT_LEFT 14 #define MA_CHANNEL_TOP_FRONT_CENTER 15 #define MA_CHANNEL_TOP_FRONT_RIGHT 16 #define MA_CHANNEL_TOP_BACK_LEFT 17 #define MA_CHANNEL_TOP_BACK_CENTER 18 #define MA_CHANNEL_TOP_BACK_RIGHT 19 #define MA_CHANNEL_AUX_0 20 #define MA_CHANNEL_AUX_1 21 #define MA_CHANNEL_AUX_2 22 #define MA_CHANNEL_AUX_3 23 #define MA_CHANNEL_AUX_4 24 #define MA_CHANNEL_AUX_5 25 #define MA_CHANNEL_AUX_6 26 #define MA_CHANNEL_AUX_7 27 #define MA_CHANNEL_AUX_8 28 #define MA_CHANNEL_AUX_9 29 #define MA_CHANNEL_AUX_10 30 #define MA_CHANNEL_AUX_11 31 #define MA_CHANNEL_AUX_12 32 #define MA_CHANNEL_AUX_13 33 #define MA_CHANNEL_AUX_14 34 #define MA_CHANNEL_AUX_15 35 #define MA_CHANNEL_AUX_16 36 #define MA_CHANNEL_AUX_17 37 #define MA_CHANNEL_AUX_18 38 #define MA_CHANNEL_AUX_19 39 #define MA_CHANNEL_AUX_20 40 #define MA_CHANNEL_AUX_21 41 #define MA_CHANNEL_AUX_22 42 #define MA_CHANNEL_AUX_23 43 #define MA_CHANNEL_AUX_24 44 #define MA_CHANNEL_AUX_25 45 #define MA_CHANNEL_AUX_26 46 #define MA_CHANNEL_AUX_27 47 #define MA_CHANNEL_AUX_28 48 #define MA_CHANNEL_AUX_29 49 #define MA_CHANNEL_AUX_30 50 #define MA_CHANNEL_AUX_31 51 #define MA_CHANNEL_LEFT MA_CHANNEL_FRONT_LEFT #define MA_CHANNEL_RIGHT MA_CHANNEL_FRONT_RIGHT #define MA_CHANNEL_POSITION_COUNT MA_CHANNEL_AUX_31 + 1 typedef int ma_result; #define MA_SUCCESS 0 /* General errors. */ #define MA_ERROR -1 /* A generic error. */ #define MA_INVALID_ARGS -2 #define MA_INVALID_OPERATION -3 #define MA_OUT_OF_MEMORY -4 #define MA_ACCESS_DENIED -5 #define MA_TOO_LARGE -6 #define MA_TIMEOUT -7 /* General miniaudio-specific errors. */ #define MA_FORMAT_NOT_SUPPORTED -100 #define MA_DEVICE_TYPE_NOT_SUPPORTED -101 #define MA_SHARE_MODE_NOT_SUPPORTED -102 #define MA_NO_BACKEND -103 #define MA_NO_DEVICE -104 #define MA_API_NOT_FOUND -105 #define MA_INVALID_DEVICE_CONFIG -106 /* State errors. */ #define MA_DEVICE_BUSY -200 #define MA_DEVICE_NOT_INITIALIZED -201 #define MA_DEVICE_NOT_STARTED -202 #define MA_DEVICE_UNAVAILABLE -203 /* Operation errors. */ #define MA_FAILED_TO_MAP_DEVICE_BUFFER -300 #define MA_FAILED_TO_UNMAP_DEVICE_BUFFER -301 #define MA_FAILED_TO_INIT_BACKEND -302 #define MA_FAILED_TO_READ_DATA_FROM_CLIENT -303 #define MA_FAILED_TO_READ_DATA_FROM_DEVICE -304 #define MA_FAILED_TO_SEND_DATA_TO_CLIENT -305 #define MA_FAILED_TO_SEND_DATA_TO_DEVICE -306 #define MA_FAILED_TO_OPEN_BACKEND_DEVICE -307 #define MA_FAILED_TO_START_BACKEND_DEVICE -308 #define MA_FAILED_TO_STOP_BACKEND_DEVICE -309 #define MA_FAILED_TO_CONFIGURE_BACKEND_DEVICE -310 #define MA_FAILED_TO_CREATE_MUTEX -311 #define MA_FAILED_TO_CREATE_EVENT -312 #define MA_FAILED_TO_CREATE_THREAD -313 /* Standard sample rates. */ #define MA_SAMPLE_RATE_8000 8000 #define MA_SAMPLE_RATE_11025 11025 #define MA_SAMPLE_RATE_16000 16000 #define MA_SAMPLE_RATE_22050 22050 #define MA_SAMPLE_RATE_24000 24000 #define MA_SAMPLE_RATE_32000 32000 #define MA_SAMPLE_RATE_44100 44100 #define MA_SAMPLE_RATE_48000 48000 #define MA_SAMPLE_RATE_88200 88200 #define MA_SAMPLE_RATE_96000 96000 #define MA_SAMPLE_RATE_176400 176400 #define MA_SAMPLE_RATE_192000 192000 #define MA_SAMPLE_RATE_352800 352800 #define MA_SAMPLE_RATE_384000 384000 #define MA_MIN_PCM_SAMPLE_SIZE_IN_BYTES 1 /* For simplicity, miniaudio does not support PCM samples that are not byte aligned. */ #define MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES 8 #define MA_MIN_CHANNELS 1 #define MA_MAX_CHANNELS 32 #define MA_MIN_SAMPLE_RATE MA_SAMPLE_RATE_8000 #define MA_MAX_SAMPLE_RATE MA_SAMPLE_RATE_384000 #define MA_SRC_SINC_MIN_WINDOW_WIDTH 2 #define MA_SRC_SINC_MAX_WINDOW_WIDTH 32 #define MA_SRC_SINC_DEFAULT_WINDOW_WIDTH 32 #define MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION 8 #define MA_SRC_INPUT_BUFFER_SIZE_IN_SAMPLES 256 typedef enum { ma_stream_format_pcm = 0, } ma_stream_format; typedef enum { ma_stream_layout_interleaved = 0, ma_stream_layout_deinterleaved } ma_stream_layout; typedef enum { ma_dither_mode_none = 0, ma_dither_mode_rectangle, ma_dither_mode_triangle } ma_dither_mode; typedef enum { /* I like to keep these explicitly defined because they're used as a key into a lookup table. When items are added to this, make sure there are no gaps and that they're added to the lookup table in ma_get_bytes_per_sample(). */ ma_format_unknown = 0, /* Mainly used for indicating an error, but also used as the default for the output format for decoders. */ ma_format_u8 = 1, ma_format_s16 = 2, /* Seems to be the most widely supported format. */ ma_format_s24 = 3, /* Tightly packed. 3 bytes per sample. */ ma_format_s32 = 4, ma_format_f32 = 5, ma_format_count } ma_format; typedef enum { ma_channel_mix_mode_rectangular = 0, /* Simple averaging based on the plane(s) the channel is sitting on. */ ma_channel_mix_mode_simple, /* Drop excess channels; zeroed out extra channels. */ ma_channel_mix_mode_custom_weights, /* Use custom weights specified in ma_channel_router_config. */ ma_channel_mix_mode_planar_blend = ma_channel_mix_mode_rectangular, ma_channel_mix_mode_default = ma_channel_mix_mode_planar_blend } ma_channel_mix_mode; typedef enum { ma_standard_channel_map_microsoft, ma_standard_channel_map_alsa, ma_standard_channel_map_rfc3551, /* Based off AIFF. */ ma_standard_channel_map_flac, ma_standard_channel_map_vorbis, ma_standard_channel_map_sound4, /* FreeBSD's sound(4). */ ma_standard_channel_map_sndio, /* www.sndio.org/tips.html */ ma_standard_channel_map_webaudio = ma_standard_channel_map_flac, /* https://webaudio.github.io/web-audio-api/#ChannelOrdering. Only 1, 2, 4 and 6 channels are defined, but can fill in the gaps with logical assumptions. */ ma_standard_channel_map_default = ma_standard_channel_map_microsoft } ma_standard_channel_map; typedef enum { ma_performance_profile_low_latency = 0, ma_performance_profile_conservative } ma_performance_profile; typedef struct ma_format_converter ma_format_converter; typedef ma_uint32 (* ma_format_converter_read_proc) (ma_format_converter* pConverter, ma_uint32 frameCount, void* pFramesOut, void* pUserData); typedef ma_uint32 (* ma_format_converter_read_deinterleaved_proc)(ma_format_converter* pConverter, ma_uint32 frameCount, void** ppSamplesOut, void* pUserData); typedef struct { ma_format formatIn; ma_format formatOut; ma_uint32 channels; ma_stream_format streamFormatIn; ma_stream_format streamFormatOut; ma_dither_mode ditherMode; ma_bool32 noSSE2 : 1; ma_bool32 noAVX2 : 1; ma_bool32 noAVX512 : 1; ma_bool32 noNEON : 1; ma_format_converter_read_proc onRead; ma_format_converter_read_deinterleaved_proc onReadDeinterleaved; void* pUserData; } ma_format_converter_config; struct ma_format_converter { ma_format_converter_config config; ma_bool32 useSSE2 : 1; ma_bool32 useAVX2 : 1; ma_bool32 useAVX512 : 1; ma_bool32 useNEON : 1; void (* onConvertPCM)(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode); void (* onInterleavePCM)(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels); void (* onDeinterleavePCM)(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels); }; typedef struct ma_channel_router ma_channel_router; typedef ma_uint32 (* ma_channel_router_read_deinterleaved_proc)(ma_channel_router* pRouter, ma_uint32 frameCount, void** ppSamplesOut, void* pUserData); typedef struct { ma_uint32 channelsIn; ma_uint32 channelsOut; ma_channel channelMapIn[MA_MAX_CHANNELS]; ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_channel_mix_mode mixingMode; float weights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ ma_bool32 noSSE2 : 1; ma_bool32 noAVX2 : 1; ma_bool32 noAVX512 : 1; ma_bool32 noNEON : 1; ma_channel_router_read_deinterleaved_proc onReadDeinterleaved; void* pUserData; } ma_channel_router_config; struct ma_channel_router { ma_channel_router_config config; ma_bool32 isPassthrough : 1; ma_bool32 isSimpleShuffle : 1; ma_bool32 useSSE2 : 1; ma_bool32 useAVX2 : 1; ma_bool32 useAVX512 : 1; ma_bool32 useNEON : 1; ma_uint8 shuffleTable[MA_MAX_CHANNELS]; }; typedef struct ma_src ma_src; typedef ma_uint32 (* ma_src_read_deinterleaved_proc)(ma_src* pSRC, ma_uint32 frameCount, void** ppSamplesOut, void* pUserData); /* Returns the number of frames that were read. */ typedef enum { ma_src_algorithm_linear = 0, ma_src_algorithm_sinc, ma_src_algorithm_none, ma_src_algorithm_default = ma_src_algorithm_linear } ma_src_algorithm; typedef enum { ma_src_sinc_window_function_hann = 0, ma_src_sinc_window_function_rectangular, ma_src_sinc_window_function_default = ma_src_sinc_window_function_hann } ma_src_sinc_window_function; typedef struct { ma_src_sinc_window_function windowFunction; ma_uint32 windowWidth; } ma_src_config_sinc; typedef struct { ma_uint32 sampleRateIn; ma_uint32 sampleRateOut; ma_uint32 channels; ma_src_algorithm algorithm; ma_bool32 neverConsumeEndOfInput : 1; ma_bool32 noSSE2 : 1; ma_bool32 noAVX2 : 1; ma_bool32 noAVX512 : 1; ma_bool32 noNEON : 1; ma_src_read_deinterleaved_proc onReadDeinterleaved; void* pUserData; union { ma_src_config_sinc sinc; }; } ma_src_config; MA_ALIGNED_STRUCT(MA_SIMD_ALIGNMENT) ma_src { union { struct { MA_ALIGN(MA_SIMD_ALIGNMENT) float input[MA_MAX_CHANNELS][MA_SRC_INPUT_BUFFER_SIZE_IN_SAMPLES]; float timeIn; ma_uint32 leftoverFrames; } linear; struct { MA_ALIGN(MA_SIMD_ALIGNMENT) float input[MA_MAX_CHANNELS][MA_SRC_SINC_MAX_WINDOW_WIDTH*2 + MA_SRC_INPUT_BUFFER_SIZE_IN_SAMPLES]; float timeIn; ma_uint32 inputFrameCount; /* The number of frames sitting in the input buffer, not including the first half of the window. */ ma_uint32 windowPosInSamples; /* An offset of . */ float table[MA_SRC_SINC_MAX_WINDOW_WIDTH*1 * MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION]; /* Precomputed lookup table. The +1 is used to avoid the need for an overflow check. */ } sinc; }; ma_src_config config; ma_bool32 isEndOfInputLoaded : 1; ma_bool32 useSSE2 : 1; ma_bool32 useAVX2 : 1; ma_bool32 useAVX512 : 1; ma_bool32 useNEON : 1; }; typedef struct ma_pcm_converter ma_pcm_converter; typedef ma_uint32 (* ma_pcm_converter_read_proc)(ma_pcm_converter* pDSP, void* pSamplesOut, ma_uint32 frameCount, void* pUserData); typedef struct { ma_format formatIn; ma_uint32 channelsIn; ma_uint32 sampleRateIn; ma_channel channelMapIn[MA_MAX_CHANNELS]; ma_format formatOut; ma_uint32 channelsOut; ma_uint32 sampleRateOut; ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_channel_mix_mode channelMixMode; ma_dither_mode ditherMode; ma_src_algorithm srcAlgorithm; ma_bool32 allowDynamicSampleRate; ma_bool32 neverConsumeEndOfInput : 1; /* <-- For SRC. */ ma_bool32 noSSE2 : 1; ma_bool32 noAVX2 : 1; ma_bool32 noAVX512 : 1; ma_bool32 noNEON : 1; ma_pcm_converter_read_proc onRead; void* pUserData; union { ma_src_config_sinc sinc; }; } ma_pcm_converter_config; MA_ALIGNED_STRUCT(MA_SIMD_ALIGNMENT) ma_pcm_converter { ma_pcm_converter_read_proc onRead; void* pUserData; ma_format_converter formatConverterIn; /* For converting data to f32 in preparation for further processing. */ ma_format_converter formatConverterOut; /* For converting data to the requested output format. Used as the final step in the processing pipeline. */ ma_channel_router channelRouter; /* For channel conversion. */ ma_src src; /* For sample rate conversion. */ ma_bool32 isDynamicSampleRateAllowed : 1; /* ma_pcm_converter_set_input_sample_rate() and ma_pcm_converter_set_output_sample_rate() will fail if this is set to false. */ ma_bool32 isPreFormatConversionRequired : 1; ma_bool32 isPostFormatConversionRequired : 1; ma_bool32 isChannelRoutingRequired : 1; ma_bool32 isSRCRequired : 1; ma_bool32 isChannelRoutingAtStart : 1; ma_bool32 isPassthrough : 1; /* <-- Will be set to true when the DSP pipeline is an optimized passthrough. */ }; /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* DATA CONVERSION =============== This section contains the APIs for data conversion. You will find everything here for channel mapping, sample format conversion, resampling, etc. ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ /************************************************************************************************************************************************************ Channel Maps ============ Below is the channel map used by ma_standard_channel_map_default: |---------------|------------------------------| | Channel Count | Mapping | |---------------|------------------------------| | 1 (Mono) | 0: MA_CHANNEL_MONO | |---------------|------------------------------| | 2 (Stereo) | 0: MA_CHANNEL_FRONT_LEFT | | | 1: MA_CHANNEL_FRONT_RIGHT | |---------------|------------------------------| | 3 | 0: MA_CHANNEL_FRONT_LEFT | | | 1: MA_CHANNEL_FRONT_RIGHT | | | 2: MA_CHANNEL_FRONT_CENTER | |---------------|------------------------------| | 4 (Surround) | 0: MA_CHANNEL_FRONT_LEFT | | | 1: MA_CHANNEL_FRONT_RIGHT | | | 2: MA_CHANNEL_FRONT_CENTER | | | 3: MA_CHANNEL_BACK_CENTER | |---------------|------------------------------| | 5 | 0: MA_CHANNEL_FRONT_LEFT | | | 1: MA_CHANNEL_FRONT_RIGHT | | | 2: MA_CHANNEL_FRONT_CENTER | | | 3: MA_CHANNEL_BACK_LEFT | | | 4: MA_CHANNEL_BACK_RIGHT | |---------------|------------------------------| | 6 (5.1) | 0: MA_CHANNEL_FRONT_LEFT | | | 1: MA_CHANNEL_FRONT_RIGHT | | | 2: MA_CHANNEL_FRONT_CENTER | | | 3: MA_CHANNEL_LFE | | | 4: MA_CHANNEL_SIDE_LEFT | | | 5: MA_CHANNEL_SIDE_RIGHT | |---------------|------------------------------| | 7 | 0: MA_CHANNEL_FRONT_LEFT | | | 1: MA_CHANNEL_FRONT_RIGHT | | | 2: MA_CHANNEL_FRONT_CENTER | | | 3: MA_CHANNEL_LFE | | | 4: MA_CHANNEL_BACK_CENTER | | | 4: MA_CHANNEL_SIDE_LEFT | | | 5: MA_CHANNEL_SIDE_RIGHT | |---------------|------------------------------| | 8 (7.1) | 0: MA_CHANNEL_FRONT_LEFT | | | 1: MA_CHANNEL_FRONT_RIGHT | | | 2: MA_CHANNEL_FRONT_CENTER | | | 3: MA_CHANNEL_LFE | | | 4: MA_CHANNEL_BACK_LEFT | | | 5: MA_CHANNEL_BACK_RIGHT | | | 6: MA_CHANNEL_SIDE_LEFT | | | 7: MA_CHANNEL_SIDE_RIGHT | |---------------|------------------------------| | Other | All channels set to 0. This | | | is equivalent to the same | | | mapping as the device. | |---------------|------------------------------| ************************************************************************************************************************************************************/ /* Helper for retrieving a standard channel map. */ void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]); /* Copies a channel map. */ void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels); /* Determines whether or not a channel map is valid. A blank channel map is valid (all channels set to MA_CHANNEL_NONE). The way a blank channel map is handled is context specific, but is usually treated as a passthrough. Invalid channel maps: - A channel map with no channels - A channel map with more than one channel and a mono channel */ ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS]); /* Helper for comparing two channel maps for equality. This assumes the channel count is the same between the two. */ ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel channelMapA[MA_MAX_CHANNELS], const ma_channel channelMapB[MA_MAX_CHANNELS]); /* Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE). */ ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS]); /* Helper for determining whether or not a channel is present in the given channel map. */ ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS], ma_channel channelPosition); /************************************************************************************************************************************************************ Format Conversion ================= The format converter serves two purposes: 1) Conversion between data formats (u8 to f32, etc.) 2) Interleaving and deinterleaving When initializing a converter, you specify the input and output formats (u8, s16, etc.) and read callbacks. There are two read callbacks - one for interleaved input data (onRead) and another for deinterleaved input data (onReadDeinterleaved). You implement whichever is most convenient for you. You can implement both, but it's not recommended as it just introduces unnecessary complexity. To read data as interleaved samples, use ma_format_converter_read(). Otherwise use ma_format_converter_read_deinterleaved(). Dithering --------- The format converter also supports dithering. Dithering can be set using ditherMode variable in the config, like so. pConfig->ditherMode = ma_dither_mode_rectangle; The different dithering modes include the following, in order of efficiency: - None: ma_dither_mode_none - Rectangle: ma_dither_mode_rectangle - Triangle: ma_dither_mode_triangle Note that even if the dither mode is set to something other than ma_dither_mode_none, it will be ignored for conversions where dithering is not needed. Dithering is available for the following conversions: - s16 -> u8 - s24 -> u8 - s32 -> u8 - f32 -> u8 - s24 -> s16 - s32 -> s16 - f32 -> s16 Note that it is not an error to pass something other than ma_dither_mode_none for conversions where dither is not used. It will just be ignored. ************************************************************************************************************************************************************/ /* Initializes a format converter. */ ma_result ma_format_converter_init(const ma_format_converter_config* pConfig, ma_format_converter* pConverter); /* Reads data from the format converter as interleaved channels. */ ma_uint64 ma_format_converter_read(ma_format_converter* pConverter, ma_uint64 frameCount, void* pFramesOut, void* pUserData); /* Reads data from the format converter as deinterleaved channels. */ ma_uint64 ma_format_converter_read_deinterleaved(ma_format_converter* pConverter, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData); /* Helper for initializing a format converter config. */ ma_format_converter_config ma_format_converter_config_init_new(void); ma_format_converter_config ma_format_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channels, ma_format_converter_read_proc onRead, void* pUserData); ma_format_converter_config ma_format_converter_config_init_deinterleaved(ma_format formatIn, ma_format formatOut, ma_uint32 channels, ma_format_converter_read_deinterleaved_proc onReadDeinterleaved, void* pUserData); /************************************************************************************************************************************************************ Channel Routing =============== There are two main things you can do with the channel router: 1) Rearrange channels 2) Convert from one channel count to another Channel Rearrangement --------------------- A simple example of channel rearrangement may be swapping the left and right channels in a stereo stream. To do this you just pass in the same channel count for both the input and output with channel maps that contain the same channels (in a different order). Channel Conversion ------------------ The channel router can also convert from one channel count to another, such as converting a 5.1 stream to stero. When changing the channel count, the router will first perform a 1:1 mapping of channel positions that are present in both the input and output channel maps. The second thing it will do is distribute the input mono channel (if any) across all output channels, excluding any None and LFE channels. If there is an output mono channel, all input channels will be averaged, excluding any None and LFE channels. The last case to consider is when a channel position in the input channel map is not present in the output channel map, and vice versa. In this case the channel router will perform a blend of other related channels to produce an audible channel. There are several blending modes. 1) Simple Unmatched channels are silenced. 2) Planar Blending Channels are blended based on a set of planes that each speaker emits audio from. Rectangular / Planar Blending ----------------------------- In this mode, channel positions are associated with a set of planes where the channel conceptually emits audio from. An example is the front/left speaker. This speaker is positioned to the front of the listener, so you can think of it as emitting audio from the front plane. It is also positioned to the left of the listener so you can think of it as also emitting audio from the left plane. Now consider the (unrealistic) situation where the input channel map contains only the front/left channel position, but the output channel map contains both the front/left and front/center channel. When deciding on the audio data to send to the front/center speaker (which has no 1:1 mapping with an input channel) we need to use some logic based on our available input channel positions. As mentioned earlier, our front/left speaker is, conceptually speaking, emitting audio from the front _and_ the left planes. Similarly, the front/center speaker is emitting audio from _only_ the front plane. What these two channels have in common is that they are both emitting audio from the front plane. Thus, it makes sense that the front/center speaker should receive some contribution from the front/left channel. How much contribution depends on their planar relationship (thus the name of this blending technique). Because the front/left channel is emitting audio from two planes (front and left), you can think of it as though it's willing to dedicate 50% of it's total volume to each of it's planes (a channel position emitting from 1 plane would be willing to given 100% of it's total volume to that plane, and a channel position emitting from 3 planes would be willing to given 33% of it's total volume to each plane). Similarly, the front/center speaker is emitting audio from only one plane so you can think of it as though it's willing to _take_ 100% of it's volume from front plane emissions. Now, since the front/left channel is willing to _give_ 50% of it's total volume to the front plane, and the front/center speaker is willing to _take_ 100% of it's total volume from the front, you can imagine that 50% of the front/left speaker will be given to the front/center speaker. Usage ----- To use the channel router you need to specify three things: 1) The input channel count and channel map 2) The output channel count and channel map 3) The mixing mode to use in the case where a 1:1 mapping is unavailable Note that input and output data is always deinterleaved 32-bit floating point. Initialize the channel router with ma_channel_router_init(). You will need to pass in a config object which specifies the input and output configuration, mixing mode and a callback for sending data to the router. This callback will be called when input data needs to be sent to the router for processing. Note that the mixing mode is only used when a 1:1 mapping is unavailable. This includes the custom weights mode. Read data from the channel router with ma_channel_router_read_deinterleaved(). Output data is always 32-bit floating point. ************************************************************************************************************************************************************/ /* Initializes a channel router where it is assumed that the input data is non-interleaved. */ ma_result ma_channel_router_init(const ma_channel_router_config* pConfig, ma_channel_router* pRouter); /* Reads data from the channel router as deinterleaved channels. */ ma_uint64 ma_channel_router_read_deinterleaved(ma_channel_router* pRouter, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData); /* Helper for initializing a channel router config. */ ma_channel_router_config ma_channel_router_config_init(ma_uint32 channelsIn, const ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint32 channelsOut, const ma_channel channelMapOut[MA_MAX_CHANNELS], ma_channel_mix_mode mixingMode, ma_channel_router_read_deinterleaved_proc onRead, void* pUserData); /************************************************************************************************************************************************************ Sample Rate Conversion ====================== ************************************************************************************************************************************************************/ /* Initializes a sample rate conversion object. */ ma_result ma_src_init(const ma_src_config* pConfig, ma_src* pSRC); /* Dynamically adjusts the sample rate. This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this is not acceptable you will need to use your own algorithm. */ ma_result ma_src_set_sample_rate(ma_src* pSRC, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); /* Reads a number of frames. Returns the number of frames actually read. */ ma_uint64 ma_src_read_deinterleaved(ma_src* pSRC, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData); /* Helper for creating a sample rate conversion config. */ ma_src_config ma_src_config_init_new(void); ma_src_config ma_src_config_init(ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_uint32 channels, ma_src_read_deinterleaved_proc onReadDeinterleaved, void* pUserData); /************************************************************************************************************************************************************ Conversion ************************************************************************************************************************************************************/ /* Initializes a DSP object. */ ma_result ma_pcm_converter_init(const ma_pcm_converter_config* pConfig, ma_pcm_converter* pDSP); /* Dynamically adjusts the input sample rate. This will fail is the DSP was not initialized with allowDynamicSampleRate. DEPRECATED. Use ma_pcm_converter_set_sample_rate() instead. */ ma_result ma_pcm_converter_set_input_sample_rate(ma_pcm_converter* pDSP, ma_uint32 sampleRateOut); /* Dynamically adjusts the output sample rate. This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this is not acceptable you will need to use your own algorithm. This will fail is the DSP was not initialized with allowDynamicSampleRate. DEPRECATED. Use ma_pcm_converter_set_sample_rate() instead. */ ma_result ma_pcm_converter_set_output_sample_rate(ma_pcm_converter* pDSP, ma_uint32 sampleRateOut); /* Dynamically adjusts the output sample rate. This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this is not acceptable you will need to use your own algorithm. This will fail if the DSP was not initialized with allowDynamicSampleRate. */ ma_result ma_pcm_converter_set_sample_rate(ma_pcm_converter* pDSP, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); /* Reads a number of frames and runs them through the DSP processor. */ ma_uint64 ma_pcm_converter_read(ma_pcm_converter* pDSP, void* pFramesOut, ma_uint64 frameCount); /* Helper for initializing a ma_pcm_converter_config object. */ ma_pcm_converter_config ma_pcm_converter_config_init_new(void); ma_pcm_converter_config ma_pcm_converter_config_init(ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, ma_pcm_converter_read_proc onRead, void* pUserData); ma_pcm_converter_config ma_pcm_converter_config_init_ex(ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_channel channelMapIn[MA_MAX_CHANNELS], ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, ma_channel channelMapOut[MA_MAX_CHANNELS], ma_pcm_converter_read_proc onRead, void* pUserData); /* High-level helper for doing a full format conversion in one go. Returns the number of output frames. Call this with pOut set to NULL to determine the required size of the output buffer. A return value of 0 indicates an error. This function is useful for one-off bulk conversions, but if you're streaming data you should use the DSP APIs instead. */ ma_uint64 ma_convert_frames(void* pOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void* pIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_uint64 frameCount); ma_uint64 ma_convert_frames_ex(void* pOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, ma_channel channelMapOut[MA_MAX_CHANNELS], const void* pIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint64 frameCount); /************************************************************************************************************************************************************ Ring Buffer =========== Features -------- - Lock free (assuming single producer, single consumer) - Support for interleaved and deinterleaved streams - Allows the caller to allocate their own block of memory Usage ----- - Call ma_rb_init() to initialize a simple buffer, with an optional pre-allocated buffer. If you pass in NULL for the pre-allocated buffer, it will be allocated for you and free()'d in ma_rb_uninit(). If you pass in your own pre-allocated buffer, free()-ing is left to you. - Call ma_rb_init_ex() if you need a deinterleaved buffer. The data for each sub-buffer is offset from each other based on the stride. Use ma_rb_get_subbuffer_stride(), ma_rb_get_subbuffer_offset() and ma_rb_get_subbuffer_ptr() to manage your sub-buffers. - Use ma_rb_acquire_read() and ma_rb_acquire_write() to retrieve a pointer to a section of the ring buffer. You specify the number of bytes you need, and on output it will set to what was actually acquired. If the read or write pointer is positioned such that the number of bytes requested will require a loop, it will be clamped to the end of the buffer. Therefore, the number of bytes you're given may be less than the number you requested. - After calling ma_rb_acquire_read/write(), you do your work on the buffer and then "commit" it with ma_rb_commit_read/write(). This is where the read/write pointers are updated. When you commit you need to pass in the buffer that was returned by the earlier call to ma_rb_acquire_read/write() and is only used for validation. The number of bytes passed to ma_rb_commit_read/write() is what's used to increment the pointers. - If you want to correct for drift between the write pointer and the read pointer you can use a combination of ma_rb_pointer_distance(), ma_rb_seek_read() and ma_rb_seek_write(). Note that you can only move the pointers forward, and you should only move the read pointer forward via the consumer thread, and the write pointer forward by the producer thread. If there is too much space between the pointers, move the read pointer forward. If there is too little space between the pointers, move the write pointer forward. Notes ----- - Thread safety depends on a single producer, single consumer model. Only one thread is allowed to write, and only one thread is allowed to read. The producer is the only one allowed to move the write pointer, and the consumer is the only one allowed to move the read pointer. - Operates on bytes. Use ma_pcm_rb to operate in terms of PCM frames. - Maximum buffer size in bytes is 0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1) because of reasons. PCM Ring Buffer =============== This is the same as the regular ring buffer, except that it works on PCM frames instead of bytes. ************************************************************************************************************************************************************/ typedef struct { void* pBuffer; ma_uint32 subbufferSizeInBytes; ma_uint32 subbufferCount; ma_uint32 subbufferStrideInBytes; volatile ma_uint32 encodedReadOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. */ volatile ma_uint32 encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. */ ma_bool32 ownsBuffer : 1; /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */ ma_bool32 clearOnWriteAcquire : 1; /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */ } ma_rb; ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void* pOptionalPreallocatedBuffer, ma_rb* pRB); ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, ma_rb* pRB); void ma_rb_uninit(ma_rb* pRB); ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut); ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut); ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut); ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut); ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes); ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes); ma_int32 ma_rb_pointer_distance(ma_rb* pRB); /* Returns the distance between the write pointer and the read pointer. Should never be negative for a correct program. */ size_t ma_rb_get_subbuffer_size(ma_rb* pRB); size_t ma_rb_get_subbuffer_stride(ma_rb* pRB); size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex); void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer); typedef struct { ma_rb rb; ma_format format; ma_uint32 channels; } ma_pcm_rb; ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, ma_pcm_rb* pRB); ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void* pOptionalPreallocatedBuffer, ma_pcm_rb* pRB); void ma_pcm_rb_uninit(ma_pcm_rb* pRB); ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut); ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut); ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut); ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut); ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames); ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames); ma_int32 ma_pcm_rb_pointer_disance(ma_pcm_rb* pRB); /* Return value is in frames. */ ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB); ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB); ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex); void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer); /************************************************************************************************************************************************************ Miscellaneous Helpers ************************************************************************************************************************************************************/ /* malloc(). Calls MA_MALLOC(). */ void* ma_malloc(size_t sz); /* realloc(). Calls MA_REALLOC(). */ void* ma_realloc(void* p, size_t sz); /* free(). Calls MA_FREE(). */ void ma_free(void* p); /* Performs an aligned malloc, with the assumption that the alignment is a power of 2. */ void* ma_aligned_malloc(size_t sz, size_t alignment); /* Free's an aligned malloc'd buffer. */ void ma_aligned_free(void* p); /* Retrieves a friendly name for a format. */ const char* ma_get_format_name(ma_format format); /* Blends two frames in floating point format. */ void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels); /* Retrieves the size of a sample in bytes for the given format. This API is efficient and is implemented using a lookup table. Thread Safety: SAFE This API is pure. */ ma_uint32 ma_get_bytes_per_sample(ma_format format); static MA_INLINE ma_uint32 ma_get_bytes_per_frame(ma_format format, ma_uint32 channels) { return ma_get_bytes_per_sample(format) * channels; } /* Converts a log level to a string. */ const char* ma_log_level_to_string(ma_uint32 logLevel); /************************************************************************************************************************************************************ Format Conversion ************************************************************************************************************************************************************/ void ma_pcm_u8_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_u8_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_u8_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_u8_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s16_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s16_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s16_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s16_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s24_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s24_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s24_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s24_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_s32_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_f32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_f32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_f32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_f32_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode); /* Deinterleaves an interleaved buffer. */ void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames); /* Interleaves a group of deinterleaved buffers. */ void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames); /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* DEVICE I/O ========== This section contains the APIs for device playback and capture. Here is where you'll find ma_device_init(), etc. ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ #ifndef MA_NO_DEVICE_IO /* Some backends are only supported on certain platforms. */ #if defined(MA_WIN32) #define MA_SUPPORT_WASAPI #if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */ #define MA_SUPPORT_DSOUND #define MA_SUPPORT_WINMM #define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */ #endif #endif #if defined(MA_UNIX) #if defined(MA_LINUX) #if !defined(MA_ANDROID) /* ALSA is not supported on Android. */ #define MA_SUPPORT_ALSA #endif #endif #if !defined(MA_BSD) && !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN) #define MA_SUPPORT_PULSEAUDIO #define MA_SUPPORT_JACK #endif #if defined(MA_ANDROID) #define MA_SUPPORT_AAUDIO #define MA_SUPPORT_OPENSL #endif #if defined(__OpenBSD__) /* <-- Change this to "#if defined(MA_BSD)" to enable sndio on all BSD flavors. */ #define MA_SUPPORT_SNDIO /* sndio is only supported on OpenBSD for now. May be expanded later if there's demand. */ #endif #if defined(__NetBSD__) || defined(__OpenBSD__) #define MA_SUPPORT_AUDIO4 /* Only support audio(4) on platforms with known support. */ #endif #if defined(__FreeBSD__) || defined(__DragonFly__) #define MA_SUPPORT_OSS /* Only support OSS on specific platforms with known support. */ #endif #endif #if defined(MA_APPLE) #define MA_SUPPORT_COREAUDIO #endif #if defined(MA_EMSCRIPTEN) #define MA_SUPPORT_WEBAUDIO #endif /* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */ #if !defined(MA_EMSCRIPTEN) #define MA_SUPPORT_NULL #endif #if !defined(MA_NO_WASAPI) && defined(MA_SUPPORT_WASAPI) #define MA_ENABLE_WASAPI #endif #if !defined(MA_NO_DSOUND) && defined(MA_SUPPORT_DSOUND) #define MA_ENABLE_DSOUND #endif #if !defined(MA_NO_WINMM) && defined(MA_SUPPORT_WINMM) #define MA_ENABLE_WINMM #endif #if !defined(MA_NO_ALSA) && defined(MA_SUPPORT_ALSA) #define MA_ENABLE_ALSA #endif #if !defined(MA_NO_PULSEAUDIO) && defined(MA_SUPPORT_PULSEAUDIO) #define MA_ENABLE_PULSEAUDIO #endif #if !defined(MA_NO_JACK) && defined(MA_SUPPORT_JACK) #define MA_ENABLE_JACK #endif #if !defined(MA_NO_COREAUDIO) && defined(MA_SUPPORT_COREAUDIO) #define MA_ENABLE_COREAUDIO #endif #if !defined(MA_NO_SNDIO) && defined(MA_SUPPORT_SNDIO) #define MA_ENABLE_SNDIO #endif #if !defined(MA_NO_AUDIO4) && defined(MA_SUPPORT_AUDIO4) #define MA_ENABLE_AUDIO4 #endif #if !defined(MA_NO_OSS) && defined(MA_SUPPORT_OSS) #define MA_ENABLE_OSS #endif #if !defined(MA_NO_AAUDIO) && defined(MA_SUPPORT_AAUDIO) #define MA_ENABLE_AAUDIO #endif #if !defined(MA_NO_OPENSL) && defined(MA_SUPPORT_OPENSL) #define MA_ENABLE_OPENSL #endif #if !defined(MA_NO_WEBAUDIO) && defined(MA_SUPPORT_WEBAUDIO) #define MA_ENABLE_WEBAUDIO #endif #if !defined(MA_NO_NULL) && defined(MA_SUPPORT_NULL) #define MA_ENABLE_NULL #endif #ifdef MA_SUPPORT_WASAPI /* We need a IMMNotificationClient object for WASAPI. */ typedef struct { void* lpVtbl; ma_uint32 counter; ma_device* pDevice; } ma_IMMNotificationClient; #endif /* Backend enums must be in priority order. */ typedef enum { ma_backend_wasapi, ma_backend_dsound, ma_backend_winmm, ma_backend_coreaudio, ma_backend_sndio, ma_backend_audio4, ma_backend_oss, ma_backend_pulseaudio, ma_backend_alsa, ma_backend_jack, ma_backend_aaudio, ma_backend_opensl, ma_backend_webaudio, ma_backend_null /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */ } ma_backend; /* Thread priorties should be ordered such that the default priority of the worker thread is 0. */ typedef enum { ma_thread_priority_idle = -5, ma_thread_priority_lowest = -4, ma_thread_priority_low = -3, ma_thread_priority_normal = -2, ma_thread_priority_high = -1, ma_thread_priority_highest = 0, ma_thread_priority_realtime = 1, ma_thread_priority_default = 0 } ma_thread_priority; typedef struct { ma_context* pContext; union { #ifdef MA_WIN32 struct { /*HANDLE*/ ma_handle hThread; } win32; #endif #ifdef MA_POSIX struct { pthread_t thread; } posix; #endif int _unused; }; } ma_thread; typedef struct { ma_context* pContext; union { #ifdef MA_WIN32 struct { /*HANDLE*/ ma_handle hMutex; } win32; #endif #ifdef MA_POSIX struct { pthread_mutex_t mutex; } posix; #endif int _unused; }; } ma_mutex; typedef struct { ma_context* pContext; union { #ifdef MA_WIN32 struct { /*HANDLE*/ ma_handle hEvent; } win32; #endif #ifdef MA_POSIX struct { pthread_mutex_t mutex; pthread_cond_t condition; ma_uint32 value; } posix; #endif int _unused; }; } ma_event; /* The callback for processing audio data from the device. pOutput is a pointer to a buffer that will receive audio data that will later be played back through the speakers. This will be non-null for a playback or full-duplex device and null for a capture device. pInput is a pointer to a buffer containing input data from the device. This will be non-null for a capture or full-duplex device, and null for a playback device. frameCount is the number of PCM frames to process. If an output buffer is provided (pOutput is not null), applications should write out to the entire output buffer. Do _not_ call any miniaudio APIs from the callback. Attempting the stop the device can result in a deadlock. The proper way to stop the device is to call ma_device_stop() from a different thread, normally the main application thread. */ typedef void (* ma_device_callback_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); /* The callback for when the device has been stopped. This will be called when the device is stopped explicitly with ma_device_stop() and also called implicitly when the device is stopped through external forces such as being unplugged or an internal error occuring. Do not restart the device from the callback. */ typedef void (* ma_stop_proc)(ma_device* pDevice); /* The callback for handling log messages. It is possible for pDevice to be null in which case the log originated from the context. If it is non-null you can assume the message came from the device. logLevel is one of the following: MA_LOG_LEVEL_VERBOSE MA_LOG_LEVEL_INFO MA_LOG_LEVEL_WARNING MA_LOG_LEVEL_ERROR */ typedef void (* ma_log_proc)(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message); typedef enum { ma_device_type_playback = 1, ma_device_type_capture = 2, ma_device_type_duplex = ma_device_type_playback | ma_device_type_capture, } ma_device_type; typedef enum { ma_share_mode_shared = 0, ma_share_mode_exclusive, } ma_share_mode; typedef union { #ifdef MA_SUPPORT_WASAPI wchar_t wasapi[64]; /* WASAPI uses a wchar_t string for identification. */ #endif #ifdef MA_SUPPORT_DSOUND ma_uint8 dsound[16]; /* DirectSound uses a GUID for identification. */ #endif #ifdef MA_SUPPORT_WINMM /*UINT_PTR*/ ma_uint32 winmm; /* When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. */ #endif #ifdef MA_SUPPORT_ALSA char alsa[256]; /* ALSA uses a name string for identification. */ #endif #ifdef MA_SUPPORT_PULSEAUDIO char pulse[256]; /* PulseAudio uses a name string for identification. */ #endif #ifdef MA_SUPPORT_JACK int jack; /* JACK always uses default devices. */ #endif #ifdef MA_SUPPORT_COREAUDIO char coreaudio[256]; /* Core Audio uses a string for identification. */ #endif #ifdef MA_SUPPORT_SNDIO char sndio[256]; /* "snd/0", etc. */ #endif #ifdef MA_SUPPORT_AUDIO4 char audio4[256]; /* "/dev/audio", etc. */ #endif #ifdef MA_SUPPORT_OSS char oss[64]; /* "dev/dsp0", etc. "dev/dsp" for the default device. */ #endif #ifdef MA_SUPPORT_AAUDIO ma_int32 aaudio; /* AAudio uses a 32-bit integer for identification. */ #endif #ifdef MA_SUPPORT_OPENSL ma_uint32 opensl; /* OpenSL|ES uses a 32-bit unsigned integer for identification. */ #endif #ifdef MA_SUPPORT_WEBAUDIO char webaudio[32]; /* Web Audio always uses default devices for now, but if this changes it'll be a GUID. */ #endif #ifdef MA_SUPPORT_NULL int nullbackend; /* The null backend uses an integer for device IDs. */ #endif } ma_device_id; typedef struct { /* Basic info. This is the only information guaranteed to be filled in during device enumeration. */ ma_device_id id; char name[256]; /* Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize a device with settings outside of this range, but it just means the data will be converted using miniaudio's data conversion pipeline before sending the data to/from the device. Most programs will need to not worry about these values, but it's provided here mainly for informational purposes or in the rare case that someone might find it useful. These will be set to 0 when returned by ma_context_enumerate_devices() or ma_context_get_devices(). */ ma_uint32 formatCount; ma_format formats[ma_format_count]; ma_uint32 minChannels; ma_uint32 maxChannels; ma_uint32 minSampleRate; ma_uint32 maxSampleRate; } ma_device_info; typedef union { ma_int64 counter; double counterD; } ma_timer; typedef struct { ma_device_type deviceType; ma_uint32 sampleRate; ma_uint32 bufferSizeInFrames; ma_uint32 bufferSizeInMilliseconds; ma_uint32 periods; ma_performance_profile performanceProfile; ma_device_callback_proc dataCallback; ma_stop_proc stopCallback; void* pUserData; struct { ma_device_id* pDeviceID; ma_format format; ma_uint32 channels; ma_channel channelMap[MA_MAX_CHANNELS]; ma_share_mode shareMode; } playback; struct { ma_device_id* pDeviceID; ma_format format; ma_uint32 channels; ma_channel channelMap[MA_MAX_CHANNELS]; ma_share_mode shareMode; } capture; struct { ma_bool32 noMMap; /* Disables MMap mode. */ } alsa; struct { const char* pStreamNamePlayback; const char* pStreamNameCapture; } pulse; } ma_device_config; typedef struct { ma_log_proc logCallback; ma_thread_priority threadPriority; void* pUserData; struct { ma_bool32 useVerboseDeviceEnumeration; } alsa; struct { const char* pApplicationName; const char* pServerName; ma_bool32 tryAutoSpawn; /* Enables autospawning of the PulseAudio daemon if necessary. */ } pulse; struct { const char* pClientName; ma_bool32 tryStartServer; } jack; } ma_context_config; typedef ma_bool32 (* ma_enum_devices_callback_proc)(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData); struct ma_context { ma_backend backend; /* DirectSound, ALSA, etc. */ ma_log_proc logCallback; ma_thread_priority threadPriority; void* pUserData; ma_mutex deviceEnumLock; /* Used to make ma_context_get_devices() thread safe. */ ma_mutex deviceInfoLock; /* Used to make ma_context_get_device_info() thread safe. */ ma_uint32 deviceInfoCapacity; /* Total capacity of pDeviceInfos. */ ma_uint32 playbackDeviceInfoCount; ma_uint32 captureDeviceInfoCount; ma_device_info* pDeviceInfos; /* Playback devices first, then capture. */ ma_bool32 isBackendAsynchronous : 1; /* Set when the context is initialized. Set to 1 for asynchronous backends such as Core Audio and JACK. Do not modify. */ ma_result (* onUninit )(ma_context* pContext); ma_bool32 (* onDeviceIDEqual )(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1); ma_result (* onEnumDevices )(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData); /* Return false from the callback to stop enumeration. */ ma_result (* onGetDeviceInfo )(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo); ma_result (* onDeviceInit )(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice); void (* onDeviceUninit )(ma_device* pDevice); ma_result (* onDeviceStart )(ma_device* pDevice); ma_result (* onDeviceStop )(ma_device* pDevice); ma_result (* onDeviceWrite )(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount); /* Data is in internal device format. */ ma_result (* onDeviceRead )(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount); /* Data is in internal device format. */ ma_result (* onDeviceMainLoop)(ma_device* pDevice); union { #ifdef MA_SUPPORT_WASAPI struct { int _unused; } wasapi; #endif #ifdef MA_SUPPORT_DSOUND struct { ma_handle hDSoundDLL; ma_proc DirectSoundCreate; ma_proc DirectSoundEnumerateA; ma_proc DirectSoundCaptureCreate; ma_proc DirectSoundCaptureEnumerateA; } dsound; #endif #ifdef MA_SUPPORT_WINMM struct { ma_handle hWinMM; ma_proc waveOutGetNumDevs; ma_proc waveOutGetDevCapsA; ma_proc waveOutOpen; ma_proc waveOutClose; ma_proc waveOutPrepareHeader; ma_proc waveOutUnprepareHeader; ma_proc waveOutWrite; ma_proc waveOutReset; ma_proc waveInGetNumDevs; ma_proc waveInGetDevCapsA; ma_proc waveInOpen; ma_proc waveInClose; ma_proc waveInPrepareHeader; ma_proc waveInUnprepareHeader; ma_proc waveInAddBuffer; ma_proc waveInStart; ma_proc waveInReset; } winmm; #endif #ifdef MA_SUPPORT_ALSA struct { ma_handle asoundSO; ma_proc snd_pcm_open; ma_proc snd_pcm_close; ma_proc snd_pcm_hw_params_sizeof; ma_proc snd_pcm_hw_params_any; ma_proc snd_pcm_hw_params_set_format; ma_proc snd_pcm_hw_params_set_format_first; ma_proc snd_pcm_hw_params_get_format_mask; ma_proc snd_pcm_hw_params_set_channels_near; ma_proc snd_pcm_hw_params_set_rate_resample; ma_proc snd_pcm_hw_params_set_rate_near; ma_proc snd_pcm_hw_params_set_buffer_size_near; ma_proc snd_pcm_hw_params_set_periods_near; ma_proc snd_pcm_hw_params_set_access; ma_proc snd_pcm_hw_params_get_format; ma_proc snd_pcm_hw_params_get_channels; ma_proc snd_pcm_hw_params_get_channels_min; ma_proc snd_pcm_hw_params_get_channels_max; ma_proc snd_pcm_hw_params_get_rate; ma_proc snd_pcm_hw_params_get_rate_min; ma_proc snd_pcm_hw_params_get_rate_max; ma_proc snd_pcm_hw_params_get_buffer_size; ma_proc snd_pcm_hw_params_get_periods; ma_proc snd_pcm_hw_params_get_access; ma_proc snd_pcm_hw_params; ma_proc snd_pcm_sw_params_sizeof; ma_proc snd_pcm_sw_params_current; ma_proc snd_pcm_sw_params_get_boundary; ma_proc snd_pcm_sw_params_set_avail_min; ma_proc snd_pcm_sw_params_set_start_threshold; ma_proc snd_pcm_sw_params_set_stop_threshold; ma_proc snd_pcm_sw_params; ma_proc snd_pcm_format_mask_sizeof; ma_proc snd_pcm_format_mask_test; ma_proc snd_pcm_get_chmap; ma_proc snd_pcm_state; ma_proc snd_pcm_prepare; ma_proc snd_pcm_start; ma_proc snd_pcm_drop; ma_proc snd_pcm_drain; ma_proc snd_device_name_hint; ma_proc snd_device_name_get_hint; ma_proc snd_card_get_index; ma_proc snd_device_name_free_hint; ma_proc snd_pcm_mmap_begin; ma_proc snd_pcm_mmap_commit; ma_proc snd_pcm_recover; ma_proc snd_pcm_readi; ma_proc snd_pcm_writei; ma_proc snd_pcm_avail; ma_proc snd_pcm_avail_update; ma_proc snd_pcm_wait; ma_proc snd_pcm_info; ma_proc snd_pcm_info_sizeof; ma_proc snd_pcm_info_get_name; ma_proc snd_config_update_free_global; ma_mutex internalDeviceEnumLock; ma_bool32 useVerboseDeviceEnumeration; } alsa; #endif #ifdef MA_SUPPORT_PULSEAUDIO struct { ma_handle pulseSO; ma_proc pa_mainloop_new; ma_proc pa_mainloop_free; ma_proc pa_mainloop_get_api; ma_proc pa_mainloop_iterate; ma_proc pa_mainloop_wakeup; ma_proc pa_context_new; ma_proc pa_context_unref; ma_proc pa_context_connect; ma_proc pa_context_disconnect; ma_proc pa_context_set_state_callback; ma_proc pa_context_get_state; ma_proc pa_context_get_sink_info_list; ma_proc pa_context_get_source_info_list; ma_proc pa_context_get_sink_info_by_name; ma_proc pa_context_get_source_info_by_name; ma_proc pa_operation_unref; ma_proc pa_operation_get_state; ma_proc pa_channel_map_init_extend; ma_proc pa_channel_map_valid; ma_proc pa_channel_map_compatible; ma_proc pa_stream_new; ma_proc pa_stream_unref; ma_proc pa_stream_connect_playback; ma_proc pa_stream_connect_record; ma_proc pa_stream_disconnect; ma_proc pa_stream_get_state; ma_proc pa_stream_get_sample_spec; ma_proc pa_stream_get_channel_map; ma_proc pa_stream_get_buffer_attr; ma_proc pa_stream_set_buffer_attr; ma_proc pa_stream_get_device_name; ma_proc pa_stream_set_write_callback; ma_proc pa_stream_set_read_callback; ma_proc pa_stream_flush; ma_proc pa_stream_drain; ma_proc pa_stream_is_corked; ma_proc pa_stream_cork; ma_proc pa_stream_trigger; ma_proc pa_stream_begin_write; ma_proc pa_stream_write; ma_proc pa_stream_peek; ma_proc pa_stream_drop; ma_proc pa_stream_writable_size; ma_proc pa_stream_readable_size; char* pApplicationName; char* pServerName; ma_bool32 tryAutoSpawn; } pulse; #endif #ifdef MA_SUPPORT_JACK struct { ma_handle jackSO; ma_proc jack_client_open; ma_proc jack_client_close; ma_proc jack_client_name_size; ma_proc jack_set_process_callback; ma_proc jack_set_buffer_size_callback; ma_proc jack_on_shutdown; ma_proc jack_get_sample_rate; ma_proc jack_get_buffer_size; ma_proc jack_get_ports; ma_proc jack_activate; ma_proc jack_deactivate; ma_proc jack_connect; ma_proc jack_port_register; ma_proc jack_port_name; ma_proc jack_port_get_buffer; ma_proc jack_free; char* pClientName; ma_bool32 tryStartServer; } jack; #endif #ifdef MA_SUPPORT_COREAUDIO struct { ma_handle hCoreFoundation; ma_proc CFStringGetCString; ma_handle hCoreAudio; ma_proc AudioObjectGetPropertyData; ma_proc AudioObjectGetPropertyDataSize; ma_proc AudioObjectSetPropertyData; ma_proc AudioObjectAddPropertyListener; ma_handle hAudioUnit; /* Could possibly be set to AudioToolbox on later versions of macOS. */ ma_proc AudioComponentFindNext; ma_proc AudioComponentInstanceDispose; ma_proc AudioComponentInstanceNew; ma_proc AudioOutputUnitStart; ma_proc AudioOutputUnitStop; ma_proc AudioUnitAddPropertyListener; ma_proc AudioUnitGetPropertyInfo; ma_proc AudioUnitGetProperty; ma_proc AudioUnitSetProperty; ma_proc AudioUnitInitialize; ma_proc AudioUnitRender; /*AudioComponent*/ ma_ptr component; } coreaudio; #endif #ifdef MA_SUPPORT_SNDIO struct { ma_handle sndioSO; ma_proc sio_open; ma_proc sio_close; ma_proc sio_setpar; ma_proc sio_getpar; ma_proc sio_getcap; ma_proc sio_start; ma_proc sio_stop; ma_proc sio_read; ma_proc sio_write; ma_proc sio_onmove; ma_proc sio_nfds; ma_proc sio_pollfd; ma_proc sio_revents; ma_proc sio_eof; ma_proc sio_setvol; ma_proc sio_onvol; ma_proc sio_initpar; } sndio; #endif #ifdef MA_SUPPORT_AUDIO4 struct { int _unused; } audio4; #endif #ifdef MA_SUPPORT_OSS struct { int versionMajor; int versionMinor; } oss; #endif #ifdef MA_SUPPORT_AAUDIO struct { ma_handle hAAudio; /* libaaudio.so */ ma_proc AAudio_createStreamBuilder; ma_proc AAudioStreamBuilder_delete; ma_proc AAudioStreamBuilder_setDeviceId; ma_proc AAudioStreamBuilder_setDirection; ma_proc AAudioStreamBuilder_setSharingMode; ma_proc AAudioStreamBuilder_setFormat; ma_proc AAudioStreamBuilder_setChannelCount; ma_proc AAudioStreamBuilder_setSampleRate; ma_proc AAudioStreamBuilder_setBufferCapacityInFrames; ma_proc AAudioStreamBuilder_setFramesPerDataCallback; ma_proc AAudioStreamBuilder_setDataCallback; ma_proc AAudioStreamBuilder_setPerformanceMode; ma_proc AAudioStreamBuilder_openStream; ma_proc AAudioStream_close; ma_proc AAudioStream_getState; ma_proc AAudioStream_waitForStateChange; ma_proc AAudioStream_getFormat; ma_proc AAudioStream_getChannelCount; ma_proc AAudioStream_getSampleRate; ma_proc AAudioStream_getBufferCapacityInFrames; ma_proc AAudioStream_getFramesPerDataCallback; ma_proc AAudioStream_getFramesPerBurst; ma_proc AAudioStream_requestStart; ma_proc AAudioStream_requestStop; } aaudio; #endif #ifdef MA_SUPPORT_OPENSL struct { int _unused; } opensl; #endif #ifdef MA_SUPPORT_WEBAUDIO struct { int _unused; } webaudio; #endif #ifdef MA_SUPPORT_NULL struct { int _unused; } null_backend; #endif }; union { #ifdef MA_WIN32 struct { /*HMODULE*/ ma_handle hOle32DLL; ma_proc CoInitializeEx; ma_proc CoUninitialize; ma_proc CoCreateInstance; ma_proc CoTaskMemFree; ma_proc PropVariantClear; ma_proc StringFromGUID2; /*HMODULE*/ ma_handle hUser32DLL; ma_proc GetForegroundWindow; ma_proc GetDesktopWindow; /*HMODULE*/ ma_handle hAdvapi32DLL; ma_proc RegOpenKeyExA; ma_proc RegCloseKey; ma_proc RegQueryValueExA; } win32; #endif #ifdef MA_POSIX struct { ma_handle pthreadSO; ma_proc pthread_create; ma_proc pthread_join; ma_proc pthread_mutex_init; ma_proc pthread_mutex_destroy; ma_proc pthread_mutex_lock; ma_proc pthread_mutex_unlock; ma_proc pthread_cond_init; ma_proc pthread_cond_destroy; ma_proc pthread_cond_wait; ma_proc pthread_cond_signal; ma_proc pthread_attr_init; ma_proc pthread_attr_destroy; ma_proc pthread_attr_setschedpolicy; ma_proc pthread_attr_getschedparam; ma_proc pthread_attr_setschedparam; } posix; #endif int _unused; }; }; MA_ALIGNED_STRUCT(MA_SIMD_ALIGNMENT) ma_device { ma_context* pContext; ma_device_type type; ma_uint32 sampleRate; ma_uint32 state; ma_device_callback_proc onData; ma_stop_proc onStop; void* pUserData; /* Application defined data. */ ma_mutex lock; ma_event wakeupEvent; ma_event startEvent; ma_event stopEvent; ma_thread thread; ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */ ma_bool32 usingDefaultSampleRate : 1; ma_bool32 usingDefaultBufferSize : 1; ma_bool32 usingDefaultPeriods : 1; ma_bool32 isOwnerOfContext : 1; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ struct { char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_bool32 usingDefaultFormat : 1; ma_bool32 usingDefaultChannels : 1; ma_bool32 usingDefaultChannelMap : 1; ma_format format; ma_uint32 channels; ma_channel channelMap[MA_MAX_CHANNELS]; ma_format internalFormat; ma_uint32 internalChannels; ma_uint32 internalSampleRate; ma_channel internalChannelMap[MA_MAX_CHANNELS]; ma_uint32 internalBufferSizeInFrames; ma_uint32 internalPeriods; ma_pcm_converter converter; ma_uint32 _dspFrameCount; /* Internal use only. Used as the data source when reading from the device. */ const ma_uint8* _dspFrames; /* ^^^ AS ABOVE ^^^ */ } playback; struct { char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_bool32 usingDefaultFormat : 1; ma_bool32 usingDefaultChannels : 1; ma_bool32 usingDefaultChannelMap : 1; ma_format format; ma_uint32 channels; ma_channel channelMap[MA_MAX_CHANNELS]; ma_format internalFormat; ma_uint32 internalChannels; ma_uint32 internalSampleRate; ma_channel internalChannelMap[MA_MAX_CHANNELS]; ma_uint32 internalBufferSizeInFrames; ma_uint32 internalPeriods; ma_pcm_converter converter; ma_uint32 _dspFrameCount; /* Internal use only. Used as the data source when reading from the device. */ const ma_uint8* _dspFrames; /* ^^^ AS ABOVE ^^^ */ } capture; union { #ifdef MA_SUPPORT_WASAPI struct { /*IAudioClient**/ ma_ptr pAudioClientPlayback; /*IAudioClient**/ ma_ptr pAudioClientCapture; /*IAudioRenderClient**/ ma_ptr pRenderClient; /*IAudioCaptureClient**/ ma_ptr pCaptureClient; /*IMMDeviceEnumerator**/ ma_ptr pDeviceEnumerator; /* Used for IMMNotificationClient notifications. Required for detecting default device changes. */ ma_IMMNotificationClient notificationClient; /*HANDLE*/ ma_handle hEventPlayback; /* Auto reset. Initialized to signaled. */ /*HANDLE*/ ma_handle hEventCapture; /* Auto reset. Initialized to unsignaled. */ ma_uint32 actualBufferSizeInFramesPlayback; /* Value from GetBufferSize(). internalBufferSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */ ma_uint32 actualBufferSizeInFramesCapture; ma_uint32 originalBufferSizeInFrames; ma_uint32 originalBufferSizeInMilliseconds; ma_uint32 originalPeriods; ma_bool32 hasDefaultPlaybackDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */ ma_bool32 hasDefaultCaptureDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */ ma_uint32 periodSizeInFramesPlayback; ma_uint32 periodSizeInFramesCapture; ma_bool32 isStartedCapture; ma_bool32 isStartedPlayback; } wasapi; #endif #ifdef MA_SUPPORT_DSOUND struct { /*LPDIRECTSOUND*/ ma_ptr pPlayback; /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackPrimaryBuffer; /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackBuffer; /*LPDIRECTSOUNDCAPTURE*/ ma_ptr pCapture; /*LPDIRECTSOUNDCAPTUREBUFFER*/ ma_ptr pCaptureBuffer; } dsound; #endif #ifdef MA_SUPPORT_WINMM struct { /*HWAVEOUT*/ ma_handle hDevicePlayback; /*HWAVEIN*/ ma_handle hDeviceCapture; /*HANDLE*/ ma_handle hEventPlayback; /*HANDLE*/ ma_handle hEventCapture; ma_uint32 fragmentSizeInFrames; ma_uint32 fragmentSizeInBytes; ma_uint32 iNextHeaderPlayback; /* [0,periods). Used as an index into pWAVEHDRPlayback. */ ma_uint32 iNextHeaderCapture; /* [0,periods). Used as an index into pWAVEHDRCapture. */ ma_uint32 headerFramesConsumedPlayback; /* The number of PCM frames consumed in the buffer in pWAVEHEADER[iNextHeader]. */ ma_uint32 headerFramesConsumedCapture; /* ^^^ */ /*WAVEHDR**/ ma_uint8* pWAVEHDRPlayback; /* One instantiation for each period. */ /*WAVEHDR**/ ma_uint8* pWAVEHDRCapture; /* One instantiation for each period. */ ma_uint8* pIntermediaryBufferPlayback; ma_uint8* pIntermediaryBufferCapture; ma_uint8* _pHeapData; /* Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. */ ma_bool32 isStarted; } winmm; #endif #ifdef MA_SUPPORT_ALSA struct { /*snd_pcm_t**/ ma_ptr pPCMPlayback; /*snd_pcm_t**/ ma_ptr pPCMCapture; ma_bool32 isUsingMMapPlayback : 1; ma_bool32 isUsingMMapCapture : 1; } alsa; #endif #ifdef MA_SUPPORT_PULSEAUDIO struct { /*pa_mainloop**/ ma_ptr pMainLoop; /*pa_mainloop_api**/ ma_ptr pAPI; /*pa_context**/ ma_ptr pPulseContext; /*pa_stream**/ ma_ptr pStreamPlayback; /*pa_stream**/ ma_ptr pStreamCapture; /*pa_context_state*/ ma_uint32 pulseContextState; void* pMappedBufferPlayback; const void* pMappedBufferCapture; ma_uint32 mappedBufferFramesRemainingPlayback; ma_uint32 mappedBufferFramesRemainingCapture; ma_uint32 mappedBufferFramesCapacityPlayback; ma_uint32 mappedBufferFramesCapacityCapture; ma_bool32 breakFromMainLoop : 1; } pulse; #endif #ifdef MA_SUPPORT_JACK struct { /*jack_client_t**/ ma_ptr pClient; /*jack_port_t**/ ma_ptr pPortsPlayback[MA_MAX_CHANNELS]; /*jack_port_t**/ ma_ptr pPortsCapture[MA_MAX_CHANNELS]; float* pIntermediaryBufferPlayback; /* Typed as a float because JACK is always floating point. */ float* pIntermediaryBufferCapture; ma_pcm_rb duplexRB; } jack; #endif #ifdef MA_SUPPORT_COREAUDIO struct { ma_uint32 deviceObjectIDPlayback; ma_uint32 deviceObjectIDCapture; /*AudioUnit*/ ma_ptr audioUnitPlayback; /*AudioUnit*/ ma_ptr audioUnitCapture; /*AudioBufferList**/ ma_ptr pAudioBufferList; /* Only used for input devices. */ ma_event stopEvent; ma_uint32 originalBufferSizeInFrames; ma_uint32 originalBufferSizeInMilliseconds; ma_uint32 originalPeriods; ma_bool32 isDefaultPlaybackDevice; ma_bool32 isDefaultCaptureDevice; ma_bool32 isSwitchingPlaybackDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */ ma_bool32 isSwitchingCaptureDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */ ma_pcm_rb duplexRB; } coreaudio; #endif #ifdef MA_SUPPORT_SNDIO struct { ma_ptr handlePlayback; ma_ptr handleCapture; ma_bool32 isStartedPlayback; ma_bool32 isStartedCapture; } sndio; #endif #ifdef MA_SUPPORT_AUDIO4 struct { int fdPlayback; int fdCapture; } audio4; #endif #ifdef MA_SUPPORT_OSS struct { int fdPlayback; int fdCapture; } oss; #endif #ifdef MA_SUPPORT_AAUDIO struct { /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; ma_pcm_rb duplexRB; } aaudio; #endif #ifdef MA_SUPPORT_OPENSL struct { /*SLObjectItf*/ ma_ptr pOutputMixObj; /*SLOutputMixItf*/ ma_ptr pOutputMix; /*SLObjectItf*/ ma_ptr pAudioPlayerObj; /*SLPlayItf*/ ma_ptr pAudioPlayer; /*SLObjectItf*/ ma_ptr pAudioRecorderObj; /*SLRecordItf*/ ma_ptr pAudioRecorder; /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback; /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture; ma_uint32 currentBufferIndexPlayback; ma_uint32 currentBufferIndexCapture; ma_uint8* pBufferPlayback; /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */ ma_uint8* pBufferCapture; ma_pcm_rb duplexRB; } opensl; #endif #ifdef MA_SUPPORT_WEBAUDIO struct { int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */ int indexCapture; ma_pcm_rb duplexRB; /* In external capture format. */ } webaudio; #endif #ifdef MA_SUPPORT_NULL struct { ma_thread deviceThread; ma_event operationEvent; ma_event operationCompletionEvent; ma_uint32 operation; ma_result operationResult; ma_timer timer; double priorRunTime; ma_uint32 currentPeriodFramesRemainingPlayback; ma_uint32 currentPeriodFramesRemainingCapture; ma_uint64 lastProcessedFramePlayback; ma_uint32 lastProcessedFrameCapture; ma_bool32 isStarted; } null_device; #endif }; }; #if defined(_MSC_VER) #pragma warning(pop) #else #pragma GCC diagnostic pop /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */ #endif /* Initializes a context. The context is used for selecting and initializing the relevant backends. Note that the location of the context cannot change throughout it's lifetime. Consider allocating the ma_context object with malloc() if this is an issue. The reason for this is that a pointer to the context is stored in the ma_device structure. is used to allow the application to prioritize backends depending on it's specific requirements. This can be null in which case it uses the default priority, which is as follows: - WASAPI - DirectSound - WinMM - Core Audio (Apple) - sndio - audio(4) - OSS - PulseAudio - ALSA - JACK - AAudio - OpenSL|ES - Web Audio / Emscripten - Null is used to configure the context. Use the logCallback config to set a callback for whenever a log message is posted. The priority of the worker thread can be set with the threadPriority config. It is recommended that only a single context is active at any given time because it's a bulky data structure which performs run-time linking for the relevant backends every time it's initialized. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: UNSAFE */ ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext); /* Uninitializes a context. Results are undefined if you call this while any device created by this context is still active. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: UNSAFE */ ma_result ma_context_uninit(ma_context* pContext); /* Enumerates over every device (both playback and capture). This is a lower-level enumeration function to the easier to use ma_context_get_devices(). Use ma_context_enumerate_devices() if you would rather not incur an internal heap allocation, or it simply suits your code better. Do _not_ assume the first enumerated device of a given type is the default device. Some backends and platforms may only support default playback and capture devices. Note that this only retrieves the ID and name/description of the device. The reason for only retrieving basic information is that it would otherwise require opening the backend device in order to probe it for more detailed information which can be inefficient. Consider using ma_context_get_device_info() for this, but don't call it from within the enumeration callback. In general, you should not do anything complicated from within the callback. In particular, do not try initializing a device from within the callback. Consider using ma_context_get_devices() for a simpler and safer API, albeit at the expense of an internal heap allocation. Returning false from the callback will stop enumeration. Returning true will continue enumeration. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: SAFE This is guarded using a simple mutex lock. */ ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData); /* Retrieves basic information about every active playback and/or capture device. You can pass in NULL for the playback or capture lists in which case they'll be ignored. It is _not_ safe to assume the first device in the list is the default device. The returned pointers will become invalid upon the next call this this function, or when the context is uninitialized. Do not free the returned pointers. This function follows the same enumeration rules as ma_context_enumerate_devices(). See documentation for ma_context_enumerate_devices() for more information. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: SAFE Since each call to this function invalidates the pointers from the previous call, you should not be calling this simultaneously across multiple threads. Instead, you need to make a copy of the returned data with your own higher level synchronization. */ ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount); /* Retrieves information about a device with the given ID. Do _not_ call this from within the ma_context_enumerate_devices() callback. It's possible for a device to have different information and capabilities depending on whether or not it's opened in shared or exclusive mode. For example, in shared mode, WASAPI always uses floating point samples for mixing, but in exclusive mode it can be anything. Therefore, this function allows you to specify which share mode you want information for. Note that not all backends and devices support shared or exclusive mode, in which case this function will fail if the requested share mode is unsupported. This leaves pDeviceInfo unmodified in the result of an error. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: SAFE This is guarded using a simple mutex lock. */ ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo); /* Initializes a device. The context can be null in which case it uses the default. This is equivalent to passing in a context that was initialized like so: ma_context_init(NULL, 0, NULL, &context); Do not pass in null for the context if you are needing to open multiple devices. You can, however, use null when initializing the first device, and then use device.pContext for the initialization of other devices. The device's configuration is controlled with pConfig. This allows you to configure the sample format, channel count, sample rate, etc. Before calling ma_device_init(), you will need to initialize a ma_device_config object using ma_device_config_init(). You must set the callback in the device config. Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device. Passing in 0 to any property in pConfig will force the use of a default value. In the case of sample format, channel count, sample rate and channel map it will default to the values used by the backend's internal device. For the size of the buffer you can set bufferSizeInFrames or bufferSizeInMilliseconds (if both are set it will prioritize bufferSizeInFrames). If both are set to zero, it will default to MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY or MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE, depending on whether or not performanceProfile is set to ma_performance_profile_low_latency or ma_performance_profile_conservative. If you request exclusive mode and the backend does not support it an error will be returned. For robustness, you may want to first try initializing the device in exclusive mode, and then fall back to shared mode if required. Alternatively you can just request shared mode (the default if you leave it unset in the config) which is the most reliable option. Some backends do not have a practical way of choosing whether or not the device should be exclusive or not (ALSA, for example) in which case it just acts as a hint. Unless you have special requirements you should try avoiding exclusive mode as it's intrusive to the user. Starting with Windows 10, miniaudio will use low-latency shared mode where possible which may make exclusive mode unnecessary. When sending or receiving data to/from a device, miniaudio will internally perform a format conversion to convert between the format specified by pConfig and the format used internally by the backend. If you pass in NULL for pConfig or 0 for the sample format, channel count, sample rate _and_ channel map, data transmission will run on an optimized pass-through fast path. The buffer size should be treated as a hint. miniaudio will try it's best to use exactly what you ask for, but it may differ. You should not assume the number of frames specified in each call to the data callback is exactly what you originally specified. The property controls how frequently the background thread is woken to check for more data. It's tied to the buffer size, so as an example, if your buffer size is equivalent to 10 milliseconds and you have 2 periods, the CPU will wake up approximately every 5 milliseconds. When compiling for UWP you must ensure you call this function on the main UI thread because the operating system may need to present the user with a message asking for permissions. Please refer to the official documentation for ActivateAudioInterfaceAsync() for more information. ALSA Specific: When initializing the default device, requesting shared mode will try using the "dmix" device for playback and the "dsnoop" device for capture. If these fail it will try falling back to the "hw" device. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: UNSAFE It is not safe to call this function simultaneously for different devices because some backends depend on and mutate global state (such as OpenSL|ES). The same applies to calling this at the same time as ma_device_uninit(). */ ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice); /* Initializes a device without a context, with extra parameters for controlling the configuration of the internal self-managed context. See ma_device_init() and ma_context_init(). */ ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pContextConfig, const ma_device_config* pConfig, ma_device* pDevice); /* Uninitializes a device. This will explicitly stop the device. You do not need to call ma_device_stop() beforehand, but it's harmless if you do. Do not call this in any callback. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: UNSAFE As soon as this API is called the device should be considered undefined. All bets are off if you try using the device at the same time as uninitializing it. */ void ma_device_uninit(ma_device* pDevice); /* Sets the callback to use when the device has stopped, either explicitly or as a result of an error. Thread Safety: SAFE This API is implemented as a simple atomic assignment. */ void ma_device_set_stop_callback(ma_device* pDevice, ma_stop_proc proc); /* Activates the device. For playback devices this begins playback. For capture devices it begins recording. For a playback device, this will retrieve an initial chunk of audio data from the client before returning. The reason for this is to ensure there is valid audio data in the buffer, which needs to be done _before_ the device begins playback. This API waits until the backend device has been started for real by the worker thread. It also waits on a mutex for thread-safety. Do not call this in any callback. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: SAFE */ ma_result ma_device_start(ma_device* pDevice); /* Puts the device to sleep, but does not uninitialize it. Use ma_device_start() to start it up again. This API needs to wait on the worker thread to stop the backend device properly before returning. It also waits on a mutex for thread-safety. In addition, some backends need to wait for the device to finish playback/recording of the current fragment which can take some time (usually proportionate to the buffer size that was specified at initialization time). This should not drop unprocessed samples. Backends are required to either pause the stream in-place or drain the buffer if pausing is not possible. The reason for this is that stopping the device and the resuming it with ma_device_start() (which you might do when your program loses focus) may result in a situation where those samples are never output to the speakers or received from the microphone which can in turn result in de-syncs. Do not call this in any callback. Return Value: MA_SUCCESS if successful; any other error code otherwise. Thread Safety: SAFE */ ma_result ma_device_stop(ma_device* pDevice); /* Determines whether or not the device is started. This is implemented as a simple accessor. Return Value: True if the device is started, false otherwise. Thread Safety: SAFE If another thread calls ma_device_start() or ma_device_stop() at this same time as this function is called, there's a very small chance the return value will be out of sync. */ ma_bool32 ma_device_is_started(ma_device* pDevice); /* Helper function for initializing a ma_context_config object. */ ma_context_config ma_context_config_init(void); /* Initializes a device config. By default, the device config will use native device settings (format, channels, sample rate, etc.). Using native settings means you will get an optimized pass-through data transmission pipeline to and from the device, but you will need to do all format conversions manually. Normally you would want to use a known format that your program can handle natively, which you can do by specifying it after this function returns, like so: ma_device_config config = ma_device_config_init(ma_device_type_playback); config.callback = my_data_callback; config.pUserData = pMyUserData; config.format = ma_format_f32; config.channels = 2; config.sampleRate = 44100; In this case miniaudio will perform all of the necessary data conversion for you behind the scenes. Currently miniaudio only supports asynchronous, callback based data delivery which means you must specify callback. A pointer to user data can also be specified which is set in the pUserData member of the ma_device object. To specify a channel map you can use ma_get_standard_channel_map(): ma_get_standard_channel_map(ma_standard_channel_map_default, config.channels, config.channelMap); Alternatively you can set the channel map manually if you need something specific or something that isn't one of miniaudio's stock channel maps. By default the system's default device will be used. Set the pDeviceID member to a pointer to a ma_device_id object to use a specific device. You can enumerate over the devices with ma_context_enumerate_devices() or ma_context_get_devices() which will give you access to the device ID. Set pDeviceID to NULL to use the default device. The device type can be one of the ma_device_type's: ma_device_type_playback ma_device_type_capture ma_device_type_duplex Thread Safety: SAFE */ ma_device_config ma_device_config_init(ma_device_type deviceType); /************************************************************************************************************************************************************ Utiltities ************************************************************************************************************************************************************/ /* Creates a mutex. A mutex must be created from a valid context. A mutex is initially unlocked. */ ma_result ma_mutex_init(ma_context* pContext, ma_mutex* pMutex); /* Deletes a mutex. */ void ma_mutex_uninit(ma_mutex* pMutex); /* Locks a mutex with an infinite timeout. */ void ma_mutex_lock(ma_mutex* pMutex); /* Unlocks a mutex. */ void ma_mutex_unlock(ma_mutex* pMutex); /* Retrieves a friendly name for a backend. */ const char* ma_get_backend_name(ma_backend backend); /* Adjust buffer size based on a scaling factor. This just multiplies the base size by the scaling factor, making sure it's a size of at least 1. */ ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale); /* Calculates a buffer size in milliseconds from the specified number of frames and sample rate. */ ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate); /* Calculates a buffer size in frames from the specified number of milliseconds and sample rate. */ ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate); /* Retrieves the default buffer size in milliseconds based on the specified performance profile. */ ma_uint32 ma_get_default_buffer_size_in_milliseconds(ma_performance_profile performanceProfile); /* Calculates a buffer size in frames for the specified performance profile and scale factor. */ ma_uint32 ma_get_default_buffer_size_in_frames(ma_performance_profile performanceProfile, ma_uint32 sampleRate); /* Copies silent frames into the given buffer. */ void ma_zero_pcm_frames(void* p, ma_uint32 frameCount, ma_format format, ma_uint32 channels); #endif /* MA_NO_DEVICE_IO */ /************************************************************************************************************************************************************ Decoding ************************************************************************************************************************************************************/ #ifndef MA_NO_DECODING typedef struct ma_decoder ma_decoder; typedef enum { ma_seek_origin_start, ma_seek_origin_current } ma_seek_origin; typedef size_t (* ma_decoder_read_proc) (ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead); /* Returns the number of bytes read. */ typedef ma_bool32 (* ma_decoder_seek_proc) (ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin); typedef ma_result (* ma_decoder_seek_to_pcm_frame_proc) (ma_decoder* pDecoder, ma_uint64 frameIndex); typedef ma_result (* ma_decoder_uninit_proc) (ma_decoder* pDecoder); typedef ma_uint64 (* ma_decoder_get_length_in_pcm_frames_proc)(ma_decoder* pDecoder); typedef struct { ma_format format; /* Set to 0 or ma_format_unknown to use the stream's internal format. */ ma_uint32 channels; /* Set to 0 to use the stream's internal channels. */ ma_uint32 sampleRate; /* Set to 0 to use the stream's internal sample rate. */ ma_channel channelMap[MA_MAX_CHANNELS]; ma_channel_mix_mode channelMixMode; ma_dither_mode ditherMode; ma_src_algorithm srcAlgorithm; union { ma_src_config_sinc sinc; } src; } ma_decoder_config; struct ma_decoder { ma_decoder_read_proc onRead; ma_decoder_seek_proc onSeek; void* pUserData; ma_uint64 readPointer; /* Used for returning back to a previous position after analysing the stream or whatnot. */ ma_format internalFormat; ma_uint32 internalChannels; ma_uint32 internalSampleRate; ma_channel internalChannelMap[MA_MAX_CHANNELS]; ma_format outputFormat; ma_uint32 outputChannels; ma_uint32 outputSampleRate; ma_channel outputChannelMap[MA_MAX_CHANNELS]; ma_pcm_converter dsp; /* <-- Format conversion is achieved by running frames through this. */ ma_decoder_seek_to_pcm_frame_proc onSeekToPCMFrame; ma_decoder_uninit_proc onUninit; ma_decoder_get_length_in_pcm_frames_proc onGetLengthInPCMFrames; void* pInternalDecoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */ struct { const ma_uint8* pData; size_t dataSize; size_t currentReadPos; } memory; /* Only used for decoders that were opened against a block of memory. */ }; ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate); ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder); ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder); #ifndef MA_NO_STDIO ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); #endif ma_result ma_decoder_uninit(ma_decoder* pDecoder); /* Retrieves the length of the decoder in PCM frames. Do not call this on streams of an undefined length, such as internet radio. If the length is unknown or an error occurs, 0 will be returned. This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio uses internally. This will run in linear time for MP3 decoders. Do not call this in time critical scenarios. */ ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder); ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount); ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex); /* Helper for opening and decoding a file into a heap allocated block of memory. Free the returned pointer with ma_free(). On input, pConfig should be set to what you want. On output it will be set to what you got. */ #ifndef MA_NO_STDIO ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppDataOut); #endif ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppDataOut); #endif /* MA_NO_DECODING */ /************************************************************************************************************************************************************ Generation ************************************************************************************************************************************************************/ typedef struct { double amplitude; double periodsPerSecond; double delta; double time; } ma_sine_wave; ma_result ma_sine_wave_init(double amplitude, double period, ma_uint32 sampleRate, ma_sine_wave* pSineWave); ma_uint64 ma_sine_wave_read_f32(ma_sine_wave* pSineWave, ma_uint64 count, float* pSamples); ma_uint64 ma_sine_wave_read_f32_ex(ma_sine_wave* pSineWave, ma_uint64 frameCount, ma_uint32 channels, ma_stream_layout layout, float** ppFrames); #ifdef __cplusplus } #endif #endif /* miniaudio_h */ /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* IMPLEMENTATION ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ #if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION) #include #include /* For INT_MAX */ #include /* sin(), etc. */ #if defined(MA_DEBUG_OUTPUT) #include /* for printf() for debug output */ #endif #ifdef MA_WIN32 #include #include #include #include #else #include /* For malloc()/free() */ #include /* For memset() */ #endif #if defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200) #include /* For mach_absolute_time() */ #endif #ifdef MA_POSIX #include #include #include #include #endif #ifdef MA_EMSCRIPTEN #include #endif #if !defined(MA_64BIT) && !defined(MA_32BIT) #ifdef _WIN32 #ifdef _WIN64 #define MA_64BIT #else #define MA_32BIT #endif #endif #endif #if !defined(MA_64BIT) && !defined(MA_32BIT) #ifdef __GNUC__ #ifdef __LP64__ #define MA_64BIT #else #define MA_32BIT #endif #endif #endif #if !defined(MA_64BIT) && !defined(MA_32BIT) #include #if INTPTR_MAX == INT64_MAX #define MA_64BIT #else #define MA_32BIT #endif #endif /* Architecture Detection */ #if defined(__x86_64__) || defined(_M_X64) #define MA_X64 #elif defined(__i386) || defined(_M_IX86) #define MA_X86 #elif defined(__arm__) || defined(_M_ARM) #define MA_ARM #endif /* Cannot currently support AVX-512 if AVX is disabled. */ #if !defined(MA_NO_AVX512) && defined(MA_NO_AVX2) #define MA_NO_AVX512 #endif /* Intrinsics Support */ #if defined(MA_X64) || defined(MA_X86) #if defined(_MSC_VER) && !defined(__clang__) /* MSVC. */ #if _MSC_VER >= 1400 && !defined(MA_NO_SSE2) /* 2005 */ #define MA_SUPPORT_SSE2 #endif /*#if _MSC_VER >= 1600 && !defined(MA_NO_AVX)*/ /* 2010 */ /* #define MA_SUPPORT_AVX*/ /*#endif*/ #if _MSC_VER >= 1700 && !defined(MA_NO_AVX2) /* 2012 */ #define MA_SUPPORT_AVX2 #endif #if _MSC_VER >= 1910 && !defined(MA_NO_AVX512) /* 2017 */ #define MA_SUPPORT_AVX512 #endif #else /* Assume GNUC-style. */ #if defined(__SSE2__) && !defined(MA_NO_SSE2) #define MA_SUPPORT_SSE2 #endif /*#if defined(__AVX__) && !defined(MA_NO_AVX)*/ /* #define MA_SUPPORT_AVX*/ /*#endif*/ #if defined(__AVX2__) && !defined(MA_NO_AVX2) #define MA_SUPPORT_AVX2 #endif #if defined(__AVX512F__) && !defined(MA_NO_AVX512) #define MA_SUPPORT_AVX512 #endif #endif /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */ #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) #if !defined(MA_SUPPORT_SSE2) && !defined(MA_NO_SSE2) && __has_include() #define MA_SUPPORT_SSE2 #endif /*#if !defined(MA_SUPPORT_AVX) && !defined(MA_NO_AVX) && __has_include()*/ /* #define MA_SUPPORT_AVX*/ /*#endif*/ #if !defined(MA_SUPPORT_AVX2) && !defined(MA_NO_AVX2) && __has_include() #define MA_SUPPORT_AVX2 #endif #if !defined(MA_SUPPORT_AVX512) && !defined(MA_NO_AVX512) && __has_include() #define MA_SUPPORT_AVX512 #endif #endif #if defined(MA_SUPPORT_AVX512) #include /* Not a mistake. Intentionally including instead of because otherwise the compiler will complain. */ #elif defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX) #include #elif defined(MA_SUPPORT_SSE2) #include #endif #endif #if defined(MA_ARM) #if !defined(MA_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) #define MA_SUPPORT_NEON #endif /* Fall back to looking for the #include file. */ #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) #if !defined(MA_SUPPORT_NEON) && !defined(MA_NO_NEON) && __has_include() #define MA_SUPPORT_NEON #endif #endif #if defined(MA_SUPPORT_NEON) #include #endif #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4752) /* found Intel(R) Advanced Vector Extensions; consider using /arch:AVX */ #endif #if defined(MA_X64) || defined(MA_X86) #if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER >= 1400 #include static MA_INLINE void ma_cpuid(int info[4], int fid) { __cpuid(info, fid); } #else #define MA_NO_CPUID #endif #if _MSC_VER >= 1600 static MA_INLINE unsigned __int64 ma_xgetbv(int reg) { return _xgetbv(reg); } #else #define MA_NO_XGETBV #endif #elif (defined(__GNUC__) || defined(__clang__)) && !defined(MA_ANDROID) static MA_INLINE void ma_cpuid(int info[4], int fid) { /* It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for supporting different assembly dialects. What's basically happening is that we're saving and restoring the ebx register manually. */ #if defined(DRFLAC_X86) && defined(__PIC__) __asm__ __volatile__ ( "xchg{l} {%%}ebx, %k1;" "cpuid;" "xchg{l} {%%}ebx, %k1;" : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) ); #else __asm__ __volatile__ ( "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) ); #endif } static MA_INLINE ma_uint64 ma_xgetbv(int reg) { unsigned int hi; unsigned int lo; __asm__ __volatile__ ( "xgetbv" : "=a"(lo), "=d"(hi) : "c"(reg) ); return ((ma_uint64)hi << 32) | (ma_uint64)lo; } #else #define MA_NO_CPUID #define MA_NO_XGETBV #endif #else #define MA_NO_CPUID #define MA_NO_XGETBV #endif static MA_INLINE ma_bool32 ma_has_sse2() { #if defined(MA_SUPPORT_SSE2) #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_SSE2) #if defined(MA_X64) return MA_TRUE; /* 64-bit targets always support SSE2. */ #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__) return MA_TRUE; /* If the compiler is allowed to freely generate SSE2 code we can assume support. */ #else #if defined(MA_NO_CPUID) return MA_FALSE; #else int info[4]; ma_cpuid(info, 1); return (info[3] & (1 << 26)) != 0; #endif #endif #else return MA_FALSE; /* SSE2 is only supported on x86 and x64 architectures. */ #endif #else return MA_FALSE; /* No compiler support. */ #endif } #if 0 static MA_INLINE ma_bool32 ma_has_avx() { #if defined(MA_SUPPORT_AVX) #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX) #if defined(_AVX_) || defined(__AVX__) return MA_TRUE; /* If the compiler is allowed to freely generate AVX code we can assume support. */ #else /* AVX requires both CPU and OS support. */ #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV) return MA_FALSE; #else int info[4]; ma_cpuid(info, 1); if (((info[2] & (1 << 27)) != 0) && ((info[2] & (1 << 28)) != 0)) { ma_uint64 xrc = ma_xgetbv(0); if ((xrc & 0x06) == 0x06) { return MA_TRUE; } else { return MA_FALSE; } } else { return MA_FALSE; } #endif #endif #else return MA_FALSE; /* AVX is only supported on x86 and x64 architectures. */ #endif #else return MA_FALSE; /* No compiler support. */ #endif } #endif static MA_INLINE ma_bool32 ma_has_avx2() { #if defined(MA_SUPPORT_AVX2) #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX2) #if defined(_AVX2_) || defined(__AVX2__) return MA_TRUE; /* If the compiler is allowed to freely generate AVX2 code we can assume support. */ #else /* AVX2 requires both CPU and OS support. */ #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV) return MA_FALSE; #else int info1[4]; int info7[4]; ma_cpuid(info1, 1); ma_cpuid(info7, 7); if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 5)) != 0)) { ma_uint64 xrc = ma_xgetbv(0); if ((xrc & 0x06) == 0x06) { return MA_TRUE; } else { return MA_FALSE; } } else { return MA_FALSE; } #endif #endif #else return MA_FALSE; /* AVX2 is only supported on x86 and x64 architectures. */ #endif #else return MA_FALSE; /* No compiler support. */ #endif } static MA_INLINE ma_bool32 ma_has_avx512f() { #if defined(MA_SUPPORT_AVX512) #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX512) #if defined(__AVX512F__) return MA_TRUE; /* If the compiler is allowed to freely generate AVX-512F code we can assume support. */ #else /* AVX-512 requires both CPU and OS support. */ #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV) return MA_FALSE; #else int info1[4]; int info7[4]; ma_cpuid(info1, 1); ma_cpuid(info7, 7); if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 16)) != 0)) { ma_uint64 xrc = ma_xgetbv(0); if ((xrc & 0xE6) == 0xE6) { return MA_TRUE; } else { return MA_FALSE; } } else { return MA_FALSE; } #endif #endif #else return MA_FALSE; /* AVX-512F is only supported on x86 and x64 architectures. */ #endif #else return MA_FALSE; /* No compiler support. */ #endif } static MA_INLINE ma_bool32 ma_has_neon() { #if defined(MA_SUPPORT_NEON) #if defined(MA_ARM) && !defined(MA_NO_NEON) #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) return MA_TRUE; /* If the compiler is allowed to freely generate NEON code we can assume support. */ #else /* TODO: Runtime check. */ return MA_FALSE; #endif #else return MA_FALSE; /* NEON is only supported on ARM architectures. */ #endif #else return MA_FALSE; /* No compiler support. */ #endif } static MA_INLINE ma_bool32 ma_is_little_endian() { #if defined(MA_X86) || defined(MA_X64) return MA_TRUE; #else int n = 1; return (*(char*)&n) == 1; #endif } static MA_INLINE ma_bool32 ma_is_big_endian() { return !ma_is_little_endian(); } #ifndef MA_COINIT_VALUE #define MA_COINIT_VALUE 0 /* 0 = COINIT_MULTITHREADED*/ #endif #ifndef MA_PI #define MA_PI 3.14159265358979323846264f #endif #ifndef MA_PI_D #define MA_PI_D 3.14159265358979323846264 #endif #ifndef MA_TAU #define MA_TAU 6.28318530717958647693f #endif #ifndef MA_TAU_D #define MA_TAU_D 6.28318530717958647693 #endif /* The default format when ma_format_unknown (0) is requested when initializing a device. */ #ifndef MA_DEFAULT_FORMAT #define MA_DEFAULT_FORMAT ma_format_f32 #endif /* The default channel count to use when 0 is used when initializing a device. */ #ifndef MA_DEFAULT_CHANNELS #define MA_DEFAULT_CHANNELS 2 #endif /* The default sample rate to use when 0 is used when initializing a device. */ #ifndef MA_DEFAULT_SAMPLE_RATE #define MA_DEFAULT_SAMPLE_RATE 48000 #endif /* Default periods when none is specified in ma_device_init(). More periods means more work on the CPU. */ #ifndef MA_DEFAULT_PERIODS #define MA_DEFAULT_PERIODS 3 #endif /* The base buffer size in milliseconds for low latency mode. */ #ifndef MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY #define MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY (10*MA_DEFAULT_PERIODS) #endif /* The base buffer size in milliseconds for conservative mode. */ #ifndef MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE #define MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE (100*MA_DEFAULT_PERIODS) #endif /* Standard sample rates, in order of priority. */ ma_uint32 g_maStandardSampleRatePriorities[] = { MA_SAMPLE_RATE_48000, /* Most common */ MA_SAMPLE_RATE_44100, MA_SAMPLE_RATE_32000, /* Lows */ MA_SAMPLE_RATE_24000, MA_SAMPLE_RATE_22050, MA_SAMPLE_RATE_88200, /* Highs */ MA_SAMPLE_RATE_96000, MA_SAMPLE_RATE_176400, MA_SAMPLE_RATE_192000, MA_SAMPLE_RATE_16000, /* Extreme lows */ MA_SAMPLE_RATE_11025, MA_SAMPLE_RATE_8000, MA_SAMPLE_RATE_352800, /* Extreme highs */ MA_SAMPLE_RATE_384000 }; ma_format g_maFormatPriorities[] = { ma_format_s16, /* Most common */ ma_format_f32, /*ma_format_s24_32,*/ /* Clean alignment */ ma_format_s32, ma_format_s24, /* Unclean alignment */ ma_format_u8 /* Low quality */ }; /****************************************************************************** Standard Library Stuff ******************************************************************************/ #ifndef MA_MALLOC #ifdef MA_WIN32 #define MA_MALLOC(sz) HeapAlloc(GetProcessHeap(), 0, (sz)) #else #define MA_MALLOC(sz) malloc((sz)) #endif #endif #ifndef MA_REALLOC #ifdef MA_WIN32 #define MA_REALLOC(p, sz) (((sz) > 0) ? ((p) ? HeapReAlloc(GetProcessHeap(), 0, (p), (sz)) : HeapAlloc(GetProcessHeap(), 0, (sz))) : ((VOID*)(size_t)(HeapFree(GetProcessHeap(), 0, (p)) & 0))) #else #define MA_REALLOC(p, sz) realloc((p), (sz)) #endif #endif #ifndef MA_FREE #ifdef MA_WIN32 #define MA_FREE(p) HeapFree(GetProcessHeap(), 0, (p)) #else #define MA_FREE(p) free((p)) #endif #endif #ifndef MA_ZERO_MEMORY #ifdef MA_WIN32 #define MA_ZERO_MEMORY(p, sz) ZeroMemory((p), (sz)) #else #define MA_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) #endif #endif #ifndef MA_COPY_MEMORY #ifdef MA_WIN32 #define MA_COPY_MEMORY(dst, src, sz) CopyMemory((dst), (src), (sz)) #else #define MA_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) #endif #endif #ifndef MA_ASSERT #ifdef MA_WIN32 #define MA_ASSERT(condition) assert(condition) #else #define MA_ASSERT(condition) assert(condition) #endif #endif #define ma_zero_memory MA_ZERO_MEMORY #define ma_copy_memory MA_COPY_MEMORY #define ma_assert MA_ASSERT #define ma_zero_object(p) ma_zero_memory((p), sizeof(*(p))) #define ma_countof(x) (sizeof(x) / sizeof(x[0])) #define ma_max(x, y) (((x) > (y)) ? (x) : (y)) #define ma_min(x, y) (((x) < (y)) ? (x) : (y)) #define ma_clamp(x, lo, hi) (ma_max(lo, ma_min(x, hi))) #define ma_offset_ptr(p, offset) (((ma_uint8*)(p)) + (offset)) #define ma_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / ma_get_bytes_per_sample(format) / (channels)) /* Return Values: 0: Success 22: EINVAL 34: ERANGE Not using symbolic constants for errors because I want to avoid #including errno.h */ int ma_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) { size_t i; if (dst == 0) { return 22; } if (dstSizeInBytes == 0) { return 34; } if (src == 0) { dst[0] = '\0'; return 22; } for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { dst[i] = src[i]; } if (i < dstSizeInBytes) { dst[i] = '\0'; return 0; } dst[0] = '\0'; return 34; } int ma_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) { size_t maxcount; size_t i; if (dst == 0) { return 22; } if (dstSizeInBytes == 0) { return 34; } if (src == 0) { dst[0] = '\0'; return 22; } maxcount = count; if (count == ((size_t)-1) || count >= dstSizeInBytes) { /* -1 = _TRUNCATE */ maxcount = dstSizeInBytes - 1; } for (i = 0; i < maxcount && src[i] != '\0'; ++i) { dst[i] = src[i]; } if (src[i] == '\0' || i == count || count == ((size_t)-1)) { dst[i] = '\0'; return 0; } dst[0] = '\0'; return 34; } int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) { char* dstorig; if (dst == 0) { return 22; } if (dstSizeInBytes == 0) { return 34; } if (src == 0) { dst[0] = '\0'; return 22; } dstorig = dst; while (dstSizeInBytes > 0 && dst[0] != '\0') { dst += 1; dstSizeInBytes -= 1; } if (dstSizeInBytes == 0) { return 22; /* Unterminated. */ } while (dstSizeInBytes > 0 && src[0] != '\0') { *dst++ = *src++; dstSizeInBytes -= 1; } if (dstSizeInBytes > 0) { dst[0] = '\0'; } else { dstorig[0] = '\0'; return 34; } return 0; } int ma_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) { char* dstorig; if (dst == 0) { return 22; } if (dstSizeInBytes == 0) { return 34; } if (src == 0) { return 22; } dstorig = dst; while (dstSizeInBytes > 0 && dst[0] != '\0') { dst += 1; dstSizeInBytes -= 1; } if (dstSizeInBytes == 0) { return 22; /* Unterminated. */ } if (count == ((size_t)-1)) { /* _TRUNCATE */ count = dstSizeInBytes - 1; } while (dstSizeInBytes > 0 && src[0] != '\0' && count > 0) { *dst++ = *src++; dstSizeInBytes -= 1; count -= 1; } if (dstSizeInBytes > 0) { dst[0] = '\0'; } else { dstorig[0] = '\0'; return 34; } return 0; } int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) { int sign; unsigned int valueU; char* dstEnd; if (dst == NULL || dstSizeInBytes == 0) { return 22; } if (radix < 2 || radix > 36) { dst[0] = '\0'; return 22; } sign = (value < 0 && radix == 10) ? -1 : 1; /* The negative sign is only used when the base is 10. */ if (value < 0) { valueU = -value; } else { valueU = value; } dstEnd = dst; do { int remainder = valueU % radix; if (remainder > 9) { *dstEnd = (char)((remainder - 10) + 'a'); } else { *dstEnd = (char)(remainder + '0'); } dstEnd += 1; dstSizeInBytes -= 1; valueU /= radix; } while (dstSizeInBytes > 0 && valueU > 0); if (dstSizeInBytes == 0) { dst[0] = '\0'; return 22; /* Ran out of room in the output buffer. */ } if (sign < 0) { *dstEnd++ = '-'; dstSizeInBytes -= 1; } if (dstSizeInBytes == 0) { dst[0] = '\0'; return 22; /* Ran out of room in the output buffer. */ } *dstEnd = '\0'; /* At this point the string will be reversed. */ dstEnd -= 1; while (dst < dstEnd) { char temp = *dst; *dst = *dstEnd; *dstEnd = temp; dst += 1; dstEnd -= 1; } return 0; } int ma_strcmp(const char* str1, const char* str2) { if (str1 == str2) return 0; /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */ if (str1 == NULL) return -1; if (str2 == NULL) return 1; for (;;) { if (str1[0] == '\0') { break; } if (str1[0] != str2[0]) { break; } str1 += 1; str2 += 1; } return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; } int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB) { int result; result = ma_strncpy_s(dst, dstSize, srcA, (size_t)-1); if (result != 0) { return result; } result = ma_strncat_s(dst, dstSize, srcB, (size_t)-1); if (result != 0) { return result; } return result; } char* ma_copy_string(const char* src) { size_t sz = strlen(src)+1; char* dst = (char*)ma_malloc(sz); if (dst == NULL) { return NULL; } ma_strcpy_s(dst, sz, src); return dst; } /* Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ static MA_INLINE unsigned int ma_next_power_of_2(unsigned int x) { x--; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x++; return x; } static MA_INLINE unsigned int ma_prev_power_of_2(unsigned int x) { return ma_next_power_of_2(x) >> 1; } static MA_INLINE unsigned int ma_round_to_power_of_2(unsigned int x) { unsigned int prev = ma_prev_power_of_2(x); unsigned int next = ma_next_power_of_2(x); if ((next - x) > (x - prev)) { return prev; } else { return next; } } static MA_INLINE unsigned int ma_count_set_bits(unsigned int x) { unsigned int count = 0; while (x != 0) { if (x & 1) { count += 1; } x = x >> 1; } return count; } /* Clamps an f32 sample to -1..1 */ static MA_INLINE float ma_clip_f32(float x) { if (x < -1) return -1; if (x > +1) return +1; return x; } static MA_INLINE float ma_mix_f32(float x, float y, float a) { return x*(1-a) + y*a; } static MA_INLINE float ma_mix_f32_fast(float x, float y, float a) { float r0 = (y - x); float r1 = r0*a; return x + r1; /*return x + (y - x)*a;*/ } #if defined(MA_SUPPORT_SSE2) static MA_INLINE __m128 ma_mix_f32_fast__sse2(__m128 x, __m128 y, __m128 a) { return _mm_add_ps(x, _mm_mul_ps(_mm_sub_ps(y, x), a)); } #endif #if defined(MA_SUPPORT_AVX2) static MA_INLINE __m256 ma_mix_f32_fast__avx2(__m256 x, __m256 y, __m256 a) { return _mm256_add_ps(x, _mm256_mul_ps(_mm256_sub_ps(y, x), a)); } #endif #if defined(MA_SUPPORT_AVX512) static MA_INLINE __m512 ma_mix_f32_fast__avx512(__m512 x, __m512 y, __m512 a) { return _mm512_add_ps(x, _mm512_mul_ps(_mm512_sub_ps(y, x), a)); } #endif #if defined(MA_SUPPORT_NEON) static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x, float32x4_t y, float32x4_t a) { return vaddq_f32(x, vmulq_f32(vsubq_f32(y, x), a)); } #endif static MA_INLINE double ma_mix_f64(double x, double y, double a) { return x*(1-a) + y*a; } static MA_INLINE double ma_mix_f64_fast(double x, double y, double a) { return x + (y - x)*a; } static MA_INLINE float ma_scale_to_range_f32(float x, float lo, float hi) { return lo + x*(hi-lo); } /* Random Number Generation miniaudio uses the LCG random number generation algorithm. This is good enough for audio. Note that miniaudio's LCG implementation uses global state which is _not_ thread-local. When this is called across multiple threads, results will be unpredictable. However, it won't crash and results will still be random enough for miniaudio's purposes. */ #define MA_LCG_M 2147483647 #define MA_LCG_A 48271 #define MA_LCG_C 0 static ma_int32 g_maLCG; void ma_seed(ma_int32 seed) { g_maLCG = seed; } ma_int32 ma_rand_s32() { ma_int32 lcg = g_maLCG; ma_int32 r = (MA_LCG_A * lcg + MA_LCG_C) % MA_LCG_M; g_maLCG = r; return r; } double ma_rand_f64() { return (ma_rand_s32() + 0x80000000) / (double)0x7FFFFFFF; } float ma_rand_f32() { return (float)ma_rand_f64(); } static MA_INLINE float ma_rand_range_f32(float lo, float hi) { return ma_scale_to_range_f32(ma_rand_f32(), lo, hi); } static MA_INLINE ma_int32 ma_rand_range_s32(ma_int32 lo, ma_int32 hi) { double x = ma_rand_f64(); return lo + (ma_int32)(x*(hi-lo)); } static MA_INLINE float ma_dither_f32_rectangle(float ditherMin, float ditherMax) { return ma_rand_range_f32(ditherMin, ditherMax); } static MA_INLINE float ma_dither_f32_triangle(float ditherMin, float ditherMax) { float a = ma_rand_range_f32(ditherMin, 0); float b = ma_rand_range_f32(0, ditherMax); return a + b; } static MA_INLINE float ma_dither_f32(ma_dither_mode ditherMode, float ditherMin, float ditherMax) { if (ditherMode == ma_dither_mode_rectangle) { return ma_dither_f32_rectangle(ditherMin, ditherMax); } if (ditherMode == ma_dither_mode_triangle) { return ma_dither_f32_triangle(ditherMin, ditherMax); } return 0; } static MA_INLINE ma_int32 ma_dither_s32(ma_dither_mode ditherMode, ma_int32 ditherMin, ma_int32 ditherMax) { if (ditherMode == ma_dither_mode_rectangle) { ma_int32 a = ma_rand_range_s32(ditherMin, ditherMax); return a; } if (ditherMode == ma_dither_mode_triangle) { ma_int32 a = ma_rand_range_s32(ditherMin, 0); ma_int32 b = ma_rand_range_s32(0, ditherMax); return a + b; } return 0; } /* Splits a buffer into parts of equal length and of the given alignment. The returned size of the split buffers will be a multiple of the alignment. The alignment must be a power of 2. */ void ma_split_buffer(void* pBuffer, size_t bufferSize, size_t splitCount, size_t alignment, void** ppBuffersOut, size_t* pSplitSizeOut) { ma_uintptr pBufferUnaligned; ma_uintptr pBufferAligned; size_t unalignedBytes; size_t splitSize; if (pSplitSizeOut) { *pSplitSizeOut = 0; } if (pBuffer == NULL || bufferSize == 0 || splitCount == 0) { return; } if (alignment == 0) { alignment = 1; } pBufferUnaligned = (ma_uintptr)pBuffer; pBufferAligned = (pBufferUnaligned + (alignment-1)) & ~(alignment-1); unalignedBytes = (size_t)(pBufferAligned - pBufferUnaligned); splitSize = 0; if (bufferSize >= unalignedBytes) { splitSize = (bufferSize - unalignedBytes) / splitCount; splitSize = splitSize & ~(alignment-1); } if (ppBuffersOut != NULL) { size_t i; for (i = 0; i < splitCount; ++i) { ppBuffersOut[i] = (ma_uint8*)(pBufferAligned + (splitSize*i)); } } if (pSplitSizeOut) { *pSplitSizeOut = splitSize; } } /****************************************************************************** Atomics ******************************************************************************/ #if defined(_WIN32) && !defined(__GNUC__) #define ma_memory_barrier() MemoryBarrier() #define ma_atomic_exchange_32(a, b) InterlockedExchange((LONG*)a, (LONG)b) #define ma_atomic_exchange_64(a, b) InterlockedExchange64((LONGLONG*)a, (LONGLONG)b) #define ma_atomic_increment_32(a) InterlockedIncrement((LONG*)a) #define ma_atomic_decrement_32(a) InterlockedDecrement((LONG*)a) #else #define ma_memory_barrier() __sync_synchronize() #define ma_atomic_exchange_32(a, b) (void)__sync_lock_test_and_set(a, b); __sync_synchronize() #define ma_atomic_exchange_64(a, b) (void)__sync_lock_test_and_set(a, b); __sync_synchronize() #define ma_atomic_increment_32(a) __sync_add_and_fetch(a, 1) #define ma_atomic_decrement_32(a) __sync_sub_and_fetch(a, 1) #endif #ifdef MA_64BIT #define ma_atomic_exchange_ptr ma_atomic_exchange_64 #endif #ifdef MA_32BIT #define ma_atomic_exchange_ptr ma_atomic_exchange_32 #endif ma_uint32 ma_get_standard_sample_rate_priority_index(ma_uint32 sampleRate) /* Lower = higher priority */ { ma_uint32 i; for (i = 0; i < ma_countof(g_maStandardSampleRatePriorities); ++i) { if (g_maStandardSampleRatePriorities[i] == sampleRate) { return i; } } return (ma_uint32)-1; } ma_uint64 ma_calculate_frame_count_after_src(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn) { double srcRatio = (double)sampleRateOut / sampleRateIn; double frameCountOutF = (ma_int64)frameCountIn * srcRatio; /* Cast to int64 required for VC6. */ ma_uint64 frameCountOut = (ma_uint64)frameCountOutF; /* If the output frame count is fractional, make sure we add an extra frame to ensure there's enough room for that last sample. */ if ((frameCountOutF - (ma_int64)frameCountOut) > 0.0) { frameCountOut += 1; } return frameCountOut; } /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* DEVICE I/O ========== ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ #ifndef MA_NO_DEVICE_IO /* Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing compile-time linking fixes this. I'm not sure why this happens, but the safest way I can think of to fix this is to simply disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere. */ /*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/ /* Disable run-time linking on certain backends. */ #ifndef MA_NO_RUNTIME_LINKING #if defined(MA_ANDROID) || defined(MA_EMSCRIPTEN) #define MA_NO_RUNTIME_LINKING #endif #endif /* Check if we have the necessary development packages for each backend at the top so we can use this to determine whether or not certain unused functions and variables can be excluded from the build to avoid warnings. */ #ifdef MA_ENABLE_WASAPI #define MA_HAS_WASAPI /* Every compiler should support WASAPI */ #endif #ifdef MA_ENABLE_DSOUND #define MA_HAS_DSOUND /* Every compiler should support DirectSound. */ #endif #ifdef MA_ENABLE_WINMM #define MA_HAS_WINMM /* Every compiler I'm aware of supports WinMM. */ #endif #ifdef MA_ENABLE_ALSA #define MA_HAS_ALSA #ifdef MA_NO_RUNTIME_LINKING #ifdef __has_include #if !__has_include() #undef MA_HAS_ALSA #endif #endif #endif #endif #ifdef MA_ENABLE_PULSEAUDIO #define MA_HAS_PULSEAUDIO #ifdef MA_NO_RUNTIME_LINKING #ifdef __has_include #if !__has_include() #undef MA_HAS_PULSEAUDIO #endif #endif #endif #endif #ifdef MA_ENABLE_JACK #define MA_HAS_JACK #ifdef MA_NO_RUNTIME_LINKING #ifdef __has_include #if !__has_include() #undef MA_HAS_JACK #endif #endif #endif #endif #ifdef MA_ENABLE_COREAUDIO #define MA_HAS_COREAUDIO #endif #ifdef MA_ENABLE_SNDIO #define MA_HAS_SNDIO #endif #ifdef MA_ENABLE_AUDIO4 #define MA_HAS_AUDIO4 #endif #ifdef MA_ENABLE_OSS #define MA_HAS_OSS #endif #ifdef MA_ENABLE_AAUDIO #define MA_HAS_AAUDIO #endif #ifdef MA_ENABLE_OPENSL #define MA_HAS_OPENSL #endif #ifdef MA_ENABLE_WEBAUDIO #define MA_HAS_WEBAUDIO #endif #ifdef MA_ENABLE_NULL #define MA_HAS_NULL /* Everything supports the null backend. */ #endif const char* ma_get_backend_name(ma_backend backend) { switch (backend) { case ma_backend_wasapi: return "WASAPI"; case ma_backend_dsound: return "DirectSound"; case ma_backend_winmm: return "WinMM"; case ma_backend_coreaudio: return "Core Audio"; case ma_backend_sndio: return "sndio"; case ma_backend_audio4: return "audio(4)"; case ma_backend_oss: return "OSS"; case ma_backend_pulseaudio: return "PulseAudio"; case ma_backend_alsa: return "ALSA"; case ma_backend_jack: return "JACK"; case ma_backend_aaudio: return "AAudio"; case ma_backend_opensl: return "OpenSL|ES"; case ma_backend_webaudio: return "Web Audio"; case ma_backend_null: return "Null"; default: return "Unknown"; } } #ifdef MA_WIN32 #define MA_THREADCALL WINAPI typedef unsigned long ma_thread_result; #else #define MA_THREADCALL typedef void* ma_thread_result; #endif typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData); #ifdef MA_WIN32 typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit); typedef void (WINAPI * MA_PFN_CoUninitialize)(); typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv); typedef void (WINAPI * MA_PFN_CoTaskMemFree)(LPVOID pv); typedef HRESULT (WINAPI * MA_PFN_PropVariantClear)(PROPVARIANT *pvar); typedef int (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, LPOLESTR lpsz, int cchMax); typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)(); typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)(); /* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */ typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); #endif #define MA_STATE_UNINITIALIZED 0 #define MA_STATE_STOPPED 1 /* The device's default state after initialization. */ #define MA_STATE_STARTED 2 /* The worker thread is in it's main loop waiting for the driver to request or deliver audio data. */ #define MA_STATE_STARTING 3 /* Transitioning from a stopped state to started. */ #define MA_STATE_STOPPING 4 /* Transitioning from a started state to stopped. */ #define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device" #define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device" const char* ma_log_level_to_string(ma_uint32 logLevel) { switch (logLevel) { case MA_LOG_LEVEL_VERBOSE: return ""; case MA_LOG_LEVEL_INFO: return "INFO"; case MA_LOG_LEVEL_WARNING: return "WARNING"; case MA_LOG_LEVEL_ERROR: return "ERROR"; default: return "ERROR"; } } /* Posts a log message. */ void ma_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) { if (pContext == NULL) { return; } #if defined(MA_LOG_LEVEL) if (logLevel <= MA_LOG_LEVEL) { ma_log_proc onLog; #if defined(MA_DEBUG_OUTPUT) if (logLevel <= MA_LOG_LEVEL) { printf("%s: %s\n", ma_log_level_to_string(logLevel), message); } #endif onLog = pContext->logCallback; if (onLog) { onLog(pContext, pDevice, logLevel, message); } } #endif } /* Posts an log message. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */ ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) { /* Derive the context from the device if necessary. */ if (pContext == NULL) { if (pDevice != NULL) { pContext = pDevice->pContext; } } ma_log(pContext, pDevice, logLevel, message); return resultCode; } ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) { return ma_context_post_error(NULL, pDevice, logLevel, message, resultCode); } /******************************************************************************* Timing *******************************************************************************/ #ifdef MA_WIN32 LARGE_INTEGER g_ma_TimerFrequency = {{0}}; void ma_timer_init(ma_timer* pTimer) { LARGE_INTEGER counter; if (g_ma_TimerFrequency.QuadPart == 0) { QueryPerformanceFrequency(&g_ma_TimerFrequency); } QueryPerformanceCounter(&counter); pTimer->counter = counter.QuadPart; } double ma_timer_get_time_in_seconds(ma_timer* pTimer) { LARGE_INTEGER counter; if (!QueryPerformanceCounter(&counter)) { return 0; } return (double)(counter.QuadPart - pTimer->counter) / g_ma_TimerFrequency.QuadPart; } #elif defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200) ma_uint64 g_ma_TimerFrequency = 0; void ma_timer_init(ma_timer* pTimer) { mach_timebase_info_data_t baseTime; mach_timebase_info(&baseTime); g_ma_TimerFrequency = (baseTime.denom * 1e9) / baseTime.numer; pTimer->counter = mach_absolute_time(); } double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter = mach_absolute_time(); ma_uint64 oldTimeCounter = pTimer->counter; return (newTimeCounter - oldTimeCounter) / g_ma_TimerFrequency; } #elif defined(MA_EMSCRIPTEN) void ma_timer_init(ma_timer* pTimer) { pTimer->counterD = emscripten_get_now(); } double ma_timer_get_time_in_seconds(ma_timer* pTimer) { return (emscripten_get_now() - pTimer->counterD) / 1000; /* Emscripten is in milliseconds. */ } #else #if _POSIX_C_SOURCE >= 199309L #if defined(CLOCK_MONOTONIC) #define MA_CLOCK_ID CLOCK_MONOTONIC #else #define MA_CLOCK_ID CLOCK_REALTIME #endif void ma_timer_init(ma_timer* pTimer) { struct timespec newTime; clock_gettime(MA_CLOCK_ID, &newTime); pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; } double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; struct timespec newTime; clock_gettime(MA_CLOCK_ID, &newTime); newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; oldTimeCounter = pTimer->counter; return (newTimeCounter - oldTimeCounter) / 1000000000.0; } #else void ma_timer_init(ma_timer* pTimer) { struct timeval newTime; gettimeofday(&newTime, NULL); pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec; } double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; struct timeval newTime; gettimeofday(&newTime, NULL); newTimeCounter = (newTime.tv_sec * 1000000) + newTime.tv_usec; oldTimeCounter = pTimer->counter; return (newTimeCounter - oldTimeCounter) / 1000000.0; } #endif #endif /******************************************************************************* Dynamic Linking *******************************************************************************/ ma_handle ma_dlopen(ma_context* pContext, const char* filename) { ma_handle handle; #if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE if (pContext != NULL) { char message[256]; ma_strappend(message, sizeof(message), "Loading library: ", filename); ma_log(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message); } #endif #ifdef _WIN32 #ifdef MA_WIN32_DESKTOP handle = (ma_handle)LoadLibraryA(filename); #else /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ WCHAR filenameW[4096]; if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { handle = NULL; } else { handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); } #endif #else handle = (ma_handle)dlopen(filename, RTLD_NOW); #endif /* I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority backend is a deliberate design choice. Instead I'm logging it as an informational message. */ #if MA_LOG_LEVEL >= MA_LOG_LEVEL_INFO if (handle == NULL) { char message[256]; ma_strappend(message, sizeof(message), "Failed to load library: ", filename); ma_log(pContext, NULL, MA_LOG_LEVEL_INFO, message); } #endif (void)pContext; /* It's possible for pContext to be unused. */ return handle; } void ma_dlclose(ma_context* pContext, ma_handle handle) { #ifdef _WIN32 FreeLibrary((HMODULE)handle); #else dlclose((void*)handle); #endif (void)pContext; } ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol) { ma_proc proc; #if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE if (pContext != NULL) { char message[256]; ma_strappend(message, sizeof(message), "Loading symbol: ", symbol); ma_log(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message); } #endif #ifdef _WIN32 proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); #else #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif proc = (ma_proc)dlsym((void*)handle, symbol); #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #pragma GCC diagnostic pop #endif #endif #if MA_LOG_LEVEL >= MA_LOG_LEVEL_WARNING if (handle == NULL) { char message[256]; ma_strappend(message, sizeof(message), "Failed to load symbol: ", symbol); ma_log(pContext, NULL, MA_LOG_LEVEL_WARNING, message); } #endif (void)pContext; /* It's possible for pContext to be unused. */ return proc; } /******************************************************************************* Threading *******************************************************************************/ #ifdef MA_WIN32 int ma_thread_priority_to_win32(ma_thread_priority priority) { switch (priority) { case ma_thread_priority_idle: return THREAD_PRIORITY_IDLE; case ma_thread_priority_lowest: return THREAD_PRIORITY_LOWEST; case ma_thread_priority_low: return THREAD_PRIORITY_BELOW_NORMAL; case ma_thread_priority_normal: return THREAD_PRIORITY_NORMAL; case ma_thread_priority_high: return THREAD_PRIORITY_ABOVE_NORMAL; case ma_thread_priority_highest: return THREAD_PRIORITY_HIGHEST; case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL; default: return THREAD_PRIORITY_NORMAL; } } ma_result ma_thread_create__win32(ma_context* pContext, ma_thread* pThread, ma_thread_entry_proc entryProc, void* pData) { pThread->win32.hThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL); if (pThread->win32.hThread == NULL) { return MA_FAILED_TO_CREATE_THREAD; } SetThreadPriority((HANDLE)pThread->win32.hThread, ma_thread_priority_to_win32(pContext->threadPriority)); return MA_SUCCESS; } void ma_thread_wait__win32(ma_thread* pThread) { WaitForSingleObject(pThread->win32.hThread, INFINITE); } void ma_sleep__win32(ma_uint32 milliseconds) { Sleep((DWORD)milliseconds); } ma_result ma_mutex_init__win32(ma_context* pContext, ma_mutex* pMutex) { (void)pContext; pMutex->win32.hMutex = CreateEventA(NULL, FALSE, TRUE, NULL); if (pMutex->win32.hMutex == NULL) { return MA_FAILED_TO_CREATE_MUTEX; } return MA_SUCCESS; } void ma_mutex_uninit__win32(ma_mutex* pMutex) { CloseHandle(pMutex->win32.hMutex); } void ma_mutex_lock__win32(ma_mutex* pMutex) { WaitForSingleObject(pMutex->win32.hMutex, INFINITE); } void ma_mutex_unlock__win32(ma_mutex* pMutex) { SetEvent(pMutex->win32.hMutex); } ma_result ma_event_init__win32(ma_context* pContext, ma_event* pEvent) { (void)pContext; pEvent->win32.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if (pEvent->win32.hEvent == NULL) { return MA_FAILED_TO_CREATE_EVENT; } return MA_SUCCESS; } void ma_event_uninit__win32(ma_event* pEvent) { CloseHandle(pEvent->win32.hEvent); } ma_bool32 ma_event_wait__win32(ma_event* pEvent) { return WaitForSingleObject(pEvent->win32.hEvent, INFINITE) == WAIT_OBJECT_0; } ma_bool32 ma_event_signal__win32(ma_event* pEvent) { return SetEvent(pEvent->win32.hEvent); } #endif #ifdef MA_POSIX #include typedef int (* ma_pthread_create_proc)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); typedef int (* ma_pthread_join_proc)(pthread_t thread, void **retval); typedef int (* ma_pthread_mutex_init_proc)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr); typedef int (* ma_pthread_mutex_destroy_proc)(pthread_mutex_t *__mutex); typedef int (* ma_pthread_mutex_lock_proc)(pthread_mutex_t *__mutex); typedef int (* ma_pthread_mutex_unlock_proc)(pthread_mutex_t *__mutex); typedef int (* ma_pthread_cond_init_proc)(pthread_cond_t *__restrict __cond, const pthread_condattr_t *__restrict __cond_attr); typedef int (* ma_pthread_cond_destroy_proc)(pthread_cond_t *__cond); typedef int (* ma_pthread_cond_signal_proc)(pthread_cond_t *__cond); typedef int (* ma_pthread_cond_wait_proc)(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex); typedef int (* ma_pthread_attr_init_proc)(pthread_attr_t *attr); typedef int (* ma_pthread_attr_destroy_proc)(pthread_attr_t *attr); typedef int (* ma_pthread_attr_setschedpolicy_proc)(pthread_attr_t *attr, int policy); typedef int (* ma_pthread_attr_getschedparam_proc)(const pthread_attr_t *attr, struct sched_param *param); typedef int (* ma_pthread_attr_setschedparam_proc)(pthread_attr_t *attr, const struct sched_param *param); ma_result ma_thread_create__posix(ma_context* pContext, ma_thread* pThread, ma_thread_entry_proc entryProc, void* pData) { int result; pthread_attr_t* pAttr = NULL; #if !defined(__EMSCRIPTEN__) /* Try setting the thread priority. It's not critical if anything fails here. */ pthread_attr_t attr; if (((ma_pthread_attr_init_proc)pContext->posix.pthread_attr_init)(&attr) == 0) { int scheduler = -1; if (pContext->threadPriority == ma_thread_priority_idle) { #ifdef SCHED_IDLE if (((ma_pthread_attr_setschedpolicy_proc)pContext->posix.pthread_attr_setschedpolicy)(&attr, SCHED_IDLE) == 0) { scheduler = SCHED_IDLE; } #endif } else if (pContext->threadPriority == ma_thread_priority_realtime) { #ifdef SCHED_FIFO if (((ma_pthread_attr_setschedpolicy_proc)pContext->posix.pthread_attr_setschedpolicy)(&attr, SCHED_FIFO) == 0) { scheduler = SCHED_FIFO; } #endif #ifdef MA_LINUX } else { scheduler = sched_getscheduler(0); #endif } if (scheduler != -1) { int priorityMin = sched_get_priority_min(scheduler); int priorityMax = sched_get_priority_max(scheduler); int priorityStep = (priorityMax - priorityMin) / 7; /* 7 = number of priorities supported by miniaudio. */ struct sched_param sched; if (((ma_pthread_attr_getschedparam_proc)pContext->posix.pthread_attr_getschedparam)(&attr, &sched) == 0) { if (pContext->threadPriority == ma_thread_priority_idle) { sched.sched_priority = priorityMin; } else if (pContext->threadPriority == ma_thread_priority_realtime) { sched.sched_priority = priorityMax; } else { sched.sched_priority += ((int)pContext->threadPriority + 5) * priorityStep; /* +5 because the lowest priority is -5. */ if (sched.sched_priority < priorityMin) { sched.sched_priority = priorityMin; } if (sched.sched_priority > priorityMax) { sched.sched_priority = priorityMax; } } if (((ma_pthread_attr_setschedparam_proc)pContext->posix.pthread_attr_setschedparam)(&attr, &sched) == 0) { pAttr = &attr; } } } ((ma_pthread_attr_destroy_proc)pContext->posix.pthread_attr_destroy)(&attr); } #endif result = ((ma_pthread_create_proc)pContext->posix.pthread_create)(&pThread->posix.thread, pAttr, entryProc, pData); if (result != 0) { return MA_FAILED_TO_CREATE_THREAD; } return MA_SUCCESS; } void ma_thread_wait__posix(ma_thread* pThread) { ((ma_pthread_join_proc)pThread->pContext->posix.pthread_join)(pThread->posix.thread, NULL); } void ma_sleep__posix(ma_uint32 milliseconds) { #ifdef MA_EMSCRIPTEN (void)milliseconds; ma_assert(MA_FALSE); /* The Emscripten build should never sleep. */ #else #if _POSIX_C_SOURCE >= 199309L struct timespec ts; ts.tv_sec = milliseconds / 1000000; ts.tv_nsec = milliseconds % 1000000 * 1000000; nanosleep(&ts, NULL); #else struct timeval tv; tv.tv_sec = milliseconds / 1000; tv.tv_usec = milliseconds % 1000 * 1000; select(0, NULL, NULL, NULL, &tv); #endif #endif } ma_result ma_mutex_init__posix(ma_context* pContext, ma_mutex* pMutex) { int result = ((ma_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pMutex->posix.mutex, NULL); if (result != 0) { return MA_FAILED_TO_CREATE_MUTEX; } return MA_SUCCESS; } void ma_mutex_uninit__posix(ma_mutex* pMutex) { ((ma_pthread_mutex_destroy_proc)pMutex->pContext->posix.pthread_mutex_destroy)(&pMutex->posix.mutex); } void ma_mutex_lock__posix(ma_mutex* pMutex) { ((ma_pthread_mutex_lock_proc)pMutex->pContext->posix.pthread_mutex_lock)(&pMutex->posix.mutex); } void ma_mutex_unlock__posix(ma_mutex* pMutex) { ((ma_pthread_mutex_unlock_proc)pMutex->pContext->posix.pthread_mutex_unlock)(&pMutex->posix.mutex); } ma_result ma_event_init__posix(ma_context* pContext, ma_event* pEvent) { if (((ma_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pEvent->posix.mutex, NULL) != 0) { return MA_FAILED_TO_CREATE_MUTEX; } if (((ma_pthread_cond_init_proc)pContext->posix.pthread_cond_init)(&pEvent->posix.condition, NULL) != 0) { return MA_FAILED_TO_CREATE_EVENT; } pEvent->posix.value = 0; return MA_SUCCESS; } void ma_event_uninit__posix(ma_event* pEvent) { ((ma_pthread_cond_destroy_proc)pEvent->pContext->posix.pthread_cond_destroy)(&pEvent->posix.condition); ((ma_pthread_mutex_destroy_proc)pEvent->pContext->posix.pthread_mutex_destroy)(&pEvent->posix.mutex); } ma_bool32 ma_event_wait__posix(ma_event* pEvent) { ((ma_pthread_mutex_lock_proc)pEvent->pContext->posix.pthread_mutex_lock)(&pEvent->posix.mutex); { while (pEvent->posix.value == 0) { ((ma_pthread_cond_wait_proc)pEvent->pContext->posix.pthread_cond_wait)(&pEvent->posix.condition, &pEvent->posix.mutex); } pEvent->posix.value = 0; /* Auto-reset. */ } ((ma_pthread_mutex_unlock_proc)pEvent->pContext->posix.pthread_mutex_unlock)(&pEvent->posix.mutex); return MA_TRUE; } ma_bool32 ma_event_signal__posix(ma_event* pEvent) { ((ma_pthread_mutex_lock_proc)pEvent->pContext->posix.pthread_mutex_lock)(&pEvent->posix.mutex); { pEvent->posix.value = 1; ((ma_pthread_cond_signal_proc)pEvent->pContext->posix.pthread_cond_signal)(&pEvent->posix.condition); } ((ma_pthread_mutex_unlock_proc)pEvent->pContext->posix.pthread_mutex_unlock)(&pEvent->posix.mutex); return MA_TRUE; } #endif ma_result ma_thread_create(ma_context* pContext, ma_thread* pThread, ma_thread_entry_proc entryProc, void* pData) { if (pContext == NULL || pThread == NULL || entryProc == NULL) { return MA_FALSE; } pThread->pContext = pContext; #ifdef MA_WIN32 return ma_thread_create__win32(pContext, pThread, entryProc, pData); #endif #ifdef MA_POSIX return ma_thread_create__posix(pContext, pThread, entryProc, pData); #endif } void ma_thread_wait(ma_thread* pThread) { if (pThread == NULL) { return; } #ifdef MA_WIN32 ma_thread_wait__win32(pThread); #endif #ifdef MA_POSIX ma_thread_wait__posix(pThread); #endif } void ma_sleep(ma_uint32 milliseconds) { #ifdef MA_WIN32 ma_sleep__win32(milliseconds); #endif #ifdef MA_POSIX ma_sleep__posix(milliseconds); #endif } ma_result ma_mutex_init(ma_context* pContext, ma_mutex* pMutex) { if (pContext == NULL || pMutex == NULL) { return MA_INVALID_ARGS; } pMutex->pContext = pContext; #ifdef MA_WIN32 return ma_mutex_init__win32(pContext, pMutex); #endif #ifdef MA_POSIX return ma_mutex_init__posix(pContext, pMutex); #endif } void ma_mutex_uninit(ma_mutex* pMutex) { if (pMutex == NULL || pMutex->pContext == NULL) { return; } #ifdef MA_WIN32 ma_mutex_uninit__win32(pMutex); #endif #ifdef MA_POSIX ma_mutex_uninit__posix(pMutex); #endif } void ma_mutex_lock(ma_mutex* pMutex) { if (pMutex == NULL || pMutex->pContext == NULL) { return; } #ifdef MA_WIN32 ma_mutex_lock__win32(pMutex); #endif #ifdef MA_POSIX ma_mutex_lock__posix(pMutex); #endif } void ma_mutex_unlock(ma_mutex* pMutex) { if (pMutex == NULL || pMutex->pContext == NULL) { return; } #ifdef MA_WIN32 ma_mutex_unlock__win32(pMutex); #endif #ifdef MA_POSIX ma_mutex_unlock__posix(pMutex); #endif } ma_result ma_event_init(ma_context* pContext, ma_event* pEvent) { if (pContext == NULL || pEvent == NULL) { return MA_FALSE; } pEvent->pContext = pContext; #ifdef MA_WIN32 return ma_event_init__win32(pContext, pEvent); #endif #ifdef MA_POSIX return ma_event_init__posix(pContext, pEvent); #endif } void ma_event_uninit(ma_event* pEvent) { if (pEvent == NULL || pEvent->pContext == NULL) { return; } #ifdef MA_WIN32 ma_event_uninit__win32(pEvent); #endif #ifdef MA_POSIX ma_event_uninit__posix(pEvent); #endif } ma_bool32 ma_event_wait(ma_event* pEvent) { if (pEvent == NULL || pEvent->pContext == NULL) { return MA_FALSE; } #ifdef MA_WIN32 return ma_event_wait__win32(pEvent); #endif #ifdef MA_POSIX return ma_event_wait__posix(pEvent); #endif } ma_bool32 ma_event_signal(ma_event* pEvent) { if (pEvent == NULL || pEvent->pContext == NULL) { return MA_FALSE; } #ifdef MA_WIN32 return ma_event_signal__win32(pEvent); #endif #ifdef MA_POSIX return ma_event_signal__posix(pEvent); #endif } ma_uint32 ma_get_best_sample_rate_within_range(ma_uint32 sampleRateMin, ma_uint32 sampleRateMax) { /* Normalize the range in case we were given something stupid. */ if (sampleRateMin < MA_MIN_SAMPLE_RATE) { sampleRateMin = MA_MIN_SAMPLE_RATE; } if (sampleRateMax > MA_MAX_SAMPLE_RATE) { sampleRateMax = MA_MAX_SAMPLE_RATE; } if (sampleRateMin > sampleRateMax) { sampleRateMin = sampleRateMax; } if (sampleRateMin == sampleRateMax) { return sampleRateMax; } else { size_t iStandardRate; for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) { ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate]; if (standardRate >= sampleRateMin && standardRate <= sampleRateMax) { return standardRate; } } } /* Should never get here. */ ma_assert(MA_FALSE); return 0; } ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn) { ma_uint32 closestRate = 0; ma_uint32 closestDiff = 0xFFFFFFFF; size_t iStandardRate; for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) { ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate]; ma_uint32 diff; if (sampleRateIn > standardRate) { diff = sampleRateIn - standardRate; } else { diff = standardRate - sampleRateIn; } if (diff == 0) { return standardRate; /* The input sample rate is a standard rate. */ } if (closestDiff > diff) { closestDiff = diff; closestRate = standardRate; } } return closestRate; } ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale) { return ma_max(1, (ma_uint32)(baseBufferSize*scale)); } ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate) { return bufferSizeInFrames / (sampleRate/1000); } ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate) { return bufferSizeInMilliseconds * (sampleRate/1000); } ma_uint32 ma_get_default_buffer_size_in_milliseconds(ma_performance_profile performanceProfile) { if (performanceProfile == ma_performance_profile_low_latency) { return MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY; } else { return MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE; } } ma_uint32 ma_get_default_buffer_size_in_frames(ma_performance_profile performanceProfile, ma_uint32 sampleRate) { ma_uint32 bufferSizeInMilliseconds; ma_uint32 sampleRateMS; bufferSizeInMilliseconds = ma_get_default_buffer_size_in_milliseconds(performanceProfile); if (bufferSizeInMilliseconds == 0) { bufferSizeInMilliseconds = 1; } sampleRateMS = (sampleRate/1000); if (sampleRateMS == 0) { sampleRateMS = 1; } return bufferSizeInMilliseconds * sampleRateMS; } ma_uint32 ma_get_fragment_size_in_bytes(ma_uint32 bufferSizeInFrames, ma_uint32 periods, ma_format format, ma_uint32 channels) { ma_uint32 fragmentSizeInFrames = bufferSizeInFrames / periods; return fragmentSizeInFrames * ma_get_bytes_per_frame(format, channels); } void ma_zero_pcm_frames(void* p, ma_uint32 frameCount, ma_format format, ma_uint32 channels) { ma_zero_memory(p, frameCount * ma_get_bytes_per_frame(format, channels)); } /* The callback for reading from the client -> DSP -> device. */ ma_uint32 ma_device__on_read_from_client(ma_pcm_converter* pDSP, void* pFramesOut, ma_uint32 frameCount, void* pUserData) { ma_device* pDevice = (ma_device*)pUserData; ma_device_callback_proc onData; ma_assert(pDevice != NULL); ma_zero_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); onData = pDevice->onData; if (onData) { onData(pDevice, pFramesOut, NULL, frameCount); return frameCount; } (void)pDSP; return 0; } /* The PCM converter callback for reading from a buffer. */ ma_uint32 ma_device__pcm_converter__on_read_from_buffer_capture(ma_pcm_converter* pConverter, void* pFramesOut, ma_uint32 frameCount, void* pUserData) { ma_device* pDevice = (ma_device*)pUserData; ma_uint32 framesToRead; ma_uint32 bytesToRead; ma_assert(pDevice != NULL); if (pDevice->capture._dspFrameCount == 0) { return 0; /* Nothing left. */ } framesToRead = frameCount; if (framesToRead > pDevice->capture._dspFrameCount) { framesToRead = pDevice->capture._dspFrameCount; } bytesToRead = framesToRead * ma_get_bytes_per_frame(pConverter->formatConverterIn.config.formatIn, pConverter->channelRouter.config.channelsIn); ma_copy_memory(pFramesOut, pDevice->capture._dspFrames, bytesToRead); pDevice->capture._dspFrameCount -= framesToRead; pDevice->capture._dspFrames += bytesToRead; return framesToRead; } ma_uint32 ma_device__pcm_converter__on_read_from_buffer_playback(ma_pcm_converter* pConverter, void* pFramesOut, ma_uint32 frameCount, void* pUserData) { ma_device* pDevice = (ma_device*)pUserData; ma_uint32 framesToRead; ma_uint32 bytesToRead; ma_assert(pDevice != NULL); if (pDevice->playback._dspFrameCount == 0) { return 0; /* Nothing left. */ } framesToRead = frameCount; if (framesToRead > pDevice->playback._dspFrameCount) { framesToRead = pDevice->playback._dspFrameCount; } bytesToRead = framesToRead * ma_get_bytes_per_frame(pConverter->formatConverterIn.config.formatIn, pConverter->channelRouter.config.channelsIn); ma_copy_memory(pFramesOut, pDevice->playback._dspFrames, bytesToRead); pDevice->playback._dspFrameCount -= framesToRead; pDevice->playback._dspFrames += bytesToRead; return framesToRead; } /* A helper function for reading sample data from the client. */ static MA_INLINE void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 frameCount, void* pSamples) { ma_device_callback_proc onData; ma_assert(pDevice != NULL); ma_assert(frameCount > 0); ma_assert(pSamples != NULL); onData = pDevice->onData; if (onData) { if (pDevice->playback.converter.isPassthrough) { ma_zero_pcm_frames(pSamples, frameCount, pDevice->playback.format, pDevice->playback.channels); onData(pDevice, pSamples, NULL, frameCount); } else { ma_pcm_converter_read(&pDevice->playback.converter, pSamples, frameCount); } } } /* A helper for sending sample data to the client. */ static MA_INLINE void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frameCount, const void* pSamples) { ma_device_callback_proc onData; ma_assert(pDevice != NULL); ma_assert(frameCount > 0); ma_assert(pSamples != NULL); onData = pDevice->onData; if (onData) { if (pDevice->capture.converter.isPassthrough) { onData(pDevice, NULL, pSamples, frameCount); } else { ma_uint8 chunkBuffer[4096]; ma_uint32 chunkFrameCount; pDevice->capture._dspFrameCount = frameCount; pDevice->capture._dspFrames = (const ma_uint8*)pSamples; chunkFrameCount = sizeof(chunkBuffer) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); for (;;) { ma_uint32 framesJustRead = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, chunkBuffer, chunkFrameCount); if (framesJustRead == 0) { break; } onData(pDevice, NULL, chunkBuffer, framesJustRead); if (framesJustRead < chunkFrameCount) { break; } } } } } static MA_INLINE ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, ma_uint32 frameCount, const void* pFramesInInternalFormat, ma_pcm_rb* pRB) { ma_result result; ma_assert(pDevice != NULL); ma_assert(frameCount > 0); ma_assert(pFramesInInternalFormat != NULL); ma_assert(pRB != NULL); pDevice->capture._dspFrameCount = (ma_uint32)frameCount; pDevice->capture._dspFrames = (const ma_uint8*)pFramesInInternalFormat; /* Write to the ring buffer. The ring buffer is in the external format. */ for (;;) { ma_uint32 framesProcessed; ma_uint32 framesToProcess = 256; void* pFramesInExternalFormat; result = ma_pcm_rb_acquire_write(pRB, &framesToProcess, &pFramesInExternalFormat); if (result != MA_SUCCESS) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.", result); break; } if (framesToProcess == 0) { if (ma_pcm_rb_pointer_disance(pRB) == (ma_int32)ma_pcm_rb_get_subbuffer_size(pRB)) { break; /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */ } } /* Convert. */ framesProcessed = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, pFramesInExternalFormat, framesToProcess); result = ma_pcm_rb_commit_write(pRB, framesProcessed, pFramesInExternalFormat); if (result != MA_SUCCESS) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.", result); break; } if (framesProcessed < framesToProcess) { break; /* Done. */ } } return MA_SUCCESS; } static MA_INLINE ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ma_uint32 frameCount, void* pFramesInInternalFormat, ma_pcm_rb* pRB) { ma_result result; ma_uint8 playbackFramesInExternalFormat[4096]; ma_uint8 silentInputFrames[4096]; ma_uint32 totalFramesToReadFromClient; ma_uint32 totalFramesReadFromClient; ma_assert(pDevice != NULL); ma_assert(frameCount > 0); ma_assert(pFramesInInternalFormat != NULL); ma_assert(pRB != NULL); /* Sitting in the ring buffer should be captured data from the capture callback in external format. If there's not enough data in there for the whole frameCount frames we just use silence instead for the input data. */ ma_zero_memory(silentInputFrames, sizeof(silentInputFrames)); /* We need to calculate how many output frames are required to be read from the client to completely fill frameCount internal frames. */ totalFramesToReadFromClient = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->playback.internalSampleRate, frameCount); /* ma_pcm_converter_get_required_input_frame_count(&pDevice->playback.converter, (ma_uint32)frameCount); */ totalFramesReadFromClient = 0; while (totalFramesReadFromClient < totalFramesToReadFromClient && ma_device_is_started(pDevice)) { ma_uint32 framesRemainingFromClient; ma_uint32 framesToProcessFromClient; ma_uint32 inputFrameCount; void* pInputFrames; framesRemainingFromClient = (totalFramesToReadFromClient - totalFramesReadFromClient); framesToProcessFromClient = sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); if (framesToProcessFromClient > framesRemainingFromClient) { framesToProcessFromClient = framesRemainingFromClient; } /* We need to grab captured samples before firing the callback. If there's not enough input samples we just pass silence. */ inputFrameCount = framesToProcessFromClient; result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames); if (result == MA_SUCCESS) { if (inputFrameCount > 0) { /* Use actual input frames. */ pDevice->onData(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount); } else { if (ma_pcm_rb_pointer_disance(pRB) == 0) { break; /* Underrun. */ } } /* We're done with the captured samples. */ result = ma_pcm_rb_commit_read(pRB, inputFrameCount, pInputFrames); if (result != MA_SUCCESS) { break; /* Don't know what to do here... Just abandon ship. */ } } else { /* Use silent input frames. */ inputFrameCount = ma_min( sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels), sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels) ); pDevice->onData(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount); } /* We have samples in external format so now we need to convert to internal format and output to the device. */ pDevice->playback._dspFrameCount = inputFrameCount; pDevice->playback._dspFrames = (const ma_uint8*)playbackFramesInExternalFormat; ma_pcm_converter_read(&pDevice->playback.converter, pFramesInInternalFormat, inputFrameCount); totalFramesReadFromClient += inputFrameCount; pFramesInInternalFormat = ma_offset_ptr(pFramesInInternalFormat, inputFrameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); } return MA_SUCCESS; } /* A helper for changing the state of the device. */ static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_uint32 newState) { ma_atomic_exchange_32(&pDevice->state, newState); } /* A helper for getting the state of the device. */ static MA_INLINE ma_uint32 ma_device__get_state(ma_device* pDevice) { return pDevice->state; } /* A helper for determining whether or not the device is running in async mode. */ static MA_INLINE ma_bool32 ma_device__is_async(ma_device* pDevice) { return pDevice->onData != NULL; } #ifdef MA_WIN32 GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ #endif ma_bool32 ma_context__device_id_equal(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); if (pID0 == pID1) return MA_TRUE; if ((pID0 == NULL && pID1 != NULL) || (pID0 != NULL && pID1 == NULL)) { return MA_FALSE; } if (pContext->onDeviceIDEqual) { return pContext->onDeviceIDEqual(pContext, pID0, pID1); } return MA_FALSE; } typedef struct { ma_device_type deviceType; const ma_device_id* pDeviceID; char* pName; size_t nameBufferSize; ma_bool32 foundDevice; } ma_context__try_get_device_name_by_id__enum_callback_data; ma_bool32 ma_context__try_get_device_name_by_id__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pDeviceInfo, void* pUserData) { ma_context__try_get_device_name_by_id__enum_callback_data* pData = (ma_context__try_get_device_name_by_id__enum_callback_data*)pUserData; ma_assert(pData != NULL); if (pData->deviceType == deviceType) { if (pContext->onDeviceIDEqual(pContext, pData->pDeviceID, &pDeviceInfo->id)) { ma_strncpy_s(pData->pName, pData->nameBufferSize, pDeviceInfo->name, (size_t)-1); pData->foundDevice = MA_TRUE; } } return !pData->foundDevice; } /* Generic function for retrieving the name of a device by it's ID. This function simply enumerates every device and then retrieves the name of the first device that has the same ID. */ ma_result ma_context__try_get_device_name_by_id(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, char* pName, size_t nameBufferSize) { ma_result result; ma_context__try_get_device_name_by_id__enum_callback_data data; ma_assert(pContext != NULL); ma_assert(pName != NULL); if (pDeviceID == NULL) { return MA_NO_DEVICE; } data.deviceType = deviceType; data.pDeviceID = pDeviceID; data.pName = pName; data.nameBufferSize = nameBufferSize; data.foundDevice = MA_FALSE; result = ma_context_enumerate_devices(pContext, ma_context__try_get_device_name_by_id__enum_callback, &data); if (result != MA_SUCCESS) { return result; } if (!data.foundDevice) { return MA_NO_DEVICE; } else { return MA_SUCCESS; } } ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */ { ma_uint32 i; for (i = 0; i < ma_countof(g_maFormatPriorities); ++i) { if (g_maFormatPriorities[i] == format) { return i; } } /* Getting here means the format could not be found or is equal to ma_format_unknown. */ return (ma_uint32)-1; } void ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType); /******************************************************************************* Null Backend *******************************************************************************/ #ifdef MA_HAS_NULL #define MA_DEVICE_OP_NONE__NULL 0 #define MA_DEVICE_OP_START__NULL 1 #define MA_DEVICE_OP_SUSPEND__NULL 2 #define MA_DEVICE_OP_KILL__NULL 3 ma_thread_result MA_THREADCALL ma_device_thread__null(void* pData) { ma_device* pDevice = (ma_device*)pData; ma_assert(pDevice != NULL); for (;;) { /* Keep the thread alive until the device is uninitialized. */ /* Wait for an operation to be requested. */ ma_event_wait(&pDevice->null_device.operationEvent); /* At this point an event should have been triggered. */ /* Starting the device needs to put the thread into a loop. */ if (pDevice->null_device.operation == MA_DEVICE_OP_START__NULL) { ma_atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL); /* Reset the timer just in case. */ ma_timer_init(&pDevice->null_device.timer); /* Keep looping until an operation has been requested. */ while (pDevice->null_device.operation != MA_DEVICE_OP_NONE__NULL && pDevice->null_device.operation != MA_DEVICE_OP_START__NULL) { ma_sleep(10); /* Don't hog the CPU. */ } /* Getting here means a suspend or kill operation has been requested. */ ma_atomic_exchange_32(&pDevice->null_device.operationResult, MA_SUCCESS); ma_event_signal(&pDevice->null_device.operationCompletionEvent); continue; } /* Suspending the device means we need to stop the timer and just continue the loop. */ if (pDevice->null_device.operation == MA_DEVICE_OP_SUSPEND__NULL) { ma_atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL); /* We need to add the current run time to the prior run time, then reset the timer. */ pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer); ma_timer_init(&pDevice->null_device.timer); /* We're done. */ ma_atomic_exchange_32(&pDevice->null_device.operationResult, MA_SUCCESS); ma_event_signal(&pDevice->null_device.operationCompletionEvent); continue; } /* Killing the device means we need to get out of this loop so that this thread can terminate. */ if (pDevice->null_device.operation == MA_DEVICE_OP_KILL__NULL) { ma_atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL); ma_atomic_exchange_32(&pDevice->null_device.operationResult, MA_SUCCESS); ma_event_signal(&pDevice->null_device.operationCompletionEvent); break; } /* Getting a signal on a "none" operation probably means an error. Return invalid operation. */ if (pDevice->null_device.operation == MA_DEVICE_OP_NONE__NULL) { ma_assert(MA_FALSE); /* <-- Trigger this in debug mode to ensure developers are aware they're doing something wrong (or there's a bug in a miniaudio). */ ma_atomic_exchange_32(&pDevice->null_device.operationResult, MA_INVALID_OPERATION); ma_event_signal(&pDevice->null_device.operationCompletionEvent); continue; /* Continue the loop. Don't terminate. */ } } return (ma_thread_result)0; } ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation) { ma_atomic_exchange_32(&pDevice->null_device.operation, operation); if (!ma_event_signal(&pDevice->null_device.operationEvent)) { return MA_ERROR; } if (!ma_event_wait(&pDevice->null_device.operationCompletionEvent)) { return MA_ERROR; } return pDevice->null_device.operationResult; } ma_uint64 ma_device_get_total_run_time_in_frames__null(ma_device* pDevice) { ma_uint32 internalSampleRate; if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { internalSampleRate = pDevice->capture.internalSampleRate; } else { internalSampleRate = pDevice->playback.internalSampleRate; } return (ma_uint64)((pDevice->null_device.priorRunTime + ma_timer_get_time_in_seconds(&pDevice->null_device.timer)) * internalSampleRate); } ma_bool32 ma_context_is_device_id_equal__null(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return pID0->nullbackend == pID1->nullbackend; } ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_bool32 cbResult = MA_TRUE; ma_assert(pContext != NULL); ma_assert(callback != NULL); /* Playback. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Playback Device", (size_t)-1); cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } /* Capture. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Capture Device", (size_t)-1); cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } return MA_SUCCESS; } ma_result ma_context_get_device_info__null(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_uint32 iFormat; ma_assert(pContext != NULL); if (pDeviceID != NULL && pDeviceID->nullbackend != 0) { return MA_NO_DEVICE; /* Don't know the device. */ } /* Name / Description */ if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Playback Device", (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Capture Device", (size_t)-1); } /* Support everything on the null backend. */ pDeviceInfo->formatCount = ma_format_count - 1; /* Minus one because we don't want to include ma_format_unknown. */ for (iFormat = 0; iFormat < pDeviceInfo->formatCount; ++iFormat) { pDeviceInfo->formats[iFormat] = (ma_format)(iFormat + 1); /* +1 to skip over ma_format_unknown. */ } pDeviceInfo->minChannels = 1; pDeviceInfo->maxChannels = MA_MAX_CHANNELS; pDeviceInfo->minSampleRate = MA_SAMPLE_RATE_8000; pDeviceInfo->maxSampleRate = MA_SAMPLE_RATE_384000; (void)pContext; (void)shareMode; return MA_SUCCESS; } void ma_device_uninit__null(ma_device* pDevice) { ma_assert(pDevice != NULL); /* Keep it clean and wait for the device thread to finish before returning. */ ma_device_do_operation__null(pDevice, MA_DEVICE_OP_KILL__NULL); /* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */ ma_event_uninit(&pDevice->null_device.operationCompletionEvent); ma_event_uninit(&pDevice->null_device.operationEvent); } ma_result ma_device_init__null(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result; ma_uint32 bufferSizeInFrames; ma_assert(pDevice != NULL); ma_zero_object(&pDevice->null_device); bufferSizeInFrames = pConfig->bufferSizeInFrames; if (bufferSizeInFrames == 0) { bufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, pConfig->sampleRate); } if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "NULL Capture Device", (size_t)-1); pDevice->capture.internalFormat = pConfig->capture.format; pDevice->capture.internalChannels = pConfig->capture.channels; ma_channel_map_copy(pDevice->capture.internalChannelMap, pConfig->capture.channelMap, pConfig->capture.channels); pDevice->capture.internalBufferSizeInFrames = bufferSizeInFrames; pDevice->capture.internalPeriods = pConfig->periods; } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "NULL Playback Device", (size_t)-1); pDevice->playback.internalFormat = pConfig->playback.format; pDevice->playback.internalChannels = pConfig->playback.channels; ma_channel_map_copy(pDevice->playback.internalChannelMap, pConfig->playback.channelMap, pConfig->playback.channels); pDevice->playback.internalBufferSizeInFrames = bufferSizeInFrames; pDevice->playback.internalPeriods = pConfig->periods; } /* In order to get timing right, we need to create a thread that does nothing but keeps track of the timer. This timer is started when the first period is "written" to it, and then stopped in ma_device_stop__null(). */ result = ma_event_init(pContext, &pDevice->null_device.operationEvent); if (result != MA_SUCCESS) { return result; } result = ma_event_init(pContext, &pDevice->null_device.operationCompletionEvent); if (result != MA_SUCCESS) { return result; } result = ma_thread_create(pContext, &pDevice->thread, ma_device_thread__null, pDevice); if (result != MA_SUCCESS) { return result; } return MA_SUCCESS; } ma_result ma_device_start__null(ma_device* pDevice) { ma_assert(pDevice != NULL); ma_device_do_operation__null(pDevice, MA_DEVICE_OP_START__NULL); ma_atomic_exchange_32(&pDevice->null_device.isStarted, MA_TRUE); return MA_SUCCESS; } ma_result ma_device_stop__null(ma_device* pDevice) { ma_assert(pDevice != NULL); ma_device_do_operation__null(pDevice, MA_DEVICE_OP_SUSPEND__NULL); ma_atomic_exchange_32(&pDevice->null_device.isStarted, MA_FALSE); return MA_SUCCESS; } ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount) { ma_result result = MA_SUCCESS; ma_uint32 totalPCMFramesProcessed; ma_bool32 wasStartedOnEntry; wasStartedOnEntry = pDevice->null_device.isStarted; /* Keep going until everything has been read. */ totalPCMFramesProcessed = 0; while (totalPCMFramesProcessed < frameCount) { ma_uint64 targetFrame; /* If there are any frames remaining in the current period, consume those first. */ if (pDevice->null_device.currentPeriodFramesRemainingPlayback > 0) { ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed); ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingPlayback; if (framesToProcess > framesRemaining) { framesToProcess = framesRemaining; } /* We don't actually do anything with pPCMFrames, so just mark it as unused to prevent a warning. */ (void)pPCMFrames; pDevice->null_device.currentPeriodFramesRemainingPlayback -= framesToProcess; totalPCMFramesProcessed += framesToProcess; } /* If we've consumed the current period we'll need to mark it as such an ensure the device is started if it's not already. */ if (pDevice->null_device.currentPeriodFramesRemainingPlayback == 0) { pDevice->null_device.currentPeriodFramesRemainingPlayback = 0; if (!pDevice->null_device.isStarted && !wasStartedOnEntry) { result = ma_device_start__null(pDevice); if (result != MA_SUCCESS) { break; } } } /* If we've consumed the whole buffer we can return now. */ ma_assert(totalPCMFramesProcessed <= frameCount); if (totalPCMFramesProcessed == frameCount) { break; } /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */ targetFrame = pDevice->null_device.lastProcessedFramePlayback; for (;;) { ma_uint64 currentFrame; /* Stop waiting if the device has been stopped. */ if (!pDevice->null_device.isStarted) { break; } currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice); if (currentFrame >= targetFrame) { break; } /* Getting here means we haven't yet reached the target sample, so continue waiting. */ ma_sleep(10); } pDevice->null_device.lastProcessedFramePlayback += pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods; pDevice->null_device.currentPeriodFramesRemainingPlayback = pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods; } return result; } ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount) { ma_result result = MA_SUCCESS; ma_uint32 totalPCMFramesProcessed; /* The device needs to be started immediately. */ if (!pDevice->null_device.isStarted) { result = ma_device_start__null(pDevice); if (result != MA_SUCCESS) { return result; } } /* Keep going until everything has been read. */ totalPCMFramesProcessed = 0; while (totalPCMFramesProcessed < frameCount) { ma_uint64 targetFrame; /* If there are any frames remaining in the current period, consume those first. */ if (pDevice->null_device.currentPeriodFramesRemainingCapture > 0) { ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed); ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingCapture; if (framesToProcess > framesRemaining) { framesToProcess = framesRemaining; } /* We need to ensured the output buffer is zeroed. */ ma_zero_memory(ma_offset_ptr(pPCMFrames, totalPCMFramesProcessed*bpf), framesToProcess*bpf); pDevice->null_device.currentPeriodFramesRemainingCapture -= framesToProcess; totalPCMFramesProcessed += framesToProcess; } /* If we've consumed the current period we'll need to mark it as such an ensure the device is started if it's not already. */ if (pDevice->null_device.currentPeriodFramesRemainingCapture == 0) { pDevice->null_device.currentPeriodFramesRemainingCapture = 0; } /* If we've consumed the whole buffer we can return now. */ ma_assert(totalPCMFramesProcessed <= frameCount); if (totalPCMFramesProcessed == frameCount) { break; } /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */ targetFrame = pDevice->null_device.lastProcessedFrameCapture + (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods); for (;;) { ma_uint64 currentFrame; /* Stop waiting if the device has been stopped. */ if (!pDevice->null_device.isStarted) { break; } currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice); if (currentFrame >= targetFrame) { break; } /* Getting here means we haven't yet reached the target sample, so continue waiting. */ ma_sleep(10); } pDevice->null_device.lastProcessedFrameCapture += pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods; pDevice->null_device.currentPeriodFramesRemainingCapture = pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods; } return result; } ma_result ma_context_uninit__null(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_null); (void)pContext; return MA_SUCCESS; } ma_result ma_context_init__null(const ma_context_config* pConfig, ma_context* pContext) { ma_assert(pContext != NULL); (void)pConfig; pContext->onUninit = ma_context_uninit__null; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__null; pContext->onEnumDevices = ma_context_enumerate_devices__null; pContext->onGetDeviceInfo = ma_context_get_device_info__null; pContext->onDeviceInit = ma_device_init__null; pContext->onDeviceUninit = ma_device_uninit__null; pContext->onDeviceStart = ma_device_start__null; pContext->onDeviceStop = ma_device_stop__null; pContext->onDeviceWrite = ma_device_write__null; pContext->onDeviceRead = ma_device_read__null; /* The null backend always works. */ return MA_SUCCESS; } #endif /******************************************************************************* WIN32 COMMON *******************************************************************************/ #if defined(MA_WIN32) #if defined(MA_WIN32_DESKTOP) #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) #define ma_CoUninitialize(pContext) ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)() #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) ((MA_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv) #define ma_CoTaskMemFree(pContext, pv) ((MA_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv) #define ma_PropVariantClear(pContext, pvar) ((MA_PFN_PropVariantClear)pContext->win32.PropVariantClear)(pvar) #else #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) CoInitializeEx(pvReserved, dwCoInit) #define ma_CoUninitialize(pContext) CoUninitialize() #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv) #define ma_CoTaskMemFree(pContext, pv) CoTaskMemFree(pv) #define ma_PropVariantClear(pContext, pvar) PropVariantClear(pvar) #endif #if !defined(MAXULONG_PTR) typedef size_t DWORD_PTR; #endif #if !defined(WAVE_FORMAT_44M08) #define WAVE_FORMAT_44M08 0x00000100 #define WAVE_FORMAT_44S08 0x00000200 #define WAVE_FORMAT_44M16 0x00000400 #define WAVE_FORMAT_44S16 0x00000800 #define WAVE_FORMAT_48M08 0x00001000 #define WAVE_FORMAT_48S08 0x00002000 #define WAVE_FORMAT_48M16 0x00004000 #define WAVE_FORMAT_48S16 0x00008000 #define WAVE_FORMAT_96M08 0x00010000 #define WAVE_FORMAT_96S08 0x00020000 #define WAVE_FORMAT_96M16 0x00040000 #define WAVE_FORMAT_96S16 0x00080000 #endif #ifndef SPEAKER_FRONT_LEFT #define SPEAKER_FRONT_LEFT 0x1 #define SPEAKER_FRONT_RIGHT 0x2 #define SPEAKER_FRONT_CENTER 0x4 #define SPEAKER_LOW_FREQUENCY 0x8 #define SPEAKER_BACK_LEFT 0x10 #define SPEAKER_BACK_RIGHT 0x20 #define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 #define SPEAKER_BACK_CENTER 0x100 #define SPEAKER_SIDE_LEFT 0x200 #define SPEAKER_SIDE_RIGHT 0x400 #define SPEAKER_TOP_CENTER 0x800 #define SPEAKER_TOP_FRONT_LEFT 0x1000 #define SPEAKER_TOP_FRONT_CENTER 0x2000 #define SPEAKER_TOP_FRONT_RIGHT 0x4000 #define SPEAKER_TOP_BACK_LEFT 0x8000 #define SPEAKER_TOP_BACK_CENTER 0x10000 #define SPEAKER_TOP_BACK_RIGHT 0x20000 #endif /* The SDK that comes with old versions of MSVC (VC6, for example) does not appear to define WAVEFORMATEXTENSIBLE. We define our own implementation in this case. */ #if (defined(_MSC_VER) && !defined(_WAVEFORMATEXTENSIBLE_)) || defined(__DMC__) typedef struct { WAVEFORMATEX Format; union { WORD wValidBitsPerSample; WORD wSamplesPerBlock; WORD wReserved; } Samples; DWORD dwChannelMask; GUID SubFormat; } WAVEFORMATEXTENSIBLE; #endif #ifndef WAVE_FORMAT_EXTENSIBLE #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #endif #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif GUID MA_GUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; /* Converts an individual Win32-style channel identifier (SPEAKER_FRONT_LEFT, etc.) to miniaudio. */ ma_uint8 ma_channel_id_to_ma__win32(DWORD id) { switch (id) { case SPEAKER_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT; case SPEAKER_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT; case SPEAKER_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER; case SPEAKER_LOW_FREQUENCY: return MA_CHANNEL_LFE; case SPEAKER_BACK_LEFT: return MA_CHANNEL_BACK_LEFT; case SPEAKER_BACK_RIGHT: return MA_CHANNEL_BACK_RIGHT; case SPEAKER_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER; case SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER; case SPEAKER_BACK_CENTER: return MA_CHANNEL_BACK_CENTER; case SPEAKER_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT; case SPEAKER_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT; case SPEAKER_TOP_CENTER: return MA_CHANNEL_TOP_CENTER; case SPEAKER_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT; case SPEAKER_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER; case SPEAKER_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT; case SPEAKER_TOP_BACK_LEFT: return MA_CHANNEL_TOP_BACK_LEFT; case SPEAKER_TOP_BACK_CENTER: return MA_CHANNEL_TOP_BACK_CENTER; case SPEAKER_TOP_BACK_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT; default: return 0; } } /* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to Win32-style. */ DWORD ma_channel_id_to_win32(DWORD id) { switch (id) { case MA_CHANNEL_MONO: return SPEAKER_FRONT_CENTER; case MA_CHANNEL_FRONT_LEFT: return SPEAKER_FRONT_LEFT; case MA_CHANNEL_FRONT_RIGHT: return SPEAKER_FRONT_RIGHT; case MA_CHANNEL_FRONT_CENTER: return SPEAKER_FRONT_CENTER; case MA_CHANNEL_LFE: return SPEAKER_LOW_FREQUENCY; case MA_CHANNEL_BACK_LEFT: return SPEAKER_BACK_LEFT; case MA_CHANNEL_BACK_RIGHT: return SPEAKER_BACK_RIGHT; case MA_CHANNEL_FRONT_LEFT_CENTER: return SPEAKER_FRONT_LEFT_OF_CENTER; case MA_CHANNEL_FRONT_RIGHT_CENTER: return SPEAKER_FRONT_RIGHT_OF_CENTER; case MA_CHANNEL_BACK_CENTER: return SPEAKER_BACK_CENTER; case MA_CHANNEL_SIDE_LEFT: return SPEAKER_SIDE_LEFT; case MA_CHANNEL_SIDE_RIGHT: return SPEAKER_SIDE_RIGHT; case MA_CHANNEL_TOP_CENTER: return SPEAKER_TOP_CENTER; case MA_CHANNEL_TOP_FRONT_LEFT: return SPEAKER_TOP_FRONT_LEFT; case MA_CHANNEL_TOP_FRONT_CENTER: return SPEAKER_TOP_FRONT_CENTER; case MA_CHANNEL_TOP_FRONT_RIGHT: return SPEAKER_TOP_FRONT_RIGHT; case MA_CHANNEL_TOP_BACK_LEFT: return SPEAKER_TOP_BACK_LEFT; case MA_CHANNEL_TOP_BACK_CENTER: return SPEAKER_TOP_BACK_CENTER; case MA_CHANNEL_TOP_BACK_RIGHT: return SPEAKER_TOP_BACK_RIGHT; default: return 0; } } /* Converts a channel mapping to a Win32-style channel mask. */ DWORD ma_channel_map_to_channel_mask__win32(const ma_channel channelMap[MA_MAX_CHANNELS], ma_uint32 channels) { DWORD dwChannelMask = 0; ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { dwChannelMask |= ma_channel_id_to_win32(channelMap[iChannel]); } return dwChannelMask; } /* Converts a Win32-style channel mask to a miniaudio channel map. */ void ma_channel_mask_to_channel_map__win32(DWORD dwChannelMask, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { if (channels == 1 && dwChannelMask == 0) { channelMap[0] = MA_CHANNEL_MONO; } else if (channels == 2 && dwChannelMask == 0) { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; } else { if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) { channelMap[0] = MA_CHANNEL_MONO; } else { /* Just iterate over each bit. */ ma_uint32 iChannel = 0; ma_uint32 iBit; for (iBit = 0; iBit < 32; ++iBit) { DWORD bitValue = (dwChannelMask & (1UL << iBit)); if (bitValue != 0) { /* The bit is set. */ channelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue); iChannel += 1; } } } } } #ifdef __cplusplus ma_bool32 ma_is_guid_equal(const void* a, const void* b) { return IsEqualGUID(*(const GUID*)a, *(const GUID*)b); } #else #define ma_is_guid_equal(a, b) IsEqualGUID((const GUID*)a, (const GUID*)b) #endif ma_format ma_format_from_WAVEFORMATEX(const WAVEFORMATEX* pWF) { ma_assert(pWF != NULL); if (pWF->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { const WAVEFORMATEXTENSIBLE* pWFEX = (const WAVEFORMATEXTENSIBLE*)pWF; if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_PCM)) { if (pWFEX->Samples.wValidBitsPerSample == 32) { return ma_format_s32; } if (pWFEX->Samples.wValidBitsPerSample == 24) { if (pWFEX->Format.wBitsPerSample == 32) { /*return ma_format_s24_32;*/ } if (pWFEX->Format.wBitsPerSample == 24) { return ma_format_s24; } } if (pWFEX->Samples.wValidBitsPerSample == 16) { return ma_format_s16; } if (pWFEX->Samples.wValidBitsPerSample == 8) { return ma_format_u8; } } if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { if (pWFEX->Samples.wValidBitsPerSample == 32) { return ma_format_f32; } /* if (pWFEX->Samples.wValidBitsPerSample == 64) { return ma_format_f64; } */ } } else { if (pWF->wFormatTag == WAVE_FORMAT_PCM) { if (pWF->wBitsPerSample == 32) { return ma_format_s32; } if (pWF->wBitsPerSample == 24) { return ma_format_s24; } if (pWF->wBitsPerSample == 16) { return ma_format_s16; } if (pWF->wBitsPerSample == 8) { return ma_format_u8; } } if (pWF->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { if (pWF->wBitsPerSample == 32) { return ma_format_f32; } if (pWF->wBitsPerSample == 64) { /*return ma_format_f64;*/ } } } return ma_format_unknown; } #endif /******************************************************************************* WASAPI Backend *******************************************************************************/ #ifdef MA_HAS_WASAPI #if 0 #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4091) /* 'typedef ': ignored on left of '' when no variable is declared */ #endif #include #include #if defined(_MSC_VER) #pragma warning(pop) #endif #endif /* 0 */ /* Some compilers don't define VerifyVersionInfoW. Need to write this ourselves. */ #define MA_WIN32_WINNT_VISTA 0x0600 #define MA_VER_MINORVERSION 0x01 #define MA_VER_MAJORVERSION 0x02 #define MA_VER_SERVICEPACKMAJOR 0x20 #define MA_VER_GREATER_EQUAL 0x03 typedef struct { DWORD dwOSVersionInfoSize; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwPlatformId; WCHAR szCSDVersion[128]; WORD wServicePackMajor; WORD wServicePackMinor; WORD wSuiteMask; BYTE wProductType; BYTE wReserved; } ma_OSVERSIONINFOEXW; typedef BOOL (WINAPI * ma_PFNVerifyVersionInfoW) (ma_OSVERSIONINFOEXW* lpVersionInfo, DWORD dwTypeMask, DWORDLONG dwlConditionMask); typedef ULONGLONG (WINAPI * ma_PFNVerSetConditionMask)(ULONGLONG dwlConditionMask, DWORD dwTypeBitMask, BYTE dwConditionMask); #ifndef PROPERTYKEY_DEFINED #define PROPERTYKEY_DEFINED typedef struct { GUID fmtid; DWORD pid; } PROPERTYKEY; #endif /* Some compilers don't define PropVariantInit(). We just do this ourselves since it's just a memset(). */ static MA_INLINE void ma_PropVariantInit(PROPVARIANT* pProp) { ma_zero_object(pProp); } const PROPERTYKEY MA_PKEY_Device_FriendlyName = {{0xA45C254E, 0xDF1C, 0x4EFD, {0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0}}, 14}; const PROPERTYKEY MA_PKEY_AudioEngine_DeviceFormat = {{0xF19F064D, 0x82C, 0x4E27, {0xBC, 0x73, 0x68, 0x82, 0xA1, 0xBB, 0x8E, 0x4C}}, 0}; const IID MA_IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; /* 00000000-0000-0000-C000-000000000046 */ const IID MA_IID_IAgileObject = {0x94EA2B94, 0xE9CC, 0x49E0, {0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90}}; /* 94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90 */ const IID MA_IID_IAudioClient = {0x1CB9AD4C, 0xDBFA, 0x4C32, {0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}}; /* 1CB9AD4C-DBFA-4C32-B178-C2F568A703B2 = __uuidof(IAudioClient) */ const IID MA_IID_IAudioClient2 = {0x726778CD, 0xF60A, 0x4EDA, {0x82, 0xDE, 0xE4, 0x76, 0x10, 0xCD, 0x78, 0xAA}}; /* 726778CD-F60A-4EDA-82DE-E47610CD78AA = __uuidof(IAudioClient2) */ const IID MA_IID_IAudioClient3 = {0x7ED4EE07, 0x8E67, 0x4CD4, {0x8C, 0x1A, 0x2B, 0x7A, 0x59, 0x87, 0xAD, 0x42}}; /* 7ED4EE07-8E67-4CD4-8C1A-2B7A5987AD42 = __uuidof(IAudioClient3) */ const IID MA_IID_IAudioRenderClient = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; /* F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) */ const IID MA_IID_IAudioCaptureClient = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; /* C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) */ const IID MA_IID_IMMNotificationClient = {0x7991EEC9, 0x7E89, 0x4D85, {0x83, 0x90, 0x6C, 0x70, 0x3C, 0xEC, 0x60, 0xC0}}; /* 7991EEC9-7E89-4D85-8390-6C703CEC60C0 = __uuidof(IMMNotificationClient) */ #ifndef MA_WIN32_DESKTOP const IID MA_IID_DEVINTERFACE_AUDIO_RENDER = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; /* E6327CAD-DCEC-4949-AE8A-991E976A79D2 */ const IID MA_IID_DEVINTERFACE_AUDIO_CAPTURE = {0x2EEF81BE, 0x33FA, 0x4800, {0x96, 0x70, 0x1C, 0xD4, 0x74, 0x97, 0x2C, 0x3F}}; /* 2EEF81BE-33FA-4800-9670-1CD474972C3F */ const IID MA_IID_IActivateAudioInterfaceCompletionHandler = {0x41D949AB, 0x9862, 0x444A, {0x80, 0xF6, 0xC2, 0x61, 0x33, 0x4D, 0xA5, 0xEB}}; /* 41D949AB-9862-444A-80F6-C261334DA5EB */ #endif const IID MA_CLSID_MMDeviceEnumerator_Instance = {0xBCDE0395, 0xE52F, 0x467C, {0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E}}; /* BCDE0395-E52F-467C-8E3D-C4579291692E = __uuidof(MMDeviceEnumerator) */ const IID MA_IID_IMMDeviceEnumerator_Instance = {0xA95664D2, 0x9614, 0x4F35, {0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6}}; /* A95664D2-9614-4F35-A746-DE8DB63617E6 = __uuidof(IMMDeviceEnumerator) */ #ifdef __cplusplus #define MA_CLSID_MMDeviceEnumerator MA_CLSID_MMDeviceEnumerator_Instance #define MA_IID_IMMDeviceEnumerator MA_IID_IMMDeviceEnumerator_Instance #else #define MA_CLSID_MMDeviceEnumerator &MA_CLSID_MMDeviceEnumerator_Instance #define MA_IID_IMMDeviceEnumerator &MA_IID_IMMDeviceEnumerator_Instance #endif typedef struct ma_IUnknown ma_IUnknown; #ifdef MA_WIN32_DESKTOP #define MA_MM_DEVICE_STATE_ACTIVE 1 #define MA_MM_DEVICE_STATE_DISABLED 2 #define MA_MM_DEVICE_STATE_NOTPRESENT 4 #define MA_MM_DEVICE_STATE_UNPLUGGED 8 typedef struct ma_IMMDeviceEnumerator ma_IMMDeviceEnumerator; typedef struct ma_IMMDeviceCollection ma_IMMDeviceCollection; typedef struct ma_IMMDevice ma_IMMDevice; #else typedef struct ma_IActivateAudioInterfaceCompletionHandler ma_IActivateAudioInterfaceCompletionHandler; typedef struct ma_IActivateAudioInterfaceAsyncOperation ma_IActivateAudioInterfaceAsyncOperation; #endif typedef struct ma_IPropertyStore ma_IPropertyStore; typedef struct ma_IAudioClient ma_IAudioClient; typedef struct ma_IAudioClient2 ma_IAudioClient2; typedef struct ma_IAudioClient3 ma_IAudioClient3; typedef struct ma_IAudioRenderClient ma_IAudioRenderClient; typedef struct ma_IAudioCaptureClient ma_IAudioCaptureClient; typedef ma_int64 MA_REFERENCE_TIME; #define MA_AUDCLNT_STREAMFLAGS_CROSSPROCESS 0x00010000 #define MA_AUDCLNT_STREAMFLAGS_LOOPBACK 0x00020000 #define MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK 0x00040000 #define MA_AUDCLNT_STREAMFLAGS_NOPERSIST 0x00080000 #define MA_AUDCLNT_STREAMFLAGS_RATEADJUST 0x00100000 #define MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000 #define MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000 #define MA_AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED 0x10000000 #define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE 0x20000000 #define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED 0x40000000 /* We only care about a few error codes. */ #define MA_AUDCLNT_E_INVALID_DEVICE_PERIOD (-2004287456) #define MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED (-2004287463) #define MA_AUDCLNT_S_BUFFER_EMPTY (143196161) #define MA_AUDCLNT_E_DEVICE_IN_USE (-2004287478) typedef enum { ma_eRender = 0, ma_eCapture = 1, ma_eAll = 2 } ma_EDataFlow; typedef enum { ma_eConsole = 0, ma_eMultimedia = 1, ma_eCommunications = 2 } ma_ERole; typedef enum { MA_AUDCLNT_SHAREMODE_SHARED, MA_AUDCLNT_SHAREMODE_EXCLUSIVE } MA_AUDCLNT_SHAREMODE; typedef enum { MA_AudioCategory_Other = 0 /* <-- miniaudio is only caring about Other. */ } MA_AUDIO_STREAM_CATEGORY; typedef struct { UINT32 cbSize; BOOL bIsOffload; MA_AUDIO_STREAM_CATEGORY eCategory; } ma_AudioClientProperties; /* IUnknown */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IUnknown* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IUnknown* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IUnknown* pThis); } ma_IUnknownVtbl; struct ma_IUnknown { ma_IUnknownVtbl* lpVtbl; }; HRESULT ma_IUnknown_QueryInterface(ma_IUnknown* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IUnknown_AddRef(ma_IUnknown* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IUnknown_Release(ma_IUnknown* pThis) { return pThis->lpVtbl->Release(pThis); } #ifdef MA_WIN32_DESKTOP /* IMMNotificationClient */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMNotificationClient* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IMMNotificationClient* pThis); /* IMMNotificationClient */ HRESULT (STDMETHODCALLTYPE * OnDeviceStateChanged) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState); HRESULT (STDMETHODCALLTYPE * OnDeviceAdded) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID); HRESULT (STDMETHODCALLTYPE * OnDeviceRemoved) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID); HRESULT (STDMETHODCALLTYPE * OnDefaultDeviceChanged)(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID); HRESULT (STDMETHODCALLTYPE * OnPropertyValueChanged)(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key); } ma_IMMNotificationClientVtbl; /* IMMDeviceEnumerator */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDeviceEnumerator* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDeviceEnumerator* pThis); /* IMMDeviceEnumerator */ HRESULT (STDMETHODCALLTYPE * EnumAudioEndpoints) (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, DWORD dwStateMask, ma_IMMDeviceCollection** ppDevices); HRESULT (STDMETHODCALLTYPE * GetDefaultAudioEndpoint) (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, ma_ERole role, ma_IMMDevice** ppEndpoint); HRESULT (STDMETHODCALLTYPE * GetDevice) (ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice); HRESULT (STDMETHODCALLTYPE * RegisterEndpointNotificationCallback) (ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient); HRESULT (STDMETHODCALLTYPE * UnregisterEndpointNotificationCallback)(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient); } ma_IMMDeviceEnumeratorVtbl; struct ma_IMMDeviceEnumerator { ma_IMMDeviceEnumeratorVtbl* lpVtbl; }; HRESULT ma_IMMDeviceEnumerator_QueryInterface(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IMMDeviceEnumerator_AddRef(ma_IMMDeviceEnumerator* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IMMDeviceEnumerator_Release(ma_IMMDeviceEnumerator* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IMMDeviceEnumerator_EnumAudioEndpoints(ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, DWORD dwStateMask, ma_IMMDeviceCollection** ppDevices) { return pThis->lpVtbl->EnumAudioEndpoints(pThis, dataFlow, dwStateMask, ppDevices); } HRESULT ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, ma_ERole role, ma_IMMDevice** ppEndpoint) { return pThis->lpVtbl->GetDefaultAudioEndpoint(pThis, dataFlow, role, ppEndpoint); } HRESULT ma_IMMDeviceEnumerator_GetDevice(ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice) { return pThis->lpVtbl->GetDevice(pThis, pID, ppDevice); } HRESULT ma_IMMDeviceEnumerator_RegisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->RegisterEndpointNotificationCallback(pThis, pClient); } HRESULT ma_IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->UnregisterEndpointNotificationCallback(pThis, pClient); } /* IMMDeviceCollection */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDeviceCollection* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDeviceCollection* pThis); /* IMMDeviceCollection */ HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IMMDeviceCollection* pThis, UINT* pDevices); HRESULT (STDMETHODCALLTYPE * Item) (ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice); } ma_IMMDeviceCollectionVtbl; struct ma_IMMDeviceCollection { ma_IMMDeviceCollectionVtbl* lpVtbl; }; HRESULT ma_IMMDeviceCollection_QueryInterface(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IMMDeviceCollection_AddRef(ma_IMMDeviceCollection* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IMMDeviceCollection_Release(ma_IMMDeviceCollection* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IMMDeviceCollection_GetCount(ma_IMMDeviceCollection* pThis, UINT* pDevices) { return pThis->lpVtbl->GetCount(pThis, pDevices); } HRESULT ma_IMMDeviceCollection_Item(ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice) { return pThis->lpVtbl->Item(pThis, nDevice, ppDevice); } /* IMMDevice */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDevice* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDevice* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDevice* pThis); /* IMMDevice */ HRESULT (STDMETHODCALLTYPE * Activate) (ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, PROPVARIANT* pActivationParams, void** ppInterface); HRESULT (STDMETHODCALLTYPE * OpenPropertyStore)(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties); HRESULT (STDMETHODCALLTYPE * GetId) (ma_IMMDevice* pThis, LPWSTR *pID); HRESULT (STDMETHODCALLTYPE * GetState) (ma_IMMDevice* pThis, DWORD *pState); } ma_IMMDeviceVtbl; struct ma_IMMDevice { ma_IMMDeviceVtbl* lpVtbl; }; HRESULT ma_IMMDevice_QueryInterface(ma_IMMDevice* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IMMDevice_AddRef(ma_IMMDevice* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IMMDevice_Release(ma_IMMDevice* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IMMDevice_Activate(ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, PROPVARIANT* pActivationParams, void** ppInterface) { return pThis->lpVtbl->Activate(pThis, iid, dwClsCtx, pActivationParams, ppInterface); } HRESULT ma_IMMDevice_OpenPropertyStore(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties) { return pThis->lpVtbl->OpenPropertyStore(pThis, stgmAccess, ppProperties); } HRESULT ma_IMMDevice_GetId(ma_IMMDevice* pThis, LPWSTR *pID) { return pThis->lpVtbl->GetId(pThis, pID); } HRESULT ma_IMMDevice_GetState(ma_IMMDevice* pThis, DWORD *pState) { return pThis->lpVtbl->GetState(pThis, pState); } #else /* IActivateAudioInterfaceAsyncOperation */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IActivateAudioInterfaceAsyncOperation* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IActivateAudioInterfaceAsyncOperation* pThis); /* IActivateAudioInterfaceAsyncOperation */ HRESULT (STDMETHODCALLTYPE * GetActivateResult)(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface); } ma_IActivateAudioInterfaceAsyncOperationVtbl; struct ma_IActivateAudioInterfaceAsyncOperation { ma_IActivateAudioInterfaceAsyncOperationVtbl* lpVtbl; }; HRESULT ma_IActivateAudioInterfaceAsyncOperation_QueryInterface(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IActivateAudioInterfaceAsyncOperation_AddRef(ma_IActivateAudioInterfaceAsyncOperation* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IActivateAudioInterfaceAsyncOperation_Release(ma_IActivateAudioInterfaceAsyncOperation* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface) { return pThis->lpVtbl->GetActivateResult(pThis, pActivateResult, ppActivatedInterface); } #endif /* IPropertyStore */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IPropertyStore* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IPropertyStore* pThis); /* IPropertyStore */ HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IPropertyStore* pThis, DWORD* pPropCount); HRESULT (STDMETHODCALLTYPE * GetAt) (ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey); HRESULT (STDMETHODCALLTYPE * GetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar); HRESULT (STDMETHODCALLTYPE * SetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const PROPVARIANT* const pPropVar); HRESULT (STDMETHODCALLTYPE * Commit) (ma_IPropertyStore* pThis); } ma_IPropertyStoreVtbl; struct ma_IPropertyStore { ma_IPropertyStoreVtbl* lpVtbl; }; HRESULT ma_IPropertyStore_QueryInterface(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IPropertyStore_AddRef(ma_IPropertyStore* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IPropertyStore_Release(ma_IPropertyStore* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IPropertyStore_GetCount(ma_IPropertyStore* pThis, DWORD* pPropCount) { return pThis->lpVtbl->GetCount(pThis, pPropCount); } HRESULT ma_IPropertyStore_GetAt(ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey) { return pThis->lpVtbl->GetAt(pThis, propIndex, pPropKey); } HRESULT ma_IPropertyStore_GetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar) { return pThis->lpVtbl->GetValue(pThis, pKey, pPropVar); } HRESULT ma_IPropertyStore_SetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const PROPVARIANT* const pPropVar) { return pThis->lpVtbl->SetValue(pThis, pKey, pPropVar); } HRESULT ma_IPropertyStore_Commit(ma_IPropertyStore* pThis) { return pThis->lpVtbl->Commit(pThis); } /* IAudioClient */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient* pThis); /* IAudioClient */ HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames); HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency); HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames); HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch); HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat); HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient* pThis); HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient* pThis); HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient* pThis); HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient* pThis, HANDLE eventHandle); HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient* pThis, const IID* const riid, void** pp); } ma_IAudioClientVtbl; struct ma_IAudioClient { ma_IAudioClientVtbl* lpVtbl; }; HRESULT ma_IAudioClient_QueryInterface(ma_IAudioClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IAudioClient_AddRef(ma_IAudioClient* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IAudioClient_Release(ma_IAudioClient* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IAudioClient_Initialize(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } HRESULT ma_IAudioClient_GetBufferSize(ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); } HRESULT ma_IAudioClient_GetStreamLatency(ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); } HRESULT ma_IAudioClient_GetCurrentPadding(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); } HRESULT ma_IAudioClient_IsFormatSupported(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } HRESULT ma_IAudioClient_GetMixFormat(ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } HRESULT ma_IAudioClient_GetDevicePeriod(ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); } HRESULT ma_IAudioClient_Start(ma_IAudioClient* pThis) { return pThis->lpVtbl->Start(pThis); } HRESULT ma_IAudioClient_Stop(ma_IAudioClient* pThis) { return pThis->lpVtbl->Stop(pThis); } HRESULT ma_IAudioClient_Reset(ma_IAudioClient* pThis) { return pThis->lpVtbl->Reset(pThis); } HRESULT ma_IAudioClient_SetEventHandle(ma_IAudioClient* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); } HRESULT ma_IAudioClient_GetService(ma_IAudioClient* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); } /* IAudioClient2 */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient2* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient2* pThis); /* IAudioClient */ HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames); HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency); HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames); HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch); HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat); HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient2* pThis); HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient2* pThis); HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient2* pThis); HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient2* pThis, HANDLE eventHandle); HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient2* pThis, const IID* const riid, void** pp); /* IAudioClient2 */ HRESULT (STDMETHODCALLTYPE * IsOffloadCapable) (ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable); HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties); HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient2* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration); } ma_IAudioClient2Vtbl; struct ma_IAudioClient2 { ma_IAudioClient2Vtbl* lpVtbl; }; HRESULT ma_IAudioClient2_QueryInterface(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IAudioClient2_AddRef(ma_IAudioClient2* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IAudioClient2_Release(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IAudioClient2_Initialize(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } HRESULT ma_IAudioClient2_GetBufferSize(ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); } HRESULT ma_IAudioClient2_GetStreamLatency(ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); } HRESULT ma_IAudioClient2_GetCurrentPadding(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); } HRESULT ma_IAudioClient2_IsFormatSupported(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } HRESULT ma_IAudioClient2_GetMixFormat(ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } HRESULT ma_IAudioClient2_GetDevicePeriod(ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); } HRESULT ma_IAudioClient2_Start(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Start(pThis); } HRESULT ma_IAudioClient2_Stop(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Stop(pThis); } HRESULT ma_IAudioClient2_Reset(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Reset(pThis); } HRESULT ma_IAudioClient2_SetEventHandle(ma_IAudioClient2* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); } HRESULT ma_IAudioClient2_GetService(ma_IAudioClient2* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); } HRESULT ma_IAudioClient2_IsOffloadCapable(ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); } HRESULT ma_IAudioClient2_SetClientProperties(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties) { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); } HRESULT ma_IAudioClient2_GetBufferSizeLimits(ma_IAudioClient2* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration) { return pThis->lpVtbl->GetBufferSizeLimits(pThis, pFormat, eventDriven, pMinBufferDuration, pMaxBufferDuration); } /* IAudioClient3 */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient3* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient3* pThis); /* IAudioClient */ HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames); HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency); HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames); HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch); HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat); HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient3* pThis); HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient3* pThis); HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient3* pThis); HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient3* pThis, HANDLE eventHandle); HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient3* pThis, const IID* const riid, void** pp); /* IAudioClient2 */ HRESULT (STDMETHODCALLTYPE * IsOffloadCapable) (ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable); HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties); HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration); /* IAudioClient3 */ HRESULT (STDMETHODCALLTYPE * GetSharedModeEnginePeriod) (ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, UINT32* pDefaultPeriodInFrames, UINT32* pFundamentalPeriodInFrames, UINT32* pMinPeriodInFrames, UINT32* pMaxPeriodInFrames); HRESULT (STDMETHODCALLTYPE * GetCurrentSharedModeEnginePeriod)(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, UINT32* pCurrentPeriodInFrames); HRESULT (STDMETHODCALLTYPE * InitializeSharedAudioStream) (ma_IAudioClient3* pThis, DWORD streamFlags, UINT32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid); } ma_IAudioClient3Vtbl; struct ma_IAudioClient3 { ma_IAudioClient3Vtbl* lpVtbl; }; HRESULT ma_IAudioClient3_QueryInterface(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IAudioClient3_AddRef(ma_IAudioClient3* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IAudioClient3_Release(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IAudioClient3_Initialize(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); } HRESULT ma_IAudioClient3_GetBufferSize(ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); } HRESULT ma_IAudioClient3_GetStreamLatency(ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); } HRESULT ma_IAudioClient3_GetCurrentPadding(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); } HRESULT ma_IAudioClient3_IsFormatSupported(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); } HRESULT ma_IAudioClient3_GetMixFormat(ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); } HRESULT ma_IAudioClient3_GetDevicePeriod(ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); } HRESULT ma_IAudioClient3_Start(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Start(pThis); } HRESULT ma_IAudioClient3_Stop(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Stop(pThis); } HRESULT ma_IAudioClient3_Reset(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Reset(pThis); } HRESULT ma_IAudioClient3_SetEventHandle(ma_IAudioClient3* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); } HRESULT ma_IAudioClient3_GetService(ma_IAudioClient3* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); } HRESULT ma_IAudioClient3_IsOffloadCapable(ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); } HRESULT ma_IAudioClient3_SetClientProperties(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties) { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); } HRESULT ma_IAudioClient3_GetBufferSizeLimits(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration) { return pThis->lpVtbl->GetBufferSizeLimits(pThis, pFormat, eventDriven, pMinBufferDuration, pMaxBufferDuration); } HRESULT ma_IAudioClient3_GetSharedModeEnginePeriod(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, UINT32* pDefaultPeriodInFrames, UINT32* pFundamentalPeriodInFrames, UINT32* pMinPeriodInFrames, UINT32* pMaxPeriodInFrames) { return pThis->lpVtbl->GetSharedModeEnginePeriod(pThis, pFormat, pDefaultPeriodInFrames, pFundamentalPeriodInFrames, pMinPeriodInFrames, pMaxPeriodInFrames); } HRESULT ma_IAudioClient3_GetCurrentSharedModeEnginePeriod(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, UINT32* pCurrentPeriodInFrames) { return pThis->lpVtbl->GetCurrentSharedModeEnginePeriod(pThis, ppFormat, pCurrentPeriodInFrames); } HRESULT ma_IAudioClient3_InitializeSharedAudioStream(ma_IAudioClient3* pThis, DWORD streamFlags, UINT32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGUID) { return pThis->lpVtbl->InitializeSharedAudioStream(pThis, streamFlags, periodInFrames, pFormat, pAudioSessionGUID); } /* IAudioRenderClient */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioRenderClient* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioRenderClient* pThis); /* IAudioRenderClient */ HRESULT (STDMETHODCALLTYPE * GetBuffer) (ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData); HRESULT (STDMETHODCALLTYPE * ReleaseBuffer)(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags); } ma_IAudioRenderClientVtbl; struct ma_IAudioRenderClient { ma_IAudioRenderClientVtbl* lpVtbl; }; HRESULT ma_IAudioRenderClient_QueryInterface(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IAudioRenderClient_AddRef(ma_IAudioRenderClient* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IAudioRenderClient_Release(ma_IAudioRenderClient* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IAudioRenderClient_GetBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData) { return pThis->lpVtbl->GetBuffer(pThis, numFramesRequested, ppData); } HRESULT ma_IAudioRenderClient_ReleaseBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesWritten, dwFlags); } /* IAudioCaptureClient */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioCaptureClient* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioCaptureClient* pThis); /* IAudioRenderClient */ HRESULT (STDMETHODCALLTYPE * GetBuffer) (ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition); HRESULT (STDMETHODCALLTYPE * ReleaseBuffer) (ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead); HRESULT (STDMETHODCALLTYPE * GetNextPacketSize)(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket); } ma_IAudioCaptureClientVtbl; struct ma_IAudioCaptureClient { ma_IAudioCaptureClientVtbl* lpVtbl; }; HRESULT ma_IAudioCaptureClient_QueryInterface(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IAudioCaptureClient_AddRef(ma_IAudioCaptureClient* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IAudioCaptureClient_Release(ma_IAudioCaptureClient* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IAudioCaptureClient_GetBuffer(ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition) { return pThis->lpVtbl->GetBuffer(pThis, ppData, pNumFramesToRead, pFlags, pDevicePosition, pQPCPosition); } HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesRead); } HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket) { return pThis->lpVtbl->GetNextPacketSize(pThis, pNumFramesInNextPacket); } #ifndef MA_WIN32_DESKTOP #include typedef struct ma_completion_handler_uwp ma_completion_handler_uwp; typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_completion_handler_uwp* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_completion_handler_uwp* pThis); /* IActivateAudioInterfaceCompletionHandler */ HRESULT (STDMETHODCALLTYPE * ActivateCompleted)(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation); } ma_completion_handler_uwp_vtbl; struct ma_completion_handler_uwp { ma_completion_handler_uwp_vtbl* lpVtbl; ma_uint32 counter; HANDLE hEvent; }; HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject) { /* We need to "implement" IAgileObject which is just an indicator that's used internally by WASAPI for some multithreading management. To "implement" this, we just make sure we return pThis when the IAgileObject is requested. */ if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IActivateAudioInterfaceCompletionHandler) && !ma_is_guid_equal(riid, &MA_IID_IAgileObject)) { *ppObject = NULL; return E_NOINTERFACE; } /* Getting here means the IID is IUnknown or IMMNotificationClient. */ *ppObject = (void*)pThis; ((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis); return S_OK; } ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_AddRef(ma_completion_handler_uwp* pThis) { return (ULONG)ma_atomic_increment_32(&pThis->counter); } ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_Release(ma_completion_handler_uwp* pThis) { ma_uint32 newRefCount = ma_atomic_decrement_32(&pThis->counter); if (newRefCount == 0) { return 0; /* We don't free anything here because we never allocate the object on the heap. */ } return (ULONG)newRefCount; } HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_ActivateCompleted(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation) { (void)pActivateOperation; SetEvent(pThis->hEvent); return S_OK; } static ma_completion_handler_uwp_vtbl g_maCompletionHandlerVtblInstance = { ma_completion_handler_uwp_QueryInterface, ma_completion_handler_uwp_AddRef, ma_completion_handler_uwp_Release, ma_completion_handler_uwp_ActivateCompleted }; ma_result ma_completion_handler_uwp_init(ma_completion_handler_uwp* pHandler) { ma_assert(pHandler != NULL); ma_zero_object(pHandler); pHandler->lpVtbl = &g_maCompletionHandlerVtblInstance; pHandler->counter = 1; pHandler->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); if (pHandler->hEvent == NULL) { return MA_ERROR; } return MA_SUCCESS; } void ma_completion_handler_uwp_uninit(ma_completion_handler_uwp* pHandler) { if (pHandler->hEvent != NULL) { CloseHandle(pHandler->hEvent); } } void ma_completion_handler_uwp_wait(ma_completion_handler_uwp* pHandler) { WaitForSingleObject(pHandler->hEvent, INFINITE); } #endif /* !MA_WIN32_DESKTOP */ /* We need a virtual table for our notification client object that's used for detecting changes to the default device. */ #ifdef MA_WIN32_DESKTOP HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject) { /* We care about two interfaces - IUnknown and IMMNotificationClient. If the requested IID is something else we just return E_NOINTERFACE. Otherwise we need to increment the reference counter and return S_OK. */ if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IMMNotificationClient)) { *ppObject = NULL; return E_NOINTERFACE; } /* Getting here means the IID is IUnknown or IMMNotificationClient. */ *ppObject = (void*)pThis; ((ma_IMMNotificationClientVtbl*)pThis->lpVtbl)->AddRef(pThis); return S_OK; } ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_AddRef(ma_IMMNotificationClient* pThis) { return (ULONG)ma_atomic_increment_32(&pThis->counter); } ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_Release(ma_IMMNotificationClient* pThis) { ma_uint32 newRefCount = ma_atomic_decrement_32(&pThis->counter); if (newRefCount == 0) { return 0; /* We don't free anything here because we never allocate the object on the heap. */ } return (ULONG)newRefCount; } HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState) { #ifdef MA_DEBUG_OUTPUT printf("IMMNotificationClient_OnDeviceStateChanged(pDeviceID=%S, dwNewState=%u)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)", (unsigned int)dwNewState); #endif (void)pThis; (void)pDeviceID; (void)dwNewState; return S_OK; } HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID) { #ifdef MA_DEBUG_OUTPUT printf("IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)"); #endif /* We don't need to worry about this event for our purposes. */ (void)pThis; (void)pDeviceID; return S_OK; } HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID) { #ifdef MA_DEBUG_OUTPUT printf("IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)"); #endif /* We don't need to worry about this event for our purposes. */ (void)pThis; (void)pDeviceID; return S_OK; } HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID) { #ifdef MA_DEBUG_OUTPUT printf("IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role, (pDefaultDeviceID != NULL) ? pDefaultDeviceID : L"(NULL)"); #endif /* We only ever use the eConsole role in miniaudio. */ if (role != ma_eConsole) { return S_OK; } /* We only care about devices with the same data flow and role as the current device. */ if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) || (pThis->pDevice->type == ma_device_type_capture && dataFlow != ma_eCapture)) { return S_OK; } /* Not currently supporting automatic stream routing in exclusive mode. This is not working correctly on my machine due to AUDCLNT_E_DEVICE_IN_USE errors when reinitializing the device. If this is a bug in miniaudio, we can try re-enabling this once it's fixed. */ if ((dataFlow == ma_eRender && pThis->pDevice->playback.shareMode == ma_share_mode_exclusive) || (dataFlow == ma_eCapture && pThis->pDevice->capture.shareMode == ma_share_mode_exclusive)) { return S_OK; } /* We don't change the device here - we change it in the worker thread to keep synchronization simple. To do this I'm just setting a flag to indicate that the default device has changed. */ if (dataFlow == ma_eRender) { ma_atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultPlaybackDeviceChanged, MA_TRUE); } if (dataFlow == ma_eCapture) { ma_atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultCaptureDeviceChanged, MA_TRUE); } (void)pDefaultDeviceID; return S_OK; } HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key) { #ifdef MA_DEBUG_OUTPUT printf("IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)"); #endif (void)pThis; (void)pDeviceID; (void)key; return S_OK; } static ma_IMMNotificationClientVtbl g_maNotificationCientVtbl = { ma_IMMNotificationClient_QueryInterface, ma_IMMNotificationClient_AddRef, ma_IMMNotificationClient_Release, ma_IMMNotificationClient_OnDeviceStateChanged, ma_IMMNotificationClient_OnDeviceAdded, ma_IMMNotificationClient_OnDeviceRemoved, ma_IMMNotificationClient_OnDefaultDeviceChanged, ma_IMMNotificationClient_OnPropertyValueChanged }; #endif /* MA_WIN32_DESKTOP */ #ifdef MA_WIN32_DESKTOP typedef ma_IMMDevice ma_WASAPIDeviceInterface; #else typedef ma_IUnknown ma_WASAPIDeviceInterface; #endif ma_bool32 ma_context_is_device_id_equal__wasapi(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return memcmp(pID0->wasapi, pID1->wasapi, sizeof(pID0->wasapi)) == 0; } void ma_set_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, ma_device_info* pInfo) { ma_assert(pWF != NULL); ma_assert(pInfo != NULL); pInfo->formatCount = 1; pInfo->formats[0] = ma_format_from_WAVEFORMATEX(pWF); pInfo->minChannels = pWF->nChannels; pInfo->maxChannels = pWF->nChannels; pInfo->minSampleRate = pWF->nSamplesPerSec; pInfo->maxSampleRate = pWF->nSamplesPerSec; } ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context* pContext, /*ma_IMMDevice**/void* pMMDevice, ma_IAudioClient* pAudioClient, ma_share_mode shareMode, ma_device_info* pInfo) { ma_assert(pAudioClient != NULL); ma_assert(pInfo != NULL); /* We use a different technique to retrieve the device information depending on whether or not we are using shared or exclusive mode. */ if (shareMode == ma_share_mode_shared) { /* Shared Mode. We use GetMixFormat() here. */ WAVEFORMATEX* pWF = NULL; HRESULT hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (WAVEFORMATEX**)&pWF); if (SUCCEEDED(hr)) { ma_set_device_info_from_WAVEFORMATEX(pWF, pInfo); return MA_SUCCESS; } else { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } else { /* Exlcusive Mode. We repeatedly call IsFormatSupported() here. This is not currently support on UWP. */ #ifdef MA_WIN32_DESKTOP /* The first thing to do is get the format from PKEY_AudioEngine_DeviceFormat. This should give us a channel count we assume is correct which will simplify our searching. */ ma_IPropertyStore *pProperties; HRESULT hr = ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice, STGM_READ, &pProperties); if (SUCCEEDED(hr)) { PROPVARIANT var; ma_PropVariantInit(&var); hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_AudioEngine_DeviceFormat, &var); if (SUCCEEDED(hr)) { WAVEFORMATEX* pWF = (WAVEFORMATEX*)var.blob.pBlobData; ma_set_device_info_from_WAVEFORMATEX(pWF, pInfo); /* In my testing, the format returned by PKEY_AudioEngine_DeviceFormat is suitable for exclusive mode so we check this format first. If this fails, fall back to a search. */ hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pWF, NULL); ma_PropVariantClear(pContext, &var); if (FAILED(hr)) { /* The format returned by PKEY_AudioEngine_DeviceFormat is not supported, so fall back to a search. We assume the channel count returned by MA_PKEY_AudioEngine_DeviceFormat is valid and correct. For simplicity we're only returning one format. */ ma_uint32 channels = pInfo->minChannels; ma_format formatsToSearch[] = { ma_format_s16, ma_format_s24, /*ma_format_s24_32,*/ ma_format_f32, ma_format_s32, ma_format_u8 }; ma_channel defaultChannelMap[MA_MAX_CHANNELS]; WAVEFORMATEXTENSIBLE wf; ma_bool32 found; ma_uint32 iFormat; ma_get_standard_channel_map(ma_standard_channel_map_microsoft, channels, defaultChannelMap); ma_zero_object(&wf); wf.Format.cbSize = sizeof(wf); wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wf.Format.nChannels = (WORD)channels; wf.dwChannelMask = ma_channel_map_to_channel_mask__win32(defaultChannelMap, channels); found = MA_FALSE; for (iFormat = 0; iFormat < ma_countof(formatsToSearch); ++iFormat) { ma_format format = formatsToSearch[iFormat]; ma_uint32 iSampleRate; wf.Format.wBitsPerSample = (WORD)ma_get_bytes_per_sample(format)*8; wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; wf.Samples.wValidBitsPerSample = /*(format == ma_format_s24_32) ? 24 :*/ wf.Format.wBitsPerSample; if (format == ma_format_f32) { wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; } else { wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM; } for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iSampleRate) { wf.Format.nSamplesPerSec = g_maStandardSampleRatePriorities[iSampleRate]; hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wf, NULL); if (SUCCEEDED(hr)) { ma_set_device_info_from_WAVEFORMATEX((WAVEFORMATEX*)&wf, pInfo); found = MA_TRUE; break; } } if (found) { break; } } if (!found) { ma_IPropertyStore_Release(pProperties); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to find suitable device format for device info retrieval.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } } else { ma_IPropertyStore_Release(pProperties); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve device format for device info retrieval.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } else { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to open property store for device info retrieval.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } return MA_SUCCESS; #else /* Exclusive mode not fully supported in UWP right now. */ return MA_ERROR; #endif } } #ifdef MA_WIN32_DESKTOP ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IMMDevice** ppMMDevice) { ma_IMMDeviceEnumerator* pDeviceEnumerator; HRESULT hr; ma_assert(pContext != NULL); ma_assert(ppMMDevice != NULL); hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.", MA_FAILED_TO_INIT_BACKEND); } if (pDeviceID == NULL) { hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, (deviceType == ma_device_type_playback) ? ma_eRender : ma_eCapture, ma_eConsole, ppMMDevice); } else { hr = ma_IMMDeviceEnumerator_GetDevice(pDeviceEnumerator, pDeviceID->wasapi, ppMMDevice); } ma_IMMDeviceEnumerator_Release(pDeviceEnumerator); if (FAILED(hr)) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } return MA_SUCCESS; } ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, ma_share_mode shareMode, ma_bool32 onlySimpleInfo, ma_device_info* pInfo) { LPWSTR id; HRESULT hr; ma_assert(pContext != NULL); ma_assert(pMMDevice != NULL); ma_assert(pInfo != NULL); /* ID. */ hr = ma_IMMDevice_GetId(pMMDevice, &id); if (SUCCEEDED(hr)) { size_t idlen = wcslen(id); if (idlen+1 > ma_countof(pInfo->id.wasapi)) { ma_CoTaskMemFree(pContext, id); ma_assert(MA_FALSE); /* NOTE: If this is triggered, please report it. It means the format of the ID must haved change and is too long to fit in our fixed sized buffer. */ return MA_ERROR; } ma_copy_memory(pInfo->id.wasapi, id, idlen * sizeof(wchar_t)); pInfo->id.wasapi[idlen] = '\0'; ma_CoTaskMemFree(pContext, id); } { ma_IPropertyStore *pProperties; hr = ma_IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pProperties); if (SUCCEEDED(hr)) { PROPVARIANT var; /* Description / Friendly Name */ ma_PropVariantInit(&var); hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &var); if (SUCCEEDED(hr)) { WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE); ma_PropVariantClear(pContext, &var); } ma_IPropertyStore_Release(pProperties); } } /* Format */ if (!onlySimpleInfo) { ma_IAudioClient* pAudioClient; hr = ma_IMMDevice_Activate(pMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient); if (SUCCEEDED(hr)) { ma_result result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, pMMDevice, pAudioClient, shareMode, pInfo); ma_IAudioClient_Release(pAudioClient); return result; } else { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } return MA_SUCCESS; } ma_result ma_context_enumerate_device_collection__wasapi(ma_context* pContext, ma_IMMDeviceCollection* pDeviceCollection, ma_device_type deviceType, ma_enum_devices_callback_proc callback, void* pUserData) { UINT deviceCount; HRESULT hr; ma_uint32 iDevice; ma_assert(pContext != NULL); ma_assert(callback != NULL); hr = ma_IMMDeviceCollection_GetCount(pDeviceCollection, &deviceCount); if (FAILED(hr)) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get playback device count.", MA_NO_DEVICE); } for (iDevice = 0; iDevice < deviceCount; ++iDevice) { ma_device_info deviceInfo; ma_IMMDevice* pMMDevice; ma_zero_object(&deviceInfo); hr = ma_IMMDeviceCollection_Item(pDeviceCollection, iDevice, &pMMDevice); if (SUCCEEDED(hr)) { ma_result result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, ma_share_mode_shared, MA_TRUE, &deviceInfo); /* MA_TRUE = onlySimpleInfo. */ ma_IMMDevice_Release(pMMDevice); if (result == MA_SUCCESS) { ma_bool32 cbResult = callback(pContext, deviceType, &deviceInfo, pUserData); if (cbResult == MA_FALSE) { break; } } } } return MA_SUCCESS; } #endif #ifdef MA_WIN32_DESKTOP ma_result ma_context_get_IAudioClient_Desktop__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_IMMDevice** ppMMDevice) { ma_result result; HRESULT hr; ma_assert(pContext != NULL); ma_assert(ppAudioClient != NULL); ma_assert(ppMMDevice != NULL); result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, ppMMDevice); if (result != MA_SUCCESS) { return result; } hr = ma_IMMDevice_Activate(*ppMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)ppAudioClient); if (FAILED(hr)) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } return MA_SUCCESS; } #else ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_IUnknown** ppActivatedInterface) { ma_IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL; ma_completion_handler_uwp completionHandler; IID iid; LPOLESTR iidStr; HRESULT hr; ma_result result; HRESULT activateResult; ma_IUnknown* pActivatedInterface; ma_assert(pContext != NULL); ma_assert(ppAudioClient != NULL); if (pDeviceID != NULL) { ma_copy_memory(&iid, pDeviceID->wasapi, sizeof(iid)); } else { if (deviceType == ma_device_type_playback) { iid = MA_IID_DEVINTERFACE_AUDIO_RENDER; } else { iid = MA_IID_DEVINTERFACE_AUDIO_CAPTURE; } } #if defined(__cplusplus) hr = StringFromIID(iid, &iidStr); #else hr = StringFromIID(&iid, &iidStr); #endif if (FAILED(hr)) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", MA_OUT_OF_MEMORY); } result = ma_completion_handler_uwp_init(&completionHandler); if (result != MA_SUCCESS) { ma_CoTaskMemFree(pContext, iidStr); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } #if defined(__cplusplus) hr = ActivateAudioInterfaceAsync(iidStr, MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp); #else hr = ActivateAudioInterfaceAsync(iidStr, &MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp); #endif if (FAILED(hr)) { ma_completion_handler_uwp_uninit(&completionHandler); ma_CoTaskMemFree(pContext, iidStr); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } ma_CoTaskMemFree(pContext, iidStr); /* Wait for the async operation for finish. */ ma_completion_handler_uwp_wait(&completionHandler); ma_completion_handler_uwp_uninit(&completionHandler); hr = ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface); ma_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp); if (FAILED(hr) || FAILED(activateResult)) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* Here is where we grab the IAudioClient interface. */ hr = ma_IUnknown_QueryInterface(pActivatedInterface, &MA_IID_IAudioClient, (void**)ppAudioClient); if (FAILED(hr)) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (ppActivatedInterface) { *ppActivatedInterface = pActivatedInterface; } else { ma_IUnknown_Release(pActivatedInterface); } return MA_SUCCESS; } #endif ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_WASAPIDeviceInterface** ppDeviceInterface) { #ifdef MA_WIN32_DESKTOP return ma_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface); #else return ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface); #endif } ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { /* Different enumeration for desktop and UWP. */ #ifdef MA_WIN32_DESKTOP /* Desktop */ HRESULT hr; ma_IMMDeviceEnumerator* pDeviceEnumerator; ma_IMMDeviceCollection* pDeviceCollection; hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* Playback. */ hr = ma_IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator, ma_eRender, MA_MM_DEVICE_STATE_ACTIVE, &pDeviceCollection); if (SUCCEEDED(hr)) { ma_context_enumerate_device_collection__wasapi(pContext, pDeviceCollection, ma_device_type_playback, callback, pUserData); ma_IMMDeviceCollection_Release(pDeviceCollection); } /* Capture. */ hr = ma_IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator, ma_eCapture, MA_MM_DEVICE_STATE_ACTIVE, &pDeviceCollection); if (SUCCEEDED(hr)) { ma_context_enumerate_device_collection__wasapi(pContext, pDeviceCollection, ma_device_type_capture, callback, pUserData); ma_IMMDeviceCollection_Release(pDeviceCollection); } ma_IMMDeviceEnumerator_Release(pDeviceEnumerator); #else /* UWP The MMDevice API is only supported on desktop applications. For now, while I'm still figuring out how to properly enumerate over devices without using MMDevice, I'm restricting devices to defaults. Hint: DeviceInformation::FindAllAsync() with DeviceClass.AudioCapture/AudioRender. https://blogs.windows.com/buildingapps/2014/05/15/real-time-audio-in-windows-store-and-windows-phone-apps/ */ if (callback) { ma_bool32 cbResult = MA_TRUE; /* Playback. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } /* Capture. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } } #endif return MA_SUCCESS; } ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { #ifdef MA_WIN32_DESKTOP ma_IMMDevice* pMMDevice = NULL; ma_result result; result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, &pMMDevice); if (result != MA_SUCCESS) { return result; } result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, shareMode, MA_FALSE, pDeviceInfo); /* MA_FALSE = !onlySimpleInfo. */ ma_IMMDevice_Release(pMMDevice); return result; #else ma_IAudioClient* pAudioClient; ma_result result; /* UWP currently only uses default devices. */ if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } /* Not currently supporting exclusive mode on UWP. */ if (shareMode == ma_share_mode_exclusive) { return MA_ERROR; } result = ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, &pAudioClient, NULL); if (result != MA_SUCCESS) { return result; } result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, NULL, pAudioClient, shareMode, pDeviceInfo); ma_IAudioClient_Release(pAudioClient); return result; #endif } void ma_device_uninit__wasapi(ma_device* pDevice) { ma_assert(pDevice != NULL); #ifdef MA_WIN32_DESKTOP if (pDevice->wasapi.pDeviceEnumerator) { ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient); ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator); } #endif if (pDevice->wasapi.pRenderClient) { ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient); } if (pDevice->wasapi.pCaptureClient) { ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); } if (pDevice->wasapi.pAudioClientPlayback) { ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); } if (pDevice->wasapi.pAudioClientCapture) { ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); } if (pDevice->wasapi.hEventPlayback) { CloseHandle(pDevice->wasapi.hEventPlayback); } if (pDevice->wasapi.hEventCapture) { CloseHandle(pDevice->wasapi.hEventCapture); } } typedef struct { /* Input. */ ma_format formatIn; ma_uint32 channelsIn; ma_uint32 sampleRateIn; ma_channel channelMapIn[MA_MAX_CHANNELS]; ma_uint32 bufferSizeInFramesIn; ma_uint32 bufferSizeInMillisecondsIn; ma_uint32 periodsIn; ma_bool32 usingDefaultFormat; ma_bool32 usingDefaultChannels; ma_bool32 usingDefaultSampleRate; ma_bool32 usingDefaultChannelMap; ma_share_mode shareMode; /* Output. */ ma_IAudioClient* pAudioClient; ma_IAudioRenderClient* pRenderClient; ma_IAudioCaptureClient* pCaptureClient; ma_format formatOut; ma_uint32 channelsOut; ma_uint32 sampleRateOut; ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_uint32 bufferSizeInFramesOut; ma_uint32 periodSizeInFramesOut; ma_uint32 periodsOut; char deviceName[256]; } ma_device_init_internal_data__wasapi; ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_init_internal_data__wasapi* pData) { HRESULT hr; ma_result result = MA_SUCCESS; const char* errorMsg = ""; MA_AUDCLNT_SHAREMODE shareMode = MA_AUDCLNT_SHAREMODE_SHARED; MA_REFERENCE_TIME bufferDurationInMicroseconds; ma_bool32 wasInitializedUsingIAudioClient3 = MA_FALSE; WAVEFORMATEXTENSIBLE wf; ma_WASAPIDeviceInterface* pDeviceInterface = NULL; ma_IAudioClient2* pAudioClient2; ma_assert(pContext != NULL); ma_assert(pData != NULL); /* This function is only used to initialize one device type: either playback or capture. Never full-duplex. */ if (deviceType == ma_device_type_duplex) { return MA_INVALID_ARGS; } pData->pAudioClient = NULL; pData->pRenderClient = NULL; pData->pCaptureClient = NULL; result = ma_context_get_IAudioClient__wasapi(pContext, deviceType, pDeviceID, &pData->pAudioClient, &pDeviceInterface); if (result != MA_SUCCESS) { goto done; } /* Try enabling hardware offloading. */ hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient2, (void**)&pAudioClient2); if (SUCCEEDED(hr)) { BOOL isHardwareOffloadingSupported = 0; hr = ma_IAudioClient2_IsOffloadCapable(pAudioClient2, MA_AudioCategory_Other, &isHardwareOffloadingSupported); if (SUCCEEDED(hr) && isHardwareOffloadingSupported) { ma_AudioClientProperties clientProperties; ma_zero_object(&clientProperties); clientProperties.cbSize = sizeof(clientProperties); clientProperties.bIsOffload = 1; clientProperties.eCategory = MA_AudioCategory_Other; ma_IAudioClient2_SetClientProperties(pAudioClient2, &clientProperties); } } /* Here is where we try to determine the best format to use with the device. If the client if wanting exclusive mode, first try finding the best format for that. If this fails, fall back to shared mode. */ result = MA_FORMAT_NOT_SUPPORTED; if (pData->shareMode == ma_share_mode_exclusive) { #ifdef MA_WIN32_DESKTOP /* In exclusive mode on desktop we always use the backend's native format. */ ma_IPropertyStore* pStore = NULL; hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pStore); if (SUCCEEDED(hr)) { PROPVARIANT prop; ma_PropVariantInit(&prop); hr = ma_IPropertyStore_GetValue(pStore, &MA_PKEY_AudioEngine_DeviceFormat, &prop); if (SUCCEEDED(hr)) { WAVEFORMATEX* pActualFormat = (WAVEFORMATEX*)prop.blob.pBlobData; hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pData->pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pActualFormat, NULL); if (SUCCEEDED(hr)) { ma_copy_memory(&wf, pActualFormat, sizeof(WAVEFORMATEXTENSIBLE)); } ma_PropVariantClear(pContext, &prop); } ma_IPropertyStore_Release(pStore); } #else /* I do not know how to query the device's native format on UWP so for now I'm just disabling support for exclusive mode. The alternative is to enumerate over different formats and check IsFormatSupported() until you find one that works. TODO: Add support for exclusive mode to UWP. */ hr = S_FALSE; #endif if (hr == S_OK) { shareMode = MA_AUDCLNT_SHAREMODE_EXCLUSIVE; result = MA_SUCCESS; } else { result = MA_SHARE_MODE_NOT_SUPPORTED; } } else { /* In shared mode we are always using the format reported by the operating system. */ WAVEFORMATEXTENSIBLE* pNativeFormat = NULL; hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pData->pAudioClient, (WAVEFORMATEX**)&pNativeFormat); if (hr != S_OK) { result = MA_FORMAT_NOT_SUPPORTED; } else { ma_copy_memory(&wf, pNativeFormat, sizeof(wf)); result = MA_SUCCESS; } ma_CoTaskMemFree(pContext, pNativeFormat); shareMode = MA_AUDCLNT_SHAREMODE_SHARED; } /* Return an error if we still haven't found a format. */ if (result != MA_SUCCESS) { errorMsg = "[WASAPI] Failed to find best device mix format."; goto done; } pData->formatOut = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)&wf); pData->channelsOut = wf.Format.nChannels; pData->sampleRateOut = wf.Format.nSamplesPerSec; /* Get the internal channel map based on the channel mask. */ ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pData->channelsOut, pData->channelMapOut); /* If we're using a default buffer size we need to calculate it based on the efficiency of the system. */ pData->periodsOut = pData->periodsIn; pData->bufferSizeInFramesOut = pData->bufferSizeInFramesIn; if (pData->bufferSizeInFramesOut == 0) { pData->bufferSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->bufferSizeInMillisecondsIn, pData->sampleRateOut); } bufferDurationInMicroseconds = ((ma_uint64)pData->bufferSizeInFramesOut * 1000 * 1000) / pData->sampleRateOut; /* Slightly different initialization for shared and exclusive modes. We try exclusive mode first, and if it fails, fall back to shared mode. */ if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) { MA_REFERENCE_TIME bufferDuration = (bufferDurationInMicroseconds / pData->periodsOut) * 10; /* If the periodicy is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing it and trying it again. */ hr = E_FAIL; for (;;) { hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL); if (hr == MA_AUDCLNT_E_INVALID_DEVICE_PERIOD) { if (bufferDuration > 500*10000) { break; } else { if (bufferDuration == 0) { /* <-- Just a sanity check to prevent an infinit loop. Should never happen, but it makes me feel better. */ break; } bufferDuration = bufferDuration * 2; continue; } } else { break; } } if (hr == MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { UINT bufferSizeInFrames; hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames); if (SUCCEEDED(hr)) { bufferDuration = (MA_REFERENCE_TIME)((10000.0 * 1000 / wf.Format.nSamplesPerSec * bufferSizeInFrames) + 0.5); /* Unfortunately we need to release and re-acquire the audio client according to MSDN. Seems silly - why not just call IAudioClient_Initialize() again?! */ ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient); #ifdef MA_WIN32_DESKTOP hr = ma_IMMDevice_Activate(pDeviceInterface, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pData->pAudioClient); #else hr = ma_IUnknown_QueryInterface(pDeviceInterface, &MA_IID_IAudioClient, (void**)&pData->pAudioClient); #endif if (SUCCEEDED(hr)) { hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL); } } } if (FAILED(hr)) { /* Failed to initialize in exclusive mode. Don't fall back to shared mode - instead tell the client about it. They can reinitialize in shared mode if they want. */ if (hr == E_ACCESSDENIED) { errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Access denied.", result = MA_ACCESS_DENIED; } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) { errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Device in use.", result = MA_DEVICE_BUSY; } else { errorMsg = "[WASAPI] Failed to initialize device in exclusive mode."; result = MA_SHARE_MODE_NOT_SUPPORTED; } goto done; } } if (shareMode == MA_AUDCLNT_SHAREMODE_SHARED) { /* Low latency shared mode via IAudioClient3. */ #ifndef MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE ma_IAudioClient3* pAudioClient3 = NULL; hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient3, (void**)&pAudioClient3); if (SUCCEEDED(hr)) { UINT32 defaultPeriodInFrames; UINT32 fundamentalPeriodInFrames; UINT32 minPeriodInFrames; UINT32 maxPeriodInFrames; hr = ma_IAudioClient3_GetSharedModeEnginePeriod(pAudioClient3, (WAVEFORMATEX*)&wf, &defaultPeriodInFrames, &fundamentalPeriodInFrames, &minPeriodInFrames, &maxPeriodInFrames); if (SUCCEEDED(hr)) { UINT32 desiredPeriodInFrames = pData->bufferSizeInFramesOut / pData->periodsOut; UINT32 actualPeriodInFrames = desiredPeriodInFrames; /* Make sure the period size is a multiple of fundamentalPeriodInFrames. */ actualPeriodInFrames = actualPeriodInFrames / fundamentalPeriodInFrames; actualPeriodInFrames = actualPeriodInFrames * fundamentalPeriodInFrames; /* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */ actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames); /* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */ if (actualPeriodInFrames >= desiredPeriodInFrames) { hr = ma_IAudioClient3_InitializeSharedAudioStream(pAudioClient3, MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK, actualPeriodInFrames, (WAVEFORMATEX*)&wf, NULL); if (SUCCEEDED(hr)) { wasInitializedUsingIAudioClient3 = MA_TRUE; pData->periodSizeInFramesOut = actualPeriodInFrames; pData->bufferSizeInFramesOut = actualPeriodInFrames * pData->periodsOut; } } } ma_IAudioClient3_Release(pAudioClient3); pAudioClient3 = NULL; } #endif /* If we don't have an IAudioClient3 then we need to use the normal initialization routine. */ if (!wasInitializedUsingIAudioClient3) { MA_REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10; hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL); if (FAILED(hr)) { if (hr == E_ACCESSDENIED) { errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MA_ACCESS_DENIED; } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) { errorMsg = "[WASAPI] Failed to initialize device. Device in use.", result = MA_DEVICE_BUSY; } else { errorMsg = "[WASAPI] Failed to initialize device.", result = MA_FAILED_TO_OPEN_BACKEND_DEVICE; } goto done; } } } if (!wasInitializedUsingIAudioClient3) { hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &pData->bufferSizeInFramesOut); if (FAILED(hr)) { errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = MA_FAILED_TO_OPEN_BACKEND_DEVICE; goto done; } pData->periodSizeInFramesOut = pData->bufferSizeInFramesOut / pData->periodsOut; } if (deviceType == ma_device_type_playback) { hr = ma_IAudioClient_GetService((ma_IAudioClient*)pData->pAudioClient, &MA_IID_IAudioRenderClient, (void**)&pData->pRenderClient); } else { hr = ma_IAudioClient_GetService((ma_IAudioClient*)pData->pAudioClient, &MA_IID_IAudioCaptureClient, (void**)&pData->pCaptureClient); } if (FAILED(hr)) { errorMsg = "[WASAPI] Failed to get audio client service.", result = MA_API_NOT_FOUND; goto done; } /* Grab the name of the device. */ #ifdef MA_WIN32_DESKTOP { ma_IPropertyStore *pProperties; hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pProperties); if (SUCCEEDED(hr)) { PROPVARIANT varName; ma_PropVariantInit(&varName); hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &varName); if (SUCCEEDED(hr)) { WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pData->deviceName, sizeof(pData->deviceName), 0, FALSE); ma_PropVariantClear(pContext, &varName); } ma_IPropertyStore_Release(pProperties); } } #endif done: /* Clean up. */ #ifdef MA_WIN32_DESKTOP if (pDeviceInterface != NULL) { ma_IMMDevice_Release(pDeviceInterface); } #else if (pDeviceInterface != NULL) { ma_IUnknown_Release(pDeviceInterface); } #endif if (result != MA_SUCCESS) { if (pData->pRenderClient) { ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pData->pRenderClient); pData->pRenderClient = NULL; } if (pData->pCaptureClient) { ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pData->pCaptureClient); pData->pCaptureClient = NULL; } if (pData->pAudioClient) { ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient); pData->pAudioClient = NULL; } return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, errorMsg, result); } else { return MA_SUCCESS; } } ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type deviceType) { ma_device_init_internal_data__wasapi data; ma_result result; ma_assert(pDevice != NULL); /* We only re-initialize the playback or capture device. Never a full-duplex device. */ if (deviceType == ma_device_type_duplex) { return MA_INVALID_ARGS; } if (deviceType == ma_device_type_capture) { data.formatIn = pDevice->capture.format; data.channelsIn = pDevice->capture.channels; ma_copy_memory(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap)); data.shareMode = pDevice->capture.shareMode; data.usingDefaultFormat = pDevice->capture.usingDefaultFormat; data.usingDefaultChannels = pDevice->capture.usingDefaultChannels; data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap; } else { data.formatIn = pDevice->playback.format; data.channelsIn = pDevice->playback.channels; ma_copy_memory(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap)); data.shareMode = pDevice->playback.shareMode; data.usingDefaultFormat = pDevice->playback.usingDefaultFormat; data.usingDefaultChannels = pDevice->playback.usingDefaultChannels; data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap; } data.sampleRateIn = pDevice->sampleRate; data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate; data.bufferSizeInFramesIn = pDevice->wasapi.originalBufferSizeInFrames; data.bufferSizeInMillisecondsIn = pDevice->wasapi.originalBufferSizeInMilliseconds; data.periodsIn = pDevice->wasapi.originalPeriods; result = ma_device_init_internal__wasapi(pDevice->pContext, deviceType, NULL, &data); if (result != MA_SUCCESS) { return result; } /* At this point we have some new objects ready to go. We need to uninitialize the previous ones and then set the new ones. */ if (deviceType == ma_device_type_capture) { if (pDevice->wasapi.pCaptureClient) { ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); pDevice->wasapi.pCaptureClient = NULL; } if (pDevice->wasapi.pAudioClientCapture) { ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); pDevice->wasapi.pAudioClientCapture = NULL; } pDevice->wasapi.pAudioClientCapture = data.pAudioClient; pDevice->wasapi.pCaptureClient = data.pCaptureClient; pDevice->capture.internalFormat = data.formatOut; pDevice->capture.internalChannels = data.channelsOut; pDevice->capture.internalSampleRate = data.sampleRateOut; ma_copy_memory(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); pDevice->capture.internalBufferSizeInFrames = data.bufferSizeInFramesOut; pDevice->capture.internalPeriods = data.periodsOut; ma_strcpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), data.deviceName); ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture); pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture); /* The device may be in a started state. If so we need to immediately restart it. */ if (pDevice->wasapi.isStartedCapture) { HRESULT hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device after reinitialization.", MA_FAILED_TO_START_BACKEND_DEVICE); } } } if (deviceType == ma_device_type_playback) { if (pDevice->wasapi.pRenderClient) { ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient); pDevice->wasapi.pRenderClient = NULL; } if (pDevice->wasapi.pAudioClientPlayback) { ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); pDevice->wasapi.pAudioClientPlayback = NULL; } pDevice->wasapi.pAudioClientPlayback = data.pAudioClient; pDevice->wasapi.pRenderClient = data.pRenderClient; pDevice->playback.internalFormat = data.formatOut; pDevice->playback.internalChannels = data.channelsOut; pDevice->playback.internalSampleRate = data.sampleRateOut; ma_copy_memory(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); pDevice->playback.internalBufferSizeInFrames = data.bufferSizeInFramesOut; pDevice->playback.internalPeriods = data.periodsOut; ma_strcpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), data.deviceName); ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback); pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback); /* The device may be in a started state. If so we need to immediately restart it. */ if (pDevice->wasapi.isStartedPlayback) { HRESULT hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device after reinitialization.", MA_FAILED_TO_START_BACKEND_DEVICE); } } } return MA_SUCCESS; } ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result = MA_SUCCESS; (void)pContext; ma_assert(pContext != NULL); ma_assert(pDevice != NULL); ma_zero_object(&pDevice->wasapi); pDevice->wasapi.originalBufferSizeInFrames = pConfig->bufferSizeInFrames; pDevice->wasapi.originalBufferSizeInMilliseconds = pConfig->bufferSizeInMilliseconds; pDevice->wasapi.originalPeriods = pConfig->periods; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_device_init_internal_data__wasapi data; data.formatIn = pConfig->capture.format; data.channelsIn = pConfig->capture.channels; data.sampleRateIn = pConfig->sampleRate; ma_copy_memory(data.channelMapIn, pConfig->capture.channelMap, sizeof(pConfig->capture.channelMap)); data.usingDefaultFormat = pDevice->capture.usingDefaultFormat; data.usingDefaultChannels = pDevice->capture.usingDefaultChannels; data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate; data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap; data.shareMode = pConfig->capture.shareMode; data.bufferSizeInFramesIn = pConfig->bufferSizeInFrames; data.bufferSizeInMillisecondsIn = pConfig->bufferSizeInMilliseconds; data.periodsIn = pConfig->periods; result = ma_device_init_internal__wasapi(pDevice->pContext, ma_device_type_capture, pConfig->capture.pDeviceID, &data); if (result != MA_SUCCESS) { return result; } pDevice->wasapi.pAudioClientCapture = data.pAudioClient; pDevice->wasapi.pCaptureClient = data.pCaptureClient; pDevice->capture.internalFormat = data.formatOut; pDevice->capture.internalChannels = data.channelsOut; pDevice->capture.internalSampleRate = data.sampleRateOut; ma_copy_memory(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); pDevice->capture.internalBufferSizeInFrames = data.bufferSizeInFramesOut; pDevice->capture.internalPeriods = data.periodsOut; ma_strcpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), data.deviceName); /* The event for capture needs to be manual reset for the same reason as playback. We keep the initial state set to unsignaled, however, because we want to block until we actually have something for the first call to ma_device_read(). */ pDevice->wasapi.hEventCapture = CreateEventA(NULL, FALSE, FALSE, NULL); /* Auto reset, unsignaled by default. */ if (pDevice->wasapi.hEventCapture == NULL) { if (pDevice->wasapi.pCaptureClient != NULL) { ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); pDevice->wasapi.pCaptureClient = NULL; } if (pDevice->wasapi.pAudioClientCapture != NULL) { ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); pDevice->wasapi.pAudioClientCapture = NULL; } return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture.", MA_FAILED_TO_CREATE_EVENT); } ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture); pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture); } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_device_init_internal_data__wasapi data; data.formatIn = pConfig->playback.format; data.channelsIn = pConfig->playback.channels; data.sampleRateIn = pConfig->sampleRate; ma_copy_memory(data.channelMapIn, pConfig->playback.channelMap, sizeof(pConfig->playback.channelMap)); data.usingDefaultFormat = pDevice->playback.usingDefaultFormat; data.usingDefaultChannels = pDevice->playback.usingDefaultChannels; data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate; data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap; data.shareMode = pConfig->playback.shareMode; data.bufferSizeInFramesIn = pConfig->bufferSizeInFrames; data.bufferSizeInMillisecondsIn = pConfig->bufferSizeInMilliseconds; data.periodsIn = pConfig->periods; result = ma_device_init_internal__wasapi(pDevice->pContext, ma_device_type_playback, pConfig->playback.pDeviceID, &data); if (result != MA_SUCCESS) { if (pConfig->deviceType == ma_device_type_duplex) { if (pDevice->wasapi.pCaptureClient != NULL) { ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); pDevice->wasapi.pCaptureClient = NULL; } if (pDevice->wasapi.pAudioClientCapture != NULL) { ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); pDevice->wasapi.pAudioClientCapture = NULL; } CloseHandle(pDevice->wasapi.hEventCapture); pDevice->wasapi.hEventCapture = NULL; } return result; } pDevice->wasapi.pAudioClientPlayback = data.pAudioClient; pDevice->wasapi.pRenderClient = data.pRenderClient; pDevice->playback.internalFormat = data.formatOut; pDevice->playback.internalChannels = data.channelsOut; pDevice->playback.internalSampleRate = data.sampleRateOut; ma_copy_memory(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); pDevice->playback.internalBufferSizeInFrames = data.bufferSizeInFramesOut; pDevice->playback.internalPeriods = data.periodsOut; ma_strcpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), data.deviceName); /* The event for playback is needs to be manual reset because we want to explicitly control the fact that it becomes signalled only after the whole available space has been filled, never before. The playback event also needs to be initially set to a signaled state so that the first call to ma_device_write() is able to get passed WaitForMultipleObjects(). */ pDevice->wasapi.hEventPlayback = CreateEventA(NULL, FALSE, TRUE, NULL); /* Auto reset, signaled by default. */ if (pDevice->wasapi.hEventPlayback == NULL) { if (pConfig->deviceType == ma_device_type_duplex) { if (pDevice->wasapi.pCaptureClient != NULL) { ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); pDevice->wasapi.pCaptureClient = NULL; } if (pDevice->wasapi.pAudioClientCapture != NULL) { ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); pDevice->wasapi.pAudioClientCapture = NULL; } CloseHandle(pDevice->wasapi.hEventCapture); pDevice->wasapi.hEventCapture = NULL; } if (pDevice->wasapi.pRenderClient != NULL) { ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient); pDevice->wasapi.pRenderClient = NULL; } if (pDevice->wasapi.pAudioClientPlayback != NULL) { ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); pDevice->wasapi.pAudioClientPlayback = NULL; } return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback.", MA_FAILED_TO_CREATE_EVENT); } ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback); pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback); } /* We need to get notifications of when the default device changes. We do this through a device enumerator by registering a IMMNotificationClient with it. We only care about this if it's the default device. */ #ifdef MA_WIN32_DESKTOP { ma_IMMDeviceEnumerator* pDeviceEnumerator; HRESULT hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { ma_device_uninit__wasapi(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } pDevice->wasapi.notificationClient.lpVtbl = (void*)&g_maNotificationCientVtbl; pDevice->wasapi.notificationClient.counter = 1; pDevice->wasapi.notificationClient.pDevice = pDevice; hr = pDeviceEnumerator->lpVtbl->RegisterEndpointNotificationCallback(pDeviceEnumerator, &pDevice->wasapi.notificationClient); if (SUCCEEDED(hr)) { pDevice->wasapi.pDeviceEnumerator = (ma_ptr)pDeviceEnumerator; } else { /* Not the end of the world if we fail to register the notification callback. We just won't support automatic stream routing. */ ma_IMMDeviceEnumerator_Release(pDeviceEnumerator); } } #endif ma_atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE); ma_atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE); return MA_SUCCESS; } ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_IAudioClient* pAudioClient, ma_uint32* pFrameCount) { ma_uint32 paddingFramesCount; HRESULT hr; ma_share_mode shareMode; ma_assert(pDevice != NULL); ma_assert(pFrameCount != NULL); *pFrameCount = 0; if ((ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientPlayback && (ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientCapture) { return MA_INVALID_OPERATION; } hr = ma_IAudioClient_GetCurrentPadding(pAudioClient, &paddingFramesCount); if (FAILED(hr)) { return MA_DEVICE_UNAVAILABLE; } /* Slightly different rules for exclusive and shared modes. */ shareMode = ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) ? pDevice->playback.shareMode : pDevice->capture.shareMode; if (shareMode == ma_share_mode_exclusive) { *pFrameCount = paddingFramesCount; } else { if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) { *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback - paddingFramesCount; } else { *pFrameCount = paddingFramesCount; } } return MA_SUCCESS; } ma_bool32 ma_device_is_reroute_required__wasapi(ma_device* pDevice, ma_device_type deviceType) { ma_assert(pDevice != NULL); if (deviceType == ma_device_type_playback) { return pDevice->wasapi.hasDefaultPlaybackDeviceChanged; } if (deviceType == ma_device_type_capture) { return pDevice->wasapi.hasDefaultCaptureDeviceChanged; } return MA_FALSE; } ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType) { ma_result result; if (deviceType == ma_device_type_duplex) { return MA_INVALID_ARGS; } if (deviceType == ma_device_type_playback) { ma_atomic_exchange_32(&pDevice->wasapi.hasDefaultPlaybackDeviceChanged, MA_FALSE); } if (deviceType == ma_device_type_capture) { ma_atomic_exchange_32(&pDevice->wasapi.hasDefaultCaptureDeviceChanged, MA_FALSE); } #ifdef MA_DEBUG_OUTPUT printf("=== CHANGING DEVICE ===\n"); #endif result = ma_device_reinit__wasapi(pDevice, deviceType); if (result != MA_SUCCESS) { return result; } ma_device__post_init_setup(pDevice, deviceType); return MA_SUCCESS; } ma_result ma_device_main_loop__wasapi(ma_device* pDevice) { ma_result result; HRESULT hr; ma_bool32 exitLoop = MA_FALSE; ma_uint32 framesWrittenToPlaybackDevice = 0; ma_uint32 mappedBufferSizeInFramesCapture = 0; ma_uint32 mappedBufferSizeInFramesPlayback = 0; ma_uint32 mappedBufferFramesRemainingCapture = 0; ma_uint32 mappedBufferFramesRemainingPlayback = 0; BYTE* pMappedBufferCapture = NULL; BYTE* pMappedBufferPlayback = NULL; ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); ma_uint8 inputDataInExternalFormat[4096]; ma_uint32 inputDataInExternalFormatCap = sizeof(inputDataInExternalFormat) / bpfCapture; ma_uint8 outputDataInExternalFormat[4096]; ma_uint32 outputDataInExternalFormatCap = sizeof(outputDataInExternalFormat) / bpfPlayback; ma_assert(pDevice != NULL); /* The playback device needs to be started immediately. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device.", MA_FAILED_TO_START_BACKEND_DEVICE); } ma_atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_TRUE); } while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) { /* We may need to reroute the device. */ if (ma_device_is_reroute_required__wasapi(pDevice, ma_device_type_playback)) { result = ma_device_reroute__wasapi(pDevice, ma_device_type_playback); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } } if (ma_device_is_reroute_required__wasapi(pDevice, ma_device_type_capture)) { result = ma_device_reroute__wasapi(pDevice, ma_device_type_capture); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } } switch (pDevice->type) { case ma_device_type_duplex: { ma_uint32 framesAvailableCapture; ma_uint32 framesAvailablePlayback; DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */ /* The process is to map the playback buffer and fill it as quickly as possible from input data. */ if (pMappedBufferPlayback == NULL) { /* WASAPI is weird with exclusive mode. You need to wait on the event _before_ querying the available frames. */ if (pDevice->playback.shareMode == ma_share_mode_exclusive) { if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) == WAIT_FAILED) { return MA_ERROR; /* Wait failed. */ } } result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); if (result != MA_SUCCESS) { return result; } /*printf("TRACE 1: framesAvailablePlayback=%d\n", framesAvailablePlayback);*/ /* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */ if (pDevice->playback.shareMode != ma_share_mode_exclusive) { if (framesAvailablePlayback >= pDevice->wasapi.periodSizeInFramesPlayback) { framesAvailablePlayback = pDevice->wasapi.periodSizeInFramesPlayback; } } /* If there's no frames available in the playback device we need to wait for more. */ if (framesAvailablePlayback == 0) { /* In exclusive mode we waited at the top. */ if (pDevice->playback.shareMode != ma_share_mode_exclusive) { if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) == WAIT_FAILED) { return MA_ERROR; /* Wait failed. */ } } continue; } /* We're ready to map the playback device's buffer. We don't release this until it's been entirely filled. */ hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedBufferPlayback); if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", MA_FAILED_TO_MAP_DEVICE_BUFFER); exitLoop = MA_TRUE; break; } mappedBufferSizeInFramesPlayback = framesAvailablePlayback; mappedBufferFramesRemainingPlayback = framesAvailablePlayback; } /* At this point we should have a buffer available for output. We need to keep writing input samples to it. */ for (;;) { /* Try grabbing some captured data if we haven't already got a mapped buffer. */ if (pMappedBufferCapture == NULL) { if (pDevice->capture.shareMode == ma_share_mode_shared) { if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) == WAIT_FAILED) { return MA_ERROR; /* Wait failed. */ } } result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } /*printf("TRACE 2: framesAvailableCapture=%d\n", framesAvailableCapture);*/ /* Wait for more if nothing is available. */ if (framesAvailableCapture == 0) { /* In exclusive mode we waited at the top. */ if (pDevice->capture.shareMode != ma_share_mode_shared) { if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) == WAIT_FAILED) { return MA_ERROR; /* Wait failed. */ } } continue; } /* Getting here means there's data available for writing to the output device. */ mappedBufferSizeInFramesCapture = framesAvailableCapture; hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedBufferCapture, &mappedBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", MA_FAILED_TO_MAP_DEVICE_BUFFER); exitLoop = MA_TRUE; break; } /* TODO: How do we handle the capture flags returned by GetBuffer()? In particular, AUDCLNT_BUFFERFLAGS_SILENT (1). */ #ifdef MA_DEBUG_OUTPUT if (flagsCapture != 0) { printf("[WASAPI] Capture Flags: %d\n", flagsCapture); } #endif mappedBufferFramesRemainingCapture = mappedBufferSizeInFramesCapture; pDevice->capture._dspFrameCount = mappedBufferSizeInFramesCapture; pDevice->capture._dspFrames = (const ma_uint8*)pMappedBufferCapture; } /* At this point we should have both input and output data available. We now need to post it to the convert the data and post it to the client. */ for (;;) { BYTE* pRunningBufferCapture; BYTE* pRunningBufferPlayback; ma_uint32 framesToProcess; ma_uint32 framesProcessed; pRunningBufferCapture = pMappedBufferCapture + ((mappedBufferSizeInFramesCapture - mappedBufferFramesRemainingCapture ) * bpfPlayback); pRunningBufferPlayback = pMappedBufferPlayback + ((mappedBufferSizeInFramesPlayback - mappedBufferFramesRemainingPlayback) * bpfPlayback); /* There may be some data sitting in the converter that needs to be processed first. Once this is exhaused, run the data callback again. */ if (!pDevice->playback.converter.isPassthrough) { framesProcessed = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, pRunningBufferPlayback, mappedBufferFramesRemainingPlayback); if (framesProcessed > 0) { mappedBufferFramesRemainingPlayback -= framesProcessed; if (mappedBufferFramesRemainingPlayback == 0) { break; } } } /* Getting here means we need to fire the callback. If format conversion is unnecessary, we can optimize this by passing the pointers to the internal buffers directly to the callback. */ if (pDevice->capture.converter.isPassthrough && pDevice->playback.converter.isPassthrough) { /* Optimal path. We can pass mapped pointers directly to the callback. */ framesToProcess = ma_min(mappedBufferFramesRemainingCapture, mappedBufferFramesRemainingPlayback); framesProcessed = framesToProcess; pDevice->onData(pDevice, pRunningBufferPlayback, pRunningBufferCapture, framesToProcess); mappedBufferFramesRemainingCapture -= framesProcessed; mappedBufferFramesRemainingPlayback -= framesProcessed; if (mappedBufferFramesRemainingCapture == 0) { break; /* Exhausted input data. */ } if (mappedBufferFramesRemainingPlayback == 0) { break; /* Exhausted output data. */ } } else if (pDevice->capture.converter.isPassthrough) { /* The input buffer is a passthrough, but the playback buffer requires a conversion. */ framesToProcess = ma_min(mappedBufferFramesRemainingCapture, outputDataInExternalFormatCap); framesProcessed = framesToProcess; pDevice->onData(pDevice, outputDataInExternalFormat, pRunningBufferCapture, framesToProcess); mappedBufferFramesRemainingCapture -= framesProcessed; pDevice->playback._dspFrameCount = framesProcessed; pDevice->playback._dspFrames = (const ma_uint8*)outputDataInExternalFormat; if (mappedBufferFramesRemainingCapture == 0) { break; /* Exhausted input data. */ } } else if (pDevice->playback.converter.isPassthrough) { /* The input buffer requires conversion, the playback buffer is passthrough. */ framesToProcess = ma_min(inputDataInExternalFormatCap, mappedBufferFramesRemainingPlayback); framesProcessed = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, inputDataInExternalFormat, framesToProcess); if (framesProcessed == 0) { /* Getting here means we've run out of input data. */ mappedBufferFramesRemainingCapture = 0; break; } pDevice->onData(pDevice, pRunningBufferPlayback, inputDataInExternalFormat, framesProcessed); mappedBufferFramesRemainingPlayback -= framesProcessed; if (framesProcessed < framesToProcess) { mappedBufferFramesRemainingCapture = 0; break; /* Exhausted input data. */ } if (mappedBufferFramesRemainingPlayback == 0) { break; /* Exhausted output data. */ } } else { framesToProcess = ma_min(inputDataInExternalFormatCap, outputDataInExternalFormatCap); framesProcessed = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, inputDataInExternalFormat, framesToProcess); if (framesProcessed == 0) { /* Getting here means we've run out of input data. */ mappedBufferFramesRemainingCapture = 0; break; } pDevice->onData(pDevice, outputDataInExternalFormat, inputDataInExternalFormat, framesProcessed); pDevice->playback._dspFrameCount = framesProcessed; pDevice->playback._dspFrames = (const ma_uint8*)outputDataInExternalFormat; if (framesProcessed < framesToProcess) { /* Getting here means we've run out of input data. */ mappedBufferFramesRemainingCapture = 0; break; } } } /* If at this point we've run out of capture data we need to release the buffer. */ if (mappedBufferFramesRemainingCapture == 0 && pMappedBufferCapture != NULL) { hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedBufferSizeInFramesCapture); if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", MA_FAILED_TO_UNMAP_DEVICE_BUFFER); exitLoop = MA_TRUE; break; } /*printf("TRACE: Released capture buffer\n");*/ pMappedBufferCapture = NULL; mappedBufferFramesRemainingCapture = 0; mappedBufferSizeInFramesCapture = 0; } /* Get out of this loop if we're run out of room in the playback buffer. */ if (mappedBufferFramesRemainingPlayback == 0) { break; } } /* If at this point we've run out of data we need to release the buffer. */ if (mappedBufferFramesRemainingPlayback == 0 && pMappedBufferPlayback != NULL) { hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedBufferSizeInFramesPlayback, 0); if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", MA_FAILED_TO_UNMAP_DEVICE_BUFFER); exitLoop = MA_TRUE; break; } /*printf("TRACE: Released playback buffer\n");*/ framesWrittenToPlaybackDevice += mappedBufferSizeInFramesPlayback; pMappedBufferPlayback = NULL; mappedBufferFramesRemainingPlayback = 0; mappedBufferSizeInFramesPlayback = 0; } if (!pDevice->wasapi.isStartedPlayback) { if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= (pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods)*2) { hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); if (FAILED(hr)) { ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", MA_FAILED_TO_START_BACKEND_DEVICE); } ma_atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE); } } } break; case ma_device_type_capture: { ma_uint32 framesAvailableCapture; DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */ /* Wait for data to become available first. */ if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) == WAIT_FAILED) { exitLoop = MA_TRUE; break; /* Wait failed. */ } /* See how many frames are available. Since we waited at the top, I don't think this should ever return 0. I'm checking for this anyway. */ result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } if (framesAvailableCapture < pDevice->wasapi.periodSizeInFramesCapture) { continue; /* Nothing available. Keep waiting. */ } /* Map a the data buffer in preparation for sending to the client. */ mappedBufferSizeInFramesCapture = framesAvailableCapture; hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedBufferCapture, &mappedBufferSizeInFramesCapture, &flagsCapture, NULL, NULL); if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", MA_FAILED_TO_MAP_DEVICE_BUFFER); exitLoop = MA_TRUE; break; } /* We should have a buffer at this point. */ ma_device__send_frames_to_client(pDevice, mappedBufferSizeInFramesCapture, pMappedBufferCapture); /* At this point we're done with the buffer. */ hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedBufferSizeInFramesCapture); pMappedBufferCapture = NULL; /* <-- Important. Not doing this can result in an error once we leave this loop because it will use this to know whether or not a final ReleaseBuffer() needs to be called. */ mappedBufferSizeInFramesCapture = 0; if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", MA_FAILED_TO_UNMAP_DEVICE_BUFFER); exitLoop = MA_TRUE; break; } } break; case ma_device_type_playback: { ma_uint32 framesAvailablePlayback; /* Wait for space to become available first. */ if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) == WAIT_FAILED) { exitLoop = MA_TRUE; break; /* Wait failed. */ } /* Check how much space is available. If this returns 0 we just keep waiting. */ result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); if (result != MA_SUCCESS) { exitLoop = MA_TRUE; break; } if (framesAvailablePlayback < pDevice->wasapi.periodSizeInFramesPlayback) { continue; /* No space available. */ } /* Map a the data buffer in preparation for the callback. */ hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedBufferPlayback); if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", MA_FAILED_TO_MAP_DEVICE_BUFFER); exitLoop = MA_TRUE; break; } /* We should have a buffer at this point. */ ma_device__read_frames_from_client(pDevice, framesAvailablePlayback, pMappedBufferPlayback); /* At this point we're done writing to the device and we just need to release the buffer. */ hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, 0); pMappedBufferPlayback = NULL; /* <-- Important. Not doing this can result in an error once we leave this loop because it will use this to know whether or not a final ReleaseBuffer() needs to be called. */ mappedBufferSizeInFramesPlayback = 0; if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", MA_FAILED_TO_UNMAP_DEVICE_BUFFER); exitLoop = MA_TRUE; break; } framesWrittenToPlaybackDevice += framesAvailablePlayback; if (!pDevice->wasapi.isStartedPlayback) { if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= (pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods)*1) { hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); if (FAILED(hr)) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", MA_FAILED_TO_START_BACKEND_DEVICE); exitLoop = MA_TRUE; break; } ma_atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE); } } } break; default: return MA_INVALID_ARGS; } } /* Here is where the device needs to be stopped. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { /* Any mapped buffers need to be released. */ if (pMappedBufferCapture != NULL) { hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedBufferSizeInFramesCapture); } hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } /* The audio client needs to be reset otherwise restarting will fail. */ hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } ma_atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { /* Any mapped buffers need to be released. */ if (pMappedBufferPlayback != NULL) { hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedBufferSizeInFramesPlayback, 0); } /* The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to the speakers. This is a problem for very short sounds because it'll result in a significant potion of it not getting played. */ if (pDevice->wasapi.isStartedPlayback) { if (pDevice->playback.shareMode == ma_share_mode_exclusive) { WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE); } else { ma_uint32 prevFramesAvaialablePlayback = (size_t)-1; ma_uint32 framesAvailablePlayback; for (;;) { result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); if (result != MA_SUCCESS) { break; } if (framesAvailablePlayback >= pDevice->wasapi.actualBufferSizeInFramesPlayback) { break; } /* Just a safety check to avoid an infinite loop. If this iteration results in a situation where the number of available frames has not changed, get out of the loop. I don't think this should ever happen, but I think it's nice to have just in case. */ if (framesAvailablePlayback == prevFramesAvaialablePlayback) { break; } prevFramesAvaialablePlayback = framesAvailablePlayback; WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE); ResetEvent(pDevice->wasapi.hEventPlayback); /* Manual reset. */ } } } hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } /* The audio client needs to be reset otherwise restarting will fail. */ hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } ma_atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE); } return MA_SUCCESS; } ma_result ma_context_uninit__wasapi(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_wasapi); (void)pContext; return MA_SUCCESS; } ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_context* pContext) { ma_result result = MA_SUCCESS; ma_assert(pContext != NULL); (void)pConfig; #ifdef MA_WIN32_DESKTOP /* WASAPI is only supported in Vista SP1 and newer. The reason for SP1 and not the base version of Vista is that event-driven exclusive mode does not work until SP1. Unfortunately older compilers don't define these functions so we need to dynamically load them in order to avoid a lin error. */ { ma_OSVERSIONINFOEXW osvi; ma_handle kernel32DLL; ma_PFNVerifyVersionInfoW _VerifyVersionInfoW; ma_PFNVerSetConditionMask _VerSetConditionMask; kernel32DLL = ma_dlopen(pContext, "kernel32.dll"); if (kernel32DLL == NULL) { return MA_NO_BACKEND; } _VerifyVersionInfoW = (ma_PFNVerifyVersionInfoW)ma_dlsym(pContext, kernel32DLL, "VerifyVersionInfoW"); _VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(pContext, kernel32DLL, "VerSetConditionMask"); if (_VerifyVersionInfoW == NULL || _VerSetConditionMask == NULL) { ma_dlclose(pContext, kernel32DLL); return MA_NO_BACKEND; } ma_zero_object(&osvi); osvi.dwOSVersionInfoSize = sizeof(osvi); osvi.dwMajorVersion = HIBYTE(MA_WIN32_WINNT_VISTA); osvi.dwMinorVersion = LOBYTE(MA_WIN32_WINNT_VISTA); osvi.wServicePackMajor = 1; if (_VerifyVersionInfoW(&osvi, MA_VER_MAJORVERSION | MA_VER_MINORVERSION | MA_VER_SERVICEPACKMAJOR, _VerSetConditionMask(_VerSetConditionMask(_VerSetConditionMask(0, MA_VER_MAJORVERSION, MA_VER_GREATER_EQUAL), MA_VER_MINORVERSION, MA_VER_GREATER_EQUAL), MA_VER_SERVICEPACKMAJOR, MA_VER_GREATER_EQUAL))) { result = MA_SUCCESS; } else { result = MA_NO_BACKEND; } ma_dlclose(pContext, kernel32DLL); } #endif if (result != MA_SUCCESS) { return result; } pContext->onUninit = ma_context_uninit__wasapi; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__wasapi; pContext->onEnumDevices = ma_context_enumerate_devices__wasapi; pContext->onGetDeviceInfo = ma_context_get_device_info__wasapi; pContext->onDeviceInit = ma_device_init__wasapi; pContext->onDeviceUninit = ma_device_uninit__wasapi; pContext->onDeviceStart = NULL; /* Not used. Started in onDeviceMainLoop. */ pContext->onDeviceStop = NULL; /* Not used. Stopped in onDeviceMainLoop. */ pContext->onDeviceWrite = NULL; pContext->onDeviceRead = NULL; pContext->onDeviceMainLoop = ma_device_main_loop__wasapi; return result; } #endif /****************************************************************************** DirectSound Backend ******************************************************************************/ #ifdef MA_HAS_DSOUND /*#include */ GUID MA_GUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}}; /* miniaudio only uses priority or exclusive modes. */ #define MA_DSSCL_NORMAL 1 #define MA_DSSCL_PRIORITY 2 #define MA_DSSCL_EXCLUSIVE 3 #define MA_DSSCL_WRITEPRIMARY 4 #define MA_DSCAPS_PRIMARYMONO 0x00000001 #define MA_DSCAPS_PRIMARYSTEREO 0x00000002 #define MA_DSCAPS_PRIMARY8BIT 0x00000004 #define MA_DSCAPS_PRIMARY16BIT 0x00000008 #define MA_DSCAPS_CONTINUOUSRATE 0x00000010 #define MA_DSCAPS_EMULDRIVER 0x00000020 #define MA_DSCAPS_CERTIFIED 0x00000040 #define MA_DSCAPS_SECONDARYMONO 0x00000100 #define MA_DSCAPS_SECONDARYSTEREO 0x00000200 #define MA_DSCAPS_SECONDARY8BIT 0x00000400 #define MA_DSCAPS_SECONDARY16BIT 0x00000800 #define MA_DSBCAPS_PRIMARYBUFFER 0x00000001 #define MA_DSBCAPS_STATIC 0x00000002 #define MA_DSBCAPS_LOCHARDWARE 0x00000004 #define MA_DSBCAPS_LOCSOFTWARE 0x00000008 #define MA_DSBCAPS_CTRL3D 0x00000010 #define MA_DSBCAPS_CTRLFREQUENCY 0x00000020 #define MA_DSBCAPS_CTRLPAN 0x00000040 #define MA_DSBCAPS_CTRLVOLUME 0x00000080 #define MA_DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100 #define MA_DSBCAPS_CTRLFX 0x00000200 #define MA_DSBCAPS_STICKYFOCUS 0x00004000 #define MA_DSBCAPS_GLOBALFOCUS 0x00008000 #define MA_DSBCAPS_GETCURRENTPOSITION2 0x00010000 #define MA_DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000 #define MA_DSBCAPS_LOCDEFER 0x00040000 #define MA_DSBCAPS_TRUEPLAYPOSITION 0x00080000 #define MA_DSBPLAY_LOOPING 0x00000001 #define MA_DSBPLAY_LOCHARDWARE 0x00000002 #define MA_DSBPLAY_LOCSOFTWARE 0x00000004 #define MA_DSBPLAY_TERMINATEBY_TIME 0x00000008 #define MA_DSBPLAY_TERMINATEBY_DISTANCE 0x00000010 #define MA_DSBPLAY_TERMINATEBY_PRIORITY 0x00000020 #define MA_DSCBSTART_LOOPING 0x00000001 typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; WAVEFORMATEX* lpwfxFormat; GUID guid3DAlgorithm; } MA_DSBUFFERDESC; typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; WAVEFORMATEX* lpwfxFormat; DWORD dwFXCount; void* lpDSCFXDesc; /* <-- miniaudio doesn't use this, so set to void*. */ } MA_DSCBUFFERDESC; typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwMinSecondarySampleRate; DWORD dwMaxSecondarySampleRate; DWORD dwPrimaryBuffers; DWORD dwMaxHwMixingAllBuffers; DWORD dwMaxHwMixingStaticBuffers; DWORD dwMaxHwMixingStreamingBuffers; DWORD dwFreeHwMixingAllBuffers; DWORD dwFreeHwMixingStaticBuffers; DWORD dwFreeHwMixingStreamingBuffers; DWORD dwMaxHw3DAllBuffers; DWORD dwMaxHw3DStaticBuffers; DWORD dwMaxHw3DStreamingBuffers; DWORD dwFreeHw3DAllBuffers; DWORD dwFreeHw3DStaticBuffers; DWORD dwFreeHw3DStreamingBuffers; DWORD dwTotalHwMemBytes; DWORD dwFreeHwMemBytes; DWORD dwMaxContigFreeHwMemBytes; DWORD dwUnlockTransferRateHwBuffers; DWORD dwPlayCpuOverheadSwBuffers; DWORD dwReserved1; DWORD dwReserved2; } MA_DSCAPS; typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwUnlockTransferRate; DWORD dwPlayCpuOverhead; } MA_DSBCAPS; typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwFormats; DWORD dwChannels; } MA_DSCCAPS; typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; } MA_DSCBCAPS; typedef struct { DWORD dwOffset; HANDLE hEventNotify; } MA_DSBPOSITIONNOTIFY; typedef struct ma_IDirectSound ma_IDirectSound; typedef struct ma_IDirectSoundBuffer ma_IDirectSoundBuffer; typedef struct ma_IDirectSoundCapture ma_IDirectSoundCapture; typedef struct ma_IDirectSoundCaptureBuffer ma_IDirectSoundCaptureBuffer; typedef struct ma_IDirectSoundNotify ma_IDirectSoundNotify; /* COM objects. The way these work is that you have a vtable (a list of function pointers, kind of like how C++ works internally), and then you have a structure with a single member, which is a pointer to the vtable. The vtable is where the methods of the object are defined. Methods need to be in a specific order, and parent classes need to have their methods declared first. */ /* IDirectSound */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSound* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSound* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSound* pThis); /* IDirectSound */ HRESULT (STDMETHODCALLTYPE * CreateSoundBuffer) (ma_IDirectSound* pThis, const MA_DSBUFFERDESC* pDSBufferDesc, ma_IDirectSoundBuffer** ppDSBuffer, void* pUnkOuter); HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps); HRESULT (STDMETHODCALLTYPE * DuplicateSoundBuffer)(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate); HRESULT (STDMETHODCALLTYPE * SetCooperativeLevel) (ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel); HRESULT (STDMETHODCALLTYPE * Compact) (ma_IDirectSound* pThis); HRESULT (STDMETHODCALLTYPE * GetSpeakerConfig) (ma_IDirectSound* pThis, DWORD* pSpeakerConfig); HRESULT (STDMETHODCALLTYPE * SetSpeakerConfig) (ma_IDirectSound* pThis, DWORD dwSpeakerConfig); HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSound* pThis, const GUID* pGuidDevice); } ma_IDirectSoundVtbl; struct ma_IDirectSound { ma_IDirectSoundVtbl* lpVtbl; }; HRESULT ma_IDirectSound_QueryInterface(ma_IDirectSound* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IDirectSound_AddRef(ma_IDirectSound* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IDirectSound_Release(ma_IDirectSound* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IDirectSound_CreateSoundBuffer(ma_IDirectSound* pThis, const MA_DSBUFFERDESC* pDSBufferDesc, ma_IDirectSoundBuffer** ppDSBuffer, void* pUnkOuter) { return pThis->lpVtbl->CreateSoundBuffer(pThis, pDSBufferDesc, ppDSBuffer, pUnkOuter); } HRESULT ma_IDirectSound_GetCaps(ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCaps); } HRESULT ma_IDirectSound_DuplicateSoundBuffer(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate) { return pThis->lpVtbl->DuplicateSoundBuffer(pThis, pDSBufferOriginal, ppDSBufferDuplicate); } HRESULT ma_IDirectSound_SetCooperativeLevel(ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel) { return pThis->lpVtbl->SetCooperativeLevel(pThis, hwnd, dwLevel); } HRESULT ma_IDirectSound_Compact(ma_IDirectSound* pThis) { return pThis->lpVtbl->Compact(pThis); } HRESULT ma_IDirectSound_GetSpeakerConfig(ma_IDirectSound* pThis, DWORD* pSpeakerConfig) { return pThis->lpVtbl->GetSpeakerConfig(pThis, pSpeakerConfig); } HRESULT ma_IDirectSound_SetSpeakerConfig(ma_IDirectSound* pThis, DWORD dwSpeakerConfig) { return pThis->lpVtbl->SetSpeakerConfig(pThis, dwSpeakerConfig); } HRESULT ma_IDirectSound_Initialize(ma_IDirectSound* pThis, const GUID* pGuidDevice) { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); } /* IDirectSoundBuffer */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundBuffer* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundBuffer* pThis); /* IDirectSoundBuffer */ HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps); HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor); HRESULT (STDMETHODCALLTYPE * GetFormat) (ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten); HRESULT (STDMETHODCALLTYPE * GetVolume) (ma_IDirectSoundBuffer* pThis, LONG* pVolume); HRESULT (STDMETHODCALLTYPE * GetPan) (ma_IDirectSoundBuffer* pThis, LONG* pPan); HRESULT (STDMETHODCALLTYPE * GetFrequency) (ma_IDirectSoundBuffer* pThis, DWORD* pFrequency); HRESULT (STDMETHODCALLTYPE * GetStatus) (ma_IDirectSoundBuffer* pThis, DWORD* pStatus); HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc); HRESULT (STDMETHODCALLTYPE * Lock) (ma_IDirectSoundBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags); HRESULT (STDMETHODCALLTYPE * Play) (ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags); HRESULT (STDMETHODCALLTYPE * SetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition); HRESULT (STDMETHODCALLTYPE * SetFormat) (ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat); HRESULT (STDMETHODCALLTYPE * SetVolume) (ma_IDirectSoundBuffer* pThis, LONG volume); HRESULT (STDMETHODCALLTYPE * SetPan) (ma_IDirectSoundBuffer* pThis, LONG pan); HRESULT (STDMETHODCALLTYPE * SetFrequency) (ma_IDirectSoundBuffer* pThis, DWORD dwFrequency); HRESULT (STDMETHODCALLTYPE * Stop) (ma_IDirectSoundBuffer* pThis); HRESULT (STDMETHODCALLTYPE * Unlock) (ma_IDirectSoundBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2); HRESULT (STDMETHODCALLTYPE * Restore) (ma_IDirectSoundBuffer* pThis); } ma_IDirectSoundBufferVtbl; struct ma_IDirectSoundBuffer { ma_IDirectSoundBufferVtbl* lpVtbl; }; HRESULT ma_IDirectSoundBuffer_QueryInterface(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IDirectSoundBuffer_AddRef(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IDirectSoundBuffer_Release(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IDirectSoundBuffer_GetCaps(ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSBufferCaps); } HRESULT ma_IDirectSoundBuffer_GetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCurrentPlayCursor, pCurrentWriteCursor); } HRESULT ma_IDirectSoundBuffer_GetFormat(ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); } HRESULT ma_IDirectSoundBuffer_GetVolume(ma_IDirectSoundBuffer* pThis, LONG* pVolume) { return pThis->lpVtbl->GetVolume(pThis, pVolume); } HRESULT ma_IDirectSoundBuffer_GetPan(ma_IDirectSoundBuffer* pThis, LONG* pPan) { return pThis->lpVtbl->GetPan(pThis, pPan); } HRESULT ma_IDirectSoundBuffer_GetFrequency(ma_IDirectSoundBuffer* pThis, DWORD* pFrequency) { return pThis->lpVtbl->GetFrequency(pThis, pFrequency); } HRESULT ma_IDirectSoundBuffer_GetStatus(ma_IDirectSoundBuffer* pThis, DWORD* pStatus) { return pThis->lpVtbl->GetStatus(pThis, pStatus); } HRESULT ma_IDirectSoundBuffer_Initialize(ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSound, pDSBufferDesc); } HRESULT ma_IDirectSoundBuffer_Lock(ma_IDirectSoundBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags) { return pThis->lpVtbl->Lock(pThis, dwOffset, dwBytes, ppAudioPtr1, pAudioBytes1, ppAudioPtr2, pAudioBytes2, dwFlags); } HRESULT ma_IDirectSoundBuffer_Play(ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) { return pThis->lpVtbl->Play(pThis, dwReserved1, dwPriority, dwFlags); } HRESULT ma_IDirectSoundBuffer_SetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition) { return pThis->lpVtbl->SetCurrentPosition(pThis, dwNewPosition); } HRESULT ma_IDirectSoundBuffer_SetFormat(ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat) { return pThis->lpVtbl->SetFormat(pThis, pFormat); } HRESULT ma_IDirectSoundBuffer_SetVolume(ma_IDirectSoundBuffer* pThis, LONG volume) { return pThis->lpVtbl->SetVolume(pThis, volume); } HRESULT ma_IDirectSoundBuffer_SetPan(ma_IDirectSoundBuffer* pThis, LONG pan) { return pThis->lpVtbl->SetPan(pThis, pan); } HRESULT ma_IDirectSoundBuffer_SetFrequency(ma_IDirectSoundBuffer* pThis, DWORD dwFrequency) { return pThis->lpVtbl->SetFrequency(pThis, dwFrequency); } HRESULT ma_IDirectSoundBuffer_Stop(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Stop(pThis); } HRESULT ma_IDirectSoundBuffer_Unlock(ma_IDirectSoundBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2) { return pThis->lpVtbl->Unlock(pThis, pAudioPtr1, dwAudioBytes1, pAudioPtr2, dwAudioBytes2); } HRESULT ma_IDirectSoundBuffer_Restore(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Restore(pThis); } /* IDirectSoundCapture */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundCapture* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundCapture* pThis); /* IDirectSoundCapture */ HRESULT (STDMETHODCALLTYPE * CreateCaptureBuffer)(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter); HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps); HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice); } ma_IDirectSoundCaptureVtbl; struct ma_IDirectSoundCapture { ma_IDirectSoundCaptureVtbl* lpVtbl; }; HRESULT ma_IDirectSoundCapture_QueryInterface(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IDirectSoundCapture_AddRef(ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IDirectSoundCapture_Release(ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IDirectSoundCapture_CreateCaptureBuffer(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter) { return pThis->lpVtbl->CreateCaptureBuffer(pThis, pDSCBufferDesc, ppDSCBuffer, pUnkOuter); } HRESULT ma_IDirectSoundCapture_GetCaps (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCCaps); } HRESULT ma_IDirectSoundCapture_Initialize (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice) { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); } /* IDirectSoundCaptureBuffer */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundCaptureBuffer* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundCaptureBuffer* pThis); /* IDirectSoundCaptureBuffer */ HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps); HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition); HRESULT (STDMETHODCALLTYPE * GetFormat) (ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten); HRESULT (STDMETHODCALLTYPE * GetStatus) (ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus); HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc); HRESULT (STDMETHODCALLTYPE * Lock) (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags); HRESULT (STDMETHODCALLTYPE * Start) (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags); HRESULT (STDMETHODCALLTYPE * Stop) (ma_IDirectSoundCaptureBuffer* pThis); HRESULT (STDMETHODCALLTYPE * Unlock) (ma_IDirectSoundCaptureBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2); } ma_IDirectSoundCaptureBufferVtbl; struct ma_IDirectSoundCaptureBuffer { ma_IDirectSoundCaptureBufferVtbl* lpVtbl; }; HRESULT ma_IDirectSoundCaptureBuffer_QueryInterface(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IDirectSoundCaptureBuffer_AddRef(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IDirectSoundCaptureBuffer_Release(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IDirectSoundCaptureBuffer_GetCaps(ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCBCaps); } HRESULT ma_IDirectSoundCaptureBuffer_GetCurrentPosition(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCapturePosition, pReadPosition); } HRESULT ma_IDirectSoundCaptureBuffer_GetFormat(ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); } HRESULT ma_IDirectSoundCaptureBuffer_GetStatus(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus) { return pThis->lpVtbl->GetStatus(pThis, pStatus); } HRESULT ma_IDirectSoundCaptureBuffer_Initialize(ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSoundCapture, pDSCBufferDesc); } HRESULT ma_IDirectSoundCaptureBuffer_Lock(ma_IDirectSoundCaptureBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags) { return pThis->lpVtbl->Lock(pThis, dwOffset, dwBytes, ppAudioPtr1, pAudioBytes1, ppAudioPtr2, pAudioBytes2, dwFlags); } HRESULT ma_IDirectSoundCaptureBuffer_Start(ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags) { return pThis->lpVtbl->Start(pThis, dwFlags); } HRESULT ma_IDirectSoundCaptureBuffer_Stop(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->Stop(pThis); } HRESULT ma_IDirectSoundCaptureBuffer_Unlock(ma_IDirectSoundCaptureBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2) { return pThis->lpVtbl->Unlock(pThis, pAudioPtr1, dwAudioBytes1, pAudioPtr2, dwAudioBytes2); } /* IDirectSoundNotify */ typedef struct { /* IUnknown */ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject); ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundNotify* pThis); ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundNotify* pThis); /* IDirectSoundNotify */ HRESULT (STDMETHODCALLTYPE * SetNotificationPositions)(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies); } ma_IDirectSoundNotifyVtbl; struct ma_IDirectSoundNotify { ma_IDirectSoundNotifyVtbl* lpVtbl; }; HRESULT ma_IDirectSoundNotify_QueryInterface(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } ULONG ma_IDirectSoundNotify_AddRef(ma_IDirectSoundNotify* pThis) { return pThis->lpVtbl->AddRef(pThis); } ULONG ma_IDirectSoundNotify_Release(ma_IDirectSoundNotify* pThis) { return pThis->lpVtbl->Release(pThis); } HRESULT ma_IDirectSoundNotify_SetNotificationPositions(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies) { return pThis->lpVtbl->SetNotificationPositions(pThis, dwPositionNotifies, pPositionNotifies); } typedef BOOL (CALLBACK * ma_DSEnumCallbackAProc) (LPGUID pDeviceGUID, LPCSTR pDeviceDescription, LPCSTR pModule, LPVOID pContext); typedef HRESULT (WINAPI * ma_DirectSoundCreateProc) (const GUID* pcGuidDevice, ma_IDirectSound** ppDS8, LPUNKNOWN pUnkOuter); typedef HRESULT (WINAPI * ma_DirectSoundEnumerateAProc) (ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext); typedef HRESULT (WINAPI * ma_DirectSoundCaptureCreateProc) (const GUID* pcGuidDevice, ma_IDirectSoundCapture** ppDSC8, LPUNKNOWN pUnkOuter); typedef HRESULT (WINAPI * ma_DirectSoundCaptureEnumerateAProc)(ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext); /* Retrieves the channel count and channel map for the given speaker configuration. If the speaker configuration is unknown, the channel count and channel map will be left unmodified. */ void ma_get_channels_from_speaker_config__dsound(DWORD speakerConfig, WORD* pChannelsOut, DWORD* pChannelMapOut) { WORD channels; DWORD channelMap; channels = 0; if (pChannelsOut != NULL) { channels = *pChannelsOut; } channelMap = 0; if (pChannelMapOut != NULL) { channelMap = *pChannelMapOut; } /* The speaker configuration is a combination of speaker config and speaker geometry. The lower 8 bits is what we care about. The upper 16 bits is for the geometry. */ switch ((BYTE)(speakerConfig)) { case 1 /*DSSPEAKER_HEADPHONE*/: channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break; case 2 /*DSSPEAKER_MONO*/: channels = 1; channelMap = SPEAKER_FRONT_CENTER; break; case 3 /*DSSPEAKER_QUAD*/: channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break; case 4 /*DSSPEAKER_STEREO*/: channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break; case 5 /*DSSPEAKER_SURROUND*/: channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER; break; case 6 /*DSSPEAKER_5POINT1_BACK*/ /*DSSPEAKER_5POINT1*/: channels = 6; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break; case 7 /*DSSPEAKER_7POINT1_WIDE*/ /*DSSPEAKER_7POINT1*/: channels = 8; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER; break; case 8 /*DSSPEAKER_7POINT1_SURROUND*/: channels = 8; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; case 9 /*DSSPEAKER_5POINT1_SURROUND*/: channels = 6; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; default: break; } if (pChannelsOut != NULL) { *pChannelsOut = channels; } if (pChannelMapOut != NULL) { *pChannelMapOut = channelMap; } } ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSound** ppDirectSound) { ma_IDirectSound* pDirectSound; HWND hWnd; ma_assert(pContext != NULL); ma_assert(ppDirectSound != NULL); *ppDirectSound = NULL; pDirectSound = NULL; if (FAILED(((ma_DirectSoundCreateProc)pContext->dsound.DirectSoundCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSound, NULL))) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* The cooperative level must be set before doing anything else. */ hWnd = ((MA_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)(); if (hWnd == NULL) { hWnd = ((MA_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)(); } if (FAILED(ma_IDirectSound_SetCooperativeLevel(pDirectSound, hWnd, (shareMode == ma_share_mode_exclusive) ? MA_DSSCL_EXCLUSIVE : MA_DSSCL_PRIORITY))) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.", MA_SHARE_MODE_NOT_SUPPORTED); } *ppDirectSound = pDirectSound; return MA_SUCCESS; } ma_result ma_context_create_IDirectSoundCapture__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSoundCapture** ppDirectSoundCapture) { ma_IDirectSoundCapture* pDirectSoundCapture; ma_assert(pContext != NULL); ma_assert(ppDirectSoundCapture != NULL); /* DirectSound does not support exclusive mode for capture. */ if (shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } *ppDirectSoundCapture = NULL; pDirectSoundCapture = NULL; if (FAILED(((ma_DirectSoundCaptureCreateProc)pContext->dsound.DirectSoundCaptureCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSoundCapture, NULL))) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } *ppDirectSoundCapture = pDirectSoundCapture; return MA_SUCCESS; } ma_result ma_context_get_format_info_for_IDirectSoundCapture__dsound(ma_context* pContext, ma_IDirectSoundCapture* pDirectSoundCapture, WORD* pChannels, WORD* pBitsPerSample, DWORD* pSampleRate) { MA_DSCCAPS caps; WORD bitsPerSample; DWORD sampleRate; ma_assert(pContext != NULL); ma_assert(pDirectSoundCapture != NULL); if (pChannels) { *pChannels = 0; } if (pBitsPerSample) { *pBitsPerSample = 0; } if (pSampleRate) { *pSampleRate = 0; } ma_zero_object(&caps); caps.dwSize = sizeof(caps); if (FAILED(ma_IDirectSoundCapture_GetCaps(pDirectSoundCapture, &caps))) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (pChannels) { *pChannels = (WORD)caps.dwChannels; } /* The device can support multiple formats. We just go through the different formats in order of priority and pick the first one. This the same type of system as the WinMM backend. */ bitsPerSample = 16; sampleRate = 48000; if (caps.dwChannels == 1) { if ((caps.dwFormats & WAVE_FORMAT_48M16) != 0) { sampleRate = 48000; } else if ((caps.dwFormats & WAVE_FORMAT_44M16) != 0) { sampleRate = 44100; } else if ((caps.dwFormats & WAVE_FORMAT_2M16) != 0) { sampleRate = 22050; } else if ((caps.dwFormats & WAVE_FORMAT_1M16) != 0) { sampleRate = 11025; } else if ((caps.dwFormats & WAVE_FORMAT_96M16) != 0) { sampleRate = 96000; } else { bitsPerSample = 8; if ((caps.dwFormats & WAVE_FORMAT_48M08) != 0) { sampleRate = 48000; } else if ((caps.dwFormats & WAVE_FORMAT_44M08) != 0) { sampleRate = 44100; } else if ((caps.dwFormats & WAVE_FORMAT_2M08) != 0) { sampleRate = 22050; } else if ((caps.dwFormats & WAVE_FORMAT_1M08) != 0) { sampleRate = 11025; } else if ((caps.dwFormats & WAVE_FORMAT_96M08) != 0) { sampleRate = 96000; } else { bitsPerSample = 16; /* Didn't find it. Just fall back to 16-bit. */ } } } else if (caps.dwChannels == 2) { if ((caps.dwFormats & WAVE_FORMAT_48S16) != 0) { sampleRate = 48000; } else if ((caps.dwFormats & WAVE_FORMAT_44S16) != 0) { sampleRate = 44100; } else if ((caps.dwFormats & WAVE_FORMAT_2S16) != 0) { sampleRate = 22050; } else if ((caps.dwFormats & WAVE_FORMAT_1S16) != 0) { sampleRate = 11025; } else if ((caps.dwFormats & WAVE_FORMAT_96S16) != 0) { sampleRate = 96000; } else { bitsPerSample = 8; if ((caps.dwFormats & WAVE_FORMAT_48S08) != 0) { sampleRate = 48000; } else if ((caps.dwFormats & WAVE_FORMAT_44S08) != 0) { sampleRate = 44100; } else if ((caps.dwFormats & WAVE_FORMAT_2S08) != 0) { sampleRate = 22050; } else if ((caps.dwFormats & WAVE_FORMAT_1S08) != 0) { sampleRate = 11025; } else if ((caps.dwFormats & WAVE_FORMAT_96S08) != 0) { sampleRate = 96000; } else { bitsPerSample = 16; /* Didn't find it. Just fall back to 16-bit. */ } } } if (pBitsPerSample) { *pBitsPerSample = bitsPerSample; } if (pSampleRate) { *pSampleRate = sampleRate; } return MA_SUCCESS; } ma_bool32 ma_context_is_device_id_equal__dsound(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return memcmp(pID0->dsound, pID1->dsound, sizeof(pID0->dsound)) == 0; } typedef struct { ma_context* pContext; ma_device_type deviceType; ma_enum_devices_callback_proc callback; void* pUserData; ma_bool32 terminated; } ma_context_enumerate_devices_callback_data__dsound; BOOL CALLBACK ma_context_enumerate_devices_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) { ma_context_enumerate_devices_callback_data__dsound* pData = (ma_context_enumerate_devices_callback_data__dsound*)lpContext; ma_device_info deviceInfo; ma_zero_object(&deviceInfo); /* ID. */ if (lpGuid != NULL) { ma_copy_memory(deviceInfo.id.dsound, lpGuid, 16); } else { ma_zero_memory(deviceInfo.id.dsound, 16); } /* Name / Description */ ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), lpcstrDescription, (size_t)-1); /* Call the callback function, but make sure we stop enumerating if the callee requested so. */ ma_assert(pData != NULL); pData->terminated = !pData->callback(pData->pContext, pData->deviceType, &deviceInfo, pData->pUserData); if (pData->terminated) { return FALSE; /* Stop enumeration. */ } else { return TRUE; /* Continue enumeration. */ } (void)lpcstrModule; } ma_result ma_context_enumerate_devices__dsound(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_context_enumerate_devices_callback_data__dsound data; ma_assert(pContext != NULL); ma_assert(callback != NULL); data.pContext = pContext; data.callback = callback; data.pUserData = pUserData; data.terminated = MA_FALSE; /* Playback. */ if (!data.terminated) { data.deviceType = ma_device_type_playback; ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data); } /* Capture. */ if (!data.terminated) { data.deviceType = ma_device_type_capture; ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data); } return MA_SUCCESS; } typedef struct { const ma_device_id* pDeviceID; ma_device_info* pDeviceInfo; ma_bool32 found; } ma_context_get_device_info_callback_data__dsound; BOOL CALLBACK ma_context_get_device_info_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) { ma_context_get_device_info_callback_data__dsound* pData = (ma_context_get_device_info_callback_data__dsound*)lpContext; ma_assert(pData != NULL); if ((pData->pDeviceID == NULL || ma_is_guid_equal(pData->pDeviceID->dsound, &MA_GUID_NULL)) && (lpGuid == NULL || ma_is_guid_equal(lpGuid, &MA_GUID_NULL))) { /* Default device. */ ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1); pData->found = MA_TRUE; return FALSE; /* Stop enumeration. */ } else { /* Not the default device. */ if (lpGuid != NULL) { if (memcmp(pData->pDeviceID->dsound, lpGuid, sizeof(pData->pDeviceID->dsound)) == 0) { ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1); pData->found = MA_TRUE; return FALSE; /* Stop enumeration. */ } } } (void)lpcstrModule; return TRUE; } ma_result ma_context_get_device_info__dsound(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { /* Exclusive mode and capture not supported with DirectSound. */ if (deviceType == ma_device_type_capture && shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } if (pDeviceID != NULL) { ma_context_get_device_info_callback_data__dsound data; /* ID. */ ma_copy_memory(pDeviceInfo->id.dsound, pDeviceID->dsound, 16); /* Name / Description. This is retrieved by enumerating over each device until we find that one that matches the input ID. */ data.pDeviceID = pDeviceID; data.pDeviceInfo = pDeviceInfo; data.found = MA_FALSE; if (deviceType == ma_device_type_playback) { ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_get_device_info_callback__dsound, &data); } else { ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_get_device_info_callback__dsound, &data); } if (!data.found) { return MA_NO_DEVICE; } } else { /* I don't think there's a way to get the name of the default device with DirectSound. In this case we just need to use defaults. */ /* ID */ ma_zero_memory(pDeviceInfo->id.dsound, 16); /* Name / Description */ if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } } /* Retrieving detailed information is slightly different depending on the device type. */ if (deviceType == ma_device_type_playback) { /* Playback. */ ma_IDirectSound* pDirectSound; ma_result result; MA_DSCAPS caps; ma_uint32 iFormat; result = ma_context_create_IDirectSound__dsound(pContext, shareMode, pDeviceID, &pDirectSound); if (result != MA_SUCCESS) { return result; } ma_zero_object(&caps); caps.dwSize = sizeof(caps); if (FAILED(ma_IDirectSound_GetCaps(pDirectSound, &caps))) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) { /* It supports at least stereo, but could support more. */ WORD channels = 2; /* Look at the speaker configuration to get a better idea on the channel count. */ DWORD speakerConfig; if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig(pDirectSound, &speakerConfig))) { ma_get_channels_from_speaker_config__dsound(speakerConfig, &channels, NULL); } pDeviceInfo->minChannels = channels; pDeviceInfo->maxChannels = channels; } else { /* It does not support stereo, which means we are stuck with mono. */ pDeviceInfo->minChannels = 1; pDeviceInfo->maxChannels = 1; } /* Sample rate. */ if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) { pDeviceInfo->minSampleRate = caps.dwMinSecondarySampleRate; pDeviceInfo->maxSampleRate = caps.dwMaxSecondarySampleRate; /* On my machine the min and max sample rates can return 100 and 200000 respectively. I'd rather these be within the range of our standard sample rates so I'm clamping. */ if (caps.dwMinSecondarySampleRate < MA_MIN_SAMPLE_RATE && caps.dwMaxSecondarySampleRate >= MA_MIN_SAMPLE_RATE) { pDeviceInfo->minSampleRate = MA_MIN_SAMPLE_RATE; } if (caps.dwMaxSecondarySampleRate > MA_MAX_SAMPLE_RATE && caps.dwMinSecondarySampleRate <= MA_MAX_SAMPLE_RATE) { pDeviceInfo->maxSampleRate = MA_MAX_SAMPLE_RATE; } } else { /* Only supports a single sample rate. Set both min an max to the same thing. Do not clamp within the standard rates. */ pDeviceInfo->minSampleRate = caps.dwMaxSecondarySampleRate; pDeviceInfo->maxSampleRate = caps.dwMaxSecondarySampleRate; } /* DirectSound can support all formats. */ pDeviceInfo->formatCount = ma_format_count - 1; /* Minus one because we don't want to include ma_format_unknown. */ for (iFormat = 0; iFormat < pDeviceInfo->formatCount; ++iFormat) { pDeviceInfo->formats[iFormat] = (ma_format)(iFormat + 1); /* +1 to skip over ma_format_unknown. */ } ma_IDirectSound_Release(pDirectSound); } else { /* Capture. This is a little different to playback due to the say the supported formats are reported. Technically capture devices can support a number of different formats, but for simplicity and consistency with ma_device_init() I'm just reporting the best format. */ ma_IDirectSoundCapture* pDirectSoundCapture; ma_result result; WORD channels; WORD bitsPerSample; DWORD sampleRate; result = ma_context_create_IDirectSoundCapture__dsound(pContext, shareMode, pDeviceID, &pDirectSoundCapture); if (result != MA_SUCCESS) { return result; } result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, pDirectSoundCapture, &channels, &bitsPerSample, &sampleRate); if (result != MA_SUCCESS) { ma_IDirectSoundCapture_Release(pDirectSoundCapture); return result; } pDeviceInfo->minChannels = channels; pDeviceInfo->maxChannels = channels; pDeviceInfo->minSampleRate = sampleRate; pDeviceInfo->maxSampleRate = sampleRate; pDeviceInfo->formatCount = 1; if (bitsPerSample == 8) { pDeviceInfo->formats[0] = ma_format_u8; } else if (bitsPerSample == 16) { pDeviceInfo->formats[0] = ma_format_s16; } else if (bitsPerSample == 24) { pDeviceInfo->formats[0] = ma_format_s24; } else if (bitsPerSample == 32) { pDeviceInfo->formats[0] = ma_format_s32; } else { ma_IDirectSoundCapture_Release(pDirectSoundCapture); return MA_FORMAT_NOT_SUPPORTED; } ma_IDirectSoundCapture_Release(pDirectSoundCapture); } return MA_SUCCESS; } typedef struct { ma_uint32 deviceCount; ma_uint32 infoCount; ma_device_info* pInfo; } ma_device_enum_data__dsound; BOOL CALLBACK ma_enum_devices_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) { ma_device_enum_data__dsound* pData = (ma_device_enum_data__dsound*)lpContext; ma_assert(pData != NULL); if (pData->pInfo != NULL) { if (pData->infoCount > 0) { ma_zero_object(pData->pInfo); ma_strncpy_s(pData->pInfo->name, sizeof(pData->pInfo->name), lpcstrDescription, (size_t)-1); if (lpGuid != NULL) { ma_copy_memory(pData->pInfo->id.dsound, lpGuid, 16); } else { ma_zero_memory(pData->pInfo->id.dsound, 16); } pData->pInfo += 1; pData->infoCount -= 1; pData->deviceCount += 1; } } else { pData->deviceCount += 1; } (void)lpcstrModule; return TRUE; } void ma_device_uninit__dsound(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->dsound.pCaptureBuffer != NULL) { ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); } if (pDevice->dsound.pCapture != NULL) { ma_IDirectSoundCapture_Release((ma_IDirectSoundCapture*)pDevice->dsound.pCapture); } if (pDevice->dsound.pPlaybackBuffer != NULL) { ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer); } if (pDevice->dsound.pPlaybackPrimaryBuffer != NULL) { ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer); } if (pDevice->dsound.pPlayback != NULL) { ma_IDirectSound_Release((ma_IDirectSound*)pDevice->dsound.pPlayback); } } ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* pChannelMap, WAVEFORMATEXTENSIBLE* pWF) { GUID subformat; switch (format) { case ma_format_u8: case ma_format_s16: case ma_format_s24: /*case ma_format_s24_32:*/ case ma_format_s32: { subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM; } break; case ma_format_f32: { subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; } break; default: return MA_FORMAT_NOT_SUPPORTED; } ma_zero_object(pWF); pWF->Format.cbSize = sizeof(*pWF); pWF->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; pWF->Format.nChannels = (WORD)channels; pWF->Format.nSamplesPerSec = (DWORD)sampleRate; pWF->Format.wBitsPerSample = (WORD)ma_get_bytes_per_sample(format)*8; pWF->Format.nBlockAlign = (pWF->Format.nChannels * pWF->Format.wBitsPerSample) / 8; pWF->Format.nAvgBytesPerSec = pWF->Format.nBlockAlign * pWF->Format.nSamplesPerSec; pWF->Samples.wValidBitsPerSample = pWF->Format.wBitsPerSample; pWF->dwChannelMask = ma_channel_map_to_channel_mask__win32(pChannelMap, channels); pWF->SubFormat = subformat; return MA_SUCCESS; } ma_result ma_device_init__dsound(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result; ma_uint32 bufferSizeInMilliseconds; ma_assert(pDevice != NULL); ma_zero_object(&pDevice->dsound); bufferSizeInMilliseconds = pConfig->bufferSizeInMilliseconds; if (bufferSizeInMilliseconds == 0) { bufferSizeInMilliseconds = ma_calculate_buffer_size_in_milliseconds_from_frames(pConfig->bufferSizeInFrames, pConfig->sampleRate); } /* DirectSound should use a latency of about 20ms per period for low latency mode. */ if (pDevice->usingDefaultBufferSize) { if (pConfig->performanceProfile == ma_performance_profile_low_latency) { bufferSizeInMilliseconds = 20 * pConfig->periods; } else { bufferSizeInMilliseconds = 200 * pConfig->periods; } } /* DirectSound breaks down with tiny buffer sizes (bad glitching and silent output). I am therefore restricting the size of the buffer to a minimum of 20 milliseconds. */ if ((bufferSizeInMilliseconds/pConfig->periods) < 20) { bufferSizeInMilliseconds = pConfig->periods * 20; } /* Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices. We need to initialize the capture device first because we'll want to match it's buffer size and period count on the playback side if we're using full-duplex mode. */ if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { WAVEFORMATEXTENSIBLE wf; MA_DSCBUFFERDESC descDS; ma_uint32 bufferSizeInFrames; char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */ WAVEFORMATEXTENSIBLE* pActualFormat; result = ma_config_to_WAVEFORMATEXTENSIBLE(pConfig->capture.format, pConfig->capture.channels, pConfig->sampleRate, pConfig->capture.channelMap, &wf); if (result != MA_SUCCESS) { return result; } result = ma_context_create_IDirectSoundCapture__dsound(pContext, pConfig->capture.shareMode, pConfig->capture.pDeviceID, (ma_IDirectSoundCapture**)&pDevice->dsound.pCapture); if (result != MA_SUCCESS) { ma_device_uninit__dsound(pDevice); return result; } result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, (ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &wf.Format.nChannels, &wf.Format.wBitsPerSample, &wf.Format.nSamplesPerSec); if (result != MA_SUCCESS) { ma_device_uninit__dsound(pDevice); return result; } wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM; /* The size of the buffer must be a clean multiple of the period count. */ bufferSizeInFrames = (ma_calculate_buffer_size_in_frames_from_milliseconds(bufferSizeInMilliseconds, wf.Format.nSamplesPerSec) / pConfig->periods) * pConfig->periods; ma_zero_object(&descDS); descDS.dwSize = sizeof(descDS); descDS.dwFlags = 0; descDS.dwBufferBytes = bufferSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, wf.Format.nChannels); descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; if (FAILED(ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL))) { ma_device_uninit__dsound(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* Get the _actual_ properties of the buffer. */ pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata; if (FAILED(ma_IDirectSoundCaptureBuffer_GetFormat((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL))) { ma_device_uninit__dsound(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer.", MA_FORMAT_NOT_SUPPORTED); } pDevice->capture.internalFormat = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat); pDevice->capture.internalChannels = pActualFormat->Format.nChannels; pDevice->capture.internalSampleRate = pActualFormat->Format.nSamplesPerSec; /* Get the internal channel map based on the channel mask. */ if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); } else { ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); } /* After getting the actual format the size of the buffer in frames may have actually changed. However, we want this to be as close to what the user has asked for as possible, so let's go ahead and release the old capture buffer and create a new one in this case. */ if (bufferSizeInFrames != (descDS.dwBufferBytes / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels))) { descDS.dwBufferBytes = bufferSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, wf.Format.nChannels); ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); if (FAILED(ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL))) { ma_device_uninit__dsound(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } /* DirectSound should give us a buffer exactly the size we asked for. */ pDevice->capture.internalBufferSizeInFrames = bufferSizeInFrames; pDevice->capture.internalPeriods = pConfig->periods; } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { WAVEFORMATEXTENSIBLE wf; MA_DSBUFFERDESC descDSPrimary; MA_DSCAPS caps; char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */ WAVEFORMATEXTENSIBLE* pActualFormat; ma_uint32 bufferSizeInFrames; MA_DSBUFFERDESC descDS; result = ma_config_to_WAVEFORMATEXTENSIBLE(pConfig->playback.format, pConfig->playback.channels, pConfig->sampleRate, pConfig->playback.channelMap, &wf); if (result != MA_SUCCESS) { return result; } result = ma_context_create_IDirectSound__dsound(pContext, pConfig->playback.shareMode, pConfig->playback.pDeviceID, (ma_IDirectSound**)&pDevice->dsound.pPlayback); if (result != MA_SUCCESS) { ma_device_uninit__dsound(pDevice); return result; } ma_zero_object(&descDSPrimary); descDSPrimary.dwSize = sizeof(MA_DSBUFFERDESC); descDSPrimary.dwFlags = MA_DSBCAPS_PRIMARYBUFFER | MA_DSBCAPS_CTRLVOLUME; if (FAILED(ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDSPrimary, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackPrimaryBuffer, NULL))) { ma_device_uninit__dsound(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* We may want to make some adjustments to the format if we are using defaults. */ ma_zero_object(&caps); caps.dwSize = sizeof(caps); if (FAILED(ma_IDirectSound_GetCaps((ma_IDirectSound*)pDevice->dsound.pPlayback, &caps))) { ma_device_uninit__dsound(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (pDevice->playback.usingDefaultChannels) { if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) { DWORD speakerConfig; /* It supports at least stereo, but could support more. */ wf.Format.nChannels = 2; /* Look at the speaker configuration to get a better idea on the channel count. */ if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)pDevice->dsound.pPlayback, &speakerConfig))) { ma_get_channels_from_speaker_config__dsound(speakerConfig, &wf.Format.nChannels, &wf.dwChannelMask); } } else { /* It does not support stereo, which means we are stuck with mono. */ wf.Format.nChannels = 1; } } if (pDevice->usingDefaultSampleRate) { /* We base the sample rate on the values returned by GetCaps(). */ if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) { wf.Format.nSamplesPerSec = ma_get_best_sample_rate_within_range(caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate); } else { wf.Format.nSamplesPerSec = caps.dwMaxSecondarySampleRate; } } wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; /* From MSDN: The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer and compare the result with the format that was requested with the SetFormat method. */ if (FAILED(ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf))) { ma_device_uninit__dsound(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer.", MA_FORMAT_NOT_SUPPORTED); } /* Get the _actual_ properties of the buffer. */ pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata; if (FAILED(ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL))) { ma_device_uninit__dsound(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", MA_FORMAT_NOT_SUPPORTED); } pDevice->playback.internalFormat = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat); pDevice->playback.internalChannels = pActualFormat->Format.nChannels; pDevice->playback.internalSampleRate = pActualFormat->Format.nSamplesPerSec; /* Get the internal channel map based on the channel mask. */ if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); } else { ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); } /* The size of the buffer must be a clean multiple of the period count. */ bufferSizeInFrames = (ma_calculate_buffer_size_in_frames_from_milliseconds(bufferSizeInMilliseconds, pDevice->playback.internalSampleRate) / pConfig->periods) * pConfig->periods; /* Meaning of dwFlags (from MSDN): DSBCAPS_CTRLPOSITIONNOTIFY The buffer has position notification capability. DSBCAPS_GLOBALFOCUS With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to another application, even if the new application uses DirectSound. DSBCAPS_GETCURRENTPOSITION2 In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the application can get a more accurate play cursor. */ ma_zero_object(&descDS); descDS.dwSize = sizeof(descDS); descDS.dwFlags = MA_DSBCAPS_CTRLPOSITIONNOTIFY | MA_DSBCAPS_GLOBALFOCUS | MA_DSBCAPS_GETCURRENTPOSITION2; descDS.dwBufferBytes = bufferSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; if (FAILED(ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDS, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackBuffer, NULL))) { ma_device_uninit__dsound(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* DirectSound should give us a buffer exactly the size we asked for. */ pDevice->playback.internalBufferSizeInFrames = bufferSizeInFrames; pDevice->playback.internalPeriods = pConfig->periods; } (void)pContext; return MA_SUCCESS; } ma_result ma_device_main_loop__dsound(ma_device* pDevice) { ma_result result = MA_SUCCESS; ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); HRESULT hr; DWORD lockOffsetInBytesCapture; DWORD lockSizeInBytesCapture; DWORD mappedSizeInBytesCapture; void* pMappedBufferCapture; DWORD lockOffsetInBytesPlayback; DWORD lockSizeInBytesPlayback; DWORD mappedSizeInBytesPlayback; void* pMappedBufferPlayback; DWORD prevReadCursorInBytesCapture = 0; DWORD prevPlayCursorInBytesPlayback = 0; ma_bool32 physicalPlayCursorLoopFlagPlayback = 0; DWORD virtualWriteCursorInBytesPlayback = 0; ma_bool32 virtualWriteCursorLoopFlagPlayback = 0; ma_bool32 isPlaybackDeviceStarted = MA_FALSE; ma_uint32 framesWrittenToPlaybackDevice = 0; /* For knowing whether or not the playback device needs to be started. */ ma_uint32 waitTimeInMilliseconds = 1; ma_assert(pDevice != NULL); /* The first thing to do is start the capture device. The playback device is only started after the first period is written. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (FAILED(ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING))) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.", MA_FAILED_TO_START_BACKEND_DEVICE); } } while (ma_device__get_state(pDevice) == MA_STATE_STARTED) { switch (pDevice->type) { case ma_device_type_duplex: { DWORD physicalCaptureCursorInBytes; DWORD physicalReadCursorInBytes; if (FAILED(ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes))) { return MA_ERROR; } /* If nothing is available we just sleep for a bit and return from this iteration. */ if (physicalReadCursorInBytes == prevReadCursorInBytesCapture) { ma_sleep(waitTimeInMilliseconds); continue; /* Nothing is available in the capture buffer. */ } /* The current position has moved. We need to map all of the captured samples and write them to the playback device, making sure we don't return until every frame has been copied over. */ if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) { /* The capture position has not looped. This is the simple case. */ lockOffsetInBytesCapture = prevReadCursorInBytesCapture; lockSizeInBytesCapture = (physicalReadCursorInBytes - prevReadCursorInBytesCapture); } else { /* The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything, do it again from the start. */ if (prevReadCursorInBytesCapture < pDevice->capture.internalBufferSizeInFrames*bpfCapture) { /* Lock up to the end of the buffer. */ lockOffsetInBytesCapture = prevReadCursorInBytesCapture; lockSizeInBytesCapture = (pDevice->capture.internalBufferSizeInFrames*bpfCapture) - prevReadCursorInBytesCapture; } else { /* Lock starting from the start of the buffer. */ lockOffsetInBytesCapture = 0; lockSizeInBytesCapture = physicalReadCursorInBytes; } } if (lockSizeInBytesCapture == 0) { ma_sleep(waitTimeInMilliseconds); continue; /* Nothing is available in the capture buffer. */ } hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", MA_FAILED_TO_MAP_DEVICE_BUFFER); } /* At this point we have some input data that we need to output. We do not return until every mapped frame of the input data is written to the playback device. */ pDevice->capture._dspFrameCount = mappedSizeInBytesCapture / bpfCapture; pDevice->capture._dspFrames = (const ma_uint8*)pMappedBufferCapture; for (;;) { /* Keep writing to the playback device. */ ma_uint8 inputFramesInExternalFormat[4096]; ma_uint32 inputFramesInExternalFormatCap = sizeof(inputFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); ma_uint32 inputFramesInExternalFormatCount; ma_uint8 outputFramesInExternalFormat[4096]; ma_uint32 outputFramesInExternalFormatCap = sizeof(outputFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); inputFramesInExternalFormatCount = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, inputFramesInExternalFormat, ma_min(inputFramesInExternalFormatCap, outputFramesInExternalFormatCap)); if (inputFramesInExternalFormatCount == 0) { break; /* No more input data. */ } pDevice->onData(pDevice, outputFramesInExternalFormat, inputFramesInExternalFormat, inputFramesInExternalFormatCount); /* At this point we have input and output data in external format. All we need to do now is convert it to the output format. This may take a few passes. */ pDevice->playback._dspFrameCount = inputFramesInExternalFormatCount; pDevice->playback._dspFrames = (const ma_uint8*)outputFramesInExternalFormat; for (;;) { ma_uint32 framesWrittenThisIteration; DWORD physicalPlayCursorInBytes; DWORD physicalWriteCursorInBytes; DWORD availableBytesPlayback; DWORD silentPaddingInBytes = 0; /* <-- Must be initialized to 0. */ /* We need the physical play and write cursors. */ if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) { break; } if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) { physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback; } prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes; /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */ if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */ if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) { availableBytesPlayback = (pDevice->playback.internalBufferSizeInFrames*bpfPlayback) - virtualWriteCursorInBytesPlayback; availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ } else { /* This is an error. */ #ifdef MA_DEBUG_OUTPUT printf("[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%d, virtualWriteCursorInBytes=%d.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); #endif availableBytesPlayback = 0; } } else { /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */ if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) { availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } else { /* This is an error. */ #ifdef MA_DEBUG_OUTPUT printf("[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%d, virtualWriteCursorInBytes=%d.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); #endif availableBytesPlayback = 0; } } #ifdef MA_DEBUG_OUTPUT /*printf("[DirectSound] (Duplex/Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/ #endif /* If there's no room available for writing we need to wait for more. */ if (availableBytesPlayback == 0) { /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */ if (!isPlaybackDeviceStarted) { if (FAILED(ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING))) { ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", MA_FAILED_TO_START_BACKEND_DEVICE); } isPlaybackDeviceStarted = MA_TRUE; } else { ma_sleep(waitTimeInMilliseconds); continue; } } /* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */ lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback; if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { /* Same loop iteration. Go up to the end of the buffer. */ lockSizeInBytesPlayback = (pDevice->playback.internalBufferSizeInFrames*bpfPlayback) - virtualWriteCursorInBytesPlayback; } else { /* Different loop iterations. Go up to the physical play cursor. */ lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0); if (FAILED(hr)) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", MA_FAILED_TO_MAP_DEVICE_BUFFER); break; } /* Experiment: If the playback buffer is being starved, pad it with some silence to get it back in sync. This will cause a glitch, but it may prevent endless glitching due to it constantly running out of data. */ if (isPlaybackDeviceStarted) { DWORD bytesQueuedForPlayback = (pDevice->playback.internalBufferSizeInFrames*bpfPlayback) - availableBytesPlayback; if (bytesQueuedForPlayback < ((pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods)*bpfPlayback)) { silentPaddingInBytes = ((pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods)*2*bpfPlayback) - bytesQueuedForPlayback; if (silentPaddingInBytes > lockSizeInBytesPlayback) { silentPaddingInBytes = lockSizeInBytesPlayback; } #ifdef MA_DEBUG_OUTPUT printf("[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%d, silentPaddingInBytes=%d\n", availableBytesPlayback, silentPaddingInBytes); #endif } } /* At this point we have a buffer for output. */ if (silentPaddingInBytes > 0) { ma_zero_memory(pMappedBufferPlayback, silentPaddingInBytes); framesWrittenThisIteration = silentPaddingInBytes/bpfPlayback; } else { framesWrittenThisIteration = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, pMappedBufferPlayback, mappedSizeInBytesPlayback/bpfPlayback); } hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedBufferPlayback, framesWrittenThisIteration*bpfPlayback, NULL, 0); if (FAILED(hr)) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", MA_FAILED_TO_UNMAP_DEVICE_BUFFER); break; } virtualWriteCursorInBytesPlayback += framesWrittenThisIteration*bpfPlayback; if ((virtualWriteCursorInBytesPlayback/bpfPlayback) == pDevice->playback.internalBufferSizeInFrames) { virtualWriteCursorInBytesPlayback = 0; virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback; } /* We may need to start the device. We want two full periods to be written before starting the playback device. Having an extra period adds a bit of a buffer to prevent the playback buffer from getting starved. */ framesWrittenToPlaybackDevice += framesWrittenThisIteration; if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= ((pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods)*2)) { if (FAILED(ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING))) { ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", MA_FAILED_TO_START_BACKEND_DEVICE); } isPlaybackDeviceStarted = MA_TRUE; } if (framesWrittenThisIteration < mappedSizeInBytesPlayback/bpfPlayback) { break; /* We're finished with the output data.*/ } } if (inputFramesInExternalFormatCount < inputFramesInExternalFormatCap) { break; /* We just consumed every input sample. */ } } /* At this point we're done with the mapped portion of the capture buffer. */ hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedBufferCapture, mappedSizeInBytesCapture, NULL, 0); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", MA_FAILED_TO_UNMAP_DEVICE_BUFFER); } prevReadCursorInBytesCapture = (lockOffsetInBytesCapture + mappedSizeInBytesCapture); } break; case ma_device_type_capture: { DWORD physicalCaptureCursorInBytes; DWORD physicalReadCursorInBytes; if (FAILED(ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes))) { return MA_ERROR; } /* If the previous capture position is the same as the current position we need to wait a bit longer. */ if (prevReadCursorInBytesCapture == physicalReadCursorInBytes) { ma_sleep(waitTimeInMilliseconds); continue; } /* Getting here means we have capture data available. */ if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) { /* The capture position has not looped. This is the simple case. */ lockOffsetInBytesCapture = prevReadCursorInBytesCapture; lockSizeInBytesCapture = (physicalReadCursorInBytes - prevReadCursorInBytesCapture); } else { /* The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything, do it again from the start. */ if (prevReadCursorInBytesCapture < pDevice->capture.internalBufferSizeInFrames*bpfCapture) { /* Lock up to the end of the buffer. */ lockOffsetInBytesCapture = prevReadCursorInBytesCapture; lockSizeInBytesCapture = (pDevice->capture.internalBufferSizeInFrames*bpfCapture) - prevReadCursorInBytesCapture; } else { /* Lock starting from the start of the buffer. */ lockOffsetInBytesCapture = 0; lockSizeInBytesCapture = physicalReadCursorInBytes; } } #ifdef MA_DEBUG_OUTPUT /*printf("[DirectSound] (Capture) physicalCaptureCursorInBytes=%d, physicalReadCursorInBytes=%d\n", physicalCaptureCursorInBytes, physicalReadCursorInBytes);*/ /*printf("[DirectSound] (Capture) lockOffsetInBytesCapture=%d, lockSizeInBytesCapture=%d\n", lockOffsetInBytesCapture, lockSizeInBytesCapture);*/ #endif if (lockSizeInBytesCapture < (pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods)) { ma_sleep(waitTimeInMilliseconds); continue; /* Nothing is available in the capture buffer. */ } hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", MA_FAILED_TO_MAP_DEVICE_BUFFER); } #ifdef MA_DEBUG_OUTPUT if (lockSizeInBytesCapture != mappedSizeInBytesCapture) { printf("[DirectSound] (Capture) lockSizeInBytesCapture=%d != mappedSizeInBytesCapture=%d\n", lockSizeInBytesCapture, mappedSizeInBytesCapture); } #endif ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfCapture, pMappedBufferCapture); hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedBufferCapture, mappedSizeInBytesCapture, NULL, 0); if (FAILED(hr)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", MA_FAILED_TO_UNMAP_DEVICE_BUFFER); } prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture; if (prevReadCursorInBytesCapture == (pDevice->capture.internalBufferSizeInFrames*bpfCapture)) { prevReadCursorInBytesCapture = 0; } } break; case ma_device_type_playback: { DWORD availableBytesPlayback; DWORD physicalPlayCursorInBytes; DWORD physicalWriteCursorInBytes; if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) { break; } if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) { physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback; } prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes; /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */ if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */ if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) { availableBytesPlayback = (pDevice->playback.internalBufferSizeInFrames*bpfPlayback) - virtualWriteCursorInBytesPlayback; availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ } else { /* This is an error. */ #ifdef MA_DEBUG_OUTPUT printf("[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%d, virtualWriteCursorInBytes=%d.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); #endif availableBytesPlayback = 0; } } else { /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */ if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) { availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } else { /* This is an error. */ #ifdef MA_DEBUG_OUTPUT printf("[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%d, virtualWriteCursorInBytes=%d.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback); #endif availableBytesPlayback = 0; } } #ifdef MA_DEBUG_OUTPUT /*printf("[DirectSound] (Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/ #endif /* If there's no room available for writing we need to wait for more. */ if (availableBytesPlayback < (pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods)) { /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */ if (availableBytesPlayback == 0 && !isPlaybackDeviceStarted) { if (FAILED(ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING))) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", MA_FAILED_TO_START_BACKEND_DEVICE); } isPlaybackDeviceStarted = MA_TRUE; } else { ma_sleep(waitTimeInMilliseconds); continue; } } /* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */ lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback; if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { /* Same loop iteration. Go up to the end of the buffer. */ lockSizeInBytesPlayback = (pDevice->playback.internalBufferSizeInFrames*bpfPlayback) - virtualWriteCursorInBytesPlayback; } else { /* Different loop iterations. Go up to the physical play cursor. */ lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0); if (FAILED(hr)) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", MA_FAILED_TO_MAP_DEVICE_BUFFER); break; } /* At this point we have a buffer for output. */ ma_device__read_frames_from_client(pDevice, (mappedSizeInBytesPlayback/bpfPlayback), pMappedBufferPlayback); hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedBufferPlayback, mappedSizeInBytesPlayback, NULL, 0); if (FAILED(hr)) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", MA_FAILED_TO_UNMAP_DEVICE_BUFFER); break; } virtualWriteCursorInBytesPlayback += mappedSizeInBytesPlayback; if (virtualWriteCursorInBytesPlayback == pDevice->playback.internalBufferSizeInFrames*bpfPlayback) { virtualWriteCursorInBytesPlayback = 0; virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback; } /* We may need to start the device. We want two full periods to be written before starting the playback device. Having an extra period adds a bit of a buffer to prevent the playback buffer from getting starved. */ framesWrittenToPlaybackDevice += mappedSizeInBytesPlayback/bpfPlayback; if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= (pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods)) { if (FAILED(ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING))) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", MA_FAILED_TO_START_BACKEND_DEVICE); } isPlaybackDeviceStarted = MA_TRUE; } } break; default: return MA_INVALID_ARGS; /* Invalid device type. */ } if (result != MA_SUCCESS) { return result; } } /* Getting here means the device is being stopped. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (FAILED(ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer))) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { /* The playback device should be drained before stopping. All we do is wait until the available bytes is equal to the size of the buffer. */ if (isPlaybackDeviceStarted) { for (;;) { DWORD availableBytesPlayback = 0; DWORD physicalPlayCursorInBytes; DWORD physicalWriteCursorInBytes; if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) { break; } if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) { physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback; } prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes; if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */ if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) { availableBytesPlayback = (pDevice->playback.internalBufferSizeInFrames*bpfPlayback) - virtualWriteCursorInBytesPlayback; availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ } else { break; } } else { /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */ if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) { availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; } else { break; } } if (availableBytesPlayback >= (pDevice->playback.internalBufferSizeInFrames*bpfPlayback)) { break; } ma_sleep(waitTimeInMilliseconds); } } if (FAILED(ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer))) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0); } return MA_SUCCESS; } ma_result ma_context_uninit__dsound(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_dsound); ma_dlclose(pContext, pContext->dsound.hDSoundDLL); return MA_SUCCESS; } ma_result ma_context_init__dsound(const ma_context_config* pConfig, ma_context* pContext) { ma_assert(pContext != NULL); (void)pConfig; pContext->dsound.hDSoundDLL = ma_dlopen(pContext, "dsound.dll"); if (pContext->dsound.hDSoundDLL == NULL) { return MA_API_NOT_FOUND; } pContext->dsound.DirectSoundCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCreate"); pContext->dsound.DirectSoundEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA"); pContext->dsound.DirectSoundCaptureCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate"); pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA"); pContext->onUninit = ma_context_uninit__dsound; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__dsound; pContext->onEnumDevices = ma_context_enumerate_devices__dsound; pContext->onGetDeviceInfo = ma_context_get_device_info__dsound; pContext->onDeviceInit = ma_device_init__dsound; pContext->onDeviceUninit = ma_device_uninit__dsound; pContext->onDeviceStart = NULL; /* Not used. Started in onDeviceMainLoop. */ pContext->onDeviceStop = NULL; /* Not used. Stopped in onDeviceMainLoop. */ pContext->onDeviceWrite = NULL; pContext->onDeviceRead = NULL; pContext->onDeviceMainLoop = ma_device_main_loop__dsound; return MA_SUCCESS; } #endif /****************************************************************************** WinMM Backend ******************************************************************************/ #ifdef MA_HAS_WINMM /* Some older compilers don't have WAVEOUTCAPS2A and WAVEINCAPS2A, so we'll need to write this ourselves. These structures are exactly the same as the older ones but they have a few GUIDs for manufacturer/product/name identification. I'm keeping the names the same as the Win32 library for consistency, but namespaced to avoid naming conflicts with the Win32 version. */ typedef struct { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR szPname[MAXPNAMELEN]; DWORD dwFormats; WORD wChannels; WORD wReserved1; DWORD dwSupport; GUID ManufacturerGuid; GUID ProductGuid; GUID NameGuid; } MA_WAVEOUTCAPS2A; typedef struct { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR szPname[MAXPNAMELEN]; DWORD dwFormats; WORD wChannels; WORD wReserved1; GUID ManufacturerGuid; GUID ProductGuid; GUID NameGuid; } MA_WAVEINCAPS2A; typedef UINT (WINAPI * MA_PFN_waveOutGetNumDevs)(void); typedef MMRESULT (WINAPI * MA_PFN_waveOutGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc); typedef MMRESULT (WINAPI * MA_PFN_waveOutOpen)(LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); typedef MMRESULT (WINAPI * MA_PFN_waveOutClose)(HWAVEOUT hwo); typedef MMRESULT (WINAPI * MA_PFN_waveOutPrepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); typedef MMRESULT (WINAPI * MA_PFN_waveOutUnprepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); typedef MMRESULT (WINAPI * MA_PFN_waveOutWrite)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); typedef MMRESULT (WINAPI * MA_PFN_waveOutReset)(HWAVEOUT hwo); typedef UINT (WINAPI * MA_PFN_waveInGetNumDevs)(void); typedef MMRESULT (WINAPI * MA_PFN_waveInGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic); typedef MMRESULT (WINAPI * MA_PFN_waveInOpen)(LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); typedef MMRESULT (WINAPI * MA_PFN_waveInClose)(HWAVEIN hwi); typedef MMRESULT (WINAPI * MA_PFN_waveInPrepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); typedef MMRESULT (WINAPI * MA_PFN_waveInUnprepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); typedef MMRESULT (WINAPI * MA_PFN_waveInAddBuffer)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); typedef MMRESULT (WINAPI * MA_PFN_waveInStart)(HWAVEIN hwi); typedef MMRESULT (WINAPI * MA_PFN_waveInReset)(HWAVEIN hwi); ma_result ma_result_from_MMRESULT(MMRESULT resultMM) { switch (resultMM) { case MMSYSERR_NOERROR: return MA_SUCCESS; case MMSYSERR_BADDEVICEID: return MA_INVALID_ARGS; case MMSYSERR_INVALHANDLE: return MA_INVALID_ARGS; case MMSYSERR_NOMEM: return MA_OUT_OF_MEMORY; case MMSYSERR_INVALFLAG: return MA_INVALID_ARGS; case MMSYSERR_INVALPARAM: return MA_INVALID_ARGS; case MMSYSERR_HANDLEBUSY: return MA_DEVICE_BUSY; case MMSYSERR_ERROR: return MA_ERROR; default: return MA_ERROR; } } char* ma_find_last_character(char* str, char ch) { char* last; if (str == NULL) { return NULL; } last = NULL; while (*str != '\0') { if (*str == ch) { last = str; } str += 1; } return last; } /* Our own "WAVECAPS" structure that contains generic information shared between WAVEOUTCAPS2 and WAVEINCAPS2 so we can do things generically and typesafely. Names are being kept the same for consistency. */ typedef struct { CHAR szPname[MAXPNAMELEN]; DWORD dwFormats; WORD wChannels; GUID NameGuid; } MA_WAVECAPSA; ma_result ma_get_best_info_from_formats_flags__winmm(DWORD dwFormats, WORD channels, WORD* pBitsPerSample, DWORD* pSampleRate) { WORD bitsPerSample = 0; DWORD sampleRate = 0; if (pBitsPerSample) { *pBitsPerSample = 0; } if (pSampleRate) { *pSampleRate = 0; } if (channels == 1) { bitsPerSample = 16; if ((dwFormats & WAVE_FORMAT_48M16) != 0) { sampleRate = 48000; } else if ((dwFormats & WAVE_FORMAT_44M16) != 0) { sampleRate = 44100; } else if ((dwFormats & WAVE_FORMAT_2M16) != 0) { sampleRate = 22050; } else if ((dwFormats & WAVE_FORMAT_1M16) != 0) { sampleRate = 11025; } else if ((dwFormats & WAVE_FORMAT_96M16) != 0) { sampleRate = 96000; } else { bitsPerSample = 8; if ((dwFormats & WAVE_FORMAT_48M08) != 0) { sampleRate = 48000; } else if ((dwFormats & WAVE_FORMAT_44M08) != 0) { sampleRate = 44100; } else if ((dwFormats & WAVE_FORMAT_2M08) != 0) { sampleRate = 22050; } else if ((dwFormats & WAVE_FORMAT_1M08) != 0) { sampleRate = 11025; } else if ((dwFormats & WAVE_FORMAT_96M08) != 0) { sampleRate = 96000; } else { return MA_FORMAT_NOT_SUPPORTED; } } } else { bitsPerSample = 16; if ((dwFormats & WAVE_FORMAT_48S16) != 0) { sampleRate = 48000; } else if ((dwFormats & WAVE_FORMAT_44S16) != 0) { sampleRate = 44100; } else if ((dwFormats & WAVE_FORMAT_2S16) != 0) { sampleRate = 22050; } else if ((dwFormats & WAVE_FORMAT_1S16) != 0) { sampleRate = 11025; } else if ((dwFormats & WAVE_FORMAT_96S16) != 0) { sampleRate = 96000; } else { bitsPerSample = 8; if ((dwFormats & WAVE_FORMAT_48S08) != 0) { sampleRate = 48000; } else if ((dwFormats & WAVE_FORMAT_44S08) != 0) { sampleRate = 44100; } else if ((dwFormats & WAVE_FORMAT_2S08) != 0) { sampleRate = 22050; } else if ((dwFormats & WAVE_FORMAT_1S08) != 0) { sampleRate = 11025; } else if ((dwFormats & WAVE_FORMAT_96S08) != 0) { sampleRate = 96000; } else { return MA_FORMAT_NOT_SUPPORTED; } } } if (pBitsPerSample) { *pBitsPerSample = bitsPerSample; } if (pSampleRate) { *pSampleRate = sampleRate; } return MA_SUCCESS; } ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD channels, WAVEFORMATEX* pWF) { ma_assert(pWF != NULL); ma_zero_object(pWF); pWF->cbSize = sizeof(*pWF); pWF->wFormatTag = WAVE_FORMAT_PCM; pWF->nChannels = (WORD)channels; if (pWF->nChannels > 2) { pWF->nChannels = 2; } if (channels == 1) { pWF->wBitsPerSample = 16; if ((dwFormats & WAVE_FORMAT_48M16) != 0) { pWF->nSamplesPerSec = 48000; } else if ((dwFormats & WAVE_FORMAT_44M16) != 0) { pWF->nSamplesPerSec = 44100; } else if ((dwFormats & WAVE_FORMAT_2M16) != 0) { pWF->nSamplesPerSec = 22050; } else if ((dwFormats & WAVE_FORMAT_1M16) != 0) { pWF->nSamplesPerSec = 11025; } else if ((dwFormats & WAVE_FORMAT_96M16) != 0) { pWF->nSamplesPerSec = 96000; } else { pWF->wBitsPerSample = 8; if ((dwFormats & WAVE_FORMAT_48M08) != 0) { pWF->nSamplesPerSec = 48000; } else if ((dwFormats & WAVE_FORMAT_44M08) != 0) { pWF->nSamplesPerSec = 44100; } else if ((dwFormats & WAVE_FORMAT_2M08) != 0) { pWF->nSamplesPerSec = 22050; } else if ((dwFormats & WAVE_FORMAT_1M08) != 0) { pWF->nSamplesPerSec = 11025; } else if ((dwFormats & WAVE_FORMAT_96M08) != 0) { pWF->nSamplesPerSec = 96000; } else { return MA_FORMAT_NOT_SUPPORTED; } } } else { pWF->wBitsPerSample = 16; if ((dwFormats & WAVE_FORMAT_48S16) != 0) { pWF->nSamplesPerSec = 48000; } else if ((dwFormats & WAVE_FORMAT_44S16) != 0) { pWF->nSamplesPerSec = 44100; } else if ((dwFormats & WAVE_FORMAT_2S16) != 0) { pWF->nSamplesPerSec = 22050; } else if ((dwFormats & WAVE_FORMAT_1S16) != 0) { pWF->nSamplesPerSec = 11025; } else if ((dwFormats & WAVE_FORMAT_96S16) != 0) { pWF->nSamplesPerSec = 96000; } else { pWF->wBitsPerSample = 8; if ((dwFormats & WAVE_FORMAT_48S08) != 0) { pWF->nSamplesPerSec = 48000; } else if ((dwFormats & WAVE_FORMAT_44S08) != 0) { pWF->nSamplesPerSec = 44100; } else if ((dwFormats & WAVE_FORMAT_2S08) != 0) { pWF->nSamplesPerSec = 22050; } else if ((dwFormats & WAVE_FORMAT_1S08) != 0) { pWF->nSamplesPerSec = 11025; } else if ((dwFormats & WAVE_FORMAT_96S08) != 0) { pWF->nSamplesPerSec = 96000; } else { return MA_FORMAT_NOT_SUPPORTED; } } } pWF->nBlockAlign = (pWF->nChannels * pWF->wBitsPerSample) / 8; pWF->nAvgBytesPerSec = pWF->nBlockAlign * pWF->nSamplesPerSec; return MA_SUCCESS; } ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, MA_WAVECAPSA* pCaps, ma_device_info* pDeviceInfo) { WORD bitsPerSample; DWORD sampleRate; ma_result result; ma_assert(pContext != NULL); ma_assert(pCaps != NULL); ma_assert(pDeviceInfo != NULL); /* Name / Description Unfortunately the name specified in WAVE(OUT/IN)CAPS2 is limited to 31 characters. This results in an unprofessional looking situation where the names of the devices are truncated. To help work around this, we need to look at the name GUID and try looking in the registry for the full name. If we can't find it there, we need to just fall back to the default name. */ /* Set the default to begin with. */ ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), pCaps->szPname, (size_t)-1); /* Now try the registry. There's a few things to consider here: - The name GUID can be null, in which we case we just need to stick to the original 31 characters. - If the name GUID is not present in the registry we'll also need to stick to the original 31 characters. - I like consistency, so I want the returned device names to be consistent with those returned by WASAPI and DirectSound. The problem, however is that WASAPI and DirectSound use " ()" format (such as "Speakers (High Definition Audio)"), but WinMM does not specificy the component name. From my admittedly limited testing, I've notice the component name seems to usually fit within the 31 characters of the fixed sized buffer, so what I'm going to do is parse that string for the component name, and then concatenate the name from the registry. */ if (!ma_is_guid_equal(&pCaps->NameGuid, &MA_GUID_NULL)) { wchar_t guidStrW[256]; if (((MA_PFN_StringFromGUID2)pContext->win32.StringFromGUID2)(&pCaps->NameGuid, guidStrW, ma_countof(guidStrW)) > 0) { char guidStr[256]; char keyStr[1024]; HKEY hKey; WideCharToMultiByte(CP_UTF8, 0, guidStrW, -1, guidStr, sizeof(guidStr), 0, FALSE); ma_strcpy_s(keyStr, sizeof(keyStr), "SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\"); ma_strcat_s(keyStr, sizeof(keyStr), guidStr); if (((MA_PFN_RegOpenKeyExA)pContext->win32.RegOpenKeyExA)(HKEY_LOCAL_MACHINE, keyStr, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { BYTE nameFromReg[512]; DWORD nameFromRegSize = sizeof(nameFromReg); result = ((MA_PFN_RegQueryValueExA)pContext->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (LPBYTE)nameFromReg, (LPDWORD)&nameFromRegSize); ((MA_PFN_RegCloseKey)pContext->win32.RegCloseKey)(hKey); if (result == ERROR_SUCCESS) { /* We have the value from the registry, so now we need to construct the name string. */ char name[1024]; if (ma_strcpy_s(name, sizeof(name), pDeviceInfo->name) == 0) { char* nameBeg = ma_find_last_character(name, '('); if (nameBeg != NULL) { size_t leadingLen = (nameBeg - name); ma_strncpy_s(nameBeg + 1, sizeof(name) - leadingLen, (const char*)nameFromReg, (size_t)-1); /* The closing ")", if it can fit. */ if (leadingLen + nameFromRegSize < sizeof(name)-1) { ma_strcat_s(name, sizeof(name), ")"); } ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), name, (size_t)-1); } } } } } } result = ma_get_best_info_from_formats_flags__winmm(pCaps->dwFormats, pCaps->wChannels, &bitsPerSample, &sampleRate); if (result != MA_SUCCESS) { return result; } pDeviceInfo->minChannels = pCaps->wChannels; pDeviceInfo->maxChannels = pCaps->wChannels; pDeviceInfo->minSampleRate = sampleRate; pDeviceInfo->maxSampleRate = sampleRate; pDeviceInfo->formatCount = 1; if (bitsPerSample == 8) { pDeviceInfo->formats[0] = ma_format_u8; } else if (bitsPerSample == 16) { pDeviceInfo->formats[0] = ma_format_s16; } else if (bitsPerSample == 24) { pDeviceInfo->formats[0] = ma_format_s24; } else if (bitsPerSample == 32) { pDeviceInfo->formats[0] = ma_format_s32; } else { return MA_FORMAT_NOT_SUPPORTED; } return MA_SUCCESS; } ma_result ma_context_get_device_info_from_WAVEOUTCAPS2(ma_context* pContext, MA_WAVEOUTCAPS2A* pCaps, ma_device_info* pDeviceInfo) { MA_WAVECAPSA caps; ma_assert(pContext != NULL); ma_assert(pCaps != NULL); ma_assert(pDeviceInfo != NULL); ma_copy_memory(caps.szPname, pCaps->szPname, sizeof(caps.szPname)); caps.dwFormats = pCaps->dwFormats; caps.wChannels = pCaps->wChannels; caps.NameGuid = pCaps->NameGuid; return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo); } ma_result ma_context_get_device_info_from_WAVEINCAPS2(ma_context* pContext, MA_WAVEINCAPS2A* pCaps, ma_device_info* pDeviceInfo) { MA_WAVECAPSA caps; ma_assert(pContext != NULL); ma_assert(pCaps != NULL); ma_assert(pDeviceInfo != NULL); ma_copy_memory(caps.szPname, pCaps->szPname, sizeof(caps.szPname)); caps.dwFormats = pCaps->dwFormats; caps.wChannels = pCaps->wChannels; caps.NameGuid = pCaps->NameGuid; return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo); } ma_bool32 ma_context_is_device_id_equal__winmm(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return pID0->winmm == pID1->winmm; } ma_result ma_context_enumerate_devices__winmm(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { UINT playbackDeviceCount; UINT captureDeviceCount; UINT iPlaybackDevice; UINT iCaptureDevice; ma_assert(pContext != NULL); ma_assert(callback != NULL); /* Playback. */ playbackDeviceCount = ((MA_PFN_waveOutGetNumDevs)pContext->winmm.waveOutGetNumDevs)(); for (iPlaybackDevice = 0; iPlaybackDevice < playbackDeviceCount; ++iPlaybackDevice) { MMRESULT result; MA_WAVEOUTCAPS2A caps; ma_zero_object(&caps); result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(iPlaybackDevice, (WAVEOUTCAPSA*)&caps, sizeof(caps)); if (result == MMSYSERR_NOERROR) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); deviceInfo.id.winmm = iPlaybackDevice; if (ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) { ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); if (cbResult == MA_FALSE) { return MA_SUCCESS; /* Enumeration was stopped. */ } } } } /* Capture. */ captureDeviceCount = ((MA_PFN_waveInGetNumDevs)pContext->winmm.waveInGetNumDevs)(); for (iCaptureDevice = 0; iCaptureDevice < captureDeviceCount; ++iCaptureDevice) { MMRESULT result; MA_WAVEINCAPS2A caps; ma_zero_object(&caps); result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(iCaptureDevice, (WAVEINCAPSA*)&caps, sizeof(caps)); if (result == MMSYSERR_NOERROR) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); deviceInfo.id.winmm = iCaptureDevice; if (ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) { ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); if (cbResult == MA_FALSE) { return MA_SUCCESS; /* Enumeration was stopped. */ } } } } return MA_SUCCESS; } ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { UINT winMMDeviceID; ma_assert(pContext != NULL); if (shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } winMMDeviceID = 0; if (pDeviceID != NULL) { winMMDeviceID = (UINT)pDeviceID->winmm; } pDeviceInfo->id.winmm = winMMDeviceID; if (deviceType == ma_device_type_playback) { MMRESULT result; MA_WAVEOUTCAPS2A caps; ma_zero_object(&caps); result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, (WAVEOUTCAPSA*)&caps, sizeof(caps)); if (result == MMSYSERR_NOERROR) { return ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, pDeviceInfo); } } else { MMRESULT result; MA_WAVEINCAPS2A caps; ma_zero_object(&caps); result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, (WAVEINCAPSA*)&caps, sizeof(caps)); if (result == MMSYSERR_NOERROR) { return ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, pDeviceInfo); } } return MA_NO_DEVICE; } void ma_device_uninit__winmm(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture); CloseHandle((HANDLE)pDevice->winmm.hEventCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback); ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback); CloseHandle((HANDLE)pDevice->winmm.hEventPlayback); } ma_free(pDevice->winmm._pHeapData); ma_zero_object(&pDevice->winmm); /* Safety. */ } ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { const char* errorMsg = ""; ma_result errorCode = MA_ERROR; ma_result result = MA_SUCCESS; ma_uint32 heapSize; UINT winMMDeviceIDPlayback = 0; UINT winMMDeviceIDCapture = 0; ma_uint32 bufferSizeInMilliseconds; ma_assert(pDevice != NULL); ma_zero_object(&pDevice->winmm); /* No exlusive mode with WinMM. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; } bufferSizeInMilliseconds = pConfig->bufferSizeInMilliseconds; if (bufferSizeInMilliseconds == 0) { bufferSizeInMilliseconds = ma_calculate_buffer_size_in_milliseconds_from_frames(pConfig->bufferSizeInFrames, pConfig->sampleRate); } /* WinMM has horrible latency. */ if (pDevice->usingDefaultBufferSize) { if (pConfig->performanceProfile == ma_performance_profile_low_latency) { bufferSizeInMilliseconds = 40 * pConfig->periods; } else { bufferSizeInMilliseconds = 400 * pConfig->periods; } } if (pConfig->playback.pDeviceID != NULL) { winMMDeviceIDPlayback = (UINT)pConfig->playback.pDeviceID->winmm; } if (pConfig->capture.pDeviceID != NULL) { winMMDeviceIDCapture = (UINT)pConfig->capture.pDeviceID->winmm; } /* The capture device needs to be initialized first. */ if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { WAVEINCAPSA caps; WAVEFORMATEX wf; MMRESULT resultMM; /* We use an event to know when a new fragment needs to be enqueued. */ pDevice->winmm.hEventCapture = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventCapture == NULL) { errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = MA_FAILED_TO_CREATE_EVENT; goto on_error; } /* The format should be based on the device's actual format. */ if (((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MMSYSERR_NOERROR) { errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED; goto on_error; } result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf); if (result != MA_SUCCESS) { errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result; goto on_error; } resultMM = ((MA_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((LPHWAVEIN)&pDevice->winmm.hDeviceCapture, winMMDeviceIDCapture, &wf, (DWORD_PTR)pDevice->winmm.hEventCapture, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC); if (resultMM != MMSYSERR_NOERROR) { errorMsg = "[WinMM] Failed to open capture device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE; goto on_error; } pDevice->capture.internalFormat = ma_format_from_WAVEFORMATEX(&wf); pDevice->capture.internalChannels = wf.nChannels; pDevice->capture.internalSampleRate = wf.nSamplesPerSec; ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); pDevice->capture.internalPeriods = pConfig->periods; pDevice->capture.internalBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(bufferSizeInMilliseconds, pDevice->capture.internalSampleRate); } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { WAVEOUTCAPSA caps; WAVEFORMATEX wf; MMRESULT resultMM; /* We use an event to know when a new fragment needs to be enqueued. */ pDevice->winmm.hEventPlayback = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventPlayback == NULL) { errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = MA_FAILED_TO_CREATE_EVENT; goto on_error; } /* The format should be based on the device's actual format. */ if (((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) { errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED; goto on_error; } result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf); if (result != MA_SUCCESS) { errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result; goto on_error; } resultMM = ((MA_PFN_waveOutOpen)pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC); if (resultMM != MMSYSERR_NOERROR) { errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE; goto on_error; } pDevice->playback.internalFormat = ma_format_from_WAVEFORMATEX(&wf); pDevice->playback.internalChannels = wf.nChannels; pDevice->playback.internalSampleRate = wf.nSamplesPerSec; ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); pDevice->playback.internalPeriods = pConfig->periods; pDevice->playback.internalBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(bufferSizeInMilliseconds, pDevice->playback.internalSampleRate); } /* The heap allocated data is allocated like so: [Capture WAVEHDRs][Playback WAVEHDRs][Capture Intermediary Buffer][Playback Intermediary Buffer] */ heapSize = 0; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { heapSize += sizeof(WAVEHDR)*pDevice->capture.internalPeriods + (pDevice->capture.internalBufferSizeInFrames*ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { heapSize += sizeof(WAVEHDR)*pDevice->playback.internalPeriods + (pDevice->playback.internalBufferSizeInFrames*ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); } pDevice->winmm._pHeapData = (ma_uint8*)ma_malloc(heapSize); if (pDevice->winmm._pHeapData == NULL) { errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY; goto on_error; } ma_zero_memory(pDevice->winmm._pHeapData, heapSize); if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_uint32 iPeriod; if (pConfig->deviceType == ma_device_type_capture) { pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData; pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods)); } else { pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData; pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods + pDevice->playback.internalPeriods)); } /* Prepare headers. */ for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) { ma_uint32 fragmentSizeInBytes = ma_get_fragment_size_in_bytes(pDevice->capture.internalBufferSizeInFrames, pDevice->capture.internalPeriods, pDevice->capture.internalFormat, pDevice->capture.internalChannels); ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferCapture + (fragmentSizeInBytes*iPeriod)); ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength = fragmentSizeInBytes; ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwFlags = 0L; ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwLoops = 0L; ((MA_PFN_waveInPrepareHeader)pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR)); /* The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means it's unlocked and available for writing. A value of 1 means it's locked. */ ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_uint32 iPeriod; if (pConfig->deviceType == ma_device_type_playback) { pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData; pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*pDevice->playback.internalPeriods); } else { pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods)); pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods + pDevice->playback.internalPeriods)) + (pDevice->playback.internalBufferSizeInFrames*ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); } /* Prepare headers. */ for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) { ma_uint32 fragmentSizeInBytes = ma_get_fragment_size_in_bytes(pDevice->playback.internalBufferSizeInFrames, pDevice->playback.internalPeriods, pDevice->playback.internalFormat, pDevice->playback.internalChannels); ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferPlayback + (fragmentSizeInBytes*iPeriod)); ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength = fragmentSizeInBytes; ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags = 0L; ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops = 0L; ((MA_PFN_waveOutPrepareHeader)pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR)); /* The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means it's unlocked and available for writing. A value of 1 means it's locked. */ ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwUser = 0; } } return MA_SUCCESS; on_error: if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (pDevice->winmm.pWAVEHDRCapture != NULL) { ma_uint32 iPeriod; for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) { ((MA_PFN_waveInUnprepareHeader)pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR)); } } ((MA_PFN_waveInClose)pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->winmm.pWAVEHDRCapture != NULL) { ma_uint32 iPeriod; for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) { ((MA_PFN_waveOutUnprepareHeader)pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR)); } } ((MA_PFN_waveOutClose)pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback); } ma_free(pDevice->winmm._pHeapData); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, errorMsg, errorCode); } ma_result ma_device_stop__winmm(ma_device* pDevice) { MMRESULT resultMM; ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (pDevice->winmm.hDeviceCapture == NULL) { return MA_INVALID_ARGS; } resultMM = ((MA_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDeviceCapture); if (resultMM != MMSYSERR_NOERROR) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset capture device.", ma_result_from_MMRESULT(resultMM)); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->winmm.hDevicePlayback == NULL) { return MA_INVALID_ARGS; } resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback); if (resultMM != MMSYSERR_NOERROR) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset playback device.", ma_result_from_MMRESULT(resultMM)); } } ma_atomic_exchange_32(&pDevice->winmm.isStarted, MA_FALSE); return MA_SUCCESS; } ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount) { ma_result result = MA_SUCCESS; MMRESULT resultMM; ma_uint32 totalFramesWritten; WAVEHDR* pWAVEHDR; ma_assert(pDevice != NULL); ma_assert(pPCMFrames != NULL); pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback; /* Keep processing as much data as possible. */ totalFramesWritten = 0; while (totalFramesWritten < frameCount) { /* If the current header has some space available we need to write part of it. */ if (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser == 0) { /* 0 = unlocked. */ /* This header has room in it. We copy as much of it as we can. If we end up fully consuming the buffer we need to write it out and move on to the next iteration. */ ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedPlayback; ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesWritten)); const void* pSrc = ma_offset_ptr(pPCMFrames, totalFramesWritten*bpf); void* pDst = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].lpData, pDevice->winmm.headerFramesConsumedPlayback*bpf); ma_copy_memory(pDst, pSrc, framesToCopy*bpf); pDevice->winmm.headerFramesConsumedPlayback += framesToCopy; totalFramesWritten += framesToCopy; /* If we've consumed the buffer entirely we need to write it out to the device. */ if (pDevice->winmm.headerFramesConsumedPlayback == (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf)) { pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 1; /* 1 = locked. */ pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */ /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */ ResetEvent((HANDLE)pDevice->winmm.hEventPlayback); /* The device will be started here. */ resultMM = ((MA_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &pWAVEHDR[pDevice->winmm.iNextHeaderPlayback], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { result = ma_result_from_MMRESULT(resultMM); ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed.", result); break; } ma_atomic_exchange_32(&pDevice->winmm.isStarted, MA_TRUE); /* Make sure we move to the next header. */ pDevice->winmm.iNextHeaderPlayback = (pDevice->winmm.iNextHeaderPlayback + 1) % pDevice->playback.internalPeriods; pDevice->winmm.headerFramesConsumedPlayback = 0; } /* If at this point we have consumed the entire input buffer we can return. */ ma_assert(totalFramesWritten <= frameCount); if (totalFramesWritten == frameCount) { break; } /* Getting here means there's more to process. */ continue; } /* Getting here means there isn't enough room in the buffer and we need to wait for one to become available. */ if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) { result = MA_ERROR; break; } /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */ if ((pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags & WHDR_DONE) != 0) { pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 0; /* 0 = unlocked (make it available for writing). */ pDevice->winmm.headerFramesConsumedPlayback = 0; } /* If the device has been stopped we need to break. */ if (!pDevice->winmm.isStarted) { break; } } return result; } ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount) { ma_result result = MA_SUCCESS; MMRESULT resultMM; ma_uint32 totalFramesRead; WAVEHDR* pWAVEHDR; ma_assert(pDevice != NULL); ma_assert(pPCMFrames != NULL); pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture; /* We want to start the device immediately. */ if (!pDevice->winmm.isStarted) { ma_uint32 iPeriod; /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */ ResetEvent((HANDLE)pDevice->winmm.hEventCapture); /* To start the device we attach all of the buffers and then start it. As the buffers are filled with data we will get notifications. */ for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) { resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.", ma_result_from_MMRESULT(resultMM)); } /* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */ pWAVEHDR[iPeriod].dwUser = 1; /* 1 = locked. */ } /* Capture devices need to be explicitly started, unlike playback devices. */ resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDeviceCapture); if (resultMM != MMSYSERR_NOERROR) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.", ma_result_from_MMRESULT(resultMM)); } ma_atomic_exchange_32(&pDevice->winmm.isStarted, MA_TRUE); } /* Keep processing as much data as possible. */ totalFramesRead = 0; while (totalFramesRead < frameCount) { /* If the current header has some space available we need to write part of it. */ if (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser == 0) { /* 0 = unlocked. */ /* The buffer is available for reading. If we fully consume it we need to add it back to the buffer. */ ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedCapture; ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesRead)); const void* pSrc = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderCapture].lpData, pDevice->winmm.headerFramesConsumedCapture*bpf); void* pDst = ma_offset_ptr(pPCMFrames, totalFramesRead*bpf); ma_copy_memory(pDst, pSrc, framesToCopy*bpf); pDevice->winmm.headerFramesConsumedCapture += framesToCopy; totalFramesRead += framesToCopy; /* If we've consumed the buffer entirely we need to add it back to the device. */ if (pDevice->winmm.headerFramesConsumedCapture == (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf)) { pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 1; /* 1 = locked. */ pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */ /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */ ResetEvent((HANDLE)pDevice->winmm.hEventCapture); /* The device will be started here. */ resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[pDevice->winmm.iNextHeaderCapture], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { result = ma_result_from_MMRESULT(resultMM); ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed.", result); break; } /* Make sure we move to the next header. */ pDevice->winmm.iNextHeaderCapture = (pDevice->winmm.iNextHeaderCapture + 1) % pDevice->capture.internalPeriods; pDevice->winmm.headerFramesConsumedCapture = 0; } /* If at this point we have filled the entire input buffer we can return. */ ma_assert(totalFramesRead <= frameCount); if (totalFramesRead == frameCount) { break; } /* Getting here means there's more to process. */ continue; } /* Getting here means there isn't enough any data left to send to the client which means we need to wait for more. */ if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventCapture, INFINITE) != WAIT_OBJECT_0) { result = MA_ERROR; break; } /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */ if ((pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags & WHDR_DONE) != 0) { pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 0; /* 0 = unlocked (make it available for reading). */ pDevice->winmm.headerFramesConsumedCapture = 0; } /* If the device has been stopped we need to break. */ if (!pDevice->winmm.isStarted) { break; } } return result; } ma_result ma_context_uninit__winmm(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_winmm); ma_dlclose(pContext, pContext->winmm.hWinMM); return MA_SUCCESS; } ma_result ma_context_init__winmm(const ma_context_config* pConfig, ma_context* pContext) { ma_assert(pContext != NULL); (void)pConfig; pContext->winmm.hWinMM = ma_dlopen(pContext, "winmm.dll"); if (pContext->winmm.hWinMM == NULL) { return MA_NO_BACKEND; } pContext->winmm.waveOutGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetNumDevs"); pContext->winmm.waveOutGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetDevCapsA"); pContext->winmm.waveOutOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutOpen"); pContext->winmm.waveOutClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutClose"); pContext->winmm.waveOutPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutPrepareHeader"); pContext->winmm.waveOutUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutUnprepareHeader"); pContext->winmm.waveOutWrite = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutWrite"); pContext->winmm.waveOutReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutReset"); pContext->winmm.waveInGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetNumDevs"); pContext->winmm.waveInGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetDevCapsA"); pContext->winmm.waveInOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInOpen"); pContext->winmm.waveInClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInClose"); pContext->winmm.waveInPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInPrepareHeader"); pContext->winmm.waveInUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInUnprepareHeader"); pContext->winmm.waveInAddBuffer = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInAddBuffer"); pContext->winmm.waveInStart = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInStart"); pContext->winmm.waveInReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInReset"); pContext->onUninit = ma_context_uninit__winmm; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__winmm; pContext->onEnumDevices = ma_context_enumerate_devices__winmm; pContext->onGetDeviceInfo = ma_context_get_device_info__winmm; pContext->onDeviceInit = ma_device_init__winmm; pContext->onDeviceUninit = ma_device_uninit__winmm; pContext->onDeviceStart = NULL; /* Not used. Started in onDeviceWrite/onDeviceRead. */ pContext->onDeviceStop = ma_device_stop__winmm; pContext->onDeviceWrite = ma_device_write__winmm; pContext->onDeviceRead = ma_device_read__winmm; return MA_SUCCESS; } #endif /****************************************************************************** ALSA Backend ******************************************************************************/ #ifdef MA_HAS_ALSA #ifdef MA_NO_RUNTIME_LINKING #include typedef snd_pcm_uframes_t ma_snd_pcm_uframes_t; typedef snd_pcm_sframes_t ma_snd_pcm_sframes_t; typedef snd_pcm_stream_t ma_snd_pcm_stream_t; typedef snd_pcm_format_t ma_snd_pcm_format_t; typedef snd_pcm_access_t ma_snd_pcm_access_t; typedef snd_pcm_t ma_snd_pcm_t; typedef snd_pcm_hw_params_t ma_snd_pcm_hw_params_t; typedef snd_pcm_sw_params_t ma_snd_pcm_sw_params_t; typedef snd_pcm_format_mask_t ma_snd_pcm_format_mask_t; typedef snd_pcm_info_t ma_snd_pcm_info_t; typedef snd_pcm_channel_area_t ma_snd_pcm_channel_area_t; typedef snd_pcm_chmap_t ma_snd_pcm_chmap_t; /* snd_pcm_stream_t */ #define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK #define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE /* snd_pcm_format_t */ #define MA_SND_PCM_FORMAT_UNKNOWN SND_PCM_FORMAT_UNKNOWN #define MA_SND_PCM_FORMAT_U8 SND_PCM_FORMAT_U8 #define MA_SND_PCM_FORMAT_S16_LE SND_PCM_FORMAT_S16_LE #define MA_SND_PCM_FORMAT_S16_BE SND_PCM_FORMAT_S16_BE #define MA_SND_PCM_FORMAT_S24_LE SND_PCM_FORMAT_S24_LE #define MA_SND_PCM_FORMAT_S24_BE SND_PCM_FORMAT_S24_BE #define MA_SND_PCM_FORMAT_S32_LE SND_PCM_FORMAT_S32_LE #define MA_SND_PCM_FORMAT_S32_BE SND_PCM_FORMAT_S32_BE #define MA_SND_PCM_FORMAT_FLOAT_LE SND_PCM_FORMAT_FLOAT_LE #define MA_SND_PCM_FORMAT_FLOAT_BE SND_PCM_FORMAT_FLOAT_BE #define MA_SND_PCM_FORMAT_FLOAT64_LE SND_PCM_FORMAT_FLOAT64_LE #define MA_SND_PCM_FORMAT_FLOAT64_BE SND_PCM_FORMAT_FLOAT64_BE #define MA_SND_PCM_FORMAT_MU_LAW SND_PCM_FORMAT_MU_LAW #define MA_SND_PCM_FORMAT_A_LAW SND_PCM_FORMAT_A_LAW #define MA_SND_PCM_FORMAT_S24_3LE SND_PCM_FORMAT_S24_3LE #define MA_SND_PCM_FORMAT_S24_3BE SND_PCM_FORMAT_S24_3BE /* ma_snd_pcm_access_t */ #define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED SND_PCM_ACCESS_MMAP_INTERLEAVED #define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED SND_PCM_ACCESS_MMAP_NONINTERLEAVED #define MA_SND_PCM_ACCESS_MMAP_COMPLEX SND_PCM_ACCESS_MMAP_COMPLEX #define MA_SND_PCM_ACCESS_RW_INTERLEAVED SND_PCM_ACCESS_RW_INTERLEAVED #define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED SND_PCM_ACCESS_RW_NONINTERLEAVED /* Channel positions. */ #define MA_SND_CHMAP_UNKNOWN SND_CHMAP_UNKNOWN #define MA_SND_CHMAP_NA SND_CHMAP_NA #define MA_SND_CHMAP_MONO SND_CHMAP_MONO #define MA_SND_CHMAP_FL SND_CHMAP_FL #define MA_SND_CHMAP_FR SND_CHMAP_FR #define MA_SND_CHMAP_RL SND_CHMAP_RL #define MA_SND_CHMAP_RR SND_CHMAP_RR #define MA_SND_CHMAP_FC SND_CHMAP_FC #define MA_SND_CHMAP_LFE SND_CHMAP_LFE #define MA_SND_CHMAP_SL SND_CHMAP_SL #define MA_SND_CHMAP_SR SND_CHMAP_SR #define MA_SND_CHMAP_RC SND_CHMAP_RC #define MA_SND_CHMAP_FLC SND_CHMAP_FLC #define MA_SND_CHMAP_FRC SND_CHMAP_FRC #define MA_SND_CHMAP_RLC SND_CHMAP_RLC #define MA_SND_CHMAP_RRC SND_CHMAP_RRC #define MA_SND_CHMAP_FLW SND_CHMAP_FLW #define MA_SND_CHMAP_FRW SND_CHMAP_FRW #define MA_SND_CHMAP_FLH SND_CHMAP_FLH #define MA_SND_CHMAP_FCH SND_CHMAP_FCH #define MA_SND_CHMAP_FRH SND_CHMAP_FRH #define MA_SND_CHMAP_TC SND_CHMAP_TC #define MA_SND_CHMAP_TFL SND_CHMAP_TFL #define MA_SND_CHMAP_TFR SND_CHMAP_TFR #define MA_SND_CHMAP_TFC SND_CHMAP_TFC #define MA_SND_CHMAP_TRL SND_CHMAP_TRL #define MA_SND_CHMAP_TRR SND_CHMAP_TRR #define MA_SND_CHMAP_TRC SND_CHMAP_TRC #define MA_SND_CHMAP_TFLC SND_CHMAP_TFLC #define MA_SND_CHMAP_TFRC SND_CHMAP_TFRC #define MA_SND_CHMAP_TSL SND_CHMAP_TSL #define MA_SND_CHMAP_TSR SND_CHMAP_TSR #define MA_SND_CHMAP_LLFE SND_CHMAP_LLFE #define MA_SND_CHMAP_RLFE SND_CHMAP_RLFE #define MA_SND_CHMAP_BC SND_CHMAP_BC #define MA_SND_CHMAP_BLC SND_CHMAP_BLC #define MA_SND_CHMAP_BRC SND_CHMAP_BRC /* Open mode flags. */ #define MA_SND_PCM_NO_AUTO_RESAMPLE SND_PCM_NO_AUTO_RESAMPLE #define MA_SND_PCM_NO_AUTO_CHANNELS SND_PCM_NO_AUTO_CHANNELS #define MA_SND_PCM_NO_AUTO_FORMAT SND_PCM_NO_AUTO_FORMAT #else #include /* For EPIPE, etc. */ typedef unsigned long ma_snd_pcm_uframes_t; typedef long ma_snd_pcm_sframes_t; typedef int ma_snd_pcm_stream_t; typedef int ma_snd_pcm_format_t; typedef int ma_snd_pcm_access_t; typedef struct ma_snd_pcm_t ma_snd_pcm_t; typedef struct ma_snd_pcm_hw_params_t ma_snd_pcm_hw_params_t; typedef struct ma_snd_pcm_sw_params_t ma_snd_pcm_sw_params_t; typedef struct ma_snd_pcm_format_mask_t ma_snd_pcm_format_mask_t; typedef struct ma_snd_pcm_info_t ma_snd_pcm_info_t; typedef struct { void* addr; unsigned int first; unsigned int step; } ma_snd_pcm_channel_area_t; typedef struct { unsigned int channels; unsigned int pos[1]; } ma_snd_pcm_chmap_t; /* snd_pcm_state_t */ #define MA_SND_PCM_STATE_OPEN 0 #define MA_SND_PCM_STATE_SETUP 1 #define MA_SND_PCM_STATE_PREPARED 2 #define MA_SND_PCM_STATE_RUNNING 3 #define MA_SND_PCM_STATE_XRUN 4 #define MA_SND_PCM_STATE_DRAINING 5 #define MA_SND_PCM_STATE_PAUSED 6 #define MA_SND_PCM_STATE_SUSPENDED 7 #define MA_SND_PCM_STATE_DISCONNECTED 8 /* snd_pcm_stream_t */ #define MA_SND_PCM_STREAM_PLAYBACK 0 #define MA_SND_PCM_STREAM_CAPTURE 1 /* snd_pcm_format_t */ #define MA_SND_PCM_FORMAT_UNKNOWN -1 #define MA_SND_PCM_FORMAT_U8 1 #define MA_SND_PCM_FORMAT_S16_LE 2 #define MA_SND_PCM_FORMAT_S16_BE 3 #define MA_SND_PCM_FORMAT_S24_LE 6 #define MA_SND_PCM_FORMAT_S24_BE 7 #define MA_SND_PCM_FORMAT_S32_LE 10 #define MA_SND_PCM_FORMAT_S32_BE 11 #define MA_SND_PCM_FORMAT_FLOAT_LE 14 #define MA_SND_PCM_FORMAT_FLOAT_BE 15 #define MA_SND_PCM_FORMAT_FLOAT64_LE 16 #define MA_SND_PCM_FORMAT_FLOAT64_BE 17 #define MA_SND_PCM_FORMAT_MU_LAW 20 #define MA_SND_PCM_FORMAT_A_LAW 21 #define MA_SND_PCM_FORMAT_S24_3LE 32 #define MA_SND_PCM_FORMAT_S24_3BE 33 /* snd_pcm_access_t */ #define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED 0 #define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED 1 #define MA_SND_PCM_ACCESS_MMAP_COMPLEX 2 #define MA_SND_PCM_ACCESS_RW_INTERLEAVED 3 #define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED 4 /* Channel positions. */ #define MA_SND_CHMAP_UNKNOWN 0 #define MA_SND_CHMAP_NA 1 #define MA_SND_CHMAP_MONO 2 #define MA_SND_CHMAP_FL 3 #define MA_SND_CHMAP_FR 4 #define MA_SND_CHMAP_RL 5 #define MA_SND_CHMAP_RR 6 #define MA_SND_CHMAP_FC 7 #define MA_SND_CHMAP_LFE 8 #define MA_SND_CHMAP_SL 9 #define MA_SND_CHMAP_SR 10 #define MA_SND_CHMAP_RC 11 #define MA_SND_CHMAP_FLC 12 #define MA_SND_CHMAP_FRC 13 #define MA_SND_CHMAP_RLC 14 #define MA_SND_CHMAP_RRC 15 #define MA_SND_CHMAP_FLW 16 #define MA_SND_CHMAP_FRW 17 #define MA_SND_CHMAP_FLH 18 #define MA_SND_CHMAP_FCH 19 #define MA_SND_CHMAP_FRH 20 #define MA_SND_CHMAP_TC 21 #define MA_SND_CHMAP_TFL 22 #define MA_SND_CHMAP_TFR 23 #define MA_SND_CHMAP_TFC 24 #define MA_SND_CHMAP_TRL 25 #define MA_SND_CHMAP_TRR 26 #define MA_SND_CHMAP_TRC 27 #define MA_SND_CHMAP_TFLC 28 #define MA_SND_CHMAP_TFRC 29 #define MA_SND_CHMAP_TSL 30 #define MA_SND_CHMAP_TSR 31 #define MA_SND_CHMAP_LLFE 32 #define MA_SND_CHMAP_RLFE 33 #define MA_SND_CHMAP_BC 34 #define MA_SND_CHMAP_BLC 35 #define MA_SND_CHMAP_BRC 36 /* Open mode flags. */ #define MA_SND_PCM_NO_AUTO_RESAMPLE 0x00010000 #define MA_SND_PCM_NO_AUTO_CHANNELS 0x00020000 #define MA_SND_PCM_NO_AUTO_FORMAT 0x00040000 #endif typedef int (* ma_snd_pcm_open_proc) (ma_snd_pcm_t **pcm, const char *name, ma_snd_pcm_stream_t stream, int mode); typedef int (* ma_snd_pcm_close_proc) (ma_snd_pcm_t *pcm); typedef size_t (* ma_snd_pcm_hw_params_sizeof_proc) (void); typedef int (* ma_snd_pcm_hw_params_any_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params); typedef int (* ma_snd_pcm_hw_params_set_format_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t val); typedef int (* ma_snd_pcm_hw_params_set_format_first_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t *format); typedef void (* ma_snd_pcm_hw_params_get_format_mask_proc) (ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_mask_t *mask); typedef int (* ma_snd_pcm_hw_params_set_channels_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val); typedef int (* ma_snd_pcm_hw_params_set_rate_resample_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val); typedef int (* ma_snd_pcm_hw_params_set_rate_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); typedef int (* ma_snd_pcm_hw_params_set_buffer_size_near_proc)(ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val); typedef int (* ma_snd_pcm_hw_params_set_periods_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); typedef int (* ma_snd_pcm_hw_params_set_access_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t _access); typedef int (* ma_snd_pcm_hw_params_get_format_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t *format); typedef int (* ma_snd_pcm_hw_params_get_channels_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val); typedef int (* ma_snd_pcm_hw_params_get_channels_min_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val); typedef int (* ma_snd_pcm_hw_params_get_channels_max_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val); typedef int (* ma_snd_pcm_hw_params_get_rate_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir); typedef int (* ma_snd_pcm_hw_params_get_rate_min_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir); typedef int (* ma_snd_pcm_hw_params_get_rate_max_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir); typedef int (* ma_snd_pcm_hw_params_get_buffer_size_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val); typedef int (* ma_snd_pcm_hw_params_get_periods_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); typedef int (* ma_snd_pcm_hw_params_get_access_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t *_access); typedef int (* ma_snd_pcm_hw_params_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params); typedef size_t (* ma_snd_pcm_sw_params_sizeof_proc) (void); typedef int (* ma_snd_pcm_sw_params_current_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params); typedef int (* ma_snd_pcm_sw_params_get_boundary_proc) (ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t* val); typedef int (* ma_snd_pcm_sw_params_set_avail_min_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val); typedef int (* ma_snd_pcm_sw_params_set_start_threshold_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val); typedef int (* ma_snd_pcm_sw_params_set_stop_threshold_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val); typedef int (* ma_snd_pcm_sw_params_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params); typedef size_t (* ma_snd_pcm_format_mask_sizeof_proc) (void); typedef int (* ma_snd_pcm_format_mask_test_proc) (const ma_snd_pcm_format_mask_t *mask, ma_snd_pcm_format_t val); typedef ma_snd_pcm_chmap_t * (* ma_snd_pcm_get_chmap_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_state_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_prepare_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_start_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_drop_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_drain_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_device_name_hint_proc) (int card, const char *iface, void ***hints); typedef char * (* ma_snd_device_name_get_hint_proc) (const void *hint, const char *id); typedef int (* ma_snd_card_get_index_proc) (const char *name); typedef int (* ma_snd_device_name_free_hint_proc) (void **hints); typedef int (* ma_snd_pcm_mmap_begin_proc) (ma_snd_pcm_t *pcm, const ma_snd_pcm_channel_area_t **areas, ma_snd_pcm_uframes_t *offset, ma_snd_pcm_uframes_t *frames); typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_mmap_commit_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_uframes_t offset, ma_snd_pcm_uframes_t frames); typedef int (* ma_snd_pcm_recover_proc) (ma_snd_pcm_t *pcm, int err, int silent); typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_readi_proc) (ma_snd_pcm_t *pcm, void *buffer, ma_snd_pcm_uframes_t size); typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_writei_proc) (ma_snd_pcm_t *pcm, const void *buffer, ma_snd_pcm_uframes_t size); typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_proc) (ma_snd_pcm_t *pcm); typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_update_proc) (ma_snd_pcm_t *pcm); typedef int (* ma_snd_pcm_wait_proc) (ma_snd_pcm_t *pcm, int timeout); typedef int (* ma_snd_pcm_info_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_info_t* info); typedef size_t (* ma_snd_pcm_info_sizeof_proc) (); typedef const char* (* ma_snd_pcm_info_get_name_proc) (const ma_snd_pcm_info_t* info); typedef int (* ma_snd_config_update_free_global_proc) (); /* This array specifies each of the common devices that can be used for both playback and capture. */ const char* g_maCommonDeviceNamesALSA[] = { "default", "null", "pulse", "jack" }; /* This array allows us to blacklist specific playback devices. */ const char* g_maBlacklistedPlaybackDeviceNamesALSA[] = { "" }; /* This array allows us to blacklist specific capture devices. */ const char* g_maBlacklistedCaptureDeviceNamesALSA[] = { "" }; /* This array allows miniaudio to control device-specific default buffer sizes. This uses a scaling factor. Order is important. If any part of the string is present in the device's name, the associated scale will be used. */ static struct { const char* name; float scale; } g_maDefaultBufferSizeScalesALSA[] = { {"bcm2835 IEC958/HDMI", 2.0f}, {"bcm2835 ALSA", 2.0f} }; float ma_find_default_buffer_size_scale__alsa(const char* deviceName) { size_t i; if (deviceName == NULL) { return 1; } for (i = 0; i < ma_countof(g_maDefaultBufferSizeScalesALSA); ++i) { if (strstr(g_maDefaultBufferSizeScalesALSA[i].name, deviceName) != NULL) { return g_maDefaultBufferSizeScalesALSA[i].scale; } } return 1; } ma_snd_pcm_format_t ma_convert_ma_format_to_alsa_format(ma_format format) { ma_snd_pcm_format_t ALSAFormats[] = { MA_SND_PCM_FORMAT_UNKNOWN, /* ma_format_unknown */ MA_SND_PCM_FORMAT_U8, /* ma_format_u8 */ MA_SND_PCM_FORMAT_S16_LE, /* ma_format_s16 */ MA_SND_PCM_FORMAT_S24_3LE, /* ma_format_s24 */ MA_SND_PCM_FORMAT_S32_LE, /* ma_format_s32 */ MA_SND_PCM_FORMAT_FLOAT_LE /* ma_format_f32 */ }; if (ma_is_big_endian()) { ALSAFormats[0] = MA_SND_PCM_FORMAT_UNKNOWN; ALSAFormats[1] = MA_SND_PCM_FORMAT_U8; ALSAFormats[2] = MA_SND_PCM_FORMAT_S16_BE; ALSAFormats[3] = MA_SND_PCM_FORMAT_S24_3BE; ALSAFormats[4] = MA_SND_PCM_FORMAT_S32_BE; ALSAFormats[5] = MA_SND_PCM_FORMAT_FLOAT_BE; } return ALSAFormats[format]; } ma_format ma_format_from_alsa(ma_snd_pcm_format_t formatALSA) { if (ma_is_little_endian()) { switch (formatALSA) { case MA_SND_PCM_FORMAT_S16_LE: return ma_format_s16; case MA_SND_PCM_FORMAT_S24_3LE: return ma_format_s24; case MA_SND_PCM_FORMAT_S32_LE: return ma_format_s32; case MA_SND_PCM_FORMAT_FLOAT_LE: return ma_format_f32; default: break; } } else { switch (formatALSA) { case MA_SND_PCM_FORMAT_S16_BE: return ma_format_s16; case MA_SND_PCM_FORMAT_S24_3BE: return ma_format_s24; case MA_SND_PCM_FORMAT_S32_BE: return ma_format_s32; case MA_SND_PCM_FORMAT_FLOAT_BE: return ma_format_f32; default: break; } } /* Endian agnostic. */ switch (formatALSA) { case MA_SND_PCM_FORMAT_U8: return ma_format_u8; default: return ma_format_unknown; } } ma_channel ma_convert_alsa_channel_position_to_ma_channel(unsigned int alsaChannelPos) { switch (alsaChannelPos) { case MA_SND_CHMAP_MONO: return MA_CHANNEL_MONO; case MA_SND_CHMAP_FL: return MA_CHANNEL_FRONT_LEFT; case MA_SND_CHMAP_FR: return MA_CHANNEL_FRONT_RIGHT; case MA_SND_CHMAP_RL: return MA_CHANNEL_BACK_LEFT; case MA_SND_CHMAP_RR: return MA_CHANNEL_BACK_RIGHT; case MA_SND_CHMAP_FC: return MA_CHANNEL_FRONT_CENTER; case MA_SND_CHMAP_LFE: return MA_CHANNEL_LFE; case MA_SND_CHMAP_SL: return MA_CHANNEL_SIDE_LEFT; case MA_SND_CHMAP_SR: return MA_CHANNEL_SIDE_RIGHT; case MA_SND_CHMAP_RC: return MA_CHANNEL_BACK_CENTER; case MA_SND_CHMAP_FLC: return MA_CHANNEL_FRONT_LEFT_CENTER; case MA_SND_CHMAP_FRC: return MA_CHANNEL_FRONT_RIGHT_CENTER; case MA_SND_CHMAP_RLC: return 0; case MA_SND_CHMAP_RRC: return 0; case MA_SND_CHMAP_FLW: return 0; case MA_SND_CHMAP_FRW: return 0; case MA_SND_CHMAP_FLH: return 0; case MA_SND_CHMAP_FCH: return 0; case MA_SND_CHMAP_FRH: return 0; case MA_SND_CHMAP_TC: return MA_CHANNEL_TOP_CENTER; case MA_SND_CHMAP_TFL: return MA_CHANNEL_TOP_FRONT_LEFT; case MA_SND_CHMAP_TFR: return MA_CHANNEL_TOP_FRONT_RIGHT; case MA_SND_CHMAP_TFC: return MA_CHANNEL_TOP_FRONT_CENTER; case MA_SND_CHMAP_TRL: return MA_CHANNEL_TOP_BACK_LEFT; case MA_SND_CHMAP_TRR: return MA_CHANNEL_TOP_BACK_RIGHT; case MA_SND_CHMAP_TRC: return MA_CHANNEL_TOP_BACK_CENTER; default: break; } return 0; } ma_bool32 ma_is_common_device_name__alsa(const char* name) { size_t iName; for (iName = 0; iName < ma_countof(g_maCommonDeviceNamesALSA); ++iName) { if (ma_strcmp(name, g_maCommonDeviceNamesALSA[iName]) == 0) { return MA_TRUE; } } return MA_FALSE; } ma_bool32 ma_is_playback_device_blacklisted__alsa(const char* name) { size_t iName; for (iName = 0; iName < ma_countof(g_maBlacklistedPlaybackDeviceNamesALSA); ++iName) { if (ma_strcmp(name, g_maBlacklistedPlaybackDeviceNamesALSA[iName]) == 0) { return MA_TRUE; } } return MA_FALSE; } ma_bool32 ma_is_capture_device_blacklisted__alsa(const char* name) { size_t iName; for (iName = 0; iName < ma_countof(g_maBlacklistedCaptureDeviceNamesALSA); ++iName) { if (ma_strcmp(name, g_maBlacklistedCaptureDeviceNamesALSA[iName]) == 0) { return MA_TRUE; } } return MA_FALSE; } ma_bool32 ma_is_device_blacklisted__alsa(ma_device_type deviceType, const char* name) { if (deviceType == ma_device_type_playback) { return ma_is_playback_device_blacklisted__alsa(name); } else { return ma_is_capture_device_blacklisted__alsa(name); } } const char* ma_find_char(const char* str, char c, int* index) { int i = 0; for (;;) { if (str[i] == '\0') { if (index) *index = -1; return NULL; } if (str[i] == c) { if (index) *index = i; return str + i; } i += 1; } /* Should never get here, but treat it as though the character was not found to make me feel better inside. */ if (index) *index = -1; return NULL; } ma_bool32 ma_is_device_name_in_hw_format__alsa(const char* hwid) { /* This function is just checking whether or not hwid is in "hw:%d,%d" format. */ int commaPos; const char* dev; int i; if (hwid == NULL) { return MA_FALSE; } if (hwid[0] != 'h' || hwid[1] != 'w' || hwid[2] != ':') { return MA_FALSE; } hwid += 3; dev = ma_find_char(hwid, ',', &commaPos); if (dev == NULL) { return MA_FALSE; } else { dev += 1; /* Skip past the ",". */ } /* Check if the part between the ":" and the "," contains only numbers. If not, return false. */ for (i = 0; i < commaPos; ++i) { if (hwid[i] < '0' || hwid[i] > '9') { return MA_FALSE; } } /* Check if everything after the "," is numeric. If not, return false. */ i = 0; while (dev[i] != '\0') { if (dev[i] < '0' || dev[i] > '9') { return MA_FALSE; } i += 1; } return MA_TRUE; } int ma_convert_device_name_to_hw_format__alsa(ma_context* pContext, char* dst, size_t dstSize, const char* src) /* Returns 0 on success, non-0 on error. */ { /* src should look something like this: "hw:CARD=I82801AAICH,DEV=0" */ int colonPos; int commaPos; char card[256]; const char* dev; int cardIndex; if (dst == NULL) { return -1; } if (dstSize < 7) { return -1; /* Absolute minimum size of the output buffer is 7 bytes. */ } *dst = '\0'; /* Safety. */ if (src == NULL) { return -1; } /* If the input name is already in "hw:%d,%d" format, just return that verbatim. */ if (ma_is_device_name_in_hw_format__alsa(src)) { return ma_strcpy_s(dst, dstSize, src); } src = ma_find_char(src, ':', &colonPos); if (src == NULL) { return -1; /* Couldn't find a colon */ } dev = ma_find_char(src, ',', &commaPos); if (dev == NULL) { dev = "0"; ma_strncpy_s(card, sizeof(card), src+6, (size_t)-1); /* +6 = ":CARD=" */ } else { dev = dev + 5; /* +5 = ",DEV=" */ ma_strncpy_s(card, sizeof(card), src+6, commaPos-6); /* +6 = ":CARD=" */ } cardIndex = ((ma_snd_card_get_index_proc)pContext->alsa.snd_card_get_index)(card); if (cardIndex < 0) { return -2; /* Failed to retrieve the card index. */ } /*printf("TESTING: CARD=%s,DEV=%s\n", card, dev); */ /* Construction. */ dst[0] = 'h'; dst[1] = 'w'; dst[2] = ':'; if (ma_itoa_s(cardIndex, dst+3, dstSize-3, 10) != 0) { return -3; } if (ma_strcat_s(dst, dstSize, ",") != 0) { return -3; } if (ma_strcat_s(dst, dstSize, dev) != 0) { return -3; } return 0; } ma_bool32 ma_does_id_exist_in_list__alsa(ma_device_id* pUniqueIDs, ma_uint32 count, const char* pHWID) { ma_uint32 i; ma_assert(pHWID != NULL); for (i = 0; i < count; ++i) { if (ma_strcmp(pUniqueIDs[i].alsa, pHWID) == 0) { return MA_TRUE; } } return MA_FALSE; } ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode shareMode, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_snd_pcm_t** ppPCM) { ma_snd_pcm_t* pPCM; ma_snd_pcm_stream_t stream; int openMode; ma_assert(pContext != NULL); ma_assert(ppPCM != NULL); *ppPCM = NULL; pPCM = NULL; stream = (deviceType == ma_device_type_playback) ? MA_SND_PCM_STREAM_PLAYBACK : MA_SND_PCM_STREAM_CAPTURE; openMode = MA_SND_PCM_NO_AUTO_RESAMPLE | MA_SND_PCM_NO_AUTO_CHANNELS | MA_SND_PCM_NO_AUTO_FORMAT; if (pDeviceID == NULL) { ma_bool32 isDeviceOpen; size_t i; /* We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes me feel better to try as hard as we can get to get _something_ working. */ const char* defaultDeviceNames[] = { "default", NULL, NULL, NULL, NULL, NULL, NULL }; if (shareMode == ma_share_mode_exclusive) { defaultDeviceNames[1] = "hw"; defaultDeviceNames[2] = "hw:0"; defaultDeviceNames[3] = "hw:0,0"; } else { if (deviceType == ma_device_type_playback) { defaultDeviceNames[1] = "dmix"; defaultDeviceNames[2] = "dmix:0"; defaultDeviceNames[3] = "dmix:0,0"; } else { defaultDeviceNames[1] = "dsnoop"; defaultDeviceNames[2] = "dsnoop:0"; defaultDeviceNames[3] = "dsnoop:0,0"; } defaultDeviceNames[4] = "hw"; defaultDeviceNames[5] = "hw:0"; defaultDeviceNames[6] = "hw:0,0"; } isDeviceOpen = MA_FALSE; for (i = 0; i < ma_countof(defaultDeviceNames); ++i) { if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') { if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, defaultDeviceNames[i], stream, openMode) == 0) { isDeviceOpen = MA_TRUE; break; } } } if (!isDeviceOpen) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } else { /* We're trying to open a specific device. There's a few things to consider here: miniaudio recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw"). */ /* May end up needing to make small adjustments to the ID, so make a copy. */ ma_device_id deviceID = *pDeviceID; ma_bool32 isDeviceOpen = MA_FALSE; if (deviceID.alsa[0] != ':') { /* The ID is not in ":0,0" format. Use the ID exactly as-is. */ if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, deviceID.alsa, stream, openMode) == 0) { isDeviceOpen = MA_TRUE; } } else { char hwid[256]; /* The ID is in ":0,0" format. Try different plugins depending on the shared mode. */ if (deviceID.alsa[1] == '\0') { deviceID.alsa[0] = '\0'; /* An ID of ":" should be converted to "". */ } if (shareMode == ma_share_mode_shared) { if (deviceType == ma_device_type_playback) { ma_strcpy_s(hwid, sizeof(hwid), "dmix"); } else { ma_strcpy_s(hwid, sizeof(hwid), "dsnoop"); } if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) { if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode) == 0) { isDeviceOpen = MA_TRUE; } } } /* If at this point we still don't have an open device it means we're either preferencing exclusive mode or opening with "dmix"/"dsnoop" failed. */ if (!isDeviceOpen) { ma_strcpy_s(hwid, sizeof(hwid), "hw"); if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) { if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode) == 0) { isDeviceOpen = MA_TRUE; } } } } if (!isDeviceOpen) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } *ppPCM = pPCM; return MA_SUCCESS; } ma_bool32 ma_context_is_device_id_equal__alsa(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return ma_strcmp(pID0->alsa, pID1->alsa) == 0; } ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_bool32 cbResult = MA_TRUE; char** ppDeviceHints; ma_device_id* pUniqueIDs = NULL; ma_uint32 uniqueIDCount = 0; char** ppNextDeviceHint; ma_assert(pContext != NULL); ma_assert(callback != NULL); ma_mutex_lock(&pContext->alsa.internalDeviceEnumLock); if (((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints) < 0) { ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock); return MA_NO_BACKEND; } ppNextDeviceHint = ppDeviceHints; while (*ppNextDeviceHint != NULL) { char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME"); char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC"); char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID"); ma_device_type deviceType = ma_device_type_playback; ma_bool32 stopEnumeration = MA_FALSE; char hwid[sizeof(pUniqueIDs->alsa)]; ma_device_info deviceInfo; if ((IOID == NULL || ma_strcmp(IOID, "Output") == 0)) { deviceType = ma_device_type_playback; } if ((IOID != NULL && ma_strcmp(IOID, "Input" ) == 0)) { deviceType = ma_device_type_capture; } if (NAME != NULL) { if (pContext->alsa.useVerboseDeviceEnumeration) { /* Verbose mode. Use the name exactly as-is. */ ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1); } else { /* Simplified mode. Use ":%d,%d" format. */ if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) { /* At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device initialization time and is used as an indicator to try and use the most appropriate plugin depending on the device type and sharing mode. */ char* dst = hwid; char* src = hwid+2; while ((*dst++ = *src++)); } else { /* Conversion to "hw:%d,%d" failed. Just use the name as-is. */ ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1); } if (ma_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) { goto next_device; /* The device has already been enumerated. Move on to the next one. */ } else { /* The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. */ ma_device_id* pNewUniqueIDs = (ma_device_id*)ma_realloc(pUniqueIDs, sizeof(*pUniqueIDs) * (uniqueIDCount + 1)); if (pNewUniqueIDs == NULL) { goto next_device; /* Failed to allocate memory. */ } pUniqueIDs = pNewUniqueIDs; ma_copy_memory(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid)); uniqueIDCount += 1; } } } else { ma_zero_memory(hwid, sizeof(hwid)); } ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.id.alsa, sizeof(deviceInfo.id.alsa), hwid, (size_t)-1); /* DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the description. The value in DESC seems to be split into two lines, with the first line being the name of the device and the second line being a description of the device. I don't like having the description be across two lines because it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line being put into parentheses. In simplified mode I'm just stripping the second line entirely. */ if (DESC != NULL) { int lfPos; const char* line2 = ma_find_char(DESC, '\n', &lfPos); if (line2 != NULL) { line2 += 1; /* Skip past the new-line character. */ if (pContext->alsa.useVerboseDeviceEnumeration) { /* Verbose mode. Put the second line in brackets. */ ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos); ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), " ("); ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), line2); ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), ")"); } else { /* Simplified mode. Strip the second line entirely. */ ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos); } } else { /* There's no second line. Just copy the whole description. */ ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, (size_t)-1); } } if (!ma_is_device_blacklisted__alsa(deviceType, NAME)) { cbResult = callback(pContext, deviceType, &deviceInfo, pUserData); } /* Some devices are both playback and capture, but they are only enumerated by ALSA once. We need to fire the callback again for the other device type in this case. We do this for known devices. */ if (cbResult) { if (ma_is_common_device_name__alsa(NAME)) { if (deviceType == ma_device_type_playback) { if (!ma_is_capture_device_blacklisted__alsa(NAME)) { cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } } else { if (!ma_is_playback_device_blacklisted__alsa(NAME)) { cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } } } } if (cbResult == MA_FALSE) { stopEnumeration = MA_TRUE; } next_device: free(NAME); free(DESC); free(IOID); ppNextDeviceHint += 1; /* We need to stop enumeration if the callback returned false. */ if (stopEnumeration) { break; } } ma_free(pUniqueIDs); ((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints); ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock); return MA_SUCCESS; } typedef struct { ma_device_type deviceType; const ma_device_id* pDeviceID; ma_share_mode shareMode; ma_device_info* pDeviceInfo; ma_bool32 foundDevice; } ma_context_get_device_info_enum_callback_data__alsa; ma_bool32 ma_context_get_device_info_enum_callback__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pDeviceInfo, void* pUserData) { ma_context_get_device_info_enum_callback_data__alsa* pData = (ma_context_get_device_info_enum_callback_data__alsa*)pUserData; ma_assert(pData != NULL); if (pData->pDeviceID == NULL && ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) { ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1); pData->foundDevice = MA_TRUE; } else { if (pData->deviceType == deviceType && ma_context_is_device_id_equal__alsa(pContext, pData->pDeviceID, &pDeviceInfo->id)) { ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1); pData->foundDevice = MA_TRUE; } } /* Keep enumerating until we have found the device. */ return !pData->foundDevice; } ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_context_get_device_info_enum_callback_data__alsa data; ma_result result; ma_snd_pcm_t* pPCM; ma_snd_pcm_hw_params_t* pHWParams; ma_snd_pcm_format_mask_t* pFormatMask; int sampleRateDir = 0; ma_assert(pContext != NULL); /* We just enumerate to find basic information about the device. */ data.deviceType = deviceType; data.pDeviceID = pDeviceID; data.shareMode = shareMode; data.pDeviceInfo = pDeviceInfo; data.foundDevice = MA_FALSE; result = ma_context_enumerate_devices__alsa(pContext, ma_context_get_device_info_enum_callback__alsa, &data); if (result != MA_SUCCESS) { return result; } if (!data.foundDevice) { return MA_NO_DEVICE; } /* For detailed info we need to open the device. */ result = ma_context_open_pcm__alsa(pContext, shareMode, deviceType, pDeviceID, &pPCM); if (result != MA_SUCCESS) { return result; } /* We need to initialize a HW parameters object in order to know what formats are supported. */ pHWParams = (ma_snd_pcm_hw_params_t*)calloc(1, ((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)()); if (pHWParams == NULL) { return MA_OUT_OF_MEMORY; } if (((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams) < 0) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", MA_FAILED_TO_CONFIGURE_BACKEND_DEVICE); } ((ma_snd_pcm_hw_params_get_channels_min_proc)pContext->alsa.snd_pcm_hw_params_get_channels_min)(pHWParams, &pDeviceInfo->minChannels); ((ma_snd_pcm_hw_params_get_channels_max_proc)pContext->alsa.snd_pcm_hw_params_get_channels_max)(pHWParams, &pDeviceInfo->maxChannels); ((ma_snd_pcm_hw_params_get_rate_min_proc)pContext->alsa.snd_pcm_hw_params_get_rate_min)(pHWParams, &pDeviceInfo->minSampleRate, &sampleRateDir); ((ma_snd_pcm_hw_params_get_rate_max_proc)pContext->alsa.snd_pcm_hw_params_get_rate_max)(pHWParams, &pDeviceInfo->maxSampleRate, &sampleRateDir); /* Formats. */ pFormatMask = (ma_snd_pcm_format_mask_t*)calloc(1, ((ma_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)()); if (pFormatMask == NULL) { return MA_OUT_OF_MEMORY; } ((ma_snd_pcm_hw_params_get_format_mask_proc)pContext->alsa.snd_pcm_hw_params_get_format_mask)(pHWParams, pFormatMask); pDeviceInfo->formatCount = 0; if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_U8)) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_u8; } if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S16_LE)) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s16; } if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S24_3LE)) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s24; } if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S32_LE)) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s32; } if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_FLOAT_LE)) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_f32; } ma_free(pFormatMask); ma_free(pHWParams); ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); return MA_SUCCESS; } #if 0 /* Waits for a number of frames to become available for either capture or playback. The return value is the number of frames available. This will return early if the main loop is broken with ma_device__break_main_loop(). */ ma_uint32 ma_device__wait_for_frames__alsa(ma_device* pDevice, ma_bool32* pRequiresRestart) { ma_assert(pDevice != NULL); if (pRequiresRestart) *pRequiresRestart = MA_FALSE; /* I want it so that this function returns the period size in frames. We just wait until that number of frames are available and then return. */ ma_uint32 periodSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods; while (!pDevice->alsa.breakFromMainLoop) { ma_snd_pcm_sframes_t framesAvailable = ((ma_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((ma_snd_pcm_t*)pDevice->alsa.pPCM); if (framesAvailable < 0) { if (framesAvailable == -EPIPE) { if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, framesAvailable, MA_TRUE) < 0) { return 0; } /* A device recovery means a restart for mmap mode. */ if (pRequiresRestart) { *pRequiresRestart = MA_TRUE; } /* Try again, but if it fails this time just return an error. */ framesAvailable = ((ma_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((ma_snd_pcm_t*)pDevice->alsa.pPCM); if (framesAvailable < 0) { return 0; } } } if (framesAvailable >= periodSizeInFrames) { return periodSizeInFrames; } if (framesAvailable < periodSizeInFrames) { /* Less than a whole period is available so keep waiting. */ int waitResult = ((ma_snd_pcm_wait_proc)pDevice->pContext->alsa.snd_pcm_wait)((ma_snd_pcm_t*)pDevice->alsa.pPCM, -1); if (waitResult < 0) { if (waitResult == -EPIPE) { if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, waitResult, MA_TRUE) < 0) { return 0; } /* A device recovery means a restart for mmap mode. */ if (pRequiresRestart) { *pRequiresRestart = MA_TRUE; } } } } } /* We'll get here if the loop was terminated. Just return whatever's available. */ ma_snd_pcm_sframes_t framesAvailable = ((ma_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((ma_snd_pcm_t*)pDevice->alsa.pPCM); if (framesAvailable < 0) { return 0; } return framesAvailable; } ma_bool32 ma_device_read_from_client_and_write__alsa(ma_device* pDevice) { ma_assert(pDevice != NULL); if (!ma_device_is_started(pDevice) && ma_device__get_state(pDevice) != MA_STATE_STARTING) { return MA_FALSE; } if (pDevice->alsa.breakFromMainLoop) { return MA_FALSE; } if (pDevice->alsa.isUsingMMap) { /* mmap. */ ma_bool32 requiresRestart; ma_uint32 framesAvailable = ma_device__wait_for_frames__alsa(pDevice, &requiresRestart); if (framesAvailable == 0) { return MA_FALSE; } /* Don't bother asking the client for more audio data if we're just stopping the device anyway. */ if (pDevice->alsa.breakFromMainLoop) { return MA_FALSE; } const ma_snd_pcm_channel_area_t* pAreas; ma_snd_pcm_uframes_t mappedOffset; ma_snd_pcm_uframes_t mappedFrames = framesAvailable; while (framesAvailable > 0) { int result = ((ma_snd_pcm_mmap_begin_proc)pDevice->pContext->alsa.snd_pcm_mmap_begin)((ma_snd_pcm_t*)pDevice->alsa.pPCM, &pAreas, &mappedOffset, &mappedFrames); if (result < 0) { return MA_FALSE; } if (mappedFrames > 0) { void* pBuffer = (ma_uint8*)pAreas[0].addr + ((pAreas[0].first + (mappedOffset * pAreas[0].step)) / 8); ma_device__read_frames_from_client(pDevice, mappedFrames, pBuffer); } result = ((ma_snd_pcm_mmap_commit_proc)pDevice->pContext->alsa.snd_pcm_mmap_commit)((ma_snd_pcm_t*)pDevice->alsa.pPCM, mappedOffset, mappedFrames); if (result < 0 || (ma_snd_pcm_uframes_t)result != mappedFrames) { ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, result, MA_TRUE); return MA_FALSE; } if (requiresRestart) { if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCM) < 0) { return MA_FALSE; } } if (framesAvailable >= mappedFrames) { framesAvailable -= mappedFrames; } else { framesAvailable = 0; } } } else { /* readi/writei. */ while (!pDevice->alsa.breakFromMainLoop) { ma_uint32 framesAvailable = ma_device__wait_for_frames__alsa(pDevice, NULL); if (framesAvailable == 0) { continue; } /* Don't bother asking the client for more audio data if we're just stopping the device anyway. */ if (pDevice->alsa.breakFromMainLoop) { return MA_FALSE; } ma_device__read_frames_from_client(pDevice, framesAvailable, pDevice->alsa.pIntermediaryBuffer); ma_snd_pcm_sframes_t framesWritten = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); if (framesWritten < 0) { if (framesWritten == -EAGAIN) { continue; /* Just keep trying... */ } else if (framesWritten == -EPIPE) { /* Underrun. Just recover and try writing again. */ if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, framesWritten, MA_TRUE) < 0) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.", MA_FAILED_TO_START_BACKEND_DEVICE); return MA_FALSE; } framesWritten = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); if (framesWritten < 0) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to write data to the internal device.", MA_FAILED_TO_SEND_DATA_TO_DEVICE); return MA_FALSE; } break; /* Success. */ } else { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_writei() failed when writing initial data.", MA_FAILED_TO_SEND_DATA_TO_DEVICE); return MA_FALSE; } } else { break; /* Success. */ } } } return MA_TRUE; } ma_bool32 ma_device_read_and_send_to_client__alsa(ma_device* pDevice) { ma_assert(pDevice != NULL); if (!ma_device_is_started(pDevice)) { return MA_FALSE; } if (pDevice->alsa.breakFromMainLoop) { return MA_FALSE; } ma_uint32 framesToSend = 0; void* pBuffer = NULL; if (pDevice->alsa.pIntermediaryBuffer == NULL) { /* mmap. */ ma_bool32 requiresRestart; ma_uint32 framesAvailable = ma_device__wait_for_frames__alsa(pDevice, &requiresRestart); if (framesAvailable == 0) { return MA_FALSE; } const ma_snd_pcm_channel_area_t* pAreas; ma_snd_pcm_uframes_t mappedOffset; ma_snd_pcm_uframes_t mappedFrames = framesAvailable; while (framesAvailable > 0) { int result = ((ma_snd_pcm_mmap_begin_proc)pDevice->pContext->alsa.snd_pcm_mmap_begin)((ma_snd_pcm_t*)pDevice->alsa.pPCM, &pAreas, &mappedOffset, &mappedFrames); if (result < 0) { return MA_FALSE; } if (mappedFrames > 0) { void* pBuffer = (ma_uint8*)pAreas[0].addr + ((pAreas[0].first + (mappedOffset * pAreas[0].step)) / 8); ma_device__send_frames_to_client(pDevice, mappedFrames, pBuffer); } result = ((ma_snd_pcm_mmap_commit_proc)pDevice->pContext->alsa.snd_pcm_mmap_commit)((ma_snd_pcm_t*)pDevice->alsa.pPCM, mappedOffset, mappedFrames); if (result < 0 || (ma_snd_pcm_uframes_t)result != mappedFrames) { ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, result, MA_TRUE); return MA_FALSE; } if (requiresRestart) { if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCM) < 0) { return MA_FALSE; } } if (framesAvailable >= mappedFrames) { framesAvailable -= mappedFrames; } else { framesAvailable = 0; } } } else { /* readi/writei. */ ma_snd_pcm_sframes_t framesRead = 0; while (!pDevice->alsa.breakFromMainLoop) { ma_uint32 framesAvailable = ma_device__wait_for_frames__alsa(pDevice, NULL); if (framesAvailable == 0) { continue; } framesRead = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); if (framesRead < 0) { if (framesRead == -EAGAIN) { continue; /* Just keep trying... */ } else if (framesRead == -EPIPE) { /* Overrun. Just recover and try reading again. */ if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, framesRead, MA_TRUE) < 0) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.", MA_FAILED_TO_START_BACKEND_DEVICE); return MA_FALSE; } framesRead = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); if (framesRead < 0) { ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to read data from the internal device.", MA_FAILED_TO_READ_DATA_FROM_DEVICE); return MA_FALSE; } break; /* Success. */ } else { return MA_FALSE; } } else { break; /* Success. */ } } framesToSend = framesRead; pBuffer = pDevice->alsa.pIntermediaryBuffer; } if (framesToSend > 0) { ma_device__send_frames_to_client(pDevice, framesToSend, pBuffer); } return MA_TRUE; } #endif /* 0 */ void ma_device_uninit__alsa(ma_device* pDevice) { ma_assert(pDevice != NULL); if ((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); } if ((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); } } ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice) { ma_result result; ma_snd_pcm_t* pPCM; ma_bool32 isUsingMMap; ma_snd_pcm_format_t formatALSA; ma_share_mode shareMode; ma_device_id* pDeviceID; ma_format internalFormat; ma_uint32 internalChannels; ma_uint32 internalSampleRate; ma_channel internalChannelMap[MA_MAX_CHANNELS]; ma_uint32 internalBufferSizeInFrames; ma_uint32 internalPeriods; ma_snd_pcm_hw_params_t* pHWParams; ma_snd_pcm_sw_params_t* pSWParams; ma_snd_pcm_uframes_t bufferBoundary; float bufferSizeScaleFactor; ma_assert(pContext != NULL); ma_assert(pConfig != NULL); ma_assert(deviceType != ma_device_type_duplex); /* This function should only be called for playback _or_ capture, never duplex. */ ma_assert(pDevice != NULL); formatALSA = ma_convert_ma_format_to_alsa_format((deviceType == ma_device_type_capture) ? pConfig->capture.format : pConfig->playback.format); shareMode = (deviceType == ma_device_type_capture) ? pConfig->capture.shareMode : pConfig->playback.shareMode; pDeviceID = (deviceType == ma_device_type_capture) ? pConfig->capture.pDeviceID : pConfig->playback.pDeviceID; result = ma_context_open_pcm__alsa(pContext, shareMode, deviceType, pDeviceID, &pPCM); if (result != MA_SUCCESS) { return result; } /* If using the default buffer size we may want to apply some device-specific scaling for known devices that have peculiar latency characteristics */ bufferSizeScaleFactor = 1; if (pDevice->usingDefaultBufferSize) { ma_snd_pcm_info_t* pInfo = (ma_snd_pcm_info_t*)calloc(1, ((ma_snd_pcm_info_sizeof_proc)pContext->alsa.snd_pcm_info_sizeof)()); if (pInfo == NULL) { return MA_OUT_OF_MEMORY; } /* We may need to scale the size of the buffer depending on the device. */ if (((ma_snd_pcm_info_proc)pContext->alsa.snd_pcm_info)(pPCM, pInfo) == 0) { const char* deviceName = ((ma_snd_pcm_info_get_name_proc)pContext->alsa.snd_pcm_info_get_name)(pInfo); if (deviceName != NULL) { if (ma_strcmp(deviceName, "default") == 0) { char** ppDeviceHints; char** ppNextDeviceHint; /* It's the default device. We need to use DESC from snd_device_name_hint(). */ if (((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints) < 0) { ma_free(pInfo); return MA_NO_BACKEND; } ppNextDeviceHint = ppDeviceHints; while (*ppNextDeviceHint != NULL) { char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME"); char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC"); char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID"); ma_bool32 foundDevice = MA_FALSE; if ((deviceType == ma_device_type_playback && (IOID == NULL || ma_strcmp(IOID, "Output") == 0)) || (deviceType == ma_device_type_capture && (IOID != NULL && ma_strcmp(IOID, "Input" ) == 0))) { if (ma_strcmp(NAME, deviceName) == 0) { bufferSizeScaleFactor = ma_find_default_buffer_size_scale__alsa(DESC); foundDevice = MA_TRUE; } } free(NAME); free(DESC); free(IOID); ppNextDeviceHint += 1; if (foundDevice) { break; } } ((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints); } else { bufferSizeScaleFactor = ma_find_default_buffer_size_scale__alsa(deviceName); } } } ma_free(pInfo); } /* Hardware parameters. */ pHWParams = (ma_snd_pcm_hw_params_t*)calloc(1, ((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)()); if (pHWParams == NULL) { return MA_OUT_OF_MEMORY; } if (((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams) < 0) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", MA_FAILED_TO_CONFIGURE_BACKEND_DEVICE); } /* MMAP Mode. Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. */ isUsingMMap = MA_FALSE; #if 0 /* NOTE: MMAP mode temporarily disabled. */ if (deviceType != ma_device_type_capture) { /* <-- Disabling MMAP mode for capture devices because I apparently do not have a device that supports it which means I can't test it... Contributions welcome. */ if (!pConfig->alsa.noMMap && ma_device__is_async(pDevice)) { if (((ma_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) { pDevice->alsa.isUsingMMap = MA_TRUE; } } } #endif if (!isUsingMMap) { if (((ma_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed.", MA_FORMAT_NOT_SUPPORTED); } } /* Most important properties first. The documentation for OSS (yes, I know this is ALSA!) recommends format, channels, then sample rate. I can't find any documentation for ALSA specifically, so I'm going to copy the recommendation for OSS. */ /* Format. */ { ma_snd_pcm_format_mask_t* pFormatMask; /* Try getting every supported format first. */ pFormatMask = (ma_snd_pcm_format_mask_t*)calloc(1, ((ma_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)()); if (pFormatMask == NULL) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return MA_OUT_OF_MEMORY; } ((ma_snd_pcm_hw_params_get_format_mask_proc)pContext->alsa.snd_pcm_hw_params_get_format_mask)(pHWParams, pFormatMask); /* At this point we should have a list of supported formats, so now we need to find the best one. We first check if the requested format is supported, and if so, use that one. If it's not supported, we just run though a list of formats and try to find the best one. */ if (!((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, formatALSA)) { size_t i; /* The requested format is not supported so now try running through the list of formats and return the best one. */ ma_snd_pcm_format_t preferredFormatsALSA[] = { MA_SND_PCM_FORMAT_S16_LE, /* ma_format_s16 */ MA_SND_PCM_FORMAT_FLOAT_LE, /* ma_format_f32 */ MA_SND_PCM_FORMAT_S32_LE, /* ma_format_s32 */ MA_SND_PCM_FORMAT_S24_3LE, /* ma_format_s24 */ MA_SND_PCM_FORMAT_U8 /* ma_format_u8 */ }; if (ma_is_big_endian()) { preferredFormatsALSA[0] = MA_SND_PCM_FORMAT_S16_BE; preferredFormatsALSA[1] = MA_SND_PCM_FORMAT_FLOAT_BE; preferredFormatsALSA[2] = MA_SND_PCM_FORMAT_S32_BE; preferredFormatsALSA[3] = MA_SND_PCM_FORMAT_S24_3BE; preferredFormatsALSA[4] = MA_SND_PCM_FORMAT_U8; } formatALSA = MA_SND_PCM_FORMAT_UNKNOWN; for (i = 0; i < (sizeof(preferredFormatsALSA) / sizeof(preferredFormatsALSA[0])); ++i) { if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, preferredFormatsALSA[i])) { formatALSA = preferredFormatsALSA[i]; break; } } if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.", MA_FORMAT_NOT_SUPPORTED); } } ma_free(pFormatMask); pFormatMask = NULL; if (((ma_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, formatALSA) < 0) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.", MA_FORMAT_NOT_SUPPORTED); } internalFormat = ma_format_from_alsa(formatALSA); if (internalFormat == ma_format_unknown) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED); } } /* Channels. */ { unsigned int channels = (deviceType == ma_device_type_capture) ? pConfig->capture.channels : pConfig->playback.channels; if (((ma_snd_pcm_hw_params_set_channels_near_proc)pContext->alsa.snd_pcm_hw_params_set_channels_near)(pPCM, pHWParams, &channels) < 0) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.", MA_FORMAT_NOT_SUPPORTED); } internalChannels = (ma_uint32)channels; } /* Sample Rate */ { unsigned int sampleRate; /* It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling enabled causes problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable resampling. To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly faster rate. miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion. I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins. */ ((ma_snd_pcm_hw_params_set_rate_resample_proc)pContext->alsa.snd_pcm_hw_params_set_rate_resample)(pPCM, pHWParams, 0); sampleRate = pConfig->sampleRate; if (((ma_snd_pcm_hw_params_set_rate_near_proc)pContext->alsa.snd_pcm_hw_params_set_rate_near)(pPCM, pHWParams, &sampleRate, 0) < 0) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.", MA_FORMAT_NOT_SUPPORTED); } internalSampleRate = (ma_uint32)sampleRate; } /* Buffer Size */ { ma_snd_pcm_uframes_t actualBufferSizeInFrames = pConfig->bufferSizeInFrames; if (actualBufferSizeInFrames == 0) { actualBufferSizeInFrames = ma_scale_buffer_size(ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, internalSampleRate), bufferSizeScaleFactor); } if (((ma_snd_pcm_hw_params_set_buffer_size_near_proc)pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)(pPCM, pHWParams, &actualBufferSizeInFrames) < 0) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.", MA_FORMAT_NOT_SUPPORTED); } internalBufferSizeInFrames = actualBufferSizeInFrames; } /* Periods. */ { ma_uint32 periods = pConfig->periods; if (((ma_snd_pcm_hw_params_set_periods_near_proc)pContext->alsa.snd_pcm_hw_params_set_periods_near)(pPCM, pHWParams, &periods, NULL) < 0) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.", MA_FORMAT_NOT_SUPPORTED); } internalPeriods = periods; } /* Apply hardware parameters. */ if (((ma_snd_pcm_hw_params_proc)pContext->alsa.snd_pcm_hw_params)(pPCM, pHWParams) < 0) { ma_free(pHWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", MA_FAILED_TO_CONFIGURE_BACKEND_DEVICE); } ma_free(pHWParams); pHWParams = NULL; /* Software parameters. */ pSWParams = (ma_snd_pcm_sw_params_t*)calloc(1, ((ma_snd_pcm_sw_params_sizeof_proc)pContext->alsa.snd_pcm_sw_params_sizeof)()); if (pSWParams == NULL) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return MA_OUT_OF_MEMORY; } if (((ma_snd_pcm_sw_params_current_proc)pContext->alsa.snd_pcm_sw_params_current)(pPCM, pSWParams) != 0) { ma_free(pSWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.", MA_FAILED_TO_CONFIGURE_BACKEND_DEVICE); } if (deviceType == ma_device_type_capture) { if (((ma_snd_pcm_sw_params_set_avail_min_proc)pContext->alsa.snd_pcm_sw_params_set_avail_min)(pPCM, pSWParams, 1) != 0) { ma_free(pSWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", MA_FORMAT_NOT_SUPPORTED); } } else { if (((ma_snd_pcm_sw_params_set_avail_min_proc)pContext->alsa.snd_pcm_sw_params_set_avail_min)(pPCM, pSWParams, 1) != 0) { ma_free(pSWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", MA_FORMAT_NOT_SUPPORTED); } } if (((ma_snd_pcm_sw_params_get_boundary_proc)pContext->alsa.snd_pcm_sw_params_get_boundary)(pSWParams, &bufferBoundary) < 0) { bufferBoundary = internalBufferSizeInFrames; } /*printf("TRACE: bufferBoundary=%ld\n", bufferBoundary);*/ if (deviceType == ma_device_type_playback && !isUsingMMap) { /* Only playback devices in writei/readi mode need a start threshold. */ /* Subtle detail here with the start threshold. When in playback-only mode (no full-duplex) we can set the start threshold to the size of a period. But for full-duplex we need to set it such that it is at least two periods. */ if (((ma_snd_pcm_sw_params_set_start_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, internalBufferSizeInFrames) != 0) { ma_free(pSWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", MA_FAILED_TO_CONFIGURE_BACKEND_DEVICE); } if (((ma_snd_pcm_sw_params_set_stop_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_stop_threshold)(pPCM, pSWParams, bufferBoundary) != 0) { /* Set to boundary to loop instead of stop in the event of an xrun. */ ma_free(pSWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed.", MA_FAILED_TO_CONFIGURE_BACKEND_DEVICE); } } if (((ma_snd_pcm_sw_params_proc)pContext->alsa.snd_pcm_sw_params)(pPCM, pSWParams) != 0) { ma_free(pSWParams); ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.", MA_FAILED_TO_CONFIGURE_BACKEND_DEVICE); } ma_free(pSWParams); pSWParams = NULL; /* Grab the internal channel map. For now we're not going to bother trying to change the channel map and instead just do it ourselves. */ { ma_snd_pcm_chmap_t* pChmap = ((ma_snd_pcm_get_chmap_proc)pContext->alsa.snd_pcm_get_chmap)(pPCM); if (pChmap != NULL) { ma_uint32 iChannel; /* There are cases where the returned channel map can have a different channel count than was returned by snd_pcm_hw_params_set_channels_near(). */ if (pChmap->channels >= internalChannels) { /* Drop excess channels. */ for (iChannel = 0; iChannel < internalChannels; ++iChannel) { internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]); } } else { ma_uint32 i; /* Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate channels. If validation fails, fall back to defaults. */ ma_bool32 isValid = MA_TRUE; /* Fill with defaults. */ ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); /* Overwrite first pChmap->channels channels. */ for (iChannel = 0; iChannel < pChmap->channels; ++iChannel) { internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]); } /* Validate. */ for (i = 0; i < internalChannels && isValid; ++i) { ma_uint32 j; for (j = i+1; j < internalChannels; ++j) { if (internalChannelMap[i] == internalChannelMap[j]) { isValid = MA_FALSE; break; } } } /* If our channel map is invalid, fall back to defaults. */ if (!isValid) { ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); } } free(pChmap); pChmap = NULL; } else { /* Could not retrieve the channel map. Fall back to a hard-coded assumption. */ ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap); } } /* We're done. Prepare the device. */ if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)(pPCM) < 0) { ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device.", MA_FAILED_TO_START_BACKEND_DEVICE); } if (deviceType == ma_device_type_capture) { pDevice->alsa.pPCMCapture = (ma_ptr)pPCM; pDevice->alsa.isUsingMMapCapture = isUsingMMap; pDevice->capture.internalFormat = internalFormat; pDevice->capture.internalChannels = internalChannels; pDevice->capture.internalSampleRate = internalSampleRate; ma_channel_map_copy(pDevice->capture.internalChannelMap, internalChannelMap, internalChannels); pDevice->capture.internalBufferSizeInFrames = internalBufferSizeInFrames; pDevice->capture.internalPeriods = internalPeriods; } else { pDevice->alsa.pPCMPlayback = (ma_ptr)pPCM; pDevice->alsa.isUsingMMapPlayback = isUsingMMap; pDevice->playback.internalFormat = internalFormat; pDevice->playback.internalChannels = internalChannels; pDevice->playback.internalSampleRate = internalSampleRate; ma_channel_map_copy(pDevice->playback.internalChannelMap, internalChannelMap, internalChannels); pDevice->playback.internalBufferSizeInFrames = internalBufferSizeInFrames; pDevice->playback.internalPeriods = internalPeriods; } return MA_SUCCESS; } ma_result ma_device_init__alsa(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_assert(pDevice != NULL); ma_zero_object(&pDevice->alsa); if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_by_type__alsa(pContext, pConfig, ma_device_type_capture, pDevice); if (result != MA_SUCCESS) { return result; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_by_type__alsa(pContext, pConfig, ma_device_type_playback, pDevice); if (result != MA_SUCCESS) { return result; } } return MA_SUCCESS; } #if 0 ma_result ma_device_start__alsa(ma_device* pDevice) { ma_assert(pDevice != NULL); /* Prepare the device first... */ if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCM) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device.", MA_FAILED_TO_START_BACKEND_DEVICE); } /* ... and then grab an initial chunk from the client. After this is done, the device should automatically start playing, since that's how we configured the software parameters. */ if (pDevice->type == ma_device_type_playback) { if (!ma_device_read_from_client_and_write__alsa(pDevice)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to write initial chunk of data to the playback device.", MA_FAILED_TO_SEND_DATA_TO_DEVICE); } /* mmap mode requires an explicit start. */ if (pDevice->alsa.isUsingMMap) { if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCM) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device.", MA_FAILED_TO_START_BACKEND_DEVICE); } } } else { if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCM) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device.", MA_FAILED_TO_START_BACKEND_DEVICE); } } return MA_SUCCESS; } #endif /* 0 */ ma_result ma_device_stop__alsa(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); /* We need to prepare the device again, otherwise we won't be able to restart the device. */ if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) { #ifdef MA_DEBUG_OUTPUT printf("[ALSA] Failed to prepare capture device after stopping.\n"); #endif } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { /* Using drain instead of drop because ma_device_stop() is defined such that pending frames are processed before returning. */ ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); /* We need to prepare the device again, otherwise we won't be able to restart the device. */ if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) { #ifdef MA_DEBUG_OUTPUT printf("[ALSA] Failed to prepare playback device after stopping.\n"); #endif } } return MA_SUCCESS; } ma_result ma_device_write__alsa(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount) { ma_snd_pcm_sframes_t resultALSA; ma_uint32 totalPCMFramesProcessed; ma_assert(pDevice != NULL); ma_assert(pPCMFrames != NULL); /*printf("TRACE: Enter write()\n");*/ totalPCMFramesProcessed = 0; while (totalPCMFramesProcessed < frameCount) { const void* pSrc = ma_offset_ptr(pPCMFrames, totalPCMFramesProcessed * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed); /*printf("TRACE: Writing %d frames (frameCount=%d)\n", framesRemaining, frameCount);*/ resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pSrc, framesRemaining); if (resultALSA < 0) { if (resultALSA == -EAGAIN) { /*printf("TRACE: EGAIN (write)\n");*/ continue; /* Try again. */ } else if (resultALSA == -EPIPE) { /*printf("TRACE: EPIPE (write)\n");*/ /* Underrun. Recover and try again. If this fails we need to return an error. */ if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, resultALSA, MA_TRUE) < 0) { /* MA_TRUE=silent (don't print anything on error). */ return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.", MA_FAILED_TO_START_BACKEND_DEVICE); } /* In my testing I have had a situation where writei() does not automatically restart the device even though I've set it up as such in the software parameters. What will happen is writei() will block indefinitely even though the number of frames is well beyond the auto-start threshold. To work around this I've needed to add an explicit start here. Not sure if this is me just being stupid and not recovering the device properly, but this definitely feels like something isn't quite right here. */ if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", MA_FAILED_TO_START_BACKEND_DEVICE); } resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pSrc, framesRemaining); if (resultALSA < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to write data to device after underrun.", MA_FAILED_TO_START_BACKEND_DEVICE); } } } totalPCMFramesProcessed += resultALSA; } return MA_SUCCESS; } ma_result ma_device_read__alsa(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount) { ma_snd_pcm_sframes_t resultALSA; ma_uint32 totalPCMFramesProcessed; ma_assert(pDevice != NULL); ma_assert(pPCMFrames != NULL); /* We need to explicitly start the device if it isn't already. */ if (((ma_snd_pcm_state_proc)pDevice->pContext->alsa.snd_pcm_state)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) != MA_SND_PCM_STATE_RUNNING) { if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device in preparation for reading.", MA_FAILED_TO_START_BACKEND_DEVICE); } } totalPCMFramesProcessed = 0; while (totalPCMFramesProcessed < frameCount) { void* pDst = ma_offset_ptr(pPCMFrames, totalPCMFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed); /*printf("TRACE: snd_pcm_readi(framesRemaining=%d)\n", framesRemaining);*/ resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pDst, framesRemaining); if (resultALSA < 0) { if (resultALSA == -EAGAIN) { /*printf("TRACE: EGAIN (read)\n");*/ continue; } else if (resultALSA == -EPIPE) { /*printf("TRACE: EPIPE (read)\n");*/ /* Overrun. Recover and try again. If this fails we need to return an error. */ if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, resultALSA, MA_TRUE) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.", MA_FAILED_TO_START_BACKEND_DEVICE); } if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", MA_FAILED_TO_START_BACKEND_DEVICE); } resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pDst, framesRemaining); if (resultALSA < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to read data from the internal device.", MA_FAILED_TO_READ_DATA_FROM_DEVICE); } } } totalPCMFramesProcessed += resultALSA; } return MA_SUCCESS; } #if 0 ma_result ma_device_break_main_loop__alsa(ma_device* pDevice) { ma_assert(pDevice != NULL); pDevice->alsa.breakFromMainLoop = MA_TRUE; return MA_SUCCESS; } ma_result ma_device_main_loop__alsa(ma_device* pDevice) { ma_assert(pDevice != NULL); pDevice->alsa.breakFromMainLoop = MA_FALSE; if (pDevice->type == ma_device_type_playback) { /* Playback. Read from client, write to device. */ while (!pDevice->alsa.breakFromMainLoop && ma_device_read_from_client_and_write__alsa(pDevice)) { } } else { /* Capture. Read from device, write to client. */ while (!pDevice->alsa.breakFromMainLoop && ma_device_read_and_send_to_client__alsa(pDevice)) { } } return MA_SUCCESS; } #endif /* 0 */ ma_result ma_context_uninit__alsa(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_alsa); /* Clean up memory for memory leak checkers. */ ((ma_snd_config_update_free_global_proc)pContext->alsa.snd_config_update_free_global)(); #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->alsa.asoundSO); #endif ma_mutex_uninit(&pContext->alsa.internalDeviceEnumLock); return MA_SUCCESS; } ma_result ma_context_init__alsa(const ma_context_config* pConfig, ma_context* pContext) { #ifndef MA_NO_RUNTIME_LINKING const char* libasoundNames[] = { "libasound.so.2", "libasound.so" }; size_t i; for (i = 0; i < ma_countof(libasoundNames); ++i) { pContext->alsa.asoundSO = ma_dlopen(pContext, libasoundNames[i]); if (pContext->alsa.asoundSO != NULL) { break; } } if (pContext->alsa.asoundSO == NULL) { #ifdef MA_DEBUG_OUTPUT printf("[ALSA] Failed to open shared object.\n"); #endif return MA_NO_BACKEND; } pContext->alsa.snd_pcm_open = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_open"); pContext->alsa.snd_pcm_close = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_close"); pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof"); pContext->alsa.snd_pcm_hw_params_any = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_any"); pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format"); pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first"); pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask"); pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near"); pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample"); pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near"); pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near"); pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near"); pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access"); pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format"); pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels"); pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min"); pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max"); pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate"); pContext->alsa.snd_pcm_hw_params_get_rate_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min"); pContext->alsa.snd_pcm_hw_params_get_rate_max = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max"); pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size"); pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods"); pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access"); pContext->alsa.snd_pcm_hw_params = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params"); pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof"); pContext->alsa.snd_pcm_sw_params_current = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_current"); pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_get_boundary"); pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min"); pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold"); pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold"); pContext->alsa.snd_pcm_sw_params = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params"); pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof"); pContext->alsa.snd_pcm_format_mask_test = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_test"); pContext->alsa.snd_pcm_get_chmap = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_get_chmap"); pContext->alsa.snd_pcm_state = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_state"); pContext->alsa.snd_pcm_prepare = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_prepare"); pContext->alsa.snd_pcm_start = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_start"); pContext->alsa.snd_pcm_drop = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drop"); pContext->alsa.snd_pcm_drain = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drain"); pContext->alsa.snd_device_name_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_hint"); pContext->alsa.snd_device_name_get_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_get_hint"); pContext->alsa.snd_card_get_index = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_card_get_index"); pContext->alsa.snd_device_name_free_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_free_hint"); pContext->alsa.snd_pcm_mmap_begin = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_begin"); pContext->alsa.snd_pcm_mmap_commit = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_commit"); pContext->alsa.snd_pcm_recover = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_recover"); pContext->alsa.snd_pcm_readi = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_readi"); pContext->alsa.snd_pcm_writei = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_writei"); pContext->alsa.snd_pcm_avail = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail"); pContext->alsa.snd_pcm_avail_update = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail_update"); pContext->alsa.snd_pcm_wait = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_wait"); pContext->alsa.snd_pcm_info = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info"); pContext->alsa.snd_pcm_info_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_sizeof"); pContext->alsa.snd_pcm_info_get_name = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_get_name"); pContext->alsa.snd_config_update_free_global = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_config_update_free_global"); #else /* The system below is just for type safety. */ ma_snd_pcm_open_proc _snd_pcm_open = snd_pcm_open; ma_snd_pcm_close_proc _snd_pcm_close = snd_pcm_close; ma_snd_pcm_hw_params_sizeof_proc _snd_pcm_hw_params_sizeof = snd_pcm_hw_params_sizeof; ma_snd_pcm_hw_params_any_proc _snd_pcm_hw_params_any = snd_pcm_hw_params_any; ma_snd_pcm_hw_params_set_format_proc _snd_pcm_hw_params_set_format = snd_pcm_hw_params_set_format; ma_snd_pcm_hw_params_set_format_first_proc _snd_pcm_hw_params_set_format_first = snd_pcm_hw_params_set_format_first; ma_snd_pcm_hw_params_get_format_mask_proc _snd_pcm_hw_params_get_format_mask = snd_pcm_hw_params_get_format_mask; ma_snd_pcm_hw_params_set_channels_near_proc _snd_pcm_hw_params_set_channels_near = snd_pcm_hw_params_set_channels_near; ma_snd_pcm_hw_params_set_rate_resample_proc _snd_pcm_hw_params_set_rate_resample = snd_pcm_hw_params_set_rate_resample; ma_snd_pcm_hw_params_set_rate_near_proc _snd_pcm_hw_params_set_rate_near = snd_pcm_hw_params_set_rate_near; ma_snd_pcm_hw_params_set_buffer_size_near_proc _snd_pcm_hw_params_set_buffer_size_near = snd_pcm_hw_params_set_buffer_size_near; ma_snd_pcm_hw_params_set_periods_near_proc _snd_pcm_hw_params_set_periods_near = snd_pcm_hw_params_set_periods_near; ma_snd_pcm_hw_params_set_access_proc _snd_pcm_hw_params_set_access = snd_pcm_hw_params_set_access; ma_snd_pcm_hw_params_get_format_proc _snd_pcm_hw_params_get_format = snd_pcm_hw_params_get_format; ma_snd_pcm_hw_params_get_channels_proc _snd_pcm_hw_params_get_channels = snd_pcm_hw_params_get_channels; ma_snd_pcm_hw_params_get_channels_min_proc _snd_pcm_hw_params_get_channels_min = snd_pcm_hw_params_get_channels_min; ma_snd_pcm_hw_params_get_channels_max_proc _snd_pcm_hw_params_get_channels_max = snd_pcm_hw_params_get_channels_max; ma_snd_pcm_hw_params_get_rate_proc _snd_pcm_hw_params_get_rate = snd_pcm_hw_params_get_rate; ma_snd_pcm_hw_params_get_rate_min_proc _snd_pcm_hw_params_get_rate_min = snd_pcm_hw_params_get_rate_min; ma_snd_pcm_hw_params_get_rate_max_proc _snd_pcm_hw_params_get_rate_max = snd_pcm_hw_params_get_rate_max; ma_snd_pcm_hw_params_get_buffer_size_proc _snd_pcm_hw_params_get_buffer_size = snd_pcm_hw_params_get_buffer_size; ma_snd_pcm_hw_params_get_periods_proc _snd_pcm_hw_params_get_periods = snd_pcm_hw_params_get_periods; ma_snd_pcm_hw_params_get_access_proc _snd_pcm_hw_params_get_access = snd_pcm_hw_params_get_access; ma_snd_pcm_hw_params_proc _snd_pcm_hw_params = snd_pcm_hw_params; ma_snd_pcm_sw_params_sizeof_proc _snd_pcm_sw_params_sizeof = snd_pcm_sw_params_sizeof; ma_snd_pcm_sw_params_current_proc _snd_pcm_sw_params_current = snd_pcm_sw_params_current; ma_snd_pcm_sw_params_get_boundary_proc _snd_pcm_sw_params_get_boundary = snd_pcm_sw_params_get_boundary; ma_snd_pcm_sw_params_set_avail_min_proc _snd_pcm_sw_params_set_avail_min = snd_pcm_sw_params_set_avail_min; ma_snd_pcm_sw_params_set_start_threshold_proc _snd_pcm_sw_params_set_start_threshold = snd_pcm_sw_params_set_start_threshold; ma_snd_pcm_sw_params_set_stop_threshold_proc _snd_pcm_sw_params_set_stop_threshold = snd_pcm_sw_params_set_stop_threshold; ma_snd_pcm_sw_params_proc _snd_pcm_sw_params = snd_pcm_sw_params; ma_snd_pcm_format_mask_sizeof_proc _snd_pcm_format_mask_sizeof = snd_pcm_format_mask_sizeof; ma_snd_pcm_format_mask_test_proc _snd_pcm_format_mask_test = snd_pcm_format_mask_test; ma_snd_pcm_get_chmap_proc _snd_pcm_get_chmap = snd_pcm_get_chmap; ma_snd_pcm_state_proc _snd_pcm_state = snd_pcm_state; ma_snd_pcm_prepare_proc _snd_pcm_prepare = snd_pcm_prepare; ma_snd_pcm_start_proc _snd_pcm_start = snd_pcm_start; ma_snd_pcm_drop_proc _snd_pcm_drop = snd_pcm_drop; ma_snd_pcm_drain_proc _snd_pcm_drain = snd_pcm_drain; ma_snd_device_name_hint_proc _snd_device_name_hint = snd_device_name_hint; ma_snd_device_name_get_hint_proc _snd_device_name_get_hint = snd_device_name_get_hint; ma_snd_card_get_index_proc _snd_card_get_index = snd_card_get_index; ma_snd_device_name_free_hint_proc _snd_device_name_free_hint = snd_device_name_free_hint; ma_snd_pcm_mmap_begin_proc _snd_pcm_mmap_begin = snd_pcm_mmap_begin; ma_snd_pcm_mmap_commit_proc _snd_pcm_mmap_commit = snd_pcm_mmap_commit; ma_snd_pcm_recover_proc _snd_pcm_recover = snd_pcm_recover; ma_snd_pcm_readi_proc _snd_pcm_readi = snd_pcm_readi; ma_snd_pcm_writei_proc _snd_pcm_writei = snd_pcm_writei; ma_snd_pcm_avail_proc _snd_pcm_avail = snd_pcm_avail; ma_snd_pcm_avail_update_proc _snd_pcm_avail_update = snd_pcm_avail_update; ma_snd_pcm_wait_proc _snd_pcm_wait = snd_pcm_wait; ma_snd_pcm_info_proc _snd_pcm_info = snd_pcm_info; ma_snd_pcm_info_sizeof_proc _snd_pcm_info_sizeof = snd_pcm_info_sizeof; ma_snd_pcm_info_get_name_proc _snd_pcm_info_get_name = snd_pcm_info_get_name; ma_snd_config_update_free_global_proc _snd_config_update_free_global = snd_config_update_free_global; pContext->alsa.snd_pcm_open = (ma_proc)_snd_pcm_open; pContext->alsa.snd_pcm_close = (ma_proc)_snd_pcm_close; pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)_snd_pcm_hw_params_sizeof; pContext->alsa.snd_pcm_hw_params_any = (ma_proc)_snd_pcm_hw_params_any; pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)_snd_pcm_hw_params_set_format; pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)_snd_pcm_hw_params_set_format_first; pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)_snd_pcm_hw_params_get_format_mask; pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)_snd_pcm_hw_params_set_channels_near; pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)_snd_pcm_hw_params_set_rate_resample; pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)_snd_pcm_hw_params_set_rate_near; pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near; pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)_snd_pcm_hw_params_set_periods_near; pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)_snd_pcm_hw_params_set_access; pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)_snd_pcm_hw_params_get_format; pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)_snd_pcm_hw_params_get_channels; pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)_snd_pcm_hw_params_get_channels_min; pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)_snd_pcm_hw_params_get_channels_max; pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)_snd_pcm_hw_params_get_rate; pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)_snd_pcm_hw_params_get_buffer_size; pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)_snd_pcm_hw_params_get_periods; pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)_snd_pcm_hw_params_get_access; pContext->alsa.snd_pcm_hw_params = (ma_proc)_snd_pcm_hw_params; pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)_snd_pcm_sw_params_sizeof; pContext->alsa.snd_pcm_sw_params_current = (ma_proc)_snd_pcm_sw_params_current; pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)_snd_pcm_sw_params_get_boundary; pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)_snd_pcm_sw_params_set_avail_min; pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)_snd_pcm_sw_params_set_start_threshold; pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)_snd_pcm_sw_params_set_stop_threshold; pContext->alsa.snd_pcm_sw_params = (ma_proc)_snd_pcm_sw_params; pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)_snd_pcm_format_mask_sizeof; pContext->alsa.snd_pcm_format_mask_test = (ma_proc)_snd_pcm_format_mask_test; pContext->alsa.snd_pcm_get_chmap = (ma_proc)_snd_pcm_get_chmap; pContext->alsa.snd_pcm_state = (ma_proc)_snd_pcm_state; pContext->alsa.snd_pcm_prepare = (ma_proc)_snd_pcm_prepare; pContext->alsa.snd_pcm_start = (ma_proc)_snd_pcm_start; pContext->alsa.snd_pcm_drop = (ma_proc)_snd_pcm_drop; pContext->alsa.snd_pcm_drain = (ma_proc)_snd_pcm_drain; pContext->alsa.snd_device_name_hint = (ma_proc)_snd_device_name_hint; pContext->alsa.snd_device_name_get_hint = (ma_proc)_snd_device_name_get_hint; pContext->alsa.snd_card_get_index = (ma_proc)_snd_card_get_index; pContext->alsa.snd_device_name_free_hint = (ma_proc)_snd_device_name_free_hint; pContext->alsa.snd_pcm_mmap_begin = (ma_proc)_snd_pcm_mmap_begin; pContext->alsa.snd_pcm_mmap_commit = (ma_proc)_snd_pcm_mmap_commit; pContext->alsa.snd_pcm_recover = (ma_proc)_snd_pcm_recover; pContext->alsa.snd_pcm_readi = (ma_proc)_snd_pcm_readi; pContext->alsa.snd_pcm_writei = (ma_proc)_snd_pcm_writei; pContext->alsa.snd_pcm_avail = (ma_proc)_snd_pcm_avail; pContext->alsa.snd_pcm_avail_update = (ma_proc)_snd_pcm_avail_update; pContext->alsa.snd_pcm_wait = (ma_proc)_snd_pcm_wait; pContext->alsa.snd_pcm_info = (ma_proc)_snd_pcm_info; pContext->alsa.snd_pcm_info_sizeof = (ma_proc)_snd_pcm_info_sizeof; pContext->alsa.snd_pcm_info_get_name = (ma_proc)_snd_pcm_info_get_name; pContext->alsa.snd_config_update_free_global = (ma_proc)_snd_config_update_free_global; #endif pContext->alsa.useVerboseDeviceEnumeration = pConfig->alsa.useVerboseDeviceEnumeration; if (ma_mutex_init(pContext, &pContext->alsa.internalDeviceEnumLock) != MA_SUCCESS) { ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration.", MA_ERROR); } pContext->onUninit = ma_context_uninit__alsa; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__alsa; pContext->onEnumDevices = ma_context_enumerate_devices__alsa; pContext->onGetDeviceInfo = ma_context_get_device_info__alsa; pContext->onDeviceInit = ma_device_init__alsa; pContext->onDeviceUninit = ma_device_uninit__alsa; pContext->onDeviceStart = NULL; /*ma_device_start__alsa;*/ pContext->onDeviceStop = ma_device_stop__alsa; pContext->onDeviceWrite = ma_device_write__alsa; pContext->onDeviceRead = ma_device_read__alsa; return MA_SUCCESS; } #endif /* ALSA */ /****************************************************************************** PulseAudio Backend ******************************************************************************/ #ifdef MA_HAS_PULSEAUDIO /* It is assumed pulseaudio.h is available when compile-time linking is being used. We use this for type safety when using compile time linking (we don't have this luxury when using runtime linking without headers). When using compile time linking, each of our ma_* equivalents should use the sames types as defined by the header. The reason for this is that it allow us to take advantage of proper type safety. */ #ifdef MA_NO_RUNTIME_LINKING #include #define MA_PA_OK PA_OK #define MA_PA_ERR_ACCESS PA_ERR_ACCESS #define MA_PA_ERR_INVALID PA_ERR_INVALID #define MA_PA_ERR_NOENTITY PA_ERR_NOENTITY #define MA_PA_CHANNELS_MAX PA_CHANNELS_MAX #define MA_PA_RATE_MAX PA_RATE_MAX typedef pa_context_flags_t ma_pa_context_flags_t; #define MA_PA_CONTEXT_NOFLAGS PA_CONTEXT_NOFLAGS #define MA_PA_CONTEXT_NOAUTOSPAWN PA_CONTEXT_NOAUTOSPAWN #define MA_PA_CONTEXT_NOFAIL PA_CONTEXT_NOFAIL typedef pa_stream_flags_t ma_pa_stream_flags_t; #define MA_PA_STREAM_NOFLAGS PA_STREAM_NOFLAGS #define MA_PA_STREAM_START_CORKED PA_STREAM_START_CORKED #define MA_PA_STREAM_INTERPOLATE_TIMING PA_STREAM_INTERPOLATE_TIMING #define MA_PA_STREAM_NOT_MONOTONIC PA_STREAM_NOT_MONOTONIC #define MA_PA_STREAM_AUTO_TIMING_UPDATE PA_STREAM_AUTO_TIMING_UPDATE #define MA_PA_STREAM_NO_REMAP_CHANNELS PA_STREAM_NO_REMAP_CHANNELS #define MA_PA_STREAM_NO_REMIX_CHANNELS PA_STREAM_NO_REMIX_CHANNELS #define MA_PA_STREAM_FIX_FORMAT PA_STREAM_FIX_FORMAT #define MA_PA_STREAM_FIX_RATE PA_STREAM_FIX_RATE #define MA_PA_STREAM_FIX_CHANNELS PA_STREAM_FIX_CHANNELS #define MA_PA_STREAM_DONT_MOVE PA_STREAM_DONT_MOVE #define MA_PA_STREAM_VARIABLE_RATE PA_STREAM_VARIABLE_RATE #define MA_PA_STREAM_PEAK_DETECT PA_STREAM_PEAK_DETECT #define MA_PA_STREAM_START_MUTED PA_STREAM_START_MUTED #define MA_PA_STREAM_ADJUST_LATENCY PA_STREAM_ADJUST_LATENCY #define MA_PA_STREAM_EARLY_REQUESTS PA_STREAM_EARLY_REQUESTS #define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND #define MA_PA_STREAM_START_UNMUTED PA_STREAM_START_UNMUTED #define MA_PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND #define MA_PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME #define MA_PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH typedef pa_sink_flags_t ma_pa_sink_flags_t; #define MA_PA_SINK_NOFLAGS PA_SINK_NOFLAGS #define MA_PA_SINK_HW_VOLUME_CTRL PA_SINK_HW_VOLUME_CTRL #define MA_PA_SINK_LATENCY PA_SINK_LATENCY #define MA_PA_SINK_HARDWARE PA_SINK_HARDWARE #define MA_PA_SINK_NETWORK PA_SINK_NETWORK #define MA_PA_SINK_HW_MUTE_CTRL PA_SINK_HW_MUTE_CTRL #define MA_PA_SINK_DECIBEL_VOLUME PA_SINK_DECIBEL_VOLUME #define MA_PA_SINK_FLAT_VOLUME PA_SINK_FLAT_VOLUME #define MA_PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY #define MA_PA_SINK_SET_FORMATS PA_SINK_SET_FORMATS typedef pa_source_flags_t ma_pa_source_flags_t; #define MA_PA_SOURCE_NOFLAGS PA_SOURCE_NOFLAGS #define MA_PA_SOURCE_HW_VOLUME_CTRL PA_SOURCE_HW_VOLUME_CTRL #define MA_PA_SOURCE_LATENCY PA_SOURCE_LATENCY #define MA_PA_SOURCE_HARDWARE PA_SOURCE_HARDWARE #define MA_PA_SOURCE_NETWORK PA_SOURCE_NETWORK #define MA_PA_SOURCE_HW_MUTE_CTRL PA_SOURCE_HW_MUTE_CTRL #define MA_PA_SOURCE_DECIBEL_VOLUME PA_SOURCE_DECIBEL_VOLUME #define MA_PA_SOURCE_DYNAMIC_LATENCY PA_SOURCE_DYNAMIC_LATENCY #define MA_PA_SOURCE_FLAT_VOLUME PA_SOURCE_FLAT_VOLUME typedef pa_context_state_t ma_pa_context_state_t; #define MA_PA_CONTEXT_UNCONNECTED PA_CONTEXT_UNCONNECTED #define MA_PA_CONTEXT_CONNECTING PA_CONTEXT_CONNECTING #define MA_PA_CONTEXT_AUTHORIZING PA_CONTEXT_AUTHORIZING #define MA_PA_CONTEXT_SETTING_NAME PA_CONTEXT_SETTING_NAME #define MA_PA_CONTEXT_READY PA_CONTEXT_READY #define MA_PA_CONTEXT_FAILED PA_CONTEXT_FAILED #define MA_PA_CONTEXT_TERMINATED PA_CONTEXT_TERMINATED typedef pa_stream_state_t ma_pa_stream_state_t; #define MA_PA_STREAM_UNCONNECTED PA_STREAM_UNCONNECTED #define MA_PA_STREAM_CREATING PA_STREAM_CREATING #define MA_PA_STREAM_READY PA_STREAM_READY #define MA_PA_STREAM_FAILED PA_STREAM_FAILED #define MA_PA_STREAM_TERMINATED PA_STREAM_TERMINATED typedef pa_operation_state_t ma_pa_operation_state_t; #define MA_PA_OPERATION_RUNNING PA_OPERATION_RUNNING #define MA_PA_OPERATION_DONE PA_OPERATION_DONE #define MA_PA_OPERATION_CANCELLED PA_OPERATION_CANCELLED typedef pa_sink_state_t ma_pa_sink_state_t; #define MA_PA_SINK_INVALID_STATE PA_SINK_INVALID_STATE #define MA_PA_SINK_RUNNING PA_SINK_RUNNING #define MA_PA_SINK_IDLE PA_SINK_IDLE #define MA_PA_SINK_SUSPENDED PA_SINK_SUSPENDED typedef pa_source_state_t ma_pa_source_state_t; #define MA_PA_SOURCE_INVALID_STATE PA_SOURCE_INVALID_STATE #define MA_PA_SOURCE_RUNNING PA_SOURCE_RUNNING #define MA_PA_SOURCE_IDLE PA_SOURCE_IDLE #define MA_PA_SOURCE_SUSPENDED PA_SOURCE_SUSPENDED typedef pa_seek_mode_t ma_pa_seek_mode_t; #define MA_PA_SEEK_RELATIVE PA_SEEK_RELATIVE #define MA_PA_SEEK_ABSOLUTE PA_SEEK_ABSOLUTE #define MA_PA_SEEK_RELATIVE_ON_READ PA_SEEK_RELATIVE_ON_READ #define MA_PA_SEEK_RELATIVE_END PA_SEEK_RELATIVE_END typedef pa_channel_position_t ma_pa_channel_position_t; #define MA_PA_CHANNEL_POSITION_INVALID PA_CHANNEL_POSITION_INVALID #define MA_PA_CHANNEL_POSITION_MONO PA_CHANNEL_POSITION_MONO #define MA_PA_CHANNEL_POSITION_FRONT_LEFT PA_CHANNEL_POSITION_FRONT_LEFT #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT PA_CHANNEL_POSITION_FRONT_RIGHT #define MA_PA_CHANNEL_POSITION_FRONT_CENTER PA_CHANNEL_POSITION_FRONT_CENTER #define MA_PA_CHANNEL_POSITION_REAR_CENTER PA_CHANNEL_POSITION_REAR_CENTER #define MA_PA_CHANNEL_POSITION_REAR_LEFT PA_CHANNEL_POSITION_REAR_LEFT #define MA_PA_CHANNEL_POSITION_REAR_RIGHT PA_CHANNEL_POSITION_REAR_RIGHT #define MA_PA_CHANNEL_POSITION_LFE PA_CHANNEL_POSITION_LFE #define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER #define MA_PA_CHANNEL_POSITION_SIDE_LEFT PA_CHANNEL_POSITION_SIDE_LEFT #define MA_PA_CHANNEL_POSITION_SIDE_RIGHT PA_CHANNEL_POSITION_SIDE_RIGHT #define MA_PA_CHANNEL_POSITION_AUX0 PA_CHANNEL_POSITION_AUX0 #define MA_PA_CHANNEL_POSITION_AUX1 PA_CHANNEL_POSITION_AUX1 #define MA_PA_CHANNEL_POSITION_AUX2 PA_CHANNEL_POSITION_AUX2 #define MA_PA_CHANNEL_POSITION_AUX3 PA_CHANNEL_POSITION_AUX3 #define MA_PA_CHANNEL_POSITION_AUX4 PA_CHANNEL_POSITION_AUX4 #define MA_PA_CHANNEL_POSITION_AUX5 PA_CHANNEL_POSITION_AUX5 #define MA_PA_CHANNEL_POSITION_AUX6 PA_CHANNEL_POSITION_AUX6 #define MA_PA_CHANNEL_POSITION_AUX7 PA_CHANNEL_POSITION_AUX7 #define MA_PA_CHANNEL_POSITION_AUX8 PA_CHANNEL_POSITION_AUX8 #define MA_PA_CHANNEL_POSITION_AUX9 PA_CHANNEL_POSITION_AUX9 #define MA_PA_CHANNEL_POSITION_AUX10 PA_CHANNEL_POSITION_AUX10 #define MA_PA_CHANNEL_POSITION_AUX11 PA_CHANNEL_POSITION_AUX11 #define MA_PA_CHANNEL_POSITION_AUX12 PA_CHANNEL_POSITION_AUX12 #define MA_PA_CHANNEL_POSITION_AUX13 PA_CHANNEL_POSITION_AUX13 #define MA_PA_CHANNEL_POSITION_AUX14 PA_CHANNEL_POSITION_AUX14 #define MA_PA_CHANNEL_POSITION_AUX15 PA_CHANNEL_POSITION_AUX15 #define MA_PA_CHANNEL_POSITION_AUX16 PA_CHANNEL_POSITION_AUX16 #define MA_PA_CHANNEL_POSITION_AUX17 PA_CHANNEL_POSITION_AUX17 #define MA_PA_CHANNEL_POSITION_AUX18 PA_CHANNEL_POSITION_AUX18 #define MA_PA_CHANNEL_POSITION_AUX19 PA_CHANNEL_POSITION_AUX19 #define MA_PA_CHANNEL_POSITION_AUX20 PA_CHANNEL_POSITION_AUX20 #define MA_PA_CHANNEL_POSITION_AUX21 PA_CHANNEL_POSITION_AUX21 #define MA_PA_CHANNEL_POSITION_AUX22 PA_CHANNEL_POSITION_AUX22 #define MA_PA_CHANNEL_POSITION_AUX23 PA_CHANNEL_POSITION_AUX23 #define MA_PA_CHANNEL_POSITION_AUX24 PA_CHANNEL_POSITION_AUX24 #define MA_PA_CHANNEL_POSITION_AUX25 PA_CHANNEL_POSITION_AUX25 #define MA_PA_CHANNEL_POSITION_AUX26 PA_CHANNEL_POSITION_AUX26 #define MA_PA_CHANNEL_POSITION_AUX27 PA_CHANNEL_POSITION_AUX27 #define MA_PA_CHANNEL_POSITION_AUX28 PA_CHANNEL_POSITION_AUX28 #define MA_PA_CHANNEL_POSITION_AUX29 PA_CHANNEL_POSITION_AUX29 #define MA_PA_CHANNEL_POSITION_AUX30 PA_CHANNEL_POSITION_AUX30 #define MA_PA_CHANNEL_POSITION_AUX31 PA_CHANNEL_POSITION_AUX31 #define MA_PA_CHANNEL_POSITION_TOP_CENTER PA_CHANNEL_POSITION_TOP_CENTER #define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT PA_CHANNEL_POSITION_TOP_FRONT_LEFT #define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT PA_CHANNEL_POSITION_TOP_FRONT_RIGHT #define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER PA_CHANNEL_POSITION_TOP_FRONT_CENTER #define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT PA_CHANNEL_POSITION_TOP_REAR_LEFT #define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT PA_CHANNEL_POSITION_TOP_REAR_RIGHT #define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER PA_CHANNEL_POSITION_TOP_REAR_CENTER #define MA_PA_CHANNEL_POSITION_LEFT PA_CHANNEL_POSITION_LEFT #define MA_PA_CHANNEL_POSITION_RIGHT PA_CHANNEL_POSITION_RIGHT #define MA_PA_CHANNEL_POSITION_CENTER PA_CHANNEL_POSITION_CENTER #define MA_PA_CHANNEL_POSITION_SUBWOOFER PA_CHANNEL_POSITION_SUBWOOFER typedef pa_channel_map_def_t ma_pa_channel_map_def_t; #define MA_PA_CHANNEL_MAP_AIFF PA_CHANNEL_MAP_AIFF #define MA_PA_CHANNEL_MAP_ALSA PA_CHANNEL_MAP_ALSA #define MA_PA_CHANNEL_MAP_AUX PA_CHANNEL_MAP_AUX #define MA_PA_CHANNEL_MAP_WAVEEX PA_CHANNEL_MAP_WAVEEX #define MA_PA_CHANNEL_MAP_OSS PA_CHANNEL_MAP_OSS #define MA_PA_CHANNEL_MAP_DEFAULT PA_CHANNEL_MAP_DEFAULT typedef pa_sample_format_t ma_pa_sample_format_t; #define MA_PA_SAMPLE_INVALID PA_SAMPLE_INVALID #define MA_PA_SAMPLE_U8 PA_SAMPLE_U8 #define MA_PA_SAMPLE_ALAW PA_SAMPLE_ALAW #define MA_PA_SAMPLE_ULAW PA_SAMPLE_ULAW #define MA_PA_SAMPLE_S16LE PA_SAMPLE_S16LE #define MA_PA_SAMPLE_S16BE PA_SAMPLE_S16BE #define MA_PA_SAMPLE_FLOAT32LE PA_SAMPLE_FLOAT32LE #define MA_PA_SAMPLE_FLOAT32BE PA_SAMPLE_FLOAT32BE #define MA_PA_SAMPLE_S32LE PA_SAMPLE_S32LE #define MA_PA_SAMPLE_S32BE PA_SAMPLE_S32BE #define MA_PA_SAMPLE_S24LE PA_SAMPLE_S24LE #define MA_PA_SAMPLE_S24BE PA_SAMPLE_S24BE #define MA_PA_SAMPLE_S24_32LE PA_SAMPLE_S24_32LE #define MA_PA_SAMPLE_S24_32BE PA_SAMPLE_S24_32BE typedef pa_mainloop ma_pa_mainloop; typedef pa_mainloop_api ma_pa_mainloop_api; typedef pa_context ma_pa_context; typedef pa_operation ma_pa_operation; typedef pa_stream ma_pa_stream; typedef pa_spawn_api ma_pa_spawn_api; typedef pa_buffer_attr ma_pa_buffer_attr; typedef pa_channel_map ma_pa_channel_map; typedef pa_cvolume ma_pa_cvolume; typedef pa_sample_spec ma_pa_sample_spec; typedef pa_sink_info ma_pa_sink_info; typedef pa_source_info ma_pa_source_info; typedef pa_context_notify_cb_t ma_pa_context_notify_cb_t; typedef pa_sink_info_cb_t ma_pa_sink_info_cb_t; typedef pa_source_info_cb_t ma_pa_source_info_cb_t; typedef pa_stream_success_cb_t ma_pa_stream_success_cb_t; typedef pa_stream_request_cb_t ma_pa_stream_request_cb_t; typedef pa_free_cb_t ma_pa_free_cb_t; #else #define MA_PA_OK 0 #define MA_PA_ERR_ACCESS 1 #define MA_PA_ERR_INVALID 2 #define MA_PA_ERR_NOENTITY 5 #define MA_PA_CHANNELS_MAX 32 #define MA_PA_RATE_MAX 384000 typedef int ma_pa_context_flags_t; #define MA_PA_CONTEXT_NOFLAGS 0x00000000 #define MA_PA_CONTEXT_NOAUTOSPAWN 0x00000001 #define MA_PA_CONTEXT_NOFAIL 0x00000002 typedef int ma_pa_stream_flags_t; #define MA_PA_STREAM_NOFLAGS 0x00000000 #define MA_PA_STREAM_START_CORKED 0x00000001 #define MA_PA_STREAM_INTERPOLATE_TIMING 0x00000002 #define MA_PA_STREAM_NOT_MONOTONIC 0x00000004 #define MA_PA_STREAM_AUTO_TIMING_UPDATE 0x00000008 #define MA_PA_STREAM_NO_REMAP_CHANNELS 0x00000010 #define MA_PA_STREAM_NO_REMIX_CHANNELS 0x00000020 #define MA_PA_STREAM_FIX_FORMAT 0x00000040 #define MA_PA_STREAM_FIX_RATE 0x00000080 #define MA_PA_STREAM_FIX_CHANNELS 0x00000100 #define MA_PA_STREAM_DONT_MOVE 0x00000200 #define MA_PA_STREAM_VARIABLE_RATE 0x00000400 #define MA_PA_STREAM_PEAK_DETECT 0x00000800 #define MA_PA_STREAM_START_MUTED 0x00001000 #define MA_PA_STREAM_ADJUST_LATENCY 0x00002000 #define MA_PA_STREAM_EARLY_REQUESTS 0x00004000 #define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND 0x00008000 #define MA_PA_STREAM_START_UNMUTED 0x00010000 #define MA_PA_STREAM_FAIL_ON_SUSPEND 0x00020000 #define MA_PA_STREAM_RELATIVE_VOLUME 0x00040000 #define MA_PA_STREAM_PASSTHROUGH 0x00080000 typedef int ma_pa_sink_flags_t; #define MA_PA_SINK_NOFLAGS 0x00000000 #define MA_PA_SINK_HW_VOLUME_CTRL 0x00000001 #define MA_PA_SINK_LATENCY 0x00000002 #define MA_PA_SINK_HARDWARE 0x00000004 #define MA_PA_SINK_NETWORK 0x00000008 #define MA_PA_SINK_HW_MUTE_CTRL 0x00000010 #define MA_PA_SINK_DECIBEL_VOLUME 0x00000020 #define MA_PA_SINK_FLAT_VOLUME 0x00000040 #define MA_PA_SINK_DYNAMIC_LATENCY 0x00000080 #define MA_PA_SINK_SET_FORMATS 0x00000100 typedef int ma_pa_source_flags_t; #define MA_PA_SOURCE_NOFLAGS 0x00000000 #define MA_PA_SOURCE_HW_VOLUME_CTRL 0x00000001 #define MA_PA_SOURCE_LATENCY 0x00000002 #define MA_PA_SOURCE_HARDWARE 0x00000004 #define MA_PA_SOURCE_NETWORK 0x00000008 #define MA_PA_SOURCE_HW_MUTE_CTRL 0x00000010 #define MA_PA_SOURCE_DECIBEL_VOLUME 0x00000020 #define MA_PA_SOURCE_DYNAMIC_LATENCY 0x00000040 #define MA_PA_SOURCE_FLAT_VOLUME 0x00000080 typedef int ma_pa_context_state_t; #define MA_PA_CONTEXT_UNCONNECTED 0 #define MA_PA_CONTEXT_CONNECTING 1 #define MA_PA_CONTEXT_AUTHORIZING 2 #define MA_PA_CONTEXT_SETTING_NAME 3 #define MA_PA_CONTEXT_READY 4 #define MA_PA_CONTEXT_FAILED 5 #define MA_PA_CONTEXT_TERMINATED 6 typedef int ma_pa_stream_state_t; #define MA_PA_STREAM_UNCONNECTED 0 #define MA_PA_STREAM_CREATING 1 #define MA_PA_STREAM_READY 2 #define MA_PA_STREAM_FAILED 3 #define MA_PA_STREAM_TERMINATED 4 typedef int ma_pa_operation_state_t; #define MA_PA_OPERATION_RUNNING 0 #define MA_PA_OPERATION_DONE 1 #define MA_PA_OPERATION_CANCELLED 2 typedef int ma_pa_sink_state_t; #define MA_PA_SINK_INVALID_STATE -1 #define MA_PA_SINK_RUNNING 0 #define MA_PA_SINK_IDLE 1 #define MA_PA_SINK_SUSPENDED 2 typedef int ma_pa_source_state_t; #define MA_PA_SOURCE_INVALID_STATE -1 #define MA_PA_SOURCE_RUNNING 0 #define MA_PA_SOURCE_IDLE 1 #define MA_PA_SOURCE_SUSPENDED 2 typedef int ma_pa_seek_mode_t; #define MA_PA_SEEK_RELATIVE 0 #define MA_PA_SEEK_ABSOLUTE 1 #define MA_PA_SEEK_RELATIVE_ON_READ 2 #define MA_PA_SEEK_RELATIVE_END 3 typedef int ma_pa_channel_position_t; #define MA_PA_CHANNEL_POSITION_INVALID -1 #define MA_PA_CHANNEL_POSITION_MONO 0 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT 1 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT 2 #define MA_PA_CHANNEL_POSITION_FRONT_CENTER 3 #define MA_PA_CHANNEL_POSITION_REAR_CENTER 4 #define MA_PA_CHANNEL_POSITION_REAR_LEFT 5 #define MA_PA_CHANNEL_POSITION_REAR_RIGHT 6 #define MA_PA_CHANNEL_POSITION_LFE 7 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER 8 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER 9 #define MA_PA_CHANNEL_POSITION_SIDE_LEFT 10 #define MA_PA_CHANNEL_POSITION_SIDE_RIGHT 11 #define MA_PA_CHANNEL_POSITION_AUX0 12 #define MA_PA_CHANNEL_POSITION_AUX1 13 #define MA_PA_CHANNEL_POSITION_AUX2 14 #define MA_PA_CHANNEL_POSITION_AUX3 15 #define MA_PA_CHANNEL_POSITION_AUX4 16 #define MA_PA_CHANNEL_POSITION_AUX5 17 #define MA_PA_CHANNEL_POSITION_AUX6 18 #define MA_PA_CHANNEL_POSITION_AUX7 19 #define MA_PA_CHANNEL_POSITION_AUX8 20 #define MA_PA_CHANNEL_POSITION_AUX9 21 #define MA_PA_CHANNEL_POSITION_AUX10 22 #define MA_PA_CHANNEL_POSITION_AUX11 23 #define MA_PA_CHANNEL_POSITION_AUX12 24 #define MA_PA_CHANNEL_POSITION_AUX13 25 #define MA_PA_CHANNEL_POSITION_AUX14 26 #define MA_PA_CHANNEL_POSITION_AUX15 27 #define MA_PA_CHANNEL_POSITION_AUX16 28 #define MA_PA_CHANNEL_POSITION_AUX17 29 #define MA_PA_CHANNEL_POSITION_AUX18 30 #define MA_PA_CHANNEL_POSITION_AUX19 31 #define MA_PA_CHANNEL_POSITION_AUX20 32 #define MA_PA_CHANNEL_POSITION_AUX21 33 #define MA_PA_CHANNEL_POSITION_AUX22 34 #define MA_PA_CHANNEL_POSITION_AUX23 35 #define MA_PA_CHANNEL_POSITION_AUX24 36 #define MA_PA_CHANNEL_POSITION_AUX25 37 #define MA_PA_CHANNEL_POSITION_AUX26 38 #define MA_PA_CHANNEL_POSITION_AUX27 39 #define MA_PA_CHANNEL_POSITION_AUX28 40 #define MA_PA_CHANNEL_POSITION_AUX29 41 #define MA_PA_CHANNEL_POSITION_AUX30 42 #define MA_PA_CHANNEL_POSITION_AUX31 43 #define MA_PA_CHANNEL_POSITION_TOP_CENTER 44 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT 45 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT 46 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER 47 #define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT 48 #define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT 49 #define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER 50 #define MA_PA_CHANNEL_POSITION_LEFT MA_PA_CHANNEL_POSITION_FRONT_LEFT #define MA_PA_CHANNEL_POSITION_RIGHT MA_PA_CHANNEL_POSITION_FRONT_RIGHT #define MA_PA_CHANNEL_POSITION_CENTER MA_PA_CHANNEL_POSITION_FRONT_CENTER #define MA_PA_CHANNEL_POSITION_SUBWOOFER MA_PA_CHANNEL_POSITION_LFE typedef int ma_pa_channel_map_def_t; #define MA_PA_CHANNEL_MAP_AIFF 0 #define MA_PA_CHANNEL_MAP_ALSA 1 #define MA_PA_CHANNEL_MAP_AUX 2 #define MA_PA_CHANNEL_MAP_WAVEEX 3 #define MA_PA_CHANNEL_MAP_OSS 4 #define MA_PA_CHANNEL_MAP_DEFAULT MA_PA_CHANNEL_MAP_AIFF typedef int ma_pa_sample_format_t; #define MA_PA_SAMPLE_INVALID -1 #define MA_PA_SAMPLE_U8 0 #define MA_PA_SAMPLE_ALAW 1 #define MA_PA_SAMPLE_ULAW 2 #define MA_PA_SAMPLE_S16LE 3 #define MA_PA_SAMPLE_S16BE 4 #define MA_PA_SAMPLE_FLOAT32LE 5 #define MA_PA_SAMPLE_FLOAT32BE 6 #define MA_PA_SAMPLE_S32LE 7 #define MA_PA_SAMPLE_S32BE 8 #define MA_PA_SAMPLE_S24LE 9 #define MA_PA_SAMPLE_S24BE 10 #define MA_PA_SAMPLE_S24_32LE 11 #define MA_PA_SAMPLE_S24_32BE 12 typedef struct ma_pa_mainloop ma_pa_mainloop; typedef struct ma_pa_mainloop_api ma_pa_mainloop_api; typedef struct ma_pa_context ma_pa_context; typedef struct ma_pa_operation ma_pa_operation; typedef struct ma_pa_stream ma_pa_stream; typedef struct ma_pa_spawn_api ma_pa_spawn_api; typedef struct { ma_uint32 maxlength; ma_uint32 tlength; ma_uint32 prebuf; ma_uint32 minreq; ma_uint32 fragsize; } ma_pa_buffer_attr; typedef struct { ma_uint8 channels; ma_pa_channel_position_t map[MA_PA_CHANNELS_MAX]; } ma_pa_channel_map; typedef struct { ma_uint8 channels; ma_uint32 values[MA_PA_CHANNELS_MAX]; } ma_pa_cvolume; typedef struct { ma_pa_sample_format_t format; ma_uint32 rate; ma_uint8 channels; } ma_pa_sample_spec; typedef struct { const char* name; ma_uint32 index; const char* description; ma_pa_sample_spec sample_spec; ma_pa_channel_map channel_map; ma_uint32 owner_module; ma_pa_cvolume volume; int mute; ma_uint32 monitor_source; const char* monitor_source_name; ma_uint64 latency; const char* driver; ma_pa_sink_flags_t flags; void* proplist; ma_uint64 configured_latency; ma_uint32 base_volume; ma_pa_sink_state_t state; ma_uint32 n_volume_steps; ma_uint32 card; ma_uint32 n_ports; void** ports; void* active_port; ma_uint8 n_formats; void** formats; } ma_pa_sink_info; typedef struct { const char *name; ma_uint32 index; const char *description; ma_pa_sample_spec sample_spec; ma_pa_channel_map channel_map; ma_uint32 owner_module; ma_pa_cvolume volume; int mute; ma_uint32 monitor_of_sink; const char *monitor_of_sink_name; ma_uint64 latency; const char *driver; ma_pa_source_flags_t flags; void* proplist; ma_uint64 configured_latency; ma_uint32 base_volume; ma_pa_source_state_t state; ma_uint32 n_volume_steps; ma_uint32 card; ma_uint32 n_ports; void** ports; void* active_port; ma_uint8 n_formats; void** formats; } ma_pa_source_info; typedef void (* ma_pa_context_notify_cb_t)(ma_pa_context* c, void* userdata); typedef void (* ma_pa_sink_info_cb_t) (ma_pa_context* c, const ma_pa_sink_info* i, int eol, void* userdata); typedef void (* ma_pa_source_info_cb_t) (ma_pa_context* c, const ma_pa_source_info* i, int eol, void* userdata); typedef void (* ma_pa_stream_success_cb_t)(ma_pa_stream* s, int success, void* userdata); typedef void (* ma_pa_stream_request_cb_t)(ma_pa_stream* s, size_t nbytes, void* userdata); typedef void (* ma_pa_free_cb_t) (void* p); #endif typedef ma_pa_mainloop* (* ma_pa_mainloop_new_proc) (); typedef void (* ma_pa_mainloop_free_proc) (ma_pa_mainloop* m); typedef ma_pa_mainloop_api* (* ma_pa_mainloop_get_api_proc) (ma_pa_mainloop* m); typedef int (* ma_pa_mainloop_iterate_proc) (ma_pa_mainloop* m, int block, int* retval); typedef void (* ma_pa_mainloop_wakeup_proc) (ma_pa_mainloop* m); typedef ma_pa_context* (* ma_pa_context_new_proc) (ma_pa_mainloop_api* mainloop, const char* name); typedef void (* ma_pa_context_unref_proc) (ma_pa_context* c); typedef int (* ma_pa_context_connect_proc) (ma_pa_context* c, const char* server, ma_pa_context_flags_t flags, const ma_pa_spawn_api* api); typedef void (* ma_pa_context_disconnect_proc) (ma_pa_context* c); typedef void (* ma_pa_context_set_state_callback_proc) (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata); typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (ma_pa_context* c); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_list_proc) (ma_pa_context* c, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_list_proc) (ma_pa_context* c, ma_pa_source_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context* c, const char* name, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_by_name_proc)(ma_pa_context* c, const char* name, ma_pa_source_info_cb_t cb, void* userdata); typedef void (* ma_pa_operation_unref_proc) (ma_pa_operation* o); typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (ma_pa_operation* o); typedef ma_pa_channel_map* (* ma_pa_channel_map_init_extend_proc) (ma_pa_channel_map* m, unsigned channels, ma_pa_channel_map_def_t def); typedef int (* ma_pa_channel_map_valid_proc) (const ma_pa_channel_map* m); typedef int (* ma_pa_channel_map_compatible_proc) (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss); typedef ma_pa_stream* (* ma_pa_stream_new_proc) (ma_pa_context* c, const char* name, const ma_pa_sample_spec* ss, const ma_pa_channel_map* map); typedef void (* ma_pa_stream_unref_proc) (ma_pa_stream* s); typedef int (* ma_pa_stream_connect_playback_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags, const ma_pa_cvolume* volume, ma_pa_stream* sync_stream); typedef int (* ma_pa_stream_connect_record_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags); typedef int (* ma_pa_stream_disconnect_proc) (ma_pa_stream* s); typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (ma_pa_stream* s); typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc) (ma_pa_stream* s); typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc) (ma_pa_stream* s); typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc) (ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) (ma_pa_stream* s, const ma_pa_buffer_attr* attr, ma_pa_stream_success_cb_t cb, void* userdata); typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s); typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_cork_proc) (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_trigger_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_begin_write_proc) (ma_pa_stream* s, void** data, size_t* nbytes); typedef int (* ma_pa_stream_write_proc) (ma_pa_stream* s, const void* data, size_t nbytes, ma_pa_free_cb_t free_cb, int64_t offset, ma_pa_seek_mode_t seek); typedef int (* ma_pa_stream_peek_proc) (ma_pa_stream* s, const void** data, size_t* nbytes); typedef int (* ma_pa_stream_drop_proc) (ma_pa_stream* s); typedef size_t (* ma_pa_stream_writable_size_proc) (ma_pa_stream* s); typedef size_t (* ma_pa_stream_readable_size_proc) (ma_pa_stream* s); typedef struct { ma_uint32 count; ma_uint32 capacity; ma_device_info* pInfo; } ma_pulse_device_enum_data; ma_result ma_result_from_pulse(int result) { switch (result) { case MA_PA_OK: return MA_SUCCESS; case MA_PA_ERR_ACCESS: return MA_ACCESS_DENIED; case MA_PA_ERR_INVALID: return MA_INVALID_ARGS; case MA_PA_ERR_NOENTITY: return MA_NO_DEVICE; default: return MA_ERROR; } } #if 0 ma_pa_sample_format_t ma_format_to_pulse(ma_format format) { if (ma_is_little_endian()) { switch (format) { case ma_format_s16: return MA_PA_SAMPLE_S16LE; case ma_format_s24: return MA_PA_SAMPLE_S24LE; case ma_format_s32: return MA_PA_SAMPLE_S32LE; case ma_format_f32: return MA_PA_SAMPLE_FLOAT32LE; default: break; } } else { switch (format) { case ma_format_s16: return MA_PA_SAMPLE_S16BE; case ma_format_s24: return MA_PA_SAMPLE_S24BE; case ma_format_s32: return MA_PA_SAMPLE_S32BE; case ma_format_f32: return MA_PA_SAMPLE_FLOAT32BE; default: break; } } /* Endian agnostic. */ switch (format) { case ma_format_u8: return MA_PA_SAMPLE_U8; default: return MA_PA_SAMPLE_INVALID; } } #endif ma_format ma_format_from_pulse(ma_pa_sample_format_t format) { if (ma_is_little_endian()) { switch (format) { case MA_PA_SAMPLE_S16LE: return ma_format_s16; case MA_PA_SAMPLE_S24LE: return ma_format_s24; case MA_PA_SAMPLE_S32LE: return ma_format_s32; case MA_PA_SAMPLE_FLOAT32LE: return ma_format_f32; default: break; } } else { switch (format) { case MA_PA_SAMPLE_S16BE: return ma_format_s16; case MA_PA_SAMPLE_S24BE: return ma_format_s24; case MA_PA_SAMPLE_S32BE: return ma_format_s32; case MA_PA_SAMPLE_FLOAT32BE: return ma_format_f32; default: break; } } /* Endian agnostic. */ switch (format) { case MA_PA_SAMPLE_U8: return ma_format_u8; default: return ma_format_unknown; } } ma_channel ma_channel_position_from_pulse(ma_pa_channel_position_t position) { switch (position) { case MA_PA_CHANNEL_POSITION_INVALID: return MA_CHANNEL_NONE; case MA_PA_CHANNEL_POSITION_MONO: return MA_CHANNEL_MONO; case MA_PA_CHANNEL_POSITION_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT; case MA_PA_CHANNEL_POSITION_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT; case MA_PA_CHANNEL_POSITION_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER; case MA_PA_CHANNEL_POSITION_REAR_CENTER: return MA_CHANNEL_BACK_CENTER; case MA_PA_CHANNEL_POSITION_REAR_LEFT: return MA_CHANNEL_BACK_LEFT; case MA_PA_CHANNEL_POSITION_REAR_RIGHT: return MA_CHANNEL_BACK_RIGHT; case MA_PA_CHANNEL_POSITION_LFE: return MA_CHANNEL_LFE; case MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER; case MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER; case MA_PA_CHANNEL_POSITION_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT; case MA_PA_CHANNEL_POSITION_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT; case MA_PA_CHANNEL_POSITION_AUX0: return MA_CHANNEL_AUX_0; case MA_PA_CHANNEL_POSITION_AUX1: return MA_CHANNEL_AUX_1; case MA_PA_CHANNEL_POSITION_AUX2: return MA_CHANNEL_AUX_2; case MA_PA_CHANNEL_POSITION_AUX3: return MA_CHANNEL_AUX_3; case MA_PA_CHANNEL_POSITION_AUX4: return MA_CHANNEL_AUX_4; case MA_PA_CHANNEL_POSITION_AUX5: return MA_CHANNEL_AUX_5; case MA_PA_CHANNEL_POSITION_AUX6: return MA_CHANNEL_AUX_6; case MA_PA_CHANNEL_POSITION_AUX7: return MA_CHANNEL_AUX_7; case MA_PA_CHANNEL_POSITION_AUX8: return MA_CHANNEL_AUX_8; case MA_PA_CHANNEL_POSITION_AUX9: return MA_CHANNEL_AUX_9; case MA_PA_CHANNEL_POSITION_AUX10: return MA_CHANNEL_AUX_10; case MA_PA_CHANNEL_POSITION_AUX11: return MA_CHANNEL_AUX_11; case MA_PA_CHANNEL_POSITION_AUX12: return MA_CHANNEL_AUX_12; case MA_PA_CHANNEL_POSITION_AUX13: return MA_CHANNEL_AUX_13; case MA_PA_CHANNEL_POSITION_AUX14: return MA_CHANNEL_AUX_14; case MA_PA_CHANNEL_POSITION_AUX15: return MA_CHANNEL_AUX_15; case MA_PA_CHANNEL_POSITION_AUX16: return MA_CHANNEL_AUX_16; case MA_PA_CHANNEL_POSITION_AUX17: return MA_CHANNEL_AUX_17; case MA_PA_CHANNEL_POSITION_AUX18: return MA_CHANNEL_AUX_18; case MA_PA_CHANNEL_POSITION_AUX19: return MA_CHANNEL_AUX_19; case MA_PA_CHANNEL_POSITION_AUX20: return MA_CHANNEL_AUX_20; case MA_PA_CHANNEL_POSITION_AUX21: return MA_CHANNEL_AUX_21; case MA_PA_CHANNEL_POSITION_AUX22: return MA_CHANNEL_AUX_22; case MA_PA_CHANNEL_POSITION_AUX23: return MA_CHANNEL_AUX_23; case MA_PA_CHANNEL_POSITION_AUX24: return MA_CHANNEL_AUX_24; case MA_PA_CHANNEL_POSITION_AUX25: return MA_CHANNEL_AUX_25; case MA_PA_CHANNEL_POSITION_AUX26: return MA_CHANNEL_AUX_26; case MA_PA_CHANNEL_POSITION_AUX27: return MA_CHANNEL_AUX_27; case MA_PA_CHANNEL_POSITION_AUX28: return MA_CHANNEL_AUX_28; case MA_PA_CHANNEL_POSITION_AUX29: return MA_CHANNEL_AUX_29; case MA_PA_CHANNEL_POSITION_AUX30: return MA_CHANNEL_AUX_30; case MA_PA_CHANNEL_POSITION_AUX31: return MA_CHANNEL_AUX_31; case MA_PA_CHANNEL_POSITION_TOP_CENTER: return MA_CHANNEL_TOP_CENTER; case MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT; case MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT; case MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER; case MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT: return MA_CHANNEL_TOP_BACK_LEFT; case MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT; case MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER: return MA_CHANNEL_TOP_BACK_CENTER; default: return MA_CHANNEL_NONE; } } #if 0 ma_pa_channel_position_t ma_channel_position_to_pulse(ma_channel position) { switch (position) { case MA_CHANNEL_NONE: return MA_PA_CHANNEL_POSITION_INVALID; case MA_CHANNEL_FRONT_LEFT: return MA_PA_CHANNEL_POSITION_FRONT_LEFT; case MA_CHANNEL_FRONT_RIGHT: return MA_PA_CHANNEL_POSITION_FRONT_RIGHT; case MA_CHANNEL_FRONT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_CENTER; case MA_CHANNEL_LFE: return MA_PA_CHANNEL_POSITION_LFE; case MA_CHANNEL_BACK_LEFT: return MA_PA_CHANNEL_POSITION_REAR_LEFT; case MA_CHANNEL_BACK_RIGHT: return MA_PA_CHANNEL_POSITION_REAR_RIGHT; case MA_CHANNEL_FRONT_LEFT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; case MA_CHANNEL_FRONT_RIGHT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; case MA_CHANNEL_BACK_CENTER: return MA_PA_CHANNEL_POSITION_REAR_CENTER; case MA_CHANNEL_SIDE_LEFT: return MA_PA_CHANNEL_POSITION_SIDE_LEFT; case MA_CHANNEL_SIDE_RIGHT: return MA_PA_CHANNEL_POSITION_SIDE_RIGHT; case MA_CHANNEL_TOP_CENTER: return MA_PA_CHANNEL_POSITION_TOP_CENTER; case MA_CHANNEL_TOP_FRONT_LEFT: return MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT; case MA_CHANNEL_TOP_FRONT_CENTER: return MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER; case MA_CHANNEL_TOP_FRONT_RIGHT: return MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; case MA_CHANNEL_TOP_BACK_LEFT: return MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT; case MA_CHANNEL_TOP_BACK_CENTER: return MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER; case MA_CHANNEL_TOP_BACK_RIGHT: return MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT; case MA_CHANNEL_19: return MA_PA_CHANNEL_POSITION_AUX18; case MA_CHANNEL_20: return MA_PA_CHANNEL_POSITION_AUX19; case MA_CHANNEL_21: return MA_PA_CHANNEL_POSITION_AUX20; case MA_CHANNEL_22: return MA_PA_CHANNEL_POSITION_AUX21; case MA_CHANNEL_23: return MA_PA_CHANNEL_POSITION_AUX22; case MA_CHANNEL_24: return MA_PA_CHANNEL_POSITION_AUX23; case MA_CHANNEL_25: return MA_PA_CHANNEL_POSITION_AUX24; case MA_CHANNEL_26: return MA_PA_CHANNEL_POSITION_AUX25; case MA_CHANNEL_27: return MA_PA_CHANNEL_POSITION_AUX26; case MA_CHANNEL_28: return MA_PA_CHANNEL_POSITION_AUX27; case MA_CHANNEL_29: return MA_PA_CHANNEL_POSITION_AUX28; case MA_CHANNEL_30: return MA_PA_CHANNEL_POSITION_AUX29; case MA_CHANNEL_31: return MA_PA_CHANNEL_POSITION_AUX30; case MA_CHANNEL_32: return MA_PA_CHANNEL_POSITION_AUX31; default: return (ma_pa_channel_position_t)position; } } #endif ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_mainloop* pMainLoop, ma_pa_operation* pOP) { ma_assert(pContext != NULL); ma_assert(pMainLoop != NULL); ma_assert(pOP != NULL); while (((ma_pa_operation_get_state_proc)pContext->pulse.pa_operation_get_state)(pOP) == MA_PA_OPERATION_RUNNING) { int error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)(pMainLoop, 1, NULL); if (error < 0) { return ma_result_from_pulse(error); } } return MA_SUCCESS; } ma_result ma_device__wait_for_operation__pulse(ma_device* pDevice, ma_pa_operation* pOP) { ma_assert(pDevice != NULL); ma_assert(pOP != NULL); return ma_wait_for_operation__pulse(pDevice->pContext, (ma_pa_mainloop*)pDevice->pulse.pMainLoop, pOP); } ma_bool32 ma_context_is_device_id_equal__pulse(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return ma_strcmp(pID0->pulse, pID1->pulse) == 0; } typedef struct { ma_context* pContext; ma_enum_devices_callback_proc callback; void* pUserData; ma_bool32 isTerminated; } ma_context_enumerate_devices_callback_data__pulse; void ma_context_enumerate_devices_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pSinkInfo, int endOfList, void* pUserData) { ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData; ma_device_info deviceInfo; ma_assert(pData != NULL); if (endOfList || pData->isTerminated) { return; } ma_zero_object(&deviceInfo); /* The name from PulseAudio is the ID for miniaudio. */ if (pSinkInfo->name != NULL) { ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSinkInfo->name, (size_t)-1); } /* The description from PulseAudio is the name for miniaudio. */ if (pSinkInfo->description != NULL) { ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSinkInfo->description, (size_t)-1); } pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_playback, &deviceInfo, pData->pUserData); (void)pPulseContext; /* Unused. */ } void ma_context_enumerate_devices_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pSinkInfo, int endOfList, void* pUserData) { ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData; ma_device_info deviceInfo; ma_assert(pData != NULL); if (endOfList || pData->isTerminated) { return; } ma_zero_object(&deviceInfo); /* The name from PulseAudio is the ID for miniaudio. */ if (pSinkInfo->name != NULL) { ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSinkInfo->name, (size_t)-1); } /* The description from PulseAudio is the name for miniaudio. */ if (pSinkInfo->description != NULL) { ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSinkInfo->description, (size_t)-1); } pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_capture, &deviceInfo, pData->pUserData); (void)pPulseContext; /* Unused. */ } ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_result result = MA_SUCCESS; ma_context_enumerate_devices_callback_data__pulse callbackData; ma_pa_operation* pOP = NULL; ma_pa_mainloop* pMainLoop; ma_pa_mainloop_api* pAPI; ma_pa_context* pPulseContext; int error; ma_assert(pContext != NULL); ma_assert(callback != NULL); callbackData.pContext = pContext; callbackData.callback = callback; callbackData.pUserData = pUserData; callbackData.isTerminated = MA_FALSE; pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)(); if (pMainLoop == NULL) { return MA_FAILED_TO_INIT_BACKEND; } pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)(pMainLoop); if (pAPI == NULL) { ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); return MA_FAILED_TO_INIT_BACKEND; } pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName); if (pPulseContext == NULL) { ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); return MA_FAILED_TO_INIT_BACKEND; } error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, (pContext->pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL); if (error != MA_PA_OK) { ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); return ma_result_from_pulse(error); } for (;;) { ma_pa_context_state_t state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)(pPulseContext); if (state == MA_PA_CONTEXT_READY) { break; /* Success. */ } if (state == MA_PA_CONTEXT_CONNECTING || state == MA_PA_CONTEXT_AUTHORIZING || state == MA_PA_CONTEXT_SETTING_NAME) { error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)(pMainLoop, 1, NULL); if (error < 0) { result = ma_result_from_pulse(error); goto done; } #ifdef MA_DEBUG_OUTPUT printf("[PulseAudio] pa_context_get_state() returned %d. Waiting.\n", state); #endif continue; /* Keep trying. */ } if (state == MA_PA_CONTEXT_UNCONNECTED || state == MA_PA_CONTEXT_FAILED || state == MA_PA_CONTEXT_TERMINATED) { #ifdef MA_DEBUG_OUTPUT printf("[PulseAudio] pa_context_get_state() returned %d. Failed.\n", state); #endif goto done; /* Failed. */ } } /* Playback. */ if (!callbackData.isTerminated) { pOP = ((ma_pa_context_get_sink_info_list_proc)pContext->pulse.pa_context_get_sink_info_list)(pPulseContext, ma_context_enumerate_devices_sink_callback__pulse, &callbackData); if (pOP == NULL) { result = MA_ERROR; goto done; } result = ma_wait_for_operation__pulse(pContext, pMainLoop, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); if (result != MA_SUCCESS) { goto done; } } /* Capture. */ if (!callbackData.isTerminated) { pOP = ((ma_pa_context_get_source_info_list_proc)pContext->pulse.pa_context_get_source_info_list)(pPulseContext, ma_context_enumerate_devices_source_callback__pulse, &callbackData); if (pOP == NULL) { result = MA_ERROR; goto done; } result = ma_wait_for_operation__pulse(pContext, pMainLoop, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); if (result != MA_SUCCESS) { goto done; } } done: ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)(pPulseContext); ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); return result; } typedef struct { ma_device_info* pDeviceInfo; ma_bool32 foundDevice; } ma_context_get_device_info_callback_data__pulse; void ma_context_get_device_info_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData) { ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData; if (endOfList > 0) { return; } ma_assert(pData != NULL); pData->foundDevice = MA_TRUE; if (pInfo->name != NULL) { ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1); } if (pInfo->description != NULL) { ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1); } pData->pDeviceInfo->minChannels = pInfo->sample_spec.channels; pData->pDeviceInfo->maxChannels = pInfo->sample_spec.channels; pData->pDeviceInfo->minSampleRate = pInfo->sample_spec.rate; pData->pDeviceInfo->maxSampleRate = pInfo->sample_spec.rate; pData->pDeviceInfo->formatCount = 1; pData->pDeviceInfo->formats[0] = ma_format_from_pulse(pInfo->sample_spec.format); (void)pPulseContext; /* Unused. */ } void ma_context_get_device_info_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData) { ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData; if (endOfList > 0) { return; } ma_assert(pData != NULL); pData->foundDevice = MA_TRUE; if (pInfo->name != NULL) { ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1); } if (pInfo->description != NULL) { ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1); } pData->pDeviceInfo->minChannels = pInfo->sample_spec.channels; pData->pDeviceInfo->maxChannels = pInfo->sample_spec.channels; pData->pDeviceInfo->minSampleRate = pInfo->sample_spec.rate; pData->pDeviceInfo->maxSampleRate = pInfo->sample_spec.rate; pData->pDeviceInfo->formatCount = 1; pData->pDeviceInfo->formats[0] = ma_format_from_pulse(pInfo->sample_spec.format); (void)pPulseContext; /* Unused. */ } ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_result result = MA_SUCCESS; ma_context_get_device_info_callback_data__pulse callbackData; ma_pa_operation* pOP = NULL; ma_pa_mainloop* pMainLoop; ma_pa_mainloop_api* pAPI; ma_pa_context* pPulseContext; int error; ma_assert(pContext != NULL); /* No exclusive mode with the PulseAudio backend. */ if (shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } callbackData.pDeviceInfo = pDeviceInfo; callbackData.foundDevice = MA_FALSE; pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)(); if (pMainLoop == NULL) { return MA_FAILED_TO_INIT_BACKEND; } pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)(pMainLoop); if (pAPI == NULL) { ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); return MA_FAILED_TO_INIT_BACKEND; } pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName); if (pPulseContext == NULL) { ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); return MA_FAILED_TO_INIT_BACKEND; } error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, 0, NULL); if (error != MA_PA_OK) { ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); return ma_result_from_pulse(error); } for (;;) { ma_pa_context_state_t state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)(pPulseContext); if (state == MA_PA_CONTEXT_READY) { break; /* Success. */ } if (state == MA_PA_CONTEXT_CONNECTING || state == MA_PA_CONTEXT_AUTHORIZING || state == MA_PA_CONTEXT_SETTING_NAME) { error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)(pMainLoop, 1, NULL); if (error < 0) { result = ma_result_from_pulse(error); goto done; } #ifdef MA_DEBUG_OUTPUT printf("[PulseAudio] pa_context_get_state() returned %d. Waiting.\n", state); #endif continue; /* Keep trying. */ } if (state == MA_PA_CONTEXT_UNCONNECTED || state == MA_PA_CONTEXT_FAILED || state == MA_PA_CONTEXT_TERMINATED) { #ifdef MA_DEBUG_OUTPUT printf("[PulseAudio] pa_context_get_state() returned %d. Failed.\n", state); #endif goto done; /* Failed. */ } } if (deviceType == ma_device_type_playback) { pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)(pPulseContext, pDeviceID->pulse, ma_context_get_device_info_sink_callback__pulse, &callbackData); } else { pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)(pPulseContext, pDeviceID->pulse, ma_context_get_device_info_source_callback__pulse, &callbackData); } if (pOP != NULL) { ma_wait_for_operation__pulse(pContext, pMainLoop, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); } else { result = MA_ERROR; goto done; } if (!callbackData.foundDevice) { result = MA_NO_DEVICE; goto done; } done: ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)(pPulseContext); ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); return result; } void ma_pulse_device_state_callback(ma_pa_context* pPulseContext, void* pUserData) { ma_device* pDevice; ma_context* pContext; pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); pContext = pDevice->pContext; ma_assert(pContext != NULL); pDevice->pulse.pulseContextState = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)(pPulseContext); } void ma_device_sink_info_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData) { ma_pa_sink_info* pInfoOut; if (endOfList > 0) { return; } pInfoOut = (ma_pa_sink_info*)pUserData; ma_assert(pInfoOut != NULL); *pInfoOut = *pInfo; (void)pPulseContext; /* Unused. */ } void ma_device_source_info_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData) { ma_pa_source_info* pInfoOut; if (endOfList > 0) { return; } pInfoOut = (ma_pa_source_info*)pUserData; ma_assert(pInfoOut != NULL); *pInfoOut = *pInfo; (void)pPulseContext; /* Unused. */ } void ma_device_sink_name_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData) { ma_device* pDevice; if (endOfList > 0) { return; } pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), pInfo->description, (size_t)-1); (void)pPulseContext; /* Unused. */ } void ma_device_source_name_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData) { ma_device* pDevice; if (endOfList > 0) { return; } pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), pInfo->description, (size_t)-1); (void)pPulseContext; /* Unused. */ } void ma_device_uninit__pulse(ma_device* pDevice) { ma_context* pContext; ma_assert(pDevice != NULL); pContext = pDevice->pContext; ma_assert(pContext != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture); ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); } ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pDevice->pulse.pPulseContext); ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pDevice->pulse.pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pDevice->pulse.pMainLoop); } ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 bufferSizeInFrames, ma_uint32 periods, const ma_pa_sample_spec* ss) { ma_pa_buffer_attr attr; attr.maxlength = bufferSizeInFrames * ma_get_bytes_per_sample(ma_format_from_pulse(ss->format)) * ss->channels; attr.tlength = attr.maxlength / periods; attr.prebuf = (ma_uint32)-1; attr.minreq = attr.maxlength / periods; attr.fragsize = attr.maxlength / periods; return attr; } ma_pa_stream* ma_device__pa_stream_new__pulse(ma_device* pDevice, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap) { static int g_StreamCounter = 0; char actualStreamName[256]; if (pStreamName != NULL) { ma_strncpy_s(actualStreamName, sizeof(actualStreamName), pStreamName, (size_t)-1); } else { ma_strcpy_s(actualStreamName, sizeof(actualStreamName), "miniaudio:"); ma_itoa_s(g_StreamCounter, actualStreamName + 8, sizeof(actualStreamName)-8, 10); /* 8 = strlen("miniaudio:") */ } g_StreamCounter += 1; return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap); } ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result = MA_SUCCESS; int error = 0; const char* devPlayback = NULL; const char* devCapture = NULL; ma_uint32 bufferSizeInMilliseconds; ma_pa_sink_info sinkInfo; ma_pa_source_info sourceInfo; ma_pa_operation* pOP = NULL; ma_pa_sample_spec ss; ma_pa_channel_map cmap; ma_pa_buffer_attr attr; const ma_pa_sample_spec* pActualSS = NULL; const ma_pa_channel_map* pActualCMap = NULL; const ma_pa_buffer_attr* pActualAttr = NULL; ma_uint32 iChannel; ma_pa_stream_flags_t streamFlags; ma_assert(pDevice != NULL); ma_zero_object(&pDevice->pulse); /* No exclusive mode with the PulseAudio backend. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; } if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID != NULL) { devPlayback = pConfig->playback.pDeviceID->pulse; } if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID != NULL) { devCapture = pConfig->capture.pDeviceID->pulse; } bufferSizeInMilliseconds = pConfig->bufferSizeInMilliseconds; if (bufferSizeInMilliseconds == 0) { bufferSizeInMilliseconds = ma_calculate_buffer_size_in_milliseconds_from_frames(pConfig->bufferSizeInFrames, pConfig->sampleRate); } pDevice->pulse.pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)(); if (pDevice->pulse.pMainLoop == NULL) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create main loop for device.", MA_FAILED_TO_INIT_BACKEND); goto on_error0; } pDevice->pulse.pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)((ma_pa_mainloop*)pDevice->pulse.pMainLoop); if (pDevice->pulse.pAPI == NULL) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve PulseAudio main loop.", MA_FAILED_TO_INIT_BACKEND); goto on_error1; } pDevice->pulse.pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)((ma_pa_mainloop_api*)pDevice->pulse.pAPI, pContext->pulse.pApplicationName); if (pDevice->pulse.pPulseContext == NULL) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context for device.", MA_FAILED_TO_INIT_BACKEND); goto on_error1; } error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pDevice->pulse.pPulseContext, pContext->pulse.pServerName, (pContext->pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL); if (error != MA_PA_OK) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context.", ma_result_from_pulse(error)); goto on_error2; } pDevice->pulse.pulseContextState = MA_PA_CONTEXT_UNCONNECTED; ((ma_pa_context_set_state_callback_proc)pContext->pulse.pa_context_set_state_callback)((ma_pa_context*)pDevice->pulse.pPulseContext, ma_pulse_device_state_callback, pDevice); /* Wait for PulseAudio to get itself ready before returning. */ for (;;) { if (pDevice->pulse.pulseContextState == MA_PA_CONTEXT_READY) { break; } /* An error may have occurred. */ if (pDevice->pulse.pulseContextState == MA_PA_CONTEXT_FAILED || pDevice->pulse.pulseContextState == MA_PA_CONTEXT_TERMINATED) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context.", MA_ERROR); goto on_error3; } error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL); if (error < 0) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] The PulseAudio main loop returned an error while connecting the PulseAudio context.", ma_result_from_pulse(error)); goto on_error3; } } if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devCapture, ma_device_source_info_callback, &sourceInfo); if (pOP != NULL) { ma_device__wait_for_operation__pulse(pDevice, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); } else { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device.", ma_result_from_pulse(error)); goto on_error3; } ss = sourceInfo.sample_spec; cmap = sourceInfo.channel_map; pDevice->capture.internalBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(bufferSizeInMilliseconds, ss.rate); pDevice->capture.internalPeriods = pConfig->periods; attr = ma_device__pa_buffer_attr_new(pDevice->capture.internalBufferSizeInFrames, pConfig->periods, &ss); #ifdef MA_DEBUG_OUTPUT printf("[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalBufferSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->capture.internalBufferSizeInFrames); #endif pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNameCapture, &ss, &cmap); if (pDevice->pulse.pStreamCapture == NULL) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); goto on_error3; } streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS; if (devCapture != NULL) { streamFlags |= MA_PA_STREAM_DONT_MOVE; } error = ((ma_pa_stream_connect_record_proc)pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags); if (error != MA_PA_OK) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.", ma_result_from_pulse(error)); goto on_error4; } while (((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)((ma_pa_stream*)pDevice->pulse.pStreamCapture) != MA_PA_STREAM_READY) { error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL); if (error < 0) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] The PulseAudio main loop returned an error while connecting the PulseAudio capture stream.", ma_result_from_pulse(error)); goto on_error5; } } /* Internal format. */ pActualSS = ((ma_pa_stream_get_sample_spec_proc)pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture); if (pActualSS != NULL) { /* If anything has changed between the requested and the actual sample spec, we need to update the buffer. */ if (ss.format != pActualSS->format || ss.channels != pActualSS->channels || ss.rate != pActualSS->rate) { attr = ma_device__pa_buffer_attr_new(pDevice->capture.internalBufferSizeInFrames, pConfig->periods, pActualSS); pOP = ((ma_pa_stream_set_buffer_attr_proc)pContext->pulse.pa_stream_set_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamCapture, &attr, NULL, NULL); if (pOP != NULL) { ma_device__wait_for_operation__pulse(pDevice, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); } } ss = *pActualSS; } pDevice->capture.internalFormat = ma_format_from_pulse(ss.format); pDevice->capture.internalChannels = ss.channels; pDevice->capture.internalSampleRate = ss.rate; /* Internal channel map. */ pActualCMap = ((ma_pa_stream_get_channel_map_proc)pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture); if (pActualCMap != NULL) { cmap = *pActualCMap; } for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) { pDevice->capture.internalChannelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); } /* Buffer. */ pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamCapture); if (pActualAttr != NULL) { attr = *pActualAttr; } pDevice->capture.internalBufferSizeInFrames = attr.maxlength / (ma_get_bytes_per_sample(pDevice->capture.internalFormat) * pDevice->capture.internalChannels); pDevice->capture.internalPeriods = attr.maxlength / attr.fragsize; #ifdef MA_DEBUG_OUTPUT printf("[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalBufferSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->capture.internalBufferSizeInFrames); #endif /* Name. */ devCapture = ((ma_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture); if (devCapture != NULL) { ma_pa_operation* pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice); if (pOP != NULL) { ma_device__wait_for_operation__pulse(pDevice, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); } } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devPlayback, ma_device_sink_info_callback, &sinkInfo); if (pOP != NULL) { ma_device__wait_for_operation__pulse(pDevice, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); } else { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.", ma_result_from_pulse(error)); goto on_error3; } ss = sinkInfo.sample_spec; cmap = sinkInfo.channel_map; pDevice->playback.internalBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(bufferSizeInMilliseconds, ss.rate); pDevice->playback.internalPeriods = pConfig->periods; attr = ma_device__pa_buffer_attr_new(pDevice->playback.internalBufferSizeInFrames, pConfig->periods, &ss); #ifdef MA_DEBUG_OUTPUT printf("[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalBufferSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->playback.internalBufferSizeInFrames); #endif pDevice->pulse.pStreamPlayback = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNamePlayback, &ss, &cmap); if (pDevice->pulse.pStreamPlayback == NULL) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); goto on_error3; } streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS; if (devPlayback != NULL) { streamFlags |= MA_PA_STREAM_DONT_MOVE; } error = ((ma_pa_stream_connect_playback_proc)pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL); if (error != MA_PA_OK) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.", ma_result_from_pulse(error)); goto on_error6; } while (((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)((ma_pa_stream*)pDevice->pulse.pStreamPlayback) != MA_PA_STREAM_READY) { error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL); if (error < 0) { result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] The PulseAudio main loop returned an error while connecting the PulseAudio playback stream.", ma_result_from_pulse(error)); goto on_error7; } } /* Internal format. */ pActualSS = ((ma_pa_stream_get_sample_spec_proc)pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (pActualSS != NULL) { /* If anything has changed between the requested and the actual sample spec, we need to update the buffer. */ if (ss.format != pActualSS->format || ss.channels != pActualSS->channels || ss.rate != pActualSS->rate) { attr = ma_device__pa_buffer_attr_new(pDevice->playback.internalBufferSizeInFrames, pConfig->periods, pActualSS); pOP = ((ma_pa_stream_set_buffer_attr_proc)pContext->pulse.pa_stream_set_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, &attr, NULL, NULL); if (pOP != NULL) { ma_device__wait_for_operation__pulse(pDevice, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); } } ss = *pActualSS; } pDevice->playback.internalFormat = ma_format_from_pulse(ss.format); pDevice->playback.internalChannels = ss.channels; pDevice->playback.internalSampleRate = ss.rate; /* Internal channel map. */ pActualCMap = ((ma_pa_stream_get_channel_map_proc)pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (pActualCMap != NULL) { cmap = *pActualCMap; } for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) { pDevice->playback.internalChannelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); } /* Buffer. */ pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (pActualAttr != NULL) { attr = *pActualAttr; } pDevice->playback.internalBufferSizeInFrames = attr.maxlength / (ma_get_bytes_per_sample(pDevice->playback.internalFormat) * pDevice->playback.internalChannels); pDevice->playback.internalPeriods = /*pConfig->periods;*/attr.maxlength / attr.tlength; #ifdef MA_DEBUG_OUTPUT printf("[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalBufferSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->playback.internalBufferSizeInFrames); #endif /* Name. */ devPlayback = ((ma_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (devPlayback != NULL) { ma_pa_operation* pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice); if (pOP != NULL) { ma_device__wait_for_operation__pulse(pDevice, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); } } } return MA_SUCCESS; on_error7: if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); } on_error6: if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); } on_error5: if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture); } on_error4: if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture); } on_error3: ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pDevice->pulse.pPulseContext); on_error2: ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pDevice->pulse.pPulseContext); on_error1: ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pDevice->pulse.pMainLoop); on_error0: return result; } void ma_pulse_operation_complete_callback(ma_pa_stream* pStream, int success, void* pUserData) { ma_bool32* pIsSuccessful = (ma_bool32*)pUserData; ma_assert(pIsSuccessful != NULL); *pIsSuccessful = (ma_bool32)success; (void)pStream; /* Unused. */ } ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_type deviceType, int cork) { ma_context* pContext = pDevice->pContext; ma_bool32 wasSuccessful; ma_pa_stream* pStream; ma_pa_operation* pOP; ma_result result; /* This should not be called with a duplex device type. */ if (deviceType == ma_device_type_duplex) { return MA_INVALID_ARGS; } wasSuccessful = MA_FALSE; pStream = (ma_pa_stream*)((deviceType == ma_device_type_capture) ? pDevice->pulse.pStreamCapture : pDevice->pulse.pStreamPlayback); ma_assert(pStream != NULL); pOP = ((ma_pa_stream_cork_proc)pContext->pulse.pa_stream_cork)(pStream, cork, ma_pulse_operation_complete_callback, &wasSuccessful); if (pOP == NULL) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.", (cork == 0) ? MA_FAILED_TO_START_BACKEND_DEVICE : MA_FAILED_TO_STOP_BACKEND_DEVICE); } result = ma_device__wait_for_operation__pulse(pDevice, pOP); ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); if (result != MA_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork.", result); } if (!wasSuccessful) { if (cork) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to stop PulseAudio stream.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } else { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to start PulseAudio stream.", MA_FAILED_TO_START_BACKEND_DEVICE); } } return MA_SUCCESS; } ma_result ma_device_stop__pulse(ma_device* pDevice) { ma_result result; ma_bool32 wasSuccessful; ma_pa_operation* pOP; ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 1); if (result != MA_SUCCESS) { return result; } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { /* The stream needs to be drained if it's a playback device. */ pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful); if (pOP != NULL) { ma_device__wait_for_operation__pulse(pDevice, pOP); ((ma_pa_operation_unref_proc)pDevice->pContext->pulse.pa_operation_unref)(pOP); } result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1); if (result != MA_SUCCESS) { return result; } } return MA_SUCCESS; } ma_result ma_device_write__pulse(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount) { ma_uint32 totalFramesWritten; ma_assert(pDevice != NULL); ma_assert(pPCMFrames != NULL); ma_assert(frameCount > 0); /* The stream needs to be uncorked first. */ if (((ma_pa_stream_is_corked_proc)pDevice->pContext->pulse.pa_stream_is_corked)((ma_pa_stream*)pDevice->pulse.pStreamPlayback)) { ma_result result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0); if (result != MA_SUCCESS) { return result; } } totalFramesWritten = 0; while (totalFramesWritten < frameCount) { /* Place the data into the mapped buffer if we have one. */ if (pDevice->pulse.pMappedBufferPlayback != NULL && pDevice->pulse.mappedBufferFramesRemainingPlayback > 0) { ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); ma_uint32 mappedBufferFramesConsumed = pDevice->pulse.mappedBufferFramesCapacityPlayback - pDevice->pulse.mappedBufferFramesRemainingPlayback; void* pDst = (ma_uint8*)pDevice->pulse.pMappedBufferPlayback + (mappedBufferFramesConsumed * bpf); const void* pSrc = (const ma_uint8*)pPCMFrames + (totalFramesWritten * bpf); ma_uint32 framesToCopy = ma_min(pDevice->pulse.mappedBufferFramesRemainingPlayback, (frameCount - totalFramesWritten)); ma_copy_memory(pDst, pSrc, framesToCopy * bpf); pDevice->pulse.mappedBufferFramesRemainingPlayback -= framesToCopy; totalFramesWritten += framesToCopy; } /* Getting here means we've run out of data in the currently mapped chunk. We need to write this to the device and then try mapping another chunk. If this fails we need to wait for space to become available. */ if (pDevice->pulse.mappedBufferFramesCapacityPlayback > 0 && pDevice->pulse.mappedBufferFramesRemainingPlayback == 0) { size_t nbytes = pDevice->pulse.mappedBufferFramesCapacityPlayback * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); int error = ((ma_pa_stream_write_proc)pDevice->pContext->pulse.pa_stream_write)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, pDevice->pulse.pMappedBufferPlayback, nbytes, NULL, 0, MA_PA_SEEK_RELATIVE); if (error < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to write data to the PulseAudio stream.", ma_result_from_pulse(error)); } pDevice->pulse.pMappedBufferPlayback = NULL; pDevice->pulse.mappedBufferFramesRemainingPlayback = 0; pDevice->pulse.mappedBufferFramesCapacityPlayback = 0; } ma_assert(totalFramesWritten <= frameCount); if (totalFramesWritten == frameCount) { break; } /* Getting here means we need to map a new buffer. If we don't have enough space we need to wait for more. */ for (;;) { size_t writableSizeInBytes; /* If the device has been corked, don't try to continue. */ if (((ma_pa_stream_is_corked_proc)pDevice->pContext->pulse.pa_stream_is_corked)((ma_pa_stream*)pDevice->pulse.pStreamPlayback)) { break; } writableSizeInBytes = ((ma_pa_stream_writable_size_proc)pDevice->pContext->pulse.pa_stream_writable_size)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); if (writableSizeInBytes != (size_t)-1) { /*size_t periodSizeInBytes = (pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods) * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);*/ if (writableSizeInBytes > 0) { /* Data is avaialable. */ size_t bytesToMap = writableSizeInBytes; int error = ((ma_pa_stream_begin_write_proc)pDevice->pContext->pulse.pa_stream_begin_write)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, &pDevice->pulse.pMappedBufferPlayback, &bytesToMap); if (error < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to map write buffer.", ma_result_from_pulse(error)); } pDevice->pulse.mappedBufferFramesCapacityPlayback = bytesToMap / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); pDevice->pulse.mappedBufferFramesRemainingPlayback = pDevice->pulse.mappedBufferFramesCapacityPlayback; break; } else { /* No data available. Need to wait for more. */ int error = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL); if (error < 0) { return ma_result_from_pulse(error); } continue; } } else { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to query the stream's writable size.", MA_ERROR); } } } return MA_SUCCESS; } ma_result ma_device_read__pulse(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount) { ma_uint32 totalFramesRead; ma_assert(pDevice != NULL); ma_assert(pPCMFrames != NULL); ma_assert(frameCount > 0); /* The stream needs to be uncorked first. */ if (((ma_pa_stream_is_corked_proc)pDevice->pContext->pulse.pa_stream_is_corked)((ma_pa_stream*)pDevice->pulse.pStreamCapture)) { ma_result result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 0); if (result != MA_SUCCESS) { return result; } } totalFramesRead = 0; while (totalFramesRead < frameCount) { if (ma_device__get_state(pDevice) != MA_STATE_STARTED) { break; } /* If a buffer is mapped we need to write to that first. Once it's consumed we reset the event and unmap it. */ if (pDevice->pulse.pMappedBufferCapture != NULL && pDevice->pulse.mappedBufferFramesRemainingCapture > 0) { ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); ma_uint32 mappedBufferFramesConsumed = pDevice->pulse.mappedBufferFramesCapacityCapture - pDevice->pulse.mappedBufferFramesRemainingCapture; ma_uint32 framesToCopy = ma_min(pDevice->pulse.mappedBufferFramesRemainingCapture, (frameCount - totalFramesRead)); void* pDst = (ma_uint8*)pPCMFrames + (totalFramesRead * bpf); /* This little bit of logic here is specifically for PulseAudio and it's hole management. The buffer pointer will be set to NULL when the current fragment is a hole. For a hole we just output silence. */ if (pDevice->pulse.pMappedBufferCapture != NULL) { const void* pSrc = (const ma_uint8*)pDevice->pulse.pMappedBufferCapture + (mappedBufferFramesConsumed * bpf); ma_copy_memory(pDst, pSrc, framesToCopy * bpf); } else { ma_zero_memory(pDst, framesToCopy * bpf); } pDevice->pulse.mappedBufferFramesRemainingCapture -= framesToCopy; totalFramesRead += framesToCopy; } /* Getting here means we've run out of data in the currently mapped chunk. We need to drop this from the device and then try mapping another chunk. If this fails we need to wait for data to become available. */ if (pDevice->pulse.mappedBufferFramesCapacityCapture > 0 && pDevice->pulse.mappedBufferFramesRemainingCapture == 0) { int error = ((ma_pa_stream_drop_proc)pDevice->pContext->pulse.pa_stream_drop)((ma_pa_stream*)pDevice->pulse.pStreamCapture); if (error != 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to drop fragment.", ma_result_from_pulse(error)); } pDevice->pulse.pMappedBufferCapture = NULL; pDevice->pulse.mappedBufferFramesRemainingCapture = 0; pDevice->pulse.mappedBufferFramesCapacityCapture = 0; } ma_assert(totalFramesRead <= frameCount); if (totalFramesRead == frameCount) { break; } /* Getting here means we need to map a new buffer. If we don't have enough data we wait for more. */ for (;;) { size_t readableSizeInBytes; if (ma_device__get_state(pDevice) != MA_STATE_STARTED) { break; } /* If the device has been corked, don't try to continue. */ if (((ma_pa_stream_is_corked_proc)pDevice->pContext->pulse.pa_stream_is_corked)((ma_pa_stream*)pDevice->pulse.pStreamCapture)) { break; } readableSizeInBytes = ((ma_pa_stream_readable_size_proc)pDevice->pContext->pulse.pa_stream_readable_size)((ma_pa_stream*)pDevice->pulse.pStreamCapture); if (readableSizeInBytes != (size_t)-1) { /*size_t periodSizeInBytes = (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods) * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);*/ if (readableSizeInBytes > 0) { /* Data is avaialable. */ size_t bytesMapped = (size_t)-1; int error = ((ma_pa_stream_peek_proc)pDevice->pContext->pulse.pa_stream_peek)((ma_pa_stream*)pDevice->pulse.pStreamCapture, &pDevice->pulse.pMappedBufferCapture, &bytesMapped); if (error < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to peek capture buffer.", ma_result_from_pulse(error)); } if (pDevice->pulse.pMappedBufferCapture == NULL && bytesMapped == 0) { /* Nothing available. This shouldn't happen because we checked earlier with pa_stream_readable_size(). I'm going to throw an error in this case. */ return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Nothing available after peeking capture buffer.", MA_ERROR); } pDevice->pulse.mappedBufferFramesCapacityCapture = bytesMapped / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); pDevice->pulse.mappedBufferFramesRemainingCapture = pDevice->pulse.mappedBufferFramesCapacityCapture; break; } else { /* No data available. Need to wait for more. */ /* I have had reports of a deadlock in this part of the code. I have reproduced this when using the "Built-in Audio Analogue Stereo" device without an actual microphone connected. I'm experimenting here by not blocking in pa_mainloop_iterate() and instead sleep for a bit when there are no dispatches. */ int error = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 0, NULL); if (error < 0) { return ma_result_from_pulse(error); } /* Sleep for a bit if nothing was dispatched. */ if (error == 0) { ma_sleep(1); } continue; } } else { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to query the stream's readable size.", MA_ERROR); } } } return MA_SUCCESS; } ma_result ma_context_uninit__pulse(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_pulseaudio); ma_free(pContext->pulse.pServerName); pContext->pulse.pServerName = NULL; ma_free(pContext->pulse.pApplicationName); pContext->pulse.pApplicationName = NULL; #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_SUCCESS; } ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* pContext) { #ifndef MA_NO_RUNTIME_LINKING const char* libpulseNames[] = { "libpulse.so", "libpulse.so.0" }; size_t i; for (i = 0; i < ma_countof(libpulseNames); ++i) { pContext->pulse.pulseSO = ma_dlopen(pContext, libpulseNames[i]); if (pContext->pulse.pulseSO != NULL) { break; } } if (pContext->pulse.pulseSO == NULL) { return MA_NO_BACKEND; } pContext->pulse.pa_mainloop_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_new"); pContext->pulse.pa_mainloop_free = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_free"); pContext->pulse.pa_mainloop_get_api = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_get_api"); pContext->pulse.pa_mainloop_iterate = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_iterate"); pContext->pulse.pa_mainloop_wakeup = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_wakeup"); pContext->pulse.pa_context_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_new"); pContext->pulse.pa_context_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_unref"); pContext->pulse.pa_context_connect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_connect"); pContext->pulse.pa_context_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_disconnect"); pContext->pulse.pa_context_set_state_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_set_state_callback"); pContext->pulse.pa_context_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_state"); pContext->pulse.pa_context_get_sink_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_list"); pContext->pulse.pa_context_get_source_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_list"); pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name"); pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_by_name"); pContext->pulse.pa_operation_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_unref"); pContext->pulse.pa_operation_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_get_state"); pContext->pulse.pa_channel_map_init_extend = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_init_extend"); pContext->pulse.pa_channel_map_valid = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_valid"); pContext->pulse.pa_channel_map_compatible = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_compatible"); pContext->pulse.pa_stream_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_new"); pContext->pulse.pa_stream_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_unref"); pContext->pulse.pa_stream_connect_playback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_playback"); pContext->pulse.pa_stream_connect_record = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_record"); pContext->pulse.pa_stream_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_disconnect"); pContext->pulse.pa_stream_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_state"); pContext->pulse.pa_stream_get_sample_spec = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_sample_spec"); pContext->pulse.pa_stream_get_channel_map = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_channel_map"); pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_buffer_attr"); pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_buffer_attr"); pContext->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_device_name"); pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback"); pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback"); pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush"); pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain"); pContext->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_corked"); pContext->pulse.pa_stream_cork = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_cork"); pContext->pulse.pa_stream_trigger = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_trigger"); pContext->pulse.pa_stream_begin_write = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_begin_write"); pContext->pulse.pa_stream_write = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_write"); pContext->pulse.pa_stream_peek = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_peek"); pContext->pulse.pa_stream_drop = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drop"); pContext->pulse.pa_stream_writable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_writable_size"); pContext->pulse.pa_stream_readable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_readable_size"); #else /* This strange assignment system is just for type safety. */ ma_pa_mainloop_new_proc _pa_mainloop_new = pa_mainloop_new; ma_pa_mainloop_free_proc _pa_mainloop_free = pa_mainloop_free; ma_pa_mainloop_get_api_proc _pa_mainloop_get_api = pa_mainloop_get_api; ma_pa_mainloop_iterate_proc _pa_mainloop_iterate = pa_mainloop_iterate; ma_pa_mainloop_wakeup_proc _pa_mainloop_wakeup = pa_mainloop_wakeup; ma_pa_context_new_proc _pa_context_new = pa_context_new; ma_pa_context_unref_proc _pa_context_unref = pa_context_unref; ma_pa_context_connect_proc _pa_context_connect = pa_context_connect; ma_pa_context_disconnect_proc _pa_context_disconnect = pa_context_disconnect; ma_pa_context_set_state_callback_proc _pa_context_set_state_callback = pa_context_set_state_callback; ma_pa_context_get_state_proc _pa_context_get_state = pa_context_get_state; ma_pa_context_get_sink_info_list_proc _pa_context_get_sink_info_list = pa_context_get_sink_info_list; ma_pa_context_get_source_info_list_proc _pa_context_get_source_info_list = pa_context_get_source_info_list; ma_pa_context_get_sink_info_by_name_proc _pa_context_get_sink_info_by_name = pa_context_get_sink_info_by_name; ma_pa_context_get_source_info_by_name_proc _pa_context_get_source_info_by_name= pa_context_get_source_info_by_name; ma_pa_operation_unref_proc _pa_operation_unref = pa_operation_unref; ma_pa_operation_get_state_proc _pa_operation_get_state = pa_operation_get_state; ma_pa_channel_map_init_extend_proc _pa_channel_map_init_extend = pa_channel_map_init_extend; ma_pa_channel_map_valid_proc _pa_channel_map_valid = pa_channel_map_valid; ma_pa_channel_map_compatible_proc _pa_channel_map_compatible = pa_channel_map_compatible; ma_pa_stream_new_proc _pa_stream_new = pa_stream_new; ma_pa_stream_unref_proc _pa_stream_unref = pa_stream_unref; ma_pa_stream_connect_playback_proc _pa_stream_connect_playback = pa_stream_connect_playback; ma_pa_stream_connect_record_proc _pa_stream_connect_record = pa_stream_connect_record; ma_pa_stream_disconnect_proc _pa_stream_disconnect = pa_stream_disconnect; ma_pa_stream_get_state_proc _pa_stream_get_state = pa_stream_get_state; ma_pa_stream_get_sample_spec_proc _pa_stream_get_sample_spec = pa_stream_get_sample_spec; ma_pa_stream_get_channel_map_proc _pa_stream_get_channel_map = pa_stream_get_channel_map; ma_pa_stream_get_buffer_attr_proc _pa_stream_get_buffer_attr = pa_stream_get_buffer_attr; ma_pa_stream_set_buffer_attr_proc _pa_stream_set_buffer_attr = pa_stream_set_buffer_attr; ma_pa_stream_get_device_name_proc _pa_stream_get_device_name = pa_stream_get_device_name; ma_pa_stream_set_write_callback_proc _pa_stream_set_write_callback = pa_stream_set_write_callback; ma_pa_stream_set_read_callback_proc _pa_stream_set_read_callback = pa_stream_set_read_callback; ma_pa_stream_flush_proc _pa_stream_flush = pa_stream_flush; ma_pa_stream_drain_proc _pa_stream_drain = pa_stream_drain; ma_pa_stream_is_corked_proc _pa_stream_is_corked = pa_stream_is_corked; ma_pa_stream_cork_proc _pa_stream_cork = pa_stream_cork; ma_pa_stream_trigger_proc _pa_stream_trigger = pa_stream_trigger; ma_pa_stream_begin_write_proc _pa_stream_begin_write = pa_stream_begin_write; ma_pa_stream_write_proc _pa_stream_write = pa_stream_write; ma_pa_stream_peek_proc _pa_stream_peek = pa_stream_peek; ma_pa_stream_drop_proc _pa_stream_drop = pa_stream_drop; ma_pa_stream_writable_size_proc _pa_stream_writable_size = pa_stream_writable_size; ma_pa_stream_readable_size_proc _pa_stream_readable_size = pa_stream_readable_size; pContext->pulse.pa_mainloop_new = (ma_proc)_pa_mainloop_new; pContext->pulse.pa_mainloop_free = (ma_proc)_pa_mainloop_free; pContext->pulse.pa_mainloop_get_api = (ma_proc)_pa_mainloop_get_api; pContext->pulse.pa_mainloop_iterate = (ma_proc)_pa_mainloop_iterate; pContext->pulse.pa_mainloop_wakeup = (ma_proc)_pa_mainloop_wakeup; pContext->pulse.pa_context_new = (ma_proc)_pa_context_new; pContext->pulse.pa_context_unref = (ma_proc)_pa_context_unref; pContext->pulse.pa_context_connect = (ma_proc)_pa_context_connect; pContext->pulse.pa_context_disconnect = (ma_proc)_pa_context_disconnect; pContext->pulse.pa_context_set_state_callback = (ma_proc)_pa_context_set_state_callback; pContext->pulse.pa_context_get_state = (ma_proc)_pa_context_get_state; pContext->pulse.pa_context_get_sink_info_list = (ma_proc)_pa_context_get_sink_info_list; pContext->pulse.pa_context_get_source_info_list = (ma_proc)_pa_context_get_source_info_list; pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)_pa_context_get_sink_info_by_name; pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)_pa_context_get_source_info_by_name; pContext->pulse.pa_operation_unref = (ma_proc)_pa_operation_unref; pContext->pulse.pa_operation_get_state = (ma_proc)_pa_operation_get_state; pContext->pulse.pa_channel_map_init_extend = (ma_proc)_pa_channel_map_init_extend; pContext->pulse.pa_channel_map_valid = (ma_proc)_pa_channel_map_valid; pContext->pulse.pa_channel_map_compatible = (ma_proc)_pa_channel_map_compatible; pContext->pulse.pa_stream_new = (ma_proc)_pa_stream_new; pContext->pulse.pa_stream_unref = (ma_proc)_pa_stream_unref; pContext->pulse.pa_stream_connect_playback = (ma_proc)_pa_stream_connect_playback; pContext->pulse.pa_stream_connect_record = (ma_proc)_pa_stream_connect_record; pContext->pulse.pa_stream_disconnect = (ma_proc)_pa_stream_disconnect; pContext->pulse.pa_stream_get_state = (ma_proc)_pa_stream_get_state; pContext->pulse.pa_stream_get_sample_spec = (ma_proc)_pa_stream_get_sample_spec; pContext->pulse.pa_stream_get_channel_map = (ma_proc)_pa_stream_get_channel_map; pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)_pa_stream_get_buffer_attr; pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)_pa_stream_set_buffer_attr; pContext->pulse.pa_stream_get_device_name = (ma_proc)_pa_stream_get_device_name; pContext->pulse.pa_stream_set_write_callback = (ma_proc)_pa_stream_set_write_callback; pContext->pulse.pa_stream_set_read_callback = (ma_proc)_pa_stream_set_read_callback; pContext->pulse.pa_stream_flush = (ma_proc)_pa_stream_flush; pContext->pulse.pa_stream_drain = (ma_proc)_pa_stream_drain; pContext->pulse.pa_stream_is_corked = (ma_proc)_pa_stream_is_corked; pContext->pulse.pa_stream_cork = (ma_proc)_pa_stream_cork; pContext->pulse.pa_stream_trigger = (ma_proc)_pa_stream_trigger; pContext->pulse.pa_stream_begin_write = (ma_proc)_pa_stream_begin_write; pContext->pulse.pa_stream_write = (ma_proc)_pa_stream_write; pContext->pulse.pa_stream_peek = (ma_proc)_pa_stream_peek; pContext->pulse.pa_stream_drop = (ma_proc)_pa_stream_drop; pContext->pulse.pa_stream_writable_size = (ma_proc)_pa_stream_writable_size; pContext->pulse.pa_stream_readable_size = (ma_proc)_pa_stream_readable_size; #endif pContext->onUninit = ma_context_uninit__pulse; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__pulse; pContext->onEnumDevices = ma_context_enumerate_devices__pulse; pContext->onGetDeviceInfo = ma_context_get_device_info__pulse; pContext->onDeviceInit = ma_device_init__pulse; pContext->onDeviceUninit = ma_device_uninit__pulse; pContext->onDeviceStart = NULL; pContext->onDeviceStop = ma_device_stop__pulse; pContext->onDeviceWrite = ma_device_write__pulse; pContext->onDeviceRead = ma_device_read__pulse; if (pConfig->pulse.pApplicationName) { pContext->pulse.pApplicationName = ma_copy_string(pConfig->pulse.pApplicationName); } if (pConfig->pulse.pServerName) { pContext->pulse.pServerName = ma_copy_string(pConfig->pulse.pServerName); } pContext->pulse.tryAutoSpawn = pConfig->pulse.tryAutoSpawn; /* Although we have found the libpulse library, it doesn't necessarily mean PulseAudio is useable. We need to initialize and connect a dummy PulseAudio context to test PulseAudio's usability. */ { ma_pa_mainloop* pMainLoop; ma_pa_mainloop_api* pAPI; ma_pa_context* pPulseContext; int error; pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)(); if (pMainLoop == NULL) { ma_free(pContext->pulse.pServerName); ma_free(pContext->pulse.pApplicationName); #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_NO_BACKEND; } pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)(pMainLoop); if (pAPI == NULL) { ma_free(pContext->pulse.pServerName); ma_free(pContext->pulse.pApplicationName); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_NO_BACKEND; } pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName); if (pPulseContext == NULL) { ma_free(pContext->pulse.pServerName); ma_free(pContext->pulse.pApplicationName); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_NO_BACKEND; } error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, 0, NULL); if (error != MA_PA_OK) { ma_free(pContext->pulse.pServerName); ma_free(pContext->pulse.pApplicationName); ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_NO_BACKEND; } ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)(pPulseContext); ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); } return MA_SUCCESS; } #endif /****************************************************************************** JACK Backend ******************************************************************************/ #ifdef MA_HAS_JACK /* It is assumed jack.h is available when compile-time linking is being used. */ #ifdef MA_NO_RUNTIME_LINKING #include typedef jack_nframes_t ma_jack_nframes_t; typedef jack_options_t ma_jack_options_t; typedef jack_status_t ma_jack_status_t; typedef jack_client_t ma_jack_client_t; typedef jack_port_t ma_jack_port_t; typedef JackProcessCallback ma_JackProcessCallback; typedef JackBufferSizeCallback ma_JackBufferSizeCallback; typedef JackShutdownCallback ma_JackShutdownCallback; #define MA_JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE #define ma_JackNoStartServer JackNoStartServer #define ma_JackPortIsInput JackPortIsInput #define ma_JackPortIsOutput JackPortIsOutput #define ma_JackPortIsPhysical JackPortIsPhysical #else typedef ma_uint32 ma_jack_nframes_t; typedef int ma_jack_options_t; typedef int ma_jack_status_t; typedef struct ma_jack_client_t ma_jack_client_t; typedef struct ma_jack_port_t ma_jack_port_t; typedef int (* ma_JackProcessCallback) (ma_jack_nframes_t nframes, void* arg); typedef int (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg); typedef void (* ma_JackShutdownCallback) (void* arg); #define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio" #define ma_JackNoStartServer 1 #define ma_JackPortIsInput 1 #define ma_JackPortIsOutput 2 #define ma_JackPortIsPhysical 4 #endif typedef ma_jack_client_t* (* ma_jack_client_open_proc) (const char* client_name, ma_jack_options_t options, ma_jack_status_t* status, ...); typedef int (* ma_jack_client_close_proc) (ma_jack_client_t* client); typedef int (* ma_jack_client_name_size_proc) (); typedef int (* ma_jack_set_process_callback_proc) (ma_jack_client_t* client, ma_JackProcessCallback process_callback, void* arg); typedef int (* ma_jack_set_buffer_size_callback_proc)(ma_jack_client_t* client, ma_JackBufferSizeCallback bufsize_callback, void* arg); typedef void (* ma_jack_on_shutdown_proc) (ma_jack_client_t* client, ma_JackShutdownCallback function, void* arg); typedef ma_jack_nframes_t (* ma_jack_get_sample_rate_proc) (ma_jack_client_t* client); typedef ma_jack_nframes_t (* ma_jack_get_buffer_size_proc) (ma_jack_client_t* client); typedef const char** (* ma_jack_get_ports_proc) (ma_jack_client_t* client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags); typedef int (* ma_jack_activate_proc) (ma_jack_client_t* client); typedef int (* ma_jack_deactivate_proc) (ma_jack_client_t* client); typedef int (* ma_jack_connect_proc) (ma_jack_client_t* client, const char* source_port, const char* destination_port); typedef ma_jack_port_t* (* ma_jack_port_register_proc) (ma_jack_client_t* client, const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); typedef const char* (* ma_jack_port_name_proc) (const ma_jack_port_t* port); typedef void* (* ma_jack_port_get_buffer_proc) (ma_jack_port_t* port, ma_jack_nframes_t nframes); typedef void (* ma_jack_free_proc) (void* ptr); ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_client_t** ppClient) { size_t maxClientNameSize; char clientName[256]; ma_jack_status_t status; ma_jack_client_t* pClient; ma_assert(pContext != NULL); ma_assert(ppClient != NULL); if (ppClient) { *ppClient = NULL; } maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */ ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1); pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL); if (pClient == NULL) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } if (ppClient) { *ppClient = pClient; } return MA_SUCCESS; } ma_bool32 ma_context_is_device_id_equal__jack(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return pID0->jack == pID1->jack; } ma_result ma_context_enumerate_devices__jack(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_bool32 cbResult = MA_TRUE; ma_assert(pContext != NULL); ma_assert(callback != NULL); /* Playback. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } /* Capture. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } return MA_SUCCESS; } ma_result ma_context_get_device_info__jack(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_jack_client_t* pClient; ma_result result; const char** ppPorts; ma_assert(pContext != NULL); /* No exclusive mode with the JACK backend. */ if (shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } if (pDeviceID != NULL && pDeviceID->jack != 0) { return MA_NO_DEVICE; /* Don't know the device. */ } /* Name / Description */ if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } /* Jack only supports f32 and has a specific channel count and sample rate. */ pDeviceInfo->formatCount = 1; pDeviceInfo->formats[0] = ma_format_f32; /* The channel count and sample rate can only be determined by opening the device. */ result = ma_context_open_client__jack(pContext, &pClient); if (result != MA_SUCCESS) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } pDeviceInfo->minSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient); pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate; pDeviceInfo->minChannels = 0; pDeviceInfo->maxChannels = 0; ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pClient, NULL, NULL, ma_JackPortIsPhysical | ((deviceType == ma_device_type_playback) ? ma_JackPortIsInput : ma_JackPortIsOutput)); if (ppPorts == NULL) { ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } while (ppPorts[pDeviceInfo->minChannels] != NULL) { pDeviceInfo->minChannels += 1; pDeviceInfo->maxChannels += 1; } ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts); ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient); (void)pContext; return MA_SUCCESS; } void ma_device_uninit__jack(ma_device* pDevice) { ma_context* pContext; ma_assert(pDevice != NULL); pContext = pDevice->pContext; ma_assert(pContext != NULL); if (pDevice->jack.pClient != NULL) { ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDevice->jack.pClient); } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_free(pDevice->jack.pIntermediaryBufferCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_free(pDevice->jack.pIntermediaryBufferPlayback); } if (pDevice->type == ma_device_type_duplex) { ma_pcm_rb_uninit(&pDevice->jack.duplexRB); } } void ma_device__jack_shutdown_callback(void* pUserData) { /* JACK died. Stop the device. */ ma_device* pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); ma_device_stop(pDevice); } int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, void* pUserData) { ma_device* pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { float* pNewBuffer = (float*)ma_realloc(pDevice->jack.pIntermediaryBufferCapture, frameCount * (pDevice->capture.internalChannels * ma_get_bytes_per_sample(pDevice->capture.internalFormat))); if (pNewBuffer == NULL) { return MA_OUT_OF_MEMORY; } pDevice->jack.pIntermediaryBufferCapture = pNewBuffer; pDevice->playback.internalBufferSizeInFrames = frameCount * pDevice->capture.internalPeriods; } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { float* pNewBuffer = (float*)ma_realloc(pDevice->jack.pIntermediaryBufferPlayback, frameCount * (pDevice->playback.internalChannels * ma_get_bytes_per_sample(pDevice->playback.internalFormat))); if (pNewBuffer == NULL) { return MA_OUT_OF_MEMORY; } pDevice->jack.pIntermediaryBufferPlayback = pNewBuffer; pDevice->playback.internalBufferSizeInFrames = frameCount * pDevice->playback.internalPeriods; } return 0; } int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* pUserData) { ma_device* pDevice; ma_context* pContext; ma_uint32 iChannel; pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); pContext = pDevice->pContext; ma_assert(pContext != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { /* Channels need to be interleaved. */ for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) { const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsCapture[iChannel], frameCount); if (pSrc != NULL) { float* pDst = pDevice->jack.pIntermediaryBufferCapture + iChannel; ma_jack_nframes_t iFrame; for (iFrame = 0; iFrame < frameCount; ++iFrame) { *pDst = *pSrc; pDst += pDevice->capture.internalChannels; pSrc += 1; } } } if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_capture(pDevice, frameCount, pDevice->jack.pIntermediaryBufferCapture, &pDevice->jack.duplexRB); } else { ma_device__send_frames_to_client(pDevice, frameCount, pDevice->jack.pIntermediaryBufferCapture); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_playback(pDevice, frameCount, pDevice->jack.pIntermediaryBufferPlayback, &pDevice->jack.duplexRB); } else { ma_device__read_frames_from_client(pDevice, frameCount, pDevice->jack.pIntermediaryBufferPlayback); } /* Channels need to be deinterleaved. */ for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) { float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[iChannel], frameCount); if (pDst != NULL) { const float* pSrc = pDevice->jack.pIntermediaryBufferPlayback + iChannel; ma_jack_nframes_t iFrame; for (iFrame = 0; iFrame < frameCount; ++iFrame) { *pDst = *pSrc; pDst += 1; pSrc += pDevice->playback.internalChannels; } } } } return 0; } ma_result ma_device_init__jack(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result; ma_uint32 periods; ma_uint32 bufferSizeInFrames; ma_assert(pContext != NULL); ma_assert(pConfig != NULL); ma_assert(pDevice != NULL); /* Only supporting default devices with JACK. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID != NULL && pConfig->playback.pDeviceID->jack != 0) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID != NULL && pConfig->capture.pDeviceID->jack != 0)) { return MA_NO_DEVICE; } /* No exclusive mode with the JACK backend. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; } /* Open the client. */ result = ma_context_open_client__jack(pContext, (ma_jack_client_t**)&pDevice->jack.pClient); if (result != MA_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* Callbacks. */ if (((ma_jack_set_process_callback_proc)pContext->jack.jack_set_process_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_process_callback, pDevice) != 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (((ma_jack_set_buffer_size_callback_proc)pContext->jack.jack_set_buffer_size_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_buffer_size_callback, pDevice) != 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } ((ma_jack_on_shutdown_proc)pContext->jack.jack_on_shutdown)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_shutdown_callback, pDevice); /* The buffer size in frames can change. */ periods = 2; bufferSizeInFrames = ((ma_jack_get_buffer_size_proc)pContext->jack.jack_get_buffer_size)((ma_jack_client_t*)pDevice->jack.pClient) * periods; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { const char** ppPorts; pDevice->capture.internalFormat = ma_format_f32; pDevice->capture.internalChannels = 0; pDevice->capture.internalSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient); ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, NULL, ma_JackPortIsPhysical | ma_JackPortIsOutput); if (ppPorts == NULL) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } while (ppPorts[pDevice->capture.internalChannels] != NULL) { char name[64]; ma_strcpy_s(name, sizeof(name), "capture"); ma_itoa_s((int)pDevice->capture.internalChannels, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */ pDevice->jack.pPortsCapture[pDevice->capture.internalChannels] = ((ma_jack_port_register_proc)pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0); if (pDevice->jack.pPortsCapture[pDevice->capture.internalChannels] == NULL) { ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts); ma_device_uninit__jack(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } pDevice->capture.internalChannels += 1; } ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts); pDevice->capture.internalBufferSizeInFrames = bufferSizeInFrames; pDevice->capture.internalPeriods = periods; pDevice->jack.pIntermediaryBufferCapture = (float*)ma_malloc((pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods) * (pDevice->capture.internalChannels * ma_get_bytes_per_sample(pDevice->capture.internalFormat))); if (pDevice->jack.pIntermediaryBufferCapture == NULL) { ma_device_uninit__jack(pDevice); return MA_OUT_OF_MEMORY; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { const char** ppPorts; pDevice->playback.internalFormat = ma_format_f32; pDevice->playback.internalChannels = 0; pDevice->playback.internalSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient); ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, NULL, ma_JackPortIsPhysical | ma_JackPortIsInput); if (ppPorts == NULL) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } while (ppPorts[pDevice->playback.internalChannels] != NULL) { char name[64]; ma_strcpy_s(name, sizeof(name), "playback"); ma_itoa_s((int)pDevice->playback.internalChannels, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */ pDevice->jack.pPortsPlayback[pDevice->playback.internalChannels] = ((ma_jack_port_register_proc)pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0); if (pDevice->jack.pPortsPlayback[pDevice->playback.internalChannels] == NULL) { ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts); ma_device_uninit__jack(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } pDevice->playback.internalChannels += 1; } ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts); pDevice->playback.internalBufferSizeInFrames = bufferSizeInFrames; pDevice->playback.internalPeriods = periods; pDevice->jack.pIntermediaryBufferPlayback = (float*)ma_malloc((pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods) * (pDevice->playback.internalChannels * ma_get_bytes_per_sample(pDevice->playback.internalFormat))); if (pDevice->jack.pIntermediaryBufferPlayback == NULL) { ma_device_uninit__jack(pDevice); return MA_OUT_OF_MEMORY; } } if (pDevice->type == ma_device_type_duplex) { ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalBufferSizeInFrames); result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->jack.duplexRB); if (result != MA_SUCCESS) { ma_device_uninit__jack(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to initialize ring buffer.", result); } } return MA_SUCCESS; } ma_result ma_device_start__jack(ma_device* pDevice) { ma_context* pContext = pDevice->pContext; int resultJACK; size_t i; resultJACK = ((ma_jack_activate_proc)pContext->jack.jack_activate)((ma_jack_client_t*)pDevice->jack.pClient); if (resultJACK != 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client.", MA_FAILED_TO_START_BACKEND_DEVICE); } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, NULL, ma_JackPortIsPhysical | ma_JackPortIsOutput); if (ppServerPorts == NULL) { ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR); } for (i = 0; ppServerPorts[i] != NULL; ++i) { const char* pServerPort = ppServerPorts[i]; const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsCapture[i]); resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pServerPort, pClientPort); if (resultJACK != 0) { ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR); } } ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, NULL, ma_JackPortIsPhysical | ma_JackPortIsInput); if (ppServerPorts == NULL) { ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR); } for (i = 0; ppServerPorts[i] != NULL; ++i) { const char* pServerPort = ppServerPorts[i]; const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[i]); resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pClientPort, pServerPort); if (resultJACK != 0) { ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR); } } ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); } return MA_SUCCESS; } ma_result ma_device_stop__jack(ma_device* pDevice) { ma_context* pContext = pDevice->pContext; ma_stop_proc onStop; if (((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient) != 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client.", MA_ERROR); } onStop = pDevice->onStop; if (onStop) { onStop(pDevice); } return MA_SUCCESS; } ma_result ma_context_uninit__jack(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_jack); ma_free(pContext->jack.pClientName); pContext->jack.pClientName = NULL; #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->jack.jackSO); #endif return MA_SUCCESS; } ma_result ma_context_init__jack(const ma_context_config* pConfig, ma_context* pContext) { #ifndef MA_NO_RUNTIME_LINKING const char* libjackNames[] = { #ifdef MA_WIN32 "libjack.dll" #else "libjack.so", "libjack.so.0" #endif }; size_t i; for (i = 0; i < ma_countof(libjackNames); ++i) { pContext->jack.jackSO = ma_dlopen(pContext, libjackNames[i]); if (pContext->jack.jackSO != NULL) { break; } } if (pContext->jack.jackSO == NULL) { return MA_NO_BACKEND; } pContext->jack.jack_client_open = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_open"); pContext->jack.jack_client_close = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_close"); pContext->jack.jack_client_name_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_name_size"); pContext->jack.jack_set_process_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_process_callback"); pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_buffer_size_callback"); pContext->jack.jack_on_shutdown = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_on_shutdown"); pContext->jack.jack_get_sample_rate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_sample_rate"); pContext->jack.jack_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_buffer_size"); pContext->jack.jack_get_ports = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_ports"); pContext->jack.jack_activate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_activate"); pContext->jack.jack_deactivate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_deactivate"); pContext->jack.jack_connect = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_connect"); pContext->jack.jack_port_register = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_register"); pContext->jack.jack_port_name = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_name"); pContext->jack.jack_port_get_buffer = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_get_buffer"); pContext->jack.jack_free = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_free"); #else /* This strange assignment system is here just to ensure type safety of miniaudio's function pointer types. If anything differs slightly the compiler should throw a warning. */ ma_jack_client_open_proc _jack_client_open = jack_client_open; ma_jack_client_close_proc _jack_client_close = jack_client_close; ma_jack_client_name_size_proc _jack_client_name_size = jack_client_name_size; ma_jack_set_process_callback_proc _jack_set_process_callback = jack_set_process_callback; ma_jack_set_buffer_size_callback_proc _jack_set_buffer_size_callback = jack_set_buffer_size_callback; ma_jack_on_shutdown_proc _jack_on_shutdown = jack_on_shutdown; ma_jack_get_sample_rate_proc _jack_get_sample_rate = jack_get_sample_rate; ma_jack_get_buffer_size_proc _jack_get_buffer_size = jack_get_buffer_size; ma_jack_get_ports_proc _jack_get_ports = jack_get_ports; ma_jack_activate_proc _jack_activate = jack_activate; ma_jack_deactivate_proc _jack_deactivate = jack_deactivate; ma_jack_connect_proc _jack_connect = jack_connect; ma_jack_port_register_proc _jack_port_register = jack_port_register; ma_jack_port_name_proc _jack_port_name = jack_port_name; ma_jack_port_get_buffer_proc _jack_port_get_buffer = jack_port_get_buffer; ma_jack_free_proc _jack_free = jack_free; pContext->jack.jack_client_open = (ma_proc)_jack_client_open; pContext->jack.jack_client_close = (ma_proc)_jack_client_close; pContext->jack.jack_client_name_size = (ma_proc)_jack_client_name_size; pContext->jack.jack_set_process_callback = (ma_proc)_jack_set_process_callback; pContext->jack.jack_set_buffer_size_callback = (ma_proc)_jack_set_buffer_size_callback; pContext->jack.jack_on_shutdown = (ma_proc)_jack_on_shutdown; pContext->jack.jack_get_sample_rate = (ma_proc)_jack_get_sample_rate; pContext->jack.jack_get_buffer_size = (ma_proc)_jack_get_buffer_size; pContext->jack.jack_get_ports = (ma_proc)_jack_get_ports; pContext->jack.jack_activate = (ma_proc)_jack_activate; pContext->jack.jack_deactivate = (ma_proc)_jack_deactivate; pContext->jack.jack_connect = (ma_proc)_jack_connect; pContext->jack.jack_port_register = (ma_proc)_jack_port_register; pContext->jack.jack_port_name = (ma_proc)_jack_port_name; pContext->jack.jack_port_get_buffer = (ma_proc)_jack_port_get_buffer; pContext->jack.jack_free = (ma_proc)_jack_free; #endif pContext->isBackendAsynchronous = MA_TRUE; pContext->onUninit = ma_context_uninit__jack; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__jack; pContext->onEnumDevices = ma_context_enumerate_devices__jack; pContext->onGetDeviceInfo = ma_context_get_device_info__jack; pContext->onDeviceInit = ma_device_init__jack; pContext->onDeviceUninit = ma_device_uninit__jack; pContext->onDeviceStart = ma_device_start__jack; pContext->onDeviceStop = ma_device_stop__jack; if (pConfig->jack.pClientName != NULL) { pContext->jack.pClientName = ma_copy_string(pConfig->jack.pClientName); } pContext->jack.tryStartServer = pConfig->jack.tryStartServer; /* Getting here means the JACK library is installed, but it doesn't necessarily mean it's usable. We need to quickly test this by connecting a temporary client. */ { ma_jack_client_t* pDummyClient; ma_result result = ma_context_open_client__jack(pContext, &pDummyClient); if (result != MA_SUCCESS) { ma_free(pContext->jack.pClientName); #ifndef MA_NO_RUNTIME_LINKING ma_dlclose(pContext, pContext->jack.jackSO); #endif return MA_NO_BACKEND; } ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDummyClient); } return MA_SUCCESS; } #endif /* JACK */ /****************************************************************************** Core Audio Backend ******************************************************************************/ #ifdef MA_HAS_COREAUDIO #include #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1 #define MA_APPLE_MOBILE #else #define MA_APPLE_DESKTOP #endif #if defined(MA_APPLE_DESKTOP) #include #else #include #endif #include /* CoreFoundation */ typedef Boolean (* ma_CFStringGetCString_proc)(CFStringRef theString, char* buffer, CFIndex bufferSize, CFStringEncoding encoding); /* CoreAudio */ #if defined(MA_APPLE_DESKTOP) typedef OSStatus (* ma_AudioObjectGetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* ioDataSize, void* outData); typedef OSStatus (* ma_AudioObjectGetPropertyDataSize_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize); typedef OSStatus (* ma_AudioObjectSetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData); typedef OSStatus (* ma_AudioObjectAddPropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData); #endif /* AudioToolbox */ typedef AudioComponent (* ma_AudioComponentFindNext_proc)(AudioComponent inComponent, const AudioComponentDescription* inDesc); typedef OSStatus (* ma_AudioComponentInstanceDispose_proc)(AudioComponentInstance inInstance); typedef OSStatus (* ma_AudioComponentInstanceNew_proc)(AudioComponent inComponent, AudioComponentInstance* outInstance); typedef OSStatus (* ma_AudioOutputUnitStart_proc)(AudioUnit inUnit); typedef OSStatus (* ma_AudioOutputUnitStop_proc)(AudioUnit inUnit); typedef OSStatus (* ma_AudioUnitAddPropertyListener_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitPropertyListenerProc inProc, void* inProcUserData); typedef OSStatus (* ma_AudioUnitGetPropertyInfo_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32* outDataSize, Boolean* outWriteable); typedef OSStatus (* ma_AudioUnitGetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData, UInt32* ioDataSize); typedef OSStatus (* ma_AudioUnitSetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize); typedef OSStatus (* ma_AudioUnitInitialize_proc)(AudioUnit inUnit); typedef OSStatus (* ma_AudioUnitRender_proc)(AudioUnit inUnit, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData); #define MA_COREAUDIO_OUTPUT_BUS 0 #define MA_COREAUDIO_INPUT_BUS 1 ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit); /* Core Audio So far, Core Audio has been the worst backend to work with due to being both unintuitive and having almost no documentation apart from comments in the headers (which admittedly are quite good). For my own purposes, and for anybody out there whose needing to figure out how this darn thing works, I'm going to outline a few things here. Since miniaudio is a fairly low-level API, one of the things it needs is control over specific devices, and it needs to be able to identify whether or not it can be used as playback and/or capture. The AudioObject API is the only one I've seen that supports this level of detail. There was some public domain sample code I stumbled across that used the AudioComponent and AudioUnit APIs, but I couldn't see anything that gave low-level control over device selection and capabilities (the distinction between playback and capture in particular). Therefore, miniaudio is using the AudioObject API. Most (all?) functions in the AudioObject API take a AudioObjectID as it's input. This is the device identifier. When retrieving global information, such as the device list, you use kAudioObjectSystemObject. When retrieving device-specific data, you pass in the ID for that device. In order to retrieve device-specific IDs you need to enumerate over each of the devices. This is done using the AudioObjectGetPropertyDataSize() and AudioObjectGetPropertyData() APIs which seem to be the central APIs for retrieving information about the system and specific devices. To use the AudioObjectGetPropertyData() API you need to use the notion of a property address. A property address is a structure with three variables and is used to identify which property you are getting or setting. The first is the "selector" which is basically the specific property that you're wanting to retrieve or set. The second is the "scope", which is typically set to kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyScopeInput for input-specific properties and kAudioObjectPropertyScopeOutput for output-specific properties. The last is the "element" which is always set to kAudioObjectPropertyElementMaster in miniaudio's case. I don't know of any cases where this would be set to anything different. Back to the earlier issue of device retrieval, you first use the AudioObjectGetPropertyDataSize() API to retrieve the size of the raw data which is just a list of AudioDeviceID's. You use the kAudioObjectSystemObject AudioObjectID, and a property address with the kAudioHardwarePropertyDevices selector and the kAudioObjectPropertyScopeGlobal scope. Once you have the size, allocate a block of memory of that size and then call AudioObjectGetPropertyData(). The data is just a list of AudioDeviceID's so just do "dataSize/sizeof(AudioDeviceID)" to know the device count. */ ma_result ma_result_from_OSStatus(OSStatus status) { switch (status) { case noErr: return MA_SUCCESS; #if defined(MA_APPLE_DESKTOP) case kAudioHardwareNotRunningError: return MA_DEVICE_NOT_STARTED; case kAudioHardwareUnspecifiedError: return MA_ERROR; case kAudioHardwareUnknownPropertyError: return MA_INVALID_ARGS; case kAudioHardwareBadPropertySizeError: return MA_INVALID_OPERATION; case kAudioHardwareIllegalOperationError: return MA_INVALID_OPERATION; case kAudioHardwareBadObjectError: return MA_INVALID_ARGS; case kAudioHardwareBadDeviceError: return MA_INVALID_ARGS; case kAudioHardwareBadStreamError: return MA_INVALID_ARGS; case kAudioHardwareUnsupportedOperationError: return MA_INVALID_OPERATION; case kAudioDeviceUnsupportedFormatError: return MA_FORMAT_NOT_SUPPORTED; case kAudioDevicePermissionsError: return MA_ACCESS_DENIED; #endif default: return MA_ERROR; } } #if 0 ma_channel ma_channel_from_AudioChannelBitmap(AudioChannelBitmap bit) { switch (bit) { case kAudioChannelBit_Left: return MA_CHANNEL_LEFT; case kAudioChannelBit_Right: return MA_CHANNEL_RIGHT; case kAudioChannelBit_Center: return MA_CHANNEL_FRONT_CENTER; case kAudioChannelBit_LFEScreen: return MA_CHANNEL_LFE; case kAudioChannelBit_LeftSurround: return MA_CHANNEL_BACK_LEFT; case kAudioChannelBit_RightSurround: return MA_CHANNEL_BACK_RIGHT; case kAudioChannelBit_LeftCenter: return MA_CHANNEL_FRONT_LEFT_CENTER; case kAudioChannelBit_RightCenter: return MA_CHANNEL_FRONT_RIGHT_CENTER; case kAudioChannelBit_CenterSurround: return MA_CHANNEL_BACK_CENTER; case kAudioChannelBit_LeftSurroundDirect: return MA_CHANNEL_SIDE_LEFT; case kAudioChannelBit_RightSurroundDirect: return MA_CHANNEL_SIDE_RIGHT; case kAudioChannelBit_TopCenterSurround: return MA_CHANNEL_TOP_CENTER; case kAudioChannelBit_VerticalHeightLeft: return MA_CHANNEL_TOP_FRONT_LEFT; case kAudioChannelBit_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER; case kAudioChannelBit_VerticalHeightRight: return MA_CHANNEL_TOP_FRONT_RIGHT; case kAudioChannelBit_TopBackLeft: return MA_CHANNEL_TOP_BACK_LEFT; case kAudioChannelBit_TopBackCenter: return MA_CHANNEL_TOP_BACK_CENTER; case kAudioChannelBit_TopBackRight: return MA_CHANNEL_TOP_BACK_RIGHT; default: return MA_CHANNEL_NONE; } } #endif ma_channel ma_channel_from_AudioChannelLabel(AudioChannelLabel label) { switch (label) { case kAudioChannelLabel_Unknown: return MA_CHANNEL_NONE; case kAudioChannelLabel_Unused: return MA_CHANNEL_NONE; case kAudioChannelLabel_UseCoordinates: return MA_CHANNEL_NONE; case kAudioChannelLabel_Left: return MA_CHANNEL_LEFT; case kAudioChannelLabel_Right: return MA_CHANNEL_RIGHT; case kAudioChannelLabel_Center: return MA_CHANNEL_FRONT_CENTER; case kAudioChannelLabel_LFEScreen: return MA_CHANNEL_LFE; case kAudioChannelLabel_LeftSurround: return MA_CHANNEL_BACK_LEFT; case kAudioChannelLabel_RightSurround: return MA_CHANNEL_BACK_RIGHT; case kAudioChannelLabel_LeftCenter: return MA_CHANNEL_FRONT_LEFT_CENTER; case kAudioChannelLabel_RightCenter: return MA_CHANNEL_FRONT_RIGHT_CENTER; case kAudioChannelLabel_CenterSurround: return MA_CHANNEL_BACK_CENTER; case kAudioChannelLabel_LeftSurroundDirect: return MA_CHANNEL_SIDE_LEFT; case kAudioChannelLabel_RightSurroundDirect: return MA_CHANNEL_SIDE_RIGHT; case kAudioChannelLabel_TopCenterSurround: return MA_CHANNEL_TOP_CENTER; case kAudioChannelLabel_VerticalHeightLeft: return MA_CHANNEL_TOP_FRONT_LEFT; case kAudioChannelLabel_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER; case kAudioChannelLabel_VerticalHeightRight: return MA_CHANNEL_TOP_FRONT_RIGHT; case kAudioChannelLabel_TopBackLeft: return MA_CHANNEL_TOP_BACK_LEFT; case kAudioChannelLabel_TopBackCenter: return MA_CHANNEL_TOP_BACK_CENTER; case kAudioChannelLabel_TopBackRight: return MA_CHANNEL_TOP_BACK_RIGHT; case kAudioChannelLabel_RearSurroundLeft: return MA_CHANNEL_BACK_LEFT; case kAudioChannelLabel_RearSurroundRight: return MA_CHANNEL_BACK_RIGHT; case kAudioChannelLabel_LeftWide: return MA_CHANNEL_SIDE_LEFT; case kAudioChannelLabel_RightWide: return MA_CHANNEL_SIDE_RIGHT; case kAudioChannelLabel_LFE2: return MA_CHANNEL_LFE; case kAudioChannelLabel_LeftTotal: return MA_CHANNEL_LEFT; case kAudioChannelLabel_RightTotal: return MA_CHANNEL_RIGHT; case kAudioChannelLabel_HearingImpaired: return MA_CHANNEL_NONE; case kAudioChannelLabel_Narration: return MA_CHANNEL_MONO; case kAudioChannelLabel_Mono: return MA_CHANNEL_MONO; case kAudioChannelLabel_DialogCentricMix: return MA_CHANNEL_MONO; case kAudioChannelLabel_CenterSurroundDirect: return MA_CHANNEL_BACK_CENTER; case kAudioChannelLabel_Haptic: return MA_CHANNEL_NONE; case kAudioChannelLabel_Ambisonic_W: return MA_CHANNEL_NONE; case kAudioChannelLabel_Ambisonic_X: return MA_CHANNEL_NONE; case kAudioChannelLabel_Ambisonic_Y: return MA_CHANNEL_NONE; case kAudioChannelLabel_Ambisonic_Z: return MA_CHANNEL_NONE; case kAudioChannelLabel_MS_Mid: return MA_CHANNEL_LEFT; case kAudioChannelLabel_MS_Side: return MA_CHANNEL_RIGHT; case kAudioChannelLabel_XY_X: return MA_CHANNEL_LEFT; case kAudioChannelLabel_XY_Y: return MA_CHANNEL_RIGHT; case kAudioChannelLabel_HeadphonesLeft: return MA_CHANNEL_LEFT; case kAudioChannelLabel_HeadphonesRight: return MA_CHANNEL_RIGHT; case kAudioChannelLabel_ClickTrack: return MA_CHANNEL_NONE; case kAudioChannelLabel_ForeignLanguage: return MA_CHANNEL_NONE; case kAudioChannelLabel_Discrete: return MA_CHANNEL_NONE; case kAudioChannelLabel_Discrete_0: return MA_CHANNEL_AUX_0; case kAudioChannelLabel_Discrete_1: return MA_CHANNEL_AUX_1; case kAudioChannelLabel_Discrete_2: return MA_CHANNEL_AUX_2; case kAudioChannelLabel_Discrete_3: return MA_CHANNEL_AUX_3; case kAudioChannelLabel_Discrete_4: return MA_CHANNEL_AUX_4; case kAudioChannelLabel_Discrete_5: return MA_CHANNEL_AUX_5; case kAudioChannelLabel_Discrete_6: return MA_CHANNEL_AUX_6; case kAudioChannelLabel_Discrete_7: return MA_CHANNEL_AUX_7; case kAudioChannelLabel_Discrete_8: return MA_CHANNEL_AUX_8; case kAudioChannelLabel_Discrete_9: return MA_CHANNEL_AUX_9; case kAudioChannelLabel_Discrete_10: return MA_CHANNEL_AUX_10; case kAudioChannelLabel_Discrete_11: return MA_CHANNEL_AUX_11; case kAudioChannelLabel_Discrete_12: return MA_CHANNEL_AUX_12; case kAudioChannelLabel_Discrete_13: return MA_CHANNEL_AUX_13; case kAudioChannelLabel_Discrete_14: return MA_CHANNEL_AUX_14; case kAudioChannelLabel_Discrete_15: return MA_CHANNEL_AUX_15; case kAudioChannelLabel_Discrete_65535: return MA_CHANNEL_NONE; #if 0 /* Introduced in a later version of macOS. */ case kAudioChannelLabel_HOA_ACN: return MA_CHANNEL_NONE; case kAudioChannelLabel_HOA_ACN_0: return MA_CHANNEL_AUX_0; case kAudioChannelLabel_HOA_ACN_1: return MA_CHANNEL_AUX_1; case kAudioChannelLabel_HOA_ACN_2: return MA_CHANNEL_AUX_2; case kAudioChannelLabel_HOA_ACN_3: return MA_CHANNEL_AUX_3; case kAudioChannelLabel_HOA_ACN_4: return MA_CHANNEL_AUX_4; case kAudioChannelLabel_HOA_ACN_5: return MA_CHANNEL_AUX_5; case kAudioChannelLabel_HOA_ACN_6: return MA_CHANNEL_AUX_6; case kAudioChannelLabel_HOA_ACN_7: return MA_CHANNEL_AUX_7; case kAudioChannelLabel_HOA_ACN_8: return MA_CHANNEL_AUX_8; case kAudioChannelLabel_HOA_ACN_9: return MA_CHANNEL_AUX_9; case kAudioChannelLabel_HOA_ACN_10: return MA_CHANNEL_AUX_10; case kAudioChannelLabel_HOA_ACN_11: return MA_CHANNEL_AUX_11; case kAudioChannelLabel_HOA_ACN_12: return MA_CHANNEL_AUX_12; case kAudioChannelLabel_HOA_ACN_13: return MA_CHANNEL_AUX_13; case kAudioChannelLabel_HOA_ACN_14: return MA_CHANNEL_AUX_14; case kAudioChannelLabel_HOA_ACN_15: return MA_CHANNEL_AUX_15; case kAudioChannelLabel_HOA_ACN_65024: return MA_CHANNEL_NONE; #endif default: return MA_CHANNEL_NONE; } } ma_result ma_format_from_AudioStreamBasicDescription(const AudioStreamBasicDescription* pDescription, ma_format* pFormatOut) { ma_assert(pDescription != NULL); ma_assert(pFormatOut != NULL); *pFormatOut = ma_format_unknown; /* Safety. */ /* There's a few things miniaudio doesn't support. */ if (pDescription->mFormatID != kAudioFormatLinearPCM) { return MA_FORMAT_NOT_SUPPORTED; } /* We don't support any non-packed formats that are aligned high. */ if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) != 0) { return MA_FORMAT_NOT_SUPPORTED; } /* Only supporting native-endian. */ if ((ma_is_little_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) || (ma_is_big_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) == 0)) { return MA_FORMAT_NOT_SUPPORTED; } /* We are not currently supporting non-interleaved formats (this will be added in a future version of miniaudio). */ /*if ((pDescription->mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) { return MA_FORMAT_NOT_SUPPORTED; }*/ if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) { if (pDescription->mBitsPerChannel == 32) { *pFormatOut = ma_format_f32; return MA_SUCCESS; } } else { if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) != 0) { if (pDescription->mBitsPerChannel == 16) { *pFormatOut = ma_format_s16; return MA_SUCCESS; } else if (pDescription->mBitsPerChannel == 24) { if (pDescription->mBytesPerFrame == (pDescription->mBitsPerChannel/8 * pDescription->mChannelsPerFrame)) { *pFormatOut = ma_format_s24; return MA_SUCCESS; } else { if (pDescription->mBytesPerFrame/pDescription->mChannelsPerFrame == sizeof(ma_int32)) { /* TODO: Implement ma_format_s24_32. */ /**pFormatOut = ma_format_s24_32;*/ /*return MA_SUCCESS;*/ return MA_FORMAT_NOT_SUPPORTED; } } } else if (pDescription->mBitsPerChannel == 32) { *pFormatOut = ma_format_s32; return MA_SUCCESS; } } else { if (pDescription->mBitsPerChannel == 8) { *pFormatOut = ma_format_u8; return MA_SUCCESS; } } } /* Getting here means the format is not supported. */ return MA_FORMAT_NOT_SUPPORTED; } ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* pChannelLayout, ma_channel channelMap[MA_MAX_CHANNELS]) { ma_assert(pChannelLayout != NULL); if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) { UInt32 iChannel; for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions; ++iChannel) { channelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel); } } else #if 0 if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) { /* This is the same kind of system that's used by Windows audio APIs. */ UInt32 iChannel = 0; UInt32 iBit; AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap; for (iBit = 0; iBit < 32; ++iBit) { AudioChannelBitmap bit = bitmap & (1 << iBit); if (bit != 0) { channelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit); } } } else #endif { /* Need to use the tag to determine the channel map. For now I'm just assuming a default channel map, but later on this should be updated to determine the mapping based on the tag. */ UInt32 channelCount = AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag); switch (pChannelLayout->mChannelLayoutTag) { case kAudioChannelLayoutTag_Mono: case kAudioChannelLayoutTag_Stereo: case kAudioChannelLayoutTag_StereoHeadphones: case kAudioChannelLayoutTag_MatrixStereo: case kAudioChannelLayoutTag_MidSide: case kAudioChannelLayoutTag_XY: case kAudioChannelLayoutTag_Binaural: case kAudioChannelLayoutTag_Ambisonic_B_Format: { ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, channelMap); } break; case kAudioChannelLayoutTag_Octagonal: { channelMap[7] = MA_CHANNEL_SIDE_RIGHT; channelMap[6] = MA_CHANNEL_SIDE_LEFT; } /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Hexagonal: { channelMap[5] = MA_CHANNEL_BACK_CENTER; } /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Pentagonal: { channelMap[4] = MA_CHANNEL_FRONT_CENTER; } /* Intentional fallghrough. */ case kAudioChannelLayoutTag_Quadraphonic: { channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[1] = MA_CHANNEL_RIGHT; channelMap[0] = MA_CHANNEL_LEFT; } break; /* TODO: Add support for more tags here. */ default: { ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, channelMap); } break; } } return MA_SUCCESS; } #if defined(MA_APPLE_DESKTOP) ma_result ma_get_device_object_ids__coreaudio(ma_context* pContext, UInt32* pDeviceCount, AudioObjectID** ppDeviceObjectIDs) /* NOTE: Free the returned buffer with ma_free(). */ { AudioObjectPropertyAddress propAddressDevices; UInt32 deviceObjectsDataSize; OSStatus status; AudioObjectID* pDeviceObjectIDs; ma_assert(pContext != NULL); ma_assert(pDeviceCount != NULL); ma_assert(ppDeviceObjectIDs != NULL); /* Safety. */ *pDeviceCount = 0; *ppDeviceObjectIDs = NULL; propAddressDevices.mSelector = kAudioHardwarePropertyDevices; propAddressDevices.mScope = kAudioObjectPropertyScopeGlobal; propAddressDevices.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize); if (status != noErr) { return ma_result_from_OSStatus(status); } pDeviceObjectIDs = (AudioObjectID*)ma_malloc(deviceObjectsDataSize); if (pDeviceObjectIDs == NULL) { return MA_OUT_OF_MEMORY; } status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize, pDeviceObjectIDs); if (status != noErr) { ma_free(pDeviceObjectIDs); return ma_result_from_OSStatus(status); } *pDeviceCount = deviceObjectsDataSize / sizeof(AudioObjectID); *ppDeviceObjectIDs = pDeviceObjectIDs; (void)pContext; /* Unused. */ return MA_SUCCESS; } ma_result ma_get_AudioObject_uid_as_CFStringRef(ma_context* pContext, AudioObjectID objectID, CFStringRef* pUID) { AudioObjectPropertyAddress propAddress; UInt32 dataSize; OSStatus status; ma_assert(pContext != NULL); propAddress.mSelector = kAudioDevicePropertyDeviceUID; propAddress.mScope = kAudioObjectPropertyScopeGlobal; propAddress.mElement = kAudioObjectPropertyElementMaster; dataSize = sizeof(*pUID); status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, pUID); if (status != noErr) { return ma_result_from_OSStatus(status); } return MA_SUCCESS; } ma_result ma_get_AudioObject_uid(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut) { CFStringRef uid; ma_result result; ma_assert(pContext != NULL); result = ma_get_AudioObject_uid_as_CFStringRef(pContext, objectID, &uid); if (result != MA_SUCCESS) { return result; } if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(uid, bufferOut, bufferSize, kCFStringEncodingUTF8)) { return MA_ERROR; } return MA_SUCCESS; } ma_result ma_get_AudioObject_name(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut) { AudioObjectPropertyAddress propAddress; CFStringRef deviceName = NULL; UInt32 dataSize; OSStatus status; ma_assert(pContext != NULL); propAddress.mSelector = kAudioDevicePropertyDeviceNameCFString; propAddress.mScope = kAudioObjectPropertyScopeGlobal; propAddress.mElement = kAudioObjectPropertyElementMaster; dataSize = sizeof(deviceName); status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, &deviceName); if (status != noErr) { return ma_result_from_OSStatus(status); } if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(deviceName, bufferOut, bufferSize, kCFStringEncodingUTF8)) { return MA_ERROR; } return MA_SUCCESS; } ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioObjectID deviceObjectID, AudioObjectPropertyScope scope) { AudioObjectPropertyAddress propAddress; UInt32 dataSize; OSStatus status; AudioBufferList* pBufferList; ma_bool32 isSupported; ma_assert(pContext != NULL); /* To know whether or not a device is an input device we need ot look at the stream configuration. If it has an output channel it's a playback device. */ propAddress.mSelector = kAudioDevicePropertyStreamConfiguration; propAddress.mScope = scope; propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); if (status != noErr) { return MA_FALSE; } pBufferList = (AudioBufferList*)ma_malloc(dataSize); if (pBufferList == NULL) { return MA_FALSE; /* Out of memory. */ } status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pBufferList); if (status != noErr) { ma_free(pBufferList); return MA_FALSE; } isSupported = MA_FALSE; if (pBufferList->mNumberBuffers > 0) { isSupported = MA_TRUE; } ma_free(pBufferList); return isSupported; } ma_bool32 ma_does_AudioObject_support_playback(ma_context* pContext, AudioObjectID deviceObjectID) { return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeOutput); } ma_bool32 ma_does_AudioObject_support_capture(ma_context* pContext, AudioObjectID deviceObjectID) { return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeInput); } ma_result ma_get_AudioObject_stream_descriptions(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, UInt32* pDescriptionCount, AudioStreamRangedDescription** ppDescriptions) /* NOTE: Free the returned pointer with ma_free(). */ { AudioObjectPropertyAddress propAddress; UInt32 dataSize; OSStatus status; AudioStreamRangedDescription* pDescriptions; ma_assert(pContext != NULL); ma_assert(pDescriptionCount != NULL); ma_assert(ppDescriptions != NULL); /* TODO: Experiment with kAudioStreamPropertyAvailablePhysicalFormats instead of (or in addition to) kAudioStreamPropertyAvailableVirtualFormats. My MacBook Pro uses s24/32 format, however, which miniaudio does not currently support. */ propAddress.mSelector = kAudioStreamPropertyAvailableVirtualFormats; /*kAudioStreamPropertyAvailablePhysicalFormats;*/ propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); if (status != noErr) { return ma_result_from_OSStatus(status); } pDescriptions = (AudioStreamRangedDescription*)ma_malloc(dataSize); if (pDescriptions == NULL) { return MA_OUT_OF_MEMORY; } status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pDescriptions); if (status != noErr) { ma_free(pDescriptions); return ma_result_from_OSStatus(status); } *pDescriptionCount = dataSize / sizeof(*pDescriptions); *ppDescriptions = pDescriptions; return MA_SUCCESS; } ma_result ma_get_AudioObject_channel_layout(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, AudioChannelLayout** ppChannelLayout) /* NOTE: Free the returned pointer with ma_free(). */ { AudioObjectPropertyAddress propAddress; UInt32 dataSize; OSStatus status; AudioChannelLayout* pChannelLayout; ma_assert(pContext != NULL); ma_assert(ppChannelLayout != NULL); *ppChannelLayout = NULL; /* Safety. */ propAddress.mSelector = kAudioDevicePropertyPreferredChannelLayout; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); if (status != noErr) { return ma_result_from_OSStatus(status); } pChannelLayout = (AudioChannelLayout*)ma_malloc(dataSize); if (pChannelLayout == NULL) { return MA_OUT_OF_MEMORY; } status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pChannelLayout); if (status != noErr) { ma_free(pChannelLayout); return ma_result_from_OSStatus(status); } *ppChannelLayout = pChannelLayout; return MA_SUCCESS; } ma_result ma_get_AudioObject_channel_count(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pChannelCount) { AudioChannelLayout* pChannelLayout; ma_result result; ma_assert(pContext != NULL); ma_assert(pChannelCount != NULL); *pChannelCount = 0; /* Safety. */ result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout); if (result != MA_SUCCESS) { return result; } if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) { *pChannelCount = pChannelLayout->mNumberChannelDescriptions; } else if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) { *pChannelCount = ma_count_set_bits(pChannelLayout->mChannelBitmap); } else { *pChannelCount = AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag); } ma_free(pChannelLayout); return MA_SUCCESS; } ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_channel channelMap[MA_MAX_CHANNELS]) { AudioChannelLayout* pChannelLayout; ma_result result; ma_assert(pContext != NULL); result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout); if (result != MA_SUCCESS) { return result; /* Rather than always failing here, would it be more robust to simply assume a default? */ } result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, channelMap); if (result != MA_SUCCESS) { ma_free(pChannelLayout); return result; } ma_free(pChannelLayout); return result; } ma_result ma_get_AudioObject_sample_rates(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, UInt32* pSampleRateRangesCount, AudioValueRange** ppSampleRateRanges) /* NOTE: Free the returned pointer with ma_free(). */ { AudioObjectPropertyAddress propAddress; UInt32 dataSize; OSStatus status; AudioValueRange* pSampleRateRanges; ma_assert(pContext != NULL); ma_assert(pSampleRateRangesCount != NULL); ma_assert(ppSampleRateRanges != NULL); /* Safety. */ *pSampleRateRangesCount = 0; *ppSampleRateRanges = NULL; propAddress.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; propAddress.mElement = kAudioObjectPropertyElementMaster; status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); if (status != noErr) { return ma_result_from_OSStatus(status); } pSampleRateRanges = (AudioValueRange*)ma_malloc(dataSize); if (pSampleRateRanges == NULL) { return MA_OUT_OF_MEMORY; } status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pSampleRateRanges); if (status != noErr) { ma_free(pSampleRateRanges); return ma_result_from_OSStatus(status); } *pSampleRateRangesCount = dataSize / sizeof(*pSampleRateRanges); *ppSampleRateRanges = pSampleRateRanges; return MA_SUCCESS; } ma_result ma_get_AudioObject_get_closest_sample_rate(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32 sampleRateIn, ma_uint32* pSampleRateOut) { UInt32 sampleRateRangeCount; AudioValueRange* pSampleRateRanges; ma_result result; ma_assert(pContext != NULL); ma_assert(pSampleRateOut != NULL); *pSampleRateOut = 0; /* Safety. */ result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges); if (result != MA_SUCCESS) { return result; } if (sampleRateRangeCount == 0) { ma_free(pSampleRateRanges); return MA_ERROR; /* Should never hit this case should we? */ } if (sampleRateIn == 0) { /* Search in order of miniaudio's preferred priority. */ UInt32 iMALSampleRate; for (iMALSampleRate = 0; iMALSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iMALSampleRate) { ma_uint32 malSampleRate = g_maStandardSampleRatePriorities[iMALSampleRate]; UInt32 iCASampleRate; for (iCASampleRate = 0; iCASampleRate < sampleRateRangeCount; ++iCASampleRate) { AudioValueRange caSampleRate = pSampleRateRanges[iCASampleRate]; if (caSampleRate.mMinimum <= malSampleRate && caSampleRate.mMaximum >= malSampleRate) { *pSampleRateOut = malSampleRate; ma_free(pSampleRateRanges); return MA_SUCCESS; } } } /* If we get here it means none of miniaudio's standard sample rates matched any of the supported sample rates from the device. In this case we just fall back to the first one reported by Core Audio. */ ma_assert(sampleRateRangeCount > 0); *pSampleRateOut = pSampleRateRanges[0].mMinimum; ma_free(pSampleRateRanges); return MA_SUCCESS; } else { /* Find the closest match to this sample rate. */ UInt32 currentAbsoluteDifference = INT32_MAX; UInt32 iCurrentClosestRange = (UInt32)-1; UInt32 iRange; for (iRange = 0; iRange < sampleRateRangeCount; ++iRange) { if (pSampleRateRanges[iRange].mMinimum <= sampleRateIn && pSampleRateRanges[iRange].mMaximum >= sampleRateIn) { *pSampleRateOut = sampleRateIn; ma_free(pSampleRateRanges); return MA_SUCCESS; } else { UInt32 absoluteDifference; if (pSampleRateRanges[iRange].mMinimum > sampleRateIn) { absoluteDifference = pSampleRateRanges[iRange].mMinimum - sampleRateIn; } else { absoluteDifference = sampleRateIn - pSampleRateRanges[iRange].mMaximum; } if (currentAbsoluteDifference > absoluteDifference) { currentAbsoluteDifference = absoluteDifference; iCurrentClosestRange = iRange; } } } ma_assert(iCurrentClosestRange != (UInt32)-1); *pSampleRateOut = pSampleRateRanges[iCurrentClosestRange].mMinimum; ma_free(pSampleRateRanges); return MA_SUCCESS; } /* Should never get here, but it would mean we weren't able to find any suitable sample rates. */ /*ma_free(pSampleRateRanges);*/ /*return MA_ERROR;*/ } ma_result ma_get_AudioObject_closest_buffer_size_in_frames(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32 bufferSizeInFramesIn, ma_uint32* pBufferSizeInFramesOut) { AudioObjectPropertyAddress propAddress; AudioValueRange bufferSizeRange; UInt32 dataSize; OSStatus status; ma_assert(pContext != NULL); ma_assert(pBufferSizeInFramesOut != NULL); *pBufferSizeInFramesOut = 0; /* Safety. */ propAddress.mSelector = kAudioDevicePropertyBufferFrameSizeRange; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; propAddress.mElement = kAudioObjectPropertyElementMaster; dataSize = sizeof(bufferSizeRange); status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &bufferSizeRange); if (status != noErr) { return ma_result_from_OSStatus(status); } /* This is just a clamp. */ if (bufferSizeInFramesIn < bufferSizeRange.mMinimum) { *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMinimum; } else if (bufferSizeInFramesIn > bufferSizeRange.mMaximum) { *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMaximum; } else { *pBufferSizeInFramesOut = bufferSizeInFramesIn; } return MA_SUCCESS; } ma_result ma_set_AudioObject_buffer_size_in_frames(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pBufferSizeInOut) { ma_result result; ma_uint32 chosenBufferSizeInFrames; AudioObjectPropertyAddress propAddress; UInt32 dataSize; OSStatus status; ma_assert(pContext != NULL); result = ma_get_AudioObject_closest_buffer_size_in_frames(pContext, deviceObjectID, deviceType, *pBufferSizeInOut, &chosenBufferSizeInFrames); if (result != MA_SUCCESS) { return result; } /* Try setting the size of the buffer... If this fails we just use whatever is currently set. */ propAddress.mSelector = kAudioDevicePropertyBufferFrameSize; propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; propAddress.mElement = kAudioObjectPropertyElementMaster; ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(chosenBufferSizeInFrames), &chosenBufferSizeInFrames); /* Get the actual size of the buffer. */ dataSize = sizeof(*pBufferSizeInOut); status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &chosenBufferSizeInFrames); if (status != noErr) { return ma_result_from_OSStatus(status); } *pBufferSizeInOut = chosenBufferSizeInFrames; return MA_SUCCESS; } ma_result ma_find_AudioObjectID(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, AudioObjectID* pDeviceObjectID) { ma_assert(pContext != NULL); ma_assert(pDeviceObjectID != NULL); /* Safety. */ *pDeviceObjectID = 0; if (pDeviceID == NULL) { /* Default device. */ AudioObjectPropertyAddress propAddressDefaultDevice; UInt32 defaultDeviceObjectIDSize = sizeof(AudioObjectID); AudioObjectID defaultDeviceObjectID; OSStatus status; propAddressDefaultDevice.mScope = kAudioObjectPropertyScopeGlobal; propAddressDefaultDevice.mElement = kAudioObjectPropertyElementMaster; if (deviceType == ma_device_type_playback) { propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultOutputDevice; } else { propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultInputDevice; } defaultDeviceObjectIDSize = sizeof(AudioObjectID); status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDefaultDevice, 0, NULL, &defaultDeviceObjectIDSize, &defaultDeviceObjectID); if (status == noErr) { *pDeviceObjectID = defaultDeviceObjectID; return MA_SUCCESS; } } else { /* Explicit device. */ UInt32 deviceCount; AudioObjectID* pDeviceObjectIDs; ma_result result; UInt32 iDevice; result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs); if (result != MA_SUCCESS) { return result; } for (iDevice = 0; iDevice < deviceCount; ++iDevice) { AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice]; char uid[256]; if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(uid), uid) != MA_SUCCESS) { continue; } if (deviceType == ma_device_type_playback) { if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) { if (strcmp(uid, pDeviceID->coreaudio) == 0) { *pDeviceObjectID = deviceObjectID; return MA_SUCCESS; } } } else { if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) { if (strcmp(uid, pDeviceID->coreaudio) == 0) { *pDeviceObjectID = deviceObjectID; return MA_SUCCESS; } } } } } /* If we get here it means we couldn't find the device. */ return MA_NO_DEVICE; } ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_bool32 usingDefaultFormat, ma_bool32 usingDefaultChannels, ma_bool32 usingDefaultSampleRate, AudioStreamBasicDescription* pFormat) { UInt32 deviceFormatDescriptionCount; AudioStreamRangedDescription* pDeviceFormatDescriptions; ma_result result; ma_uint32 desiredSampleRate; ma_uint32 desiredChannelCount; ma_format desiredFormat; AudioStreamBasicDescription bestDeviceFormatSoFar; ma_bool32 hasSupportedFormat; UInt32 iFormat; result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &deviceFormatDescriptionCount, &pDeviceFormatDescriptions); if (result != MA_SUCCESS) { return result; } desiredSampleRate = sampleRate; if (usingDefaultSampleRate) { /* When using the device's default sample rate, we get the highest priority standard rate supported by the device. Otherwise we just use the pre-set rate. */ ma_uint32 iStandardRate; for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) { ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate]; ma_bool32 foundRate = MA_FALSE; UInt32 iDeviceRate; for (iDeviceRate = 0; iDeviceRate < deviceFormatDescriptionCount; ++iDeviceRate) { ma_uint32 deviceRate = (ma_uint32)pDeviceFormatDescriptions[iDeviceRate].mFormat.mSampleRate; if (deviceRate == standardRate) { desiredSampleRate = standardRate; foundRate = MA_TRUE; break; } } if (foundRate) { break; } } } desiredChannelCount = channels; if (usingDefaultChannels) { ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &desiredChannelCount); /* <-- Not critical if this fails. */ } desiredFormat = format; if (usingDefaultFormat) { desiredFormat = g_maFormatPriorities[0]; } /* If we get here it means we don't have an exact match to what the client is asking for. We'll need to find the closest one. The next loop will check for formats that have the same sample rate to what we're asking for. If there is, we prefer that one in all cases. */ ma_zero_object(&bestDeviceFormatSoFar); hasSupportedFormat = MA_FALSE; for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) { ma_format format; ma_result formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &format); if (formatResult == MA_SUCCESS && format != ma_format_unknown) { hasSupportedFormat = MA_TRUE; bestDeviceFormatSoFar = pDeviceFormatDescriptions[iFormat].mFormat; break; } } if (!hasSupportedFormat) { return MA_FORMAT_NOT_SUPPORTED; } for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) { AudioStreamBasicDescription thisDeviceFormat = pDeviceFormatDescriptions[iFormat].mFormat; ma_format thisSampleFormat; ma_result formatResult; ma_format bestSampleFormatSoFar; /* If the format is not supported by miniaudio we need to skip this one entirely. */ formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &thisSampleFormat); if (formatResult != MA_SUCCESS || thisSampleFormat == ma_format_unknown) { continue; /* The format is not supported by miniaudio. Skip. */ } ma_format_from_AudioStreamBasicDescription(&bestDeviceFormatSoFar, &bestSampleFormatSoFar); /* Getting here means the format is supported by miniaudio which makes this format a candidate. */ if (thisDeviceFormat.mSampleRate != desiredSampleRate) { /* The sample rate does not match, but this format could still be usable, although it's a very low priority. If the best format so far has an equal sample rate we can just ignore this one. */ if (bestDeviceFormatSoFar.mSampleRate == desiredSampleRate) { continue; /* The best sample rate so far has the same sample rate as what we requested which means it's still the best so far. Skip this format. */ } else { /* In this case, neither the best format so far nor this one have the same sample rate. Check the channel count next. */ if (thisDeviceFormat.mChannelsPerFrame != desiredChannelCount) { /* This format has a different sample rate _and_ a different channel count. */ if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) { continue; /* No change to the best format. */ } else { /* Both this format and the best so far have different sample rates and different channel counts. Whichever has the best format is the new best. */ if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) { bestDeviceFormatSoFar = thisDeviceFormat; continue; } else { continue; /* No change to the best format. */ } } } else { /* This format has a different sample rate but the desired channel count. */ if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) { /* Both this format and the best so far have the desired channel count. Whichever has the best format is the new best. */ if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) { bestDeviceFormatSoFar = thisDeviceFormat; continue; } else { continue; /* No change to the best format for now. */ } } else { /* This format has the desired channel count, but the best so far does not. We have a new best. */ bestDeviceFormatSoFar = thisDeviceFormat; continue; } } } } else { /* The sample rates match which makes this format a very high priority contender. If the best format so far has a different sample rate it needs to be replaced with this one. */ if (bestDeviceFormatSoFar.mSampleRate != desiredSampleRate) { bestDeviceFormatSoFar = thisDeviceFormat; continue; } else { /* In this case both this format and the best format so far have the same sample rate. Check the channel count next. */ if (thisDeviceFormat.mChannelsPerFrame == desiredChannelCount) { /* In this case this format has the same channel count as what the client is requesting. If the best format so far has a different count, this one becomes the new best. */ if (bestDeviceFormatSoFar.mChannelsPerFrame != desiredChannelCount) { bestDeviceFormatSoFar = thisDeviceFormat; continue; } else { /* In this case both this format and the best so far have the ideal sample rate and channel count. Check the format. */ if (thisSampleFormat == desiredFormat) { bestDeviceFormatSoFar = thisDeviceFormat; break; /* Found the exact match. */ } else { /* The formats are different. The new best format is the one with the highest priority format according to miniaudio. */ if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) { bestDeviceFormatSoFar = thisDeviceFormat; continue; } else { continue; /* No change to the best format for now. */ } } } } else { /* In this case the channel count is different to what the client has requested. If the best so far has the same channel count as the requested count then it remains the best. */ if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) { continue; } else { /* This is the case where both have the same sample rate (good) but different channel counts. Right now both have about the same priority, but we need to compare the format now. */ if (thisSampleFormat == bestSampleFormatSoFar) { if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) { bestDeviceFormatSoFar = thisDeviceFormat; continue; } else { continue; /* No change to the best format for now. */ } } } } } } } *pFormat = bestDeviceFormatSoFar; return MA_SUCCESS; } #endif ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit audioUnit, ma_device_type deviceType, ma_channel channelMap[MA_MAX_CHANNELS]) { AudioUnitScope deviceScope; AudioUnitElement deviceBus; UInt32 channelLayoutSize; OSStatus status; AudioChannelLayout* pChannelLayout; ma_result result; ma_assert(pContext != NULL); if (deviceType == ma_device_type_playback) { deviceScope = kAudioUnitScope_Output; deviceBus = MA_COREAUDIO_OUTPUT_BUS; } else { deviceScope = kAudioUnitScope_Input; deviceBus = MA_COREAUDIO_INPUT_BUS; } status = ((ma_AudioUnitGetPropertyInfo_proc)pContext->coreaudio.AudioUnitGetPropertyInfo)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, &channelLayoutSize, NULL); if (status != noErr) { return ma_result_from_OSStatus(status); } pChannelLayout = (AudioChannelLayout*)ma_malloc(channelLayoutSize); if (pChannelLayout == NULL) { return MA_OUT_OF_MEMORY; } status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, pChannelLayout, &channelLayoutSize); if (status != noErr) { ma_free(pChannelLayout); return ma_result_from_OSStatus(status); } result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, channelMap); if (result != MA_SUCCESS) { ma_free(pChannelLayout); return result; } ma_free(pChannelLayout); return MA_SUCCESS; } ma_bool32 ma_context_is_device_id_equal__coreaudio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return strcmp(pID0->coreaudio, pID1->coreaudio) == 0; } ma_result ma_context_enumerate_devices__coreaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { #if defined(MA_APPLE_DESKTOP) UInt32 deviceCount; AudioObjectID* pDeviceObjectIDs; ma_result result; UInt32 iDevice; result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs); if (result != MA_SUCCESS) { return result; } for (iDevice = 0; iDevice < deviceCount; ++iDevice) { AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice]; ma_device_info info; ma_zero_object(&info); if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(info.id.coreaudio), info.id.coreaudio) != MA_SUCCESS) { continue; } if (ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(info.name), info.name) != MA_SUCCESS) { continue; } if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) { if (!callback(pContext, ma_device_type_playback, &info, pUserData)) { break; } } if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) { if (!callback(pContext, ma_device_type_capture, &info, pUserData)) { break; } } } ma_free(pDeviceObjectIDs); #else /* Only supporting default devices on non-Desktop platforms. */ ma_device_info info; ma_zero_object(&info); ma_strncpy_s(info.name, sizeof(info.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); if (!callback(pContext, ma_device_type_playback, &info, pUserData)) { return MA_SUCCESS; } ma_zero_object(&info); ma_strncpy_s(info.name, sizeof(info.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); if (!callback(pContext, ma_device_type_capture, &info, pUserData)) { return MA_SUCCESS; } #endif return MA_SUCCESS; } ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_result result; ma_assert(pContext != NULL); /* No exclusive mode with the Core Audio backend for now. */ if (shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } #if defined(MA_APPLE_DESKTOP) /* Desktop */ { AudioObjectID deviceObjectID; UInt32 streamDescriptionCount; AudioStreamRangedDescription* pStreamDescriptions; UInt32 iStreamDescription; UInt32 sampleRateRangeCount; AudioValueRange* pSampleRateRanges; result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID); if (result != MA_SUCCESS) { return result; } result = ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(pDeviceInfo->id.coreaudio), pDeviceInfo->id.coreaudio); if (result != MA_SUCCESS) { return result; } result = ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pDeviceInfo->name), pDeviceInfo->name); if (result != MA_SUCCESS) { return result; } /* Formats. */ result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &streamDescriptionCount, &pStreamDescriptions); if (result != MA_SUCCESS) { return result; } for (iStreamDescription = 0; iStreamDescription < streamDescriptionCount; ++iStreamDescription) { ma_format format; ma_bool32 formatExists = MA_FALSE; ma_uint32 iOutputFormat; result = ma_format_from_AudioStreamBasicDescription(&pStreamDescriptions[iStreamDescription].mFormat, &format); if (result != MA_SUCCESS) { continue; } ma_assert(format != ma_format_unknown); /* Make sure the format isn't already in the output list. */ for (iOutputFormat = 0; iOutputFormat < pDeviceInfo->formatCount; ++iOutputFormat) { if (pDeviceInfo->formats[iOutputFormat] == format) { formatExists = MA_TRUE; break; } } if (!formatExists) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = format; } } ma_free(pStreamDescriptions); /* Channels. */ result = ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &pDeviceInfo->minChannels); if (result != MA_SUCCESS) { return result; } pDeviceInfo->maxChannels = pDeviceInfo->minChannels; /* Sample rates. */ result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges); if (result != MA_SUCCESS) { return result; } if (sampleRateRangeCount > 0) { UInt32 iSampleRate; pDeviceInfo->minSampleRate = UINT32_MAX; pDeviceInfo->maxSampleRate = 0; for (iSampleRate = 0; iSampleRate < sampleRateRangeCount; ++iSampleRate) { if (pDeviceInfo->minSampleRate > pSampleRateRanges[iSampleRate].mMinimum) { pDeviceInfo->minSampleRate = pSampleRateRanges[iSampleRate].mMinimum; } if (pDeviceInfo->maxSampleRate < pSampleRateRanges[iSampleRate].mMaximum) { pDeviceInfo->maxSampleRate = pSampleRateRanges[iSampleRate].mMaximum; } } } } #else /* Mobile */ { AudioComponentDescription desc; AudioComponent component; AudioUnit audioUnit; OSStatus status; AudioUnitScope formatScope; AudioUnitElement formatElement; AudioStreamBasicDescription bestFormat; UInt32 propSize; if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } /* Retrieving device information is more annoying on mobile than desktop. For simplicity I'm locking this down to whatever format is reported on a temporary I/O unit. The problem, however, is that this doesn't return a value for the sample rate which we need to retrieve from the AVAudioSession shared instance. */ desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_RemoteIO; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc); if (component == NULL) { return MA_FAILED_TO_INIT_BACKEND; } status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)(component, &audioUnit); if (status != noErr) { return ma_result_from_OSStatus(status); } formatScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output; formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS; propSize = sizeof(bestFormat); status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit); return ma_result_from_OSStatus(status); } ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit); audioUnit = NULL; pDeviceInfo->minChannels = bestFormat.mChannelsPerFrame; pDeviceInfo->maxChannels = bestFormat.mChannelsPerFrame; pDeviceInfo->formatCount = 1; result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->formats[0]); if (result != MA_SUCCESS) { return result; } /* It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do this we just get the shared instance and inspect. */ @autoreleasepool { AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; ma_assert(pAudioSession != NULL); pDeviceInfo->minSampleRate = (ma_uint32)pAudioSession.sampleRate; pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate; } } #endif (void)pDeviceInfo; /* Unused. */ return MA_SUCCESS; } void ma_device_uninit__coreaudio(ma_device* pDevice) { ma_assert(pDevice != NULL); ma_assert(ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED); if (pDevice->coreaudio.audioUnitCapture != NULL) { ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); } if (pDevice->coreaudio.audioUnitPlayback != NULL) { ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); } if (pDevice->coreaudio.pAudioBufferList) { ma_free(pDevice->coreaudio.pAudioBufferList); } if (pDevice->type == ma_device_type_duplex) { ma_pcm_rb_uninit(&pDevice->coreaudio.duplexRB); } } OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufferList) { ma_device* pDevice = (ma_device*)pUserData; ma_stream_layout layout; ma_assert(pDevice != NULL); #if defined(MA_DEBUG_OUTPUT) printf("INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pBufferList->mNumberBuffers); #endif /* We need to check whether or not we are outputting interleaved or non-interleaved samples. The way we do this is slightly different for each type. */ layout = ma_stream_layout_interleaved; if (pBufferList->mBuffers[0].mNumberChannels != pDevice->playback.internalChannels) { layout = ma_stream_layout_deinterleaved; } if (layout == ma_stream_layout_interleaved) { /* For now we can assume everything is interleaved. */ UInt32 iBuffer; for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) { if (pBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->playback.internalChannels) { ma_uint32 frameCountForThisBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); if (frameCountForThisBuffer > 0) { if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_playback(pDevice, frameCountForThisBuffer, pBufferList->mBuffers[iBuffer].mData, &pDevice->coreaudio.duplexRB); } else { ma_device__read_frames_from_client(pDevice, frameCountForThisBuffer, pBufferList->mBuffers[iBuffer].mData); } } #if defined(MA_DEBUG_OUTPUT) printf(" frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize); #endif } else { /* This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams. We just output silence here. */ ma_zero_memory(pBufferList->mBuffers[iBuffer].mData, pBufferList->mBuffers[iBuffer].mDataByteSize); #if defined(MA_DEBUG_OUTPUT) printf(" WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize); #endif } } } else { /* This is the deinterleaved case. We need to update each buffer in groups of internalChannels. This assumes each buffer is the same size. */ ma_uint8 tempBuffer[4096]; UInt32 iBuffer; for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; iBuffer += pDevice->playback.internalChannels) { ma_uint32 frameCountPerBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_sample(pDevice->playback.internalFormat); ma_uint32 framesRemaining = frameCountPerBuffer; while (framesRemaining > 0) { void* ppDeinterleavedBuffers[MA_MAX_CHANNELS]; ma_uint32 iChannel; ma_uint32 framesToRead = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); if (framesToRead > framesRemaining) { framesToRead = framesRemaining; } if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_playback(pDevice, framesToRead, tempBuffer, &pDevice->coreaudio.duplexRB); } else { ma_device__read_frames_from_client(pDevice, framesToRead, tempBuffer); } for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) { ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pBufferList->mBuffers[iBuffer].mData, (frameCountPerBuffer - framesRemaining) * ma_get_bytes_per_sample(pDevice->playback.internalFormat)); } ma_deinterleave_pcm_frames(pDevice->playback.internalFormat, pDevice->playback.internalChannels, framesToRead, tempBuffer, ppDeinterleavedBuffers); framesRemaining -= framesToRead; } } } (void)pActionFlags; (void)pTimeStamp; (void)busNumber; return noErr; } OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pUnusedBufferList) { ma_device* pDevice = (ma_device*)pUserData; AudioBufferList* pRenderedBufferList; ma_stream_layout layout; OSStatus status; ma_assert(pDevice != NULL); pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList; ma_assert(pRenderedBufferList); /* We need to check whether or not we are outputting interleaved or non-interleaved samples. The way we do this is slightly different for each type. */ layout = ma_stream_layout_interleaved; if (pRenderedBufferList->mBuffers[0].mNumberChannels != pDevice->capture.internalChannels) { layout = ma_stream_layout_deinterleaved; } #if defined(MA_DEBUG_OUTPUT) printf("INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pRenderedBufferList->mNumberBuffers); #endif status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList); if (status != noErr) { #if defined(MA_DEBUG_OUTPUT) printf(" ERROR: AudioUnitRender() failed with %d\n", status); #endif return status; } if (layout == ma_stream_layout_interleaved) { UInt32 iBuffer; for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) { if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) { if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_capture(pDevice, frameCount, pRenderedBufferList->mBuffers[iBuffer].mData, &pDevice->coreaudio.duplexRB); } else { ma_device__send_frames_to_client(pDevice, frameCount, pRenderedBufferList->mBuffers[iBuffer].mData); } #if defined(MA_DEBUG_OUTPUT) printf(" mDataByteSize=%d\n", pRenderedBufferList->mBuffers[iBuffer].mDataByteSize); #endif } else { /* This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams. */ ma_uint8 silentBuffer[4096]; ma_uint32 framesRemaining; ma_zero_memory(silentBuffer, sizeof(silentBuffer)); framesRemaining = frameCount; while (framesRemaining > 0) { ma_uint32 framesToSend = sizeof(silentBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); if (framesToSend > framesRemaining) { framesToSend = framesRemaining; } if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_capture(pDevice, framesToSend, silentBuffer, &pDevice->coreaudio.duplexRB); } else { ma_device__send_frames_to_client(pDevice, framesToSend, silentBuffer); } framesRemaining -= framesToSend; } #if defined(MA_DEBUG_OUTPUT) printf(" WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, pRenderedBufferList->mBuffers[iBuffer].mDataByteSize); #endif } } } else { /* This is the deinterleaved case. We need to interleave the audio data before sending it to the client. This assumes each buffer is the same size. */ ma_uint8 tempBuffer[4096]; UInt32 iBuffer; for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; iBuffer += pDevice->capture.internalChannels) { ma_uint32 framesRemaining = frameCount; while (framesRemaining > 0) { void* ppDeinterleavedBuffers[MA_MAX_CHANNELS]; ma_uint32 iChannel; ma_uint32 framesToSend = sizeof(tempBuffer) / ma_get_bytes_per_sample(pDevice->capture.internalFormat); if (framesToSend > framesRemaining) { framesToSend = framesRemaining; } for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) { ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pRenderedBufferList->mBuffers[iBuffer].mData, (frameCount - framesRemaining) * ma_get_bytes_per_sample(pDevice->capture.internalFormat)); } ma_interleave_pcm_frames(pDevice->capture.internalFormat, pDevice->capture.internalChannels, framesToSend, (const void**)ppDeinterleavedBuffers, tempBuffer); if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_capture(pDevice, framesToSend, tempBuffer, &pDevice->coreaudio.duplexRB); } else { ma_device__send_frames_to_client(pDevice, framesToSend, tempBuffer); } framesRemaining -= framesToSend; } } } (void)pActionFlags; (void)pTimeStamp; (void)busNumber; (void)frameCount; (void)pUnusedBufferList; return noErr; } void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, AudioUnitPropertyID propertyID, AudioUnitScope scope, AudioUnitElement element) { ma_device* pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); /* There's been a report of a deadlock here when triggered by ma_device_uninit(). It looks like AudioUnitGetProprty (called below) and AudioComponentInstanceDispose (called in ma_device_uninit) can try waiting on the same lock. I'm going to try working around this by not calling any Core Audio APIs in the callback when the device has been stopped or uninitialized. */ if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED || ma_device__get_state(pDevice) == MA_STATE_STOPPING || ma_device__get_state(pDevice) == MA_STATE_STOPPED) { ma_stop_proc onStop = pDevice->onStop; if (onStop) { onStop(pDevice); } ma_event_signal(&pDevice->coreaudio.stopEvent); } else { UInt32 isRunning; UInt32 isRunningSize = sizeof(isRunning); OSStatus status = ((ma_AudioUnitGetProperty_proc)pDevice->pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioOutputUnitProperty_IsRunning, scope, element, &isRunning, &isRunningSize); if (status != noErr) { return; /* Don't really know what to do in this case... just ignore it, I suppose... */ } if (!isRunning) { ma_stop_proc onStop; /* The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider: 1) When the device is unplugged, this will be called _before_ the default device change notification. 2) When the device is changed via the default device change notification, this will be called _after_ the switch. For case #1, we just check if there's a new default device available. If so, we just ignore the stop event. For case #2 we check a flag. */ if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isDefaultPlaybackDevice) || ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isDefaultCaptureDevice)) { /* It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the device to be seamless to the client (we don't want them receiving the onStop event and thinking that the device has stopped when it hasn't!). */ if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) || ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isSwitchingCaptureDevice)) { return; } /* Getting here means the device is not reinitializing which means it may have been unplugged. From what I can see, it looks like Core Audio will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most likely be successful in switching to the new device. TODO: Try to predict if Core Audio will switch devices. If not, the onStop callback needs to be posted. */ return; } /* Getting here means we need to stop the device. */ onStop = pDevice->onStop; if (onStop) { onStop(pDevice); } } } (void)propertyID; /* Unused. */ } #if defined(MA_APPLE_DESKTOP) OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UInt32 addressCount, const AudioObjectPropertyAddress* pAddresses, void* pUserData) { ma_device* pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); /* Not sure if I really need to check this, but it makes me feel better. */ if (addressCount == 0) { return noErr; } if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultOutputDevice) { ma_result reinitResult; pDevice->coreaudio.isSwitchingPlaybackDevice = MA_TRUE; reinitResult = ma_device_reinit_internal__coreaudio(pDevice, ma_device_type_playback, MA_TRUE); pDevice->coreaudio.isSwitchingPlaybackDevice = MA_FALSE; if (reinitResult == MA_SUCCESS) { ma_device__post_init_setup(pDevice, ma_device_type_playback); /* Restart the device if required. If this fails we need to stop the device entirely. */ if (ma_device__get_state(pDevice) == MA_STATE_STARTED) { OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); if (status != noErr) { if (pDevice->type == ma_device_type_duplex) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); } ma_device__set_state(pDevice, MA_STATE_STOPPED); } } } } if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultInputDevice) { ma_result reinitResult; pDevice->coreaudio.isSwitchingPlaybackDevice = MA_TRUE; reinitResult = ma_device_reinit_internal__coreaudio(pDevice, ma_device_type_capture, MA_TRUE); pDevice->coreaudio.isSwitchingPlaybackDevice = MA_FALSE; if (reinitResult == MA_SUCCESS) { ma_device__post_init_setup(pDevice, ma_device_type_capture); /* Restart the device if required. If this fails we need to stop the device entirely. */ if (ma_device__get_state(pDevice) == MA_STATE_STARTED) { OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture); if (status != noErr) { if (pDevice->type == ma_device_type_duplex) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); } ma_device__set_state(pDevice, MA_STATE_STOPPED); } } } } (void)objectID; /* Unused. */ return noErr; } #endif typedef struct { /* Input. */ ma_format formatIn; ma_uint32 channelsIn; ma_uint32 sampleRateIn; ma_channel channelMapIn[MA_MAX_CHANNELS]; ma_uint32 bufferSizeInFramesIn; ma_uint32 bufferSizeInMillisecondsIn; ma_uint32 periodsIn; ma_bool32 usingDefaultFormat; ma_bool32 usingDefaultChannels; ma_bool32 usingDefaultSampleRate; ma_bool32 usingDefaultChannelMap; ma_share_mode shareMode; ma_bool32 registerStopEvent; /* Output. */ #if defined(MA_APPLE_DESKTOP) AudioObjectID deviceObjectID; #endif AudioComponent component; AudioUnit audioUnit; AudioBufferList* pAudioBufferList; /* Only used for input devices. */ ma_format formatOut; ma_uint32 channelsOut; ma_uint32 sampleRateOut; ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_uint32 bufferSizeInFramesOut; ma_uint32 periodsOut; char deviceName[256]; } ma_device_init_internal_data__coreaudio; ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_init_internal_data__coreaudio* pData, void* pDevice_DoNotReference) /* <-- pDevice is typed as void* intentionally so as to avoid accidentally referencing it. */ { ma_result result; OSStatus status; UInt32 enableIOFlag; AudioStreamBasicDescription bestFormat; ma_uint32 actualBufferSizeInFrames; AURenderCallbackStruct callbackInfo; #if defined(MA_APPLE_DESKTOP) AudioObjectID deviceObjectID; #endif /* This API should only be used for a single device type: playback or capture. No full-duplex mode. */ if (deviceType == ma_device_type_duplex) { return MA_INVALID_ARGS; } ma_assert(pContext != NULL); ma_assert(deviceType == ma_device_type_playback || deviceType == ma_device_type_capture); #if defined(MA_APPLE_DESKTOP) pData->deviceObjectID = 0; #endif pData->component = NULL; pData->audioUnit = NULL; pData->pAudioBufferList = NULL; #if defined(MA_APPLE_DESKTOP) result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID); if (result != MA_SUCCESS) { return result; } pData->deviceObjectID = deviceObjectID; #endif /* Core audio doesn't really use the notion of a period so we can leave this unmodified, but not too over the top. */ pData->periodsOut = pData->periodsIn; if (pData->periodsOut < 1) { pData->periodsOut = 1; } if (pData->periodsOut > 16) { pData->periodsOut = 16; } /* Audio unit. */ status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)((AudioComponent)pContext->coreaudio.component, (AudioUnit*)&pData->audioUnit); if (status != noErr) { return ma_result_from_OSStatus(status); } /* The input/output buses need to be explicitly enabled and disabled. We set the flag based on the output unit first, then we just swap it for input. */ enableIOFlag = 1; if (deviceType == ma_device_type_capture) { enableIOFlag = 0; } status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } enableIOFlag = (enableIOFlag == 0) ? 1 : 0; status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &enableIOFlag, sizeof(enableIOFlag)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */ #if defined(MA_APPLE_DESKTOP) status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS, &deviceObjectID, sizeof(AudioDeviceID)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(result); } #endif /* Format. This is the hardest part of initialization because there's a few variables to take into account. 1) The format must be supported by the device. 2) The format must be supported miniaudio. 3) There's a priority that miniaudio prefers. Ideally we would like to use a format that's as close to the hardware as possible so we can get as close to a passthrough as possible. The most important property is the sample rate. miniaudio can do format conversion for any sample rate and channel count, but cannot do the same for the sample data format. If the sample data format is not supported by miniaudio it must be ignored completely. On mobile platforms this is a bit different. We just force the use of whatever the audio unit's current format is set to. */ { AudioUnitScope formatScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output; AudioUnitElement formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS; #if defined(MA_APPLE_DESKTOP) AudioStreamBasicDescription origFormat; UInt32 origFormatSize; result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, pData->usingDefaultFormat, pData->usingDefaultChannels, pData->usingDefaultSampleRate, &bestFormat); if (result != MA_SUCCESS) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return result; } /* From what I can see, Apple's documentation implies that we should keep the sample rate consistent. */ origFormatSize = sizeof(origFormat); if (deviceType == ma_device_type_playback) { status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &origFormat, &origFormatSize); } else { status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &origFormat, &origFormatSize); } if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return result; } bestFormat.mSampleRate = origFormat.mSampleRate; status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat)); if (status != noErr) { /* We failed to set the format, so fall back to the current format of the audio unit. */ bestFormat = origFormat; } #else UInt32 propSize = sizeof(bestFormat); status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } /* Sample rate is a little different here because for some reason kAudioUnitProperty_StreamFormat returns 0... Oh well. We need to instead try setting the sample rate to what the user has requested and then just see the results of it. Need to use some Objective-C here for this since it depends on Apple's AVAudioSession API. To do this we just get the shared AVAudioSession instance and then set it. Note that from what I can tell, it looks like the sample rate is shared between playback and capture for everything. */ @autoreleasepool { AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; ma_assert(pAudioSession != NULL); [pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil]; bestFormat.mSampleRate = pAudioSession.sampleRate; } status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } #endif result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pData->formatOut); if (result != MA_SUCCESS) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return result; } if (pData->formatOut == ma_format_unknown) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return MA_FORMAT_NOT_SUPPORTED; } pData->channelsOut = bestFormat.mChannelsPerFrame; pData->sampleRateOut = bestFormat.mSampleRate; } /* Internal channel map. This is weird in my testing. If I use the AudioObject to get the channel map, the channel descriptions are set to "Unknown" for some reason. To work around this it looks like retrieving it from the AudioUnit will work. However, and this is where it gets weird, it doesn't seem to work with capture devices, nor at all on iOS... Therefore I'm going to fall back to a default assumption in these cases. */ #if defined(MA_APPLE_DESKTOP) result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut); if (result != MA_SUCCESS) { #if 0 /* Try falling back to the channel map from the AudioObject. */ result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut); if (result != MA_SUCCESS) { return result; } #else /* Fall back to default assumptions. */ ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut); #endif } #else /* TODO: Figure out how to get the channel map using AVAudioSession. */ ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut); #endif /* Buffer size. Not allowing this to be configurable on iOS. */ actualBufferSizeInFrames = pData->bufferSizeInFramesIn; #if defined(MA_APPLE_DESKTOP) if (actualBufferSizeInFrames == 0) { actualBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->bufferSizeInMillisecondsIn, pData->sampleRateOut); } actualBufferSizeInFrames = actualBufferSizeInFrames / pData->periodsOut; result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualBufferSizeInFrames); if (result != MA_SUCCESS) { return result; } pData->bufferSizeInFramesOut = actualBufferSizeInFrames * pData->periodsOut; #else actualBufferSizeInFrames = 4096; pData->bufferSizeInFramesOut = actualBufferSizeInFrames; #endif /* During testing I discovered that the buffer size can be too big. You'll get an error like this: kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=4096, mMaxFramesPerSlice=512 Note how inFramesToProcess is smaller than mMaxFramesPerSlice. To fix, we need to set kAudioUnitProperty_MaximumFramesPerSlice to that of the size of our buffer, or do it the other way around and set our buffer size to the kAudioUnitProperty_MaximumFramesPerSlice. */ { /*AudioUnitScope propScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output; AudioUnitElement propBus = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS; status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, propScope, propBus, &actualBufferSizeInFrames, sizeof(actualBufferSizeInFrames)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); }*/ status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualBufferSizeInFrames, sizeof(actualBufferSizeInFrames)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } } /* We need a buffer list if this is an input device. We render into this in the input callback. */ if (deviceType == ma_device_type_capture) { ma_bool32 isInterleaved = (bestFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; size_t allocationSize; AudioBufferList* pBufferList; allocationSize = sizeof(AudioBufferList) - sizeof(AudioBuffer); /* Subtract sizeof(AudioBuffer) because that part is dynamically sized. */ if (isInterleaved) { /* Interleaved case. This is the simple case because we just have one buffer. */ allocationSize += sizeof(AudioBuffer) * 1; allocationSize += actualBufferSizeInFrames * ma_get_bytes_per_frame(pData->formatOut, pData->channelsOut); } else { /* Non-interleaved case. This is the more complex case because there's more than one buffer. */ allocationSize += sizeof(AudioBuffer) * pData->channelsOut; allocationSize += actualBufferSizeInFrames * ma_get_bytes_per_sample(pData->formatOut) * pData->channelsOut; } pBufferList = (AudioBufferList*)ma_malloc(allocationSize); if (pBufferList == NULL) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return MA_OUT_OF_MEMORY; } if (isInterleaved) { pBufferList->mNumberBuffers = 1; pBufferList->mBuffers[0].mNumberChannels = pData->channelsOut; pBufferList->mBuffers[0].mDataByteSize = actualBufferSizeInFrames * ma_get_bytes_per_frame(pData->formatOut, pData->channelsOut); pBufferList->mBuffers[0].mData = (ma_uint8*)pBufferList + sizeof(AudioBufferList); } else { ma_uint32 iBuffer; pBufferList->mNumberBuffers = pData->channelsOut; for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) { pBufferList->mBuffers[iBuffer].mNumberChannels = 1; pBufferList->mBuffers[iBuffer].mDataByteSize = actualBufferSizeInFrames * ma_get_bytes_per_sample(pData->formatOut); pBufferList->mBuffers[iBuffer].mData = (ma_uint8*)pBufferList + ((sizeof(AudioBufferList) - sizeof(AudioBuffer)) + (sizeof(AudioBuffer) * pData->channelsOut)) + (actualBufferSizeInFrames * ma_get_bytes_per_sample(pData->formatOut) * iBuffer); } } pData->pAudioBufferList = pBufferList; } /* Callbacks. */ callbackInfo.inputProcRefCon = pDevice_DoNotReference; if (deviceType == ma_device_type_playback) { callbackInfo.inputProc = ma_on_output__coreaudio; status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, MA_COREAUDIO_OUTPUT_BUS, &callbackInfo, sizeof(callbackInfo)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } } else { callbackInfo.inputProc = ma_on_input__coreaudio; status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, MA_COREAUDIO_INPUT_BUS, &callbackInfo, sizeof(callbackInfo)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } } /* We need to listen for stop events. */ if (pData->registerStopEvent) { status = ((ma_AudioUnitAddPropertyListener_proc)pContext->coreaudio.AudioUnitAddPropertyListener)(pData->audioUnit, kAudioOutputUnitProperty_IsRunning, on_start_stop__coreaudio, pDevice_DoNotReference); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } } /* Initialize the audio unit. */ status = ((ma_AudioUnitInitialize_proc)pContext->coreaudio.AudioUnitInitialize)(pData->audioUnit); if (status != noErr) { ma_free(pData->pAudioBufferList); pData->pAudioBufferList = NULL; ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); return ma_result_from_OSStatus(status); } /* Grab the name. */ #if defined(MA_APPLE_DESKTOP) ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pData->deviceName), pData->deviceName); #else if (deviceType == ma_device_type_playback) { ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_PLAYBACK_DEVICE_NAME); } else { ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_CAPTURE_DEVICE_NAME); } #endif return result; } ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit) { ma_device_init_internal_data__coreaudio data; ma_result result; /* This should only be called for playback or capture, not duplex. */ if (deviceType == ma_device_type_duplex) { return MA_INVALID_ARGS; } if (deviceType == ma_device_type_capture) { data.formatIn = pDevice->capture.format; data.channelsIn = pDevice->capture.channels; data.sampleRateIn = pDevice->sampleRate; ma_copy_memory(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap)); data.usingDefaultFormat = pDevice->capture.usingDefaultFormat; data.usingDefaultChannels = pDevice->capture.usingDefaultChannels; data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate; data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap; data.shareMode = pDevice->capture.shareMode; data.registerStopEvent = MA_TRUE; if (disposePreviousAudioUnit) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); } if (pDevice->coreaudio.pAudioBufferList) { ma_free(pDevice->coreaudio.pAudioBufferList); } #if defined(MA_APPLE_DESKTOP) pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID; #endif pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit; pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList; } if (deviceType == ma_device_type_playback) { data.formatIn = pDevice->playback.format; data.channelsIn = pDevice->playback.channels; data.sampleRateIn = pDevice->sampleRate; ma_copy_memory(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap)); data.usingDefaultFormat = pDevice->playback.usingDefaultFormat; data.usingDefaultChannels = pDevice->playback.usingDefaultChannels; data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate; data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap; data.shareMode = pDevice->playback.shareMode; data.registerStopEvent = (pDevice->type != ma_device_type_duplex); if (disposePreviousAudioUnit) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); } #if defined(MA_APPLE_DESKTOP) pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID; #endif pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit; } data.bufferSizeInFramesIn = pDevice->coreaudio.originalBufferSizeInFrames; data.bufferSizeInMillisecondsIn = pDevice->coreaudio.originalBufferSizeInMilliseconds; data.periodsIn = pDevice->coreaudio.originalPeriods; result = ma_device_init_internal__coreaudio(pDevice->pContext, deviceType, NULL, &data, (void*)pDevice); if (result != MA_SUCCESS) { return result; } return MA_SUCCESS; } ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result; ma_assert(pContext != NULL); ma_assert(pConfig != NULL); ma_assert(pDevice != NULL); /* No exclusive mode with the Core Audio backend for now. */ if (((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; } /* Capture needs to be initialized first. */ if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_device_init_internal_data__coreaudio data; data.formatIn = pConfig->capture.format; data.channelsIn = pConfig->capture.channels; data.sampleRateIn = pConfig->sampleRate; ma_copy_memory(data.channelMapIn, pConfig->capture.channelMap, sizeof(pConfig->capture.channelMap)); data.usingDefaultFormat = pDevice->capture.usingDefaultFormat; data.usingDefaultChannels = pDevice->capture.usingDefaultChannels; data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate; data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap; data.shareMode = pConfig->capture.shareMode; data.bufferSizeInFramesIn = pConfig->bufferSizeInFrames; data.bufferSizeInMillisecondsIn = pConfig->bufferSizeInMilliseconds; data.registerStopEvent = MA_TRUE; result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pConfig->capture.pDeviceID, &data, (void*)pDevice); if (result != MA_SUCCESS) { return result; } pDevice->coreaudio.isDefaultCaptureDevice = (pConfig->capture.pDeviceID == NULL); #if defined(MA_APPLE_DESKTOP) pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID; #endif pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit; pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList; pDevice->capture.internalFormat = data.formatOut; pDevice->capture.internalChannels = data.channelsOut; pDevice->capture.internalSampleRate = data.sampleRateOut; ma_copy_memory(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); pDevice->capture.internalBufferSizeInFrames = data.bufferSizeInFramesOut; pDevice->capture.internalPeriods = data.periodsOut; /* TODO: This needs to be made global. */ #if defined(MA_APPLE_DESKTOP) /* If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly switch the device in the background. */ if (pConfig->capture.pDeviceID == NULL) { AudioObjectPropertyAddress propAddress; propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; propAddress.mScope = kAudioObjectPropertyScopeGlobal; propAddress.mElement = kAudioObjectPropertyElementMaster; ((ma_AudioObjectAddPropertyListener_proc)pDevice->pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, pDevice); } #endif } /* Playback. */ if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_device_init_internal_data__coreaudio data; data.formatIn = pConfig->playback.format; data.channelsIn = pConfig->playback.channels; data.sampleRateIn = pConfig->sampleRate; ma_copy_memory(data.channelMapIn, pConfig->playback.channelMap, sizeof(pConfig->playback.channelMap)); data.usingDefaultFormat = pDevice->playback.usingDefaultFormat; data.usingDefaultChannels = pDevice->playback.usingDefaultChannels; data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate; data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap; data.shareMode = pConfig->playback.shareMode; /* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */ if (pConfig->deviceType == ma_device_type_duplex) { data.bufferSizeInFramesIn = pDevice->capture.internalBufferSizeInFrames; data.periodsIn = pDevice->capture.internalPeriods; data.registerStopEvent = MA_FALSE; } else { data.bufferSizeInFramesIn = pConfig->bufferSizeInFrames; data.bufferSizeInMillisecondsIn = pConfig->bufferSizeInMilliseconds; data.periodsIn = pConfig->periods; data.registerStopEvent = MA_TRUE; } result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pConfig->playback.pDeviceID, &data, (void*)pDevice); if (result != MA_SUCCESS) { if (pConfig->deviceType == ma_device_type_duplex) { ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); if (pDevice->coreaudio.pAudioBufferList) { ma_free(pDevice->coreaudio.pAudioBufferList); } } return result; } pDevice->coreaudio.isDefaultPlaybackDevice = (pConfig->playback.pDeviceID == NULL); #if defined(MA_APPLE_DESKTOP) pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID; #endif pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit; pDevice->playback.internalFormat = data.formatOut; pDevice->playback.internalChannels = data.channelsOut; pDevice->playback.internalSampleRate = data.sampleRateOut; ma_copy_memory(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); pDevice->playback.internalBufferSizeInFrames = data.bufferSizeInFramesOut; pDevice->playback.internalPeriods = data.periodsOut; /* TODO: This needs to be made global. */ #if defined(MA_APPLE_DESKTOP) /* If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly switch the device in the background. */ if (pConfig->playback.pDeviceID == NULL) { AudioObjectPropertyAddress propAddress; propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; propAddress.mScope = kAudioObjectPropertyScopeGlobal; propAddress.mElement = kAudioObjectPropertyElementMaster; ((ma_AudioObjectAddPropertyListener_proc)pDevice->pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, pDevice); } #endif } pDevice->coreaudio.originalBufferSizeInFrames = pConfig->bufferSizeInFrames; pDevice->coreaudio.originalBufferSizeInMilliseconds = pConfig->bufferSizeInMilliseconds; pDevice->coreaudio.originalPeriods = pConfig->periods; /* When stopping the device, a callback is called on another thread. We need to wait for this callback before returning from ma_device_stop(). This event is used for this. */ ma_event_init(pContext, &pDevice->coreaudio.stopEvent); /* Need a ring buffer for duplex mode. */ if (pConfig->deviceType == ma_device_type_duplex) { ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalBufferSizeInFrames); ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->coreaudio.duplexRB); if (result != MA_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[Core Audio] Failed to initialize ring buffer.", result); } } return MA_SUCCESS; } ma_result ma_device_start__coreaudio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture); if (status != noErr) { return ma_result_from_OSStatus(status); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); if (status != noErr) { if (pDevice->type == ma_device_type_duplex) { ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); } return ma_result_from_OSStatus(status); } } return MA_SUCCESS; } ma_result ma_device_stop__coreaudio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); if (status != noErr) { return ma_result_from_OSStatus(status); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); if (status != noErr) { return ma_result_from_OSStatus(status); } } /* We need to wait for the callback to finish before returning. */ ma_event_wait(&pDevice->coreaudio.stopEvent); return MA_SUCCESS; } ma_result ma_context_uninit__coreaudio(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_coreaudio); #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); #endif (void)pContext; return MA_SUCCESS; } ma_result ma_context_init__coreaudio(const ma_context_config* pConfig, ma_context* pContext) { ma_assert(pContext != NULL); (void)pConfig; #if defined(MA_APPLE_MOBILE) @autoreleasepool { AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; ma_assert(pAudioSession != NULL); [pAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord error:nil]; /* By default we want miniaudio to use the speakers instead of the receiver. In the future this may be customizable. */ ma_bool32 useSpeakers = MA_TRUE; if (useSpeakers) { [pAudioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil]; } } #endif #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) pContext->coreaudio.hCoreFoundation = ma_dlopen(pContext, "CoreFoundation.framework/CoreFoundation"); if (pContext->coreaudio.hCoreFoundation == NULL) { return MA_API_NOT_FOUND; } pContext->coreaudio.CFStringGetCString = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFStringGetCString"); pContext->coreaudio.hCoreAudio = ma_dlopen(pContext, "CoreAudio.framework/CoreAudio"); if (pContext->coreaudio.hCoreAudio == NULL) { ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } pContext->coreaudio.AudioObjectGetPropertyData = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData"); pContext->coreaudio.AudioObjectGetPropertyDataSize = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize"); pContext->coreaudio.AudioObjectSetPropertyData = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData"); pContext->coreaudio.AudioObjectAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener"); /* It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback. The way it'll work is that it'll first try AudioUnit, and if the required symbols are not present there we'll fall back to AudioToolbox. */ pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit"); if (pContext->coreaudio.hAudioUnit == NULL) { ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } if (ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) { /* Couldn't find the required symbols in AudioUnit, so fall back to AudioToolbox. */ ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioToolbox.framework/AudioToolbox"); if (pContext->coreaudio.hAudioUnit == NULL) { ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } } pContext->coreaudio.AudioComponentFindNext = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext"); pContext->coreaudio.AudioComponentInstanceDispose = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose"); pContext->coreaudio.AudioComponentInstanceNew = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew"); pContext->coreaudio.AudioOutputUnitStart = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart"); pContext->coreaudio.AudioOutputUnitStop = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop"); pContext->coreaudio.AudioUnitAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener"); pContext->coreaudio.AudioUnitGetPropertyInfo = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo"); pContext->coreaudio.AudioUnitGetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty"); pContext->coreaudio.AudioUnitSetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty"); pContext->coreaudio.AudioUnitInitialize = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitInitialize"); pContext->coreaudio.AudioUnitRender = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitRender"); #else pContext->coreaudio.CFStringGetCString = (ma_proc)CFStringGetCString; #if defined(MA_APPLE_DESKTOP) pContext->coreaudio.AudioObjectGetPropertyData = (ma_proc)AudioObjectGetPropertyData; pContext->coreaudio.AudioObjectGetPropertyDataSize = (ma_proc)AudioObjectGetPropertyDataSize; pContext->coreaudio.AudioObjectSetPropertyData = (ma_proc)AudioObjectSetPropertyData; pContext->coreaudio.AudioObjectAddPropertyListener = (ma_proc)AudioObjectAddPropertyListener; #endif pContext->coreaudio.AudioComponentFindNext = (ma_proc)AudioComponentFindNext; pContext->coreaudio.AudioComponentInstanceDispose = (ma_proc)AudioComponentInstanceDispose; pContext->coreaudio.AudioComponentInstanceNew = (ma_proc)AudioComponentInstanceNew; pContext->coreaudio.AudioOutputUnitStart = (ma_proc)AudioOutputUnitStart; pContext->coreaudio.AudioOutputUnitStop = (ma_proc)AudioOutputUnitStop; pContext->coreaudio.AudioUnitAddPropertyListener = (ma_proc)AudioUnitAddPropertyListener; pContext->coreaudio.AudioUnitGetPropertyInfo = (ma_proc)AudioUnitGetPropertyInfo; pContext->coreaudio.AudioUnitGetProperty = (ma_proc)AudioUnitGetProperty; pContext->coreaudio.AudioUnitSetProperty = (ma_proc)AudioUnitSetProperty; pContext->coreaudio.AudioUnitInitialize = (ma_proc)AudioUnitInitialize; pContext->coreaudio.AudioUnitRender = (ma_proc)AudioUnitRender; #endif pContext->isBackendAsynchronous = MA_TRUE; pContext->onUninit = ma_context_uninit__coreaudio; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__coreaudio; pContext->onEnumDevices = ma_context_enumerate_devices__coreaudio; pContext->onGetDeviceInfo = ma_context_get_device_info__coreaudio; pContext->onDeviceInit = ma_device_init__coreaudio; pContext->onDeviceUninit = ma_device_uninit__coreaudio; pContext->onDeviceStart = ma_device_start__coreaudio; pContext->onDeviceStop = ma_device_stop__coreaudio; /* Audio component. */ { AudioComponentDescription desc; desc.componentType = kAudioUnitType_Output; #if defined(MA_APPLE_DESKTOP) desc.componentSubType = kAudioUnitSubType_HALOutput; #else desc.componentSubType = kAudioUnitSubType_RemoteIO; #endif desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; pContext->coreaudio.component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc); if (pContext->coreaudio.component == NULL) { #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); #endif return MA_FAILED_TO_INIT_BACKEND; } } return MA_SUCCESS; } #endif /* Core Audio */ /****************************************************************************** sndio Backend ******************************************************************************/ #ifdef MA_HAS_SNDIO #include #include /* Only supporting OpenBSD. This did not work very well at all on FreeBSD when I tried it. Not sure if this is due to miniaudio's implementation or if it's some kind of system configuration issue, but basically the default device just doesn't emit any sound, or at times you'll hear tiny pieces. I will consider enabling this when there's demand for it or if I can get it tested and debugged more thoroughly. */ #if 0 #if defined(__NetBSD__) || defined(__OpenBSD__) #include #endif #if defined(__FreeBSD__) || defined(__DragonFly__) #include #endif #endif #define MA_SIO_DEVANY "default" #define MA_SIO_PLAY 1 #define MA_SIO_REC 2 #define MA_SIO_NENC 8 #define MA_SIO_NCHAN 8 #define MA_SIO_NRATE 16 #define MA_SIO_NCONF 4 struct ma_sio_hdl; /* <-- Opaque */ struct ma_sio_par { unsigned int bits; unsigned int bps; unsigned int sig; unsigned int le; unsigned int msb; unsigned int rchan; unsigned int pchan; unsigned int rate; unsigned int bufsz; unsigned int xrun; unsigned int round; unsigned int appbufsz; int __pad[3]; unsigned int __magic; }; struct ma_sio_enc { unsigned int bits; unsigned int bps; unsigned int sig; unsigned int le; unsigned int msb; }; struct ma_sio_conf { unsigned int enc; unsigned int rchan; unsigned int pchan; unsigned int rate; }; struct ma_sio_cap { struct ma_sio_enc enc[MA_SIO_NENC]; unsigned int rchan[MA_SIO_NCHAN]; unsigned int pchan[MA_SIO_NCHAN]; unsigned int rate[MA_SIO_NRATE]; int __pad[7]; unsigned int nconf; struct ma_sio_conf confs[MA_SIO_NCONF]; }; typedef struct ma_sio_hdl* (* ma_sio_open_proc) (const char*, unsigned int, int); typedef void (* ma_sio_close_proc) (struct ma_sio_hdl*); typedef int (* ma_sio_setpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*); typedef int (* ma_sio_getpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*); typedef int (* ma_sio_getcap_proc) (struct ma_sio_hdl*, struct ma_sio_cap*); typedef size_t (* ma_sio_write_proc) (struct ma_sio_hdl*, const void*, size_t); typedef size_t (* ma_sio_read_proc) (struct ma_sio_hdl*, void*, size_t); typedef int (* ma_sio_start_proc) (struct ma_sio_hdl*); typedef int (* ma_sio_stop_proc) (struct ma_sio_hdl*); typedef int (* ma_sio_initpar_proc)(struct ma_sio_par*); ma_format ma_format_from_sio_enc__sndio(unsigned int bits, unsigned int bps, unsigned int sig, unsigned int le, unsigned int msb) { /* We only support native-endian right now. */ if ((ma_is_little_endian() && le == 0) || (ma_is_big_endian() && le == 1)) { return ma_format_unknown; } if (bits == 8 && bps == 1 && sig == 0) { return ma_format_u8; } if (bits == 16 && bps == 2 && sig == 1) { return ma_format_s16; } if (bits == 24 && bps == 3 && sig == 1) { return ma_format_s24; } if (bits == 24 && bps == 4 && sig == 1 && msb == 0) { /*return ma_format_s24_32;*/ } if (bits == 32 && bps == 4 && sig == 1) { return ma_format_s32; } return ma_format_unknown; } ma_format ma_find_best_format_from_sio_cap__sndio(struct ma_sio_cap* caps) { ma_format bestFormat; unsigned int iConfig; ma_assert(caps != NULL); bestFormat = ma_format_unknown; for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) { unsigned int iEncoding; for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) { unsigned int bits; unsigned int bps; unsigned int sig; unsigned int le; unsigned int msb; ma_format format; if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) { continue; } bits = caps->enc[iEncoding].bits; bps = caps->enc[iEncoding].bps; sig = caps->enc[iEncoding].sig; le = caps->enc[iEncoding].le; msb = caps->enc[iEncoding].msb; format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb); if (format == ma_format_unknown) { continue; /* Format not supported. */ } if (bestFormat == ma_format_unknown) { bestFormat = format; } else { if (ma_get_format_priority_index(bestFormat) > ma_get_format_priority_index(format)) { /* <-- Lower = better. */ bestFormat = format; } } } } return ma_format_unknown; } ma_uint32 ma_find_best_channels_from_sio_cap__sndio(struct ma_sio_cap* caps, ma_device_type deviceType, ma_format requiredFormat) { ma_uint32 maxChannels; unsigned int iConfig; ma_assert(caps != NULL); ma_assert(requiredFormat != ma_format_unknown); /* Just pick whatever configuration has the most channels. */ maxChannels = 0; for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) { /* The encoding should be of requiredFormat. */ unsigned int iEncoding; for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) { unsigned int iChannel; unsigned int bits; unsigned int bps; unsigned int sig; unsigned int le; unsigned int msb; ma_format format; if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) { continue; } bits = caps->enc[iEncoding].bits; bps = caps->enc[iEncoding].bps; sig = caps->enc[iEncoding].sig; le = caps->enc[iEncoding].le; msb = caps->enc[iEncoding].msb; format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb); if (format != requiredFormat) { continue; } /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */ for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) { unsigned int chan = 0; unsigned int channels; if (deviceType == ma_device_type_playback) { chan = caps->confs[iConfig].pchan; } else { chan = caps->confs[iConfig].rchan; } if ((chan & (1UL << iChannel)) == 0) { continue; } if (deviceType == ma_device_type_playback) { channels = caps->pchan[iChannel]; } else { channels = caps->rchan[iChannel]; } if (maxChannels < channels) { maxChannels = channels; } } } } return maxChannels; } ma_uint32 ma_find_best_sample_rate_from_sio_cap__sndio(struct ma_sio_cap* caps, ma_device_type deviceType, ma_format requiredFormat, ma_uint32 requiredChannels) { ma_uint32 firstSampleRate; ma_uint32 bestSampleRate; unsigned int iConfig; ma_assert(caps != NULL); ma_assert(requiredFormat != ma_format_unknown); ma_assert(requiredChannels > 0); ma_assert(requiredChannels <= MA_MAX_CHANNELS); firstSampleRate = 0; /* <-- If the device does not support a standard rate we'll fall back to the first one that's found. */ bestSampleRate = 0; for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) { /* The encoding should be of requiredFormat. */ unsigned int iEncoding; for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) { unsigned int iChannel; unsigned int bits; unsigned int bps; unsigned int sig; unsigned int le; unsigned int msb; ma_format format; if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) { continue; } bits = caps->enc[iEncoding].bits; bps = caps->enc[iEncoding].bps; sig = caps->enc[iEncoding].sig; le = caps->enc[iEncoding].le; msb = caps->enc[iEncoding].msb; format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb); if (format != requiredFormat) { continue; } /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */ for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) { unsigned int chan = 0; unsigned int channels; unsigned int iRate; if (deviceType == ma_device_type_playback) { chan = caps->confs[iConfig].pchan; } else { chan = caps->confs[iConfig].rchan; } if ((chan & (1UL << iChannel)) == 0) { continue; } if (deviceType == ma_device_type_playback) { channels = caps->pchan[iChannel]; } else { channels = caps->rchan[iChannel]; } if (channels != requiredChannels) { continue; } /* Getting here means we have found a compatible encoding/channel pair. */ for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) { ma_uint32 rate = (ma_uint32)caps->rate[iRate]; ma_uint32 ratePriority; if (firstSampleRate == 0) { firstSampleRate = rate; } /* Disregard this rate if it's not a standard one. */ ratePriority = ma_get_standard_sample_rate_priority_index(rate); if (ratePriority == (ma_uint32)-1) { continue; } if (ma_get_standard_sample_rate_priority_index(bestSampleRate) > ratePriority) { /* Lower = better. */ bestSampleRate = rate; } } } } } /* If a standard sample rate was not found just fall back to the first one that was iterated. */ if (bestSampleRate == 0) { bestSampleRate = firstSampleRate; } return bestSampleRate; } ma_bool32 ma_context_is_device_id_equal__sndio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return ma_strcmp(pID0->sndio, pID1->sndio) == 0; } ma_result ma_context_enumerate_devices__sndio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_bool32 isTerminating = MA_FALSE; struct ma_sio_hdl* handle; ma_assert(pContext != NULL); ma_assert(callback != NULL); /* sndio doesn't seem to have a good device enumeration API, so I'm therefore only enumerating over default devices for now. */ /* Playback. */ if (!isTerminating) { handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_PLAY, 0); if (handle != NULL) { /* Supports playback. */ ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), MA_SIO_DEVANY); ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME); isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); ((ma_sio_close_proc)pContext->sndio.sio_close)(handle); } } /* Capture. */ if (!isTerminating) { handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_REC, 0); if (handle != NULL) { /* Supports capture. */ ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), "default"); ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME); isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); ((ma_sio_close_proc)pContext->sndio.sio_close)(handle); } } return MA_SUCCESS; } ma_result ma_context_get_device_info__sndio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { char devid[256]; struct ma_sio_hdl* handle; struct ma_sio_cap caps; unsigned int iConfig; ma_assert(pContext != NULL); (void)shareMode; /* We need to open the device before we can get information about it. */ if (pDeviceID == NULL) { ma_strcpy_s(devid, sizeof(devid), MA_SIO_DEVANY); ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (deviceType == ma_device_type_playback) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : MA_DEFAULT_CAPTURE_DEVICE_NAME); } else { ma_strcpy_s(devid, sizeof(devid), pDeviceID->sndio); ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), devid); } handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(devid, (deviceType == ma_device_type_playback) ? MA_SIO_PLAY : MA_SIO_REC, 0); if (handle == NULL) { return MA_NO_DEVICE; } if (((ma_sio_getcap_proc)pContext->sndio.sio_getcap)(handle, &caps) == 0) { return MA_ERROR; } for (iConfig = 0; iConfig < caps.nconf; iConfig += 1) { /* The main thing we care about is that the encoding is supported by miniaudio. If it is, we want to give preference to some formats over others. */ unsigned int iEncoding; unsigned int iChannel; unsigned int iRate; for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) { unsigned int bits; unsigned int bps; unsigned int sig; unsigned int le; unsigned int msb; ma_format format; ma_bool32 formatExists = MA_FALSE; ma_uint32 iExistingFormat; if ((caps.confs[iConfig].enc & (1UL << iEncoding)) == 0) { continue; } bits = caps.enc[iEncoding].bits; bps = caps.enc[iEncoding].bps; sig = caps.enc[iEncoding].sig; le = caps.enc[iEncoding].le; msb = caps.enc[iEncoding].msb; format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb); if (format == ma_format_unknown) { continue; /* Format not supported. */ } /* Add this format if it doesn't already exist. */ for (iExistingFormat = 0; iExistingFormat < pDeviceInfo->formatCount; iExistingFormat += 1) { if (pDeviceInfo->formats[iExistingFormat] == format) { formatExists = MA_TRUE; break; } } if (!formatExists) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = format; } } /* Channels. */ for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) { unsigned int chan = 0; unsigned int channels; if (deviceType == ma_device_type_playback) { chan = caps.confs[iConfig].pchan; } else { chan = caps.confs[iConfig].rchan; } if ((chan & (1UL << iChannel)) == 0) { continue; } if (deviceType == ma_device_type_playback) { channels = caps.pchan[iChannel]; } else { channels = caps.rchan[iChannel]; } if (pDeviceInfo->minChannels > channels) { pDeviceInfo->minChannels = channels; } if (pDeviceInfo->maxChannels < channels) { pDeviceInfo->maxChannels = channels; } } /* Sample rates. */ for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) { if ((caps.confs[iConfig].rate & (1UL << iRate)) != 0) { unsigned int rate = caps.rate[iRate]; if (pDeviceInfo->minSampleRate > rate) { pDeviceInfo->minSampleRate = rate; } if (pDeviceInfo->maxSampleRate < rate) { pDeviceInfo->maxSampleRate = rate; } } } } ((ma_sio_close_proc)pContext->sndio.sio_close)(handle); return MA_SUCCESS; } void ma_device_uninit__sndio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handleCapture); } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); } } ma_result ma_device_init_handle__sndio(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice) { const char* pDeviceName; ma_ptr handle; int openFlags = 0; struct ma_sio_cap caps; struct ma_sio_par par; ma_device_id* pDeviceID; ma_format format; ma_uint32 channels; ma_uint32 sampleRate; ma_format internalFormat; ma_uint32 internalChannels; ma_uint32 internalSampleRate; ma_uint32 internalBufferSizeInFrames; ma_uint32 internalPeriods; ma_assert(pContext != NULL); ma_assert(pConfig != NULL); ma_assert(deviceType != ma_device_type_duplex); ma_assert(pDevice != NULL); if (deviceType == ma_device_type_capture) { openFlags = MA_SIO_REC; pDeviceID = pConfig->capture.pDeviceID; format = pConfig->capture.format; channels = pConfig->capture.channels; sampleRate = pConfig->sampleRate; } else { openFlags = MA_SIO_PLAY; pDeviceID = pConfig->playback.pDeviceID; format = pConfig->playback.format; channels = pConfig->playback.channels; sampleRate = pConfig->sampleRate; } pDeviceName = MA_SIO_DEVANY; if (pDeviceID != NULL) { pDeviceName = pDeviceID->sndio; } handle = (ma_ptr)((ma_sio_open_proc)pContext->sndio.sio_open)(pDeviceName, openFlags, 0); if (handle == NULL) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* We need to retrieve the device caps to determine the most appropriate format to use. */ if (((ma_sio_getcap_proc)pContext->sndio.sio_getcap)((struct ma_sio_hdl*)handle, &caps) == 0) { ((ma_sio_close_proc)pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps.", MA_ERROR); } /* Note: sndio reports a huge range of available channels. This is inconvenient for us because there's no real way, as far as I can tell, to get the _actual_ channel count of the device. I'm therefore restricting this to the requested channels, regardless of whether or not the default channel count is requested. For hardware devices, I'm suspecting only a single channel count will be reported and we can safely use the value returned by ma_find_best_channels_from_sio_cap__sndio(). */ if (deviceType == ma_device_type_capture) { if (pDevice->capture.usingDefaultFormat) { format = ma_find_best_format_from_sio_cap__sndio(&caps); } if (pDevice->capture.usingDefaultChannels) { if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) { channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format); } } } else { if (pDevice->playback.usingDefaultFormat) { format = ma_find_best_format_from_sio_cap__sndio(&caps); } if (pDevice->playback.usingDefaultChannels) { if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) { channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format); } } } if (pDevice->usingDefaultSampleRate) { sampleRate = ma_find_best_sample_rate_from_sio_cap__sndio(&caps, pConfig->deviceType, format, channels); } ((ma_sio_initpar_proc)pDevice->pContext->sndio.sio_initpar)(&par); par.msb = 0; par.le = ma_is_little_endian(); switch (format) { case ma_format_u8: { par.bits = 8; par.bps = 1; par.sig = 0; } break; case ma_format_s24: { par.bits = 24; par.bps = 3; par.sig = 1; } break; case ma_format_s32: { par.bits = 32; par.bps = 4; par.sig = 1; } break; case ma_format_s16: case ma_format_f32: default: { par.bits = 16; par.bps = 2; par.sig = 1; } break; } if (deviceType == ma_device_type_capture) { par.rchan = channels; } else { par.pchan = channels; } par.rate = sampleRate; internalBufferSizeInFrames = pConfig->bufferSizeInFrames; if (internalBufferSizeInFrames == 0) { internalBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, par.rate); } par.round = internalBufferSizeInFrames / pConfig->periods; par.appbufsz = par.round * pConfig->periods; if (((ma_sio_setpar_proc)pContext->sndio.sio_setpar)((struct ma_sio_hdl*)handle, &par) == 0) { ((ma_sio_close_proc)pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size.", MA_FORMAT_NOT_SUPPORTED); } if (((ma_sio_getpar_proc)pContext->sndio.sio_getpar)((struct ma_sio_hdl*)handle, &par) == 0) { ((ma_sio_close_proc)pContext->sndio.sio_close)((struct ma_sio_hdl*)handle); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size.", MA_FORMAT_NOT_SUPPORTED); } internalFormat = ma_format_from_sio_enc__sndio(par.bits, par.bps, par.sig, par.le, par.msb); internalChannels = (deviceType == ma_device_type_capture) ? par.rchan : par.pchan; internalSampleRate = par.rate; internalPeriods = par.appbufsz / par.round; internalBufferSizeInFrames = par.appbufsz; if (deviceType == ma_device_type_capture) { pDevice->sndio.handleCapture = handle; pDevice->capture.internalFormat = internalFormat; pDevice->capture.internalChannels = internalChannels; pDevice->capture.internalSampleRate = internalSampleRate; ma_get_standard_channel_map(ma_standard_channel_map_sndio, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); pDevice->capture.internalBufferSizeInFrames = internalBufferSizeInFrames; pDevice->capture.internalPeriods = internalPeriods; } else { pDevice->sndio.handlePlayback = handle; pDevice->playback.internalFormat = internalFormat; pDevice->playback.internalChannels = internalChannels; pDevice->playback.internalSampleRate = internalSampleRate; ma_get_standard_channel_map(ma_standard_channel_map_sndio, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); pDevice->playback.internalBufferSizeInFrames = internalBufferSizeInFrames; pDevice->playback.internalPeriods = internalPeriods; } #ifdef MA_DEBUG_OUTPUT printf("DEVICE INFO\n"); printf(" Format: %s\n", ma_get_format_name(internalFormat)); printf(" Channels: %d\n", internalChannels); printf(" Sample Rate: %d\n", internalSampleRate); printf(" Buffer Size: %d\n", internalBufferSizeInFrames); printf(" Periods: %d\n", internalPeriods); printf(" appbufsz: %d\n", par.appbufsz); printf(" round: %d\n", par.round); #endif return MA_SUCCESS; } ma_result ma_device_init__sndio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_assert(pDevice != NULL); ma_zero_object(&pDevice->sndio); if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_handle__sndio(pContext, pConfig, ma_device_type_capture, pDevice); if (result != MA_SUCCESS) { return result; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_handle__sndio(pContext, pConfig, ma_device_type_playback, pDevice); if (result != MA_SUCCESS) { return result; } } return MA_SUCCESS; } ma_result ma_device_stop__sndio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handleCapture); ma_atomic_exchange_32(&pDevice->sndio.isStartedCapture, MA_FALSE); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); ma_atomic_exchange_32(&pDevice->sndio.isStartedPlayback, MA_FALSE); } return MA_SUCCESS; } ma_result ma_device_write__sndio(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount) { int result; if (!pDevice->sndio.isStartedPlayback) { ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); /* <-- Doesn't actually playback until data is written. */ ma_atomic_exchange_32(&pDevice->sndio.isStartedPlayback, MA_TRUE); } result = ((ma_sio_write_proc)pDevice->pContext->sndio.sio_write)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (result == 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device.", MA_FAILED_TO_SEND_DATA_TO_DEVICE); } return MA_SUCCESS; } ma_result ma_device_read__sndio(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount) { int result; if (!pDevice->sndio.isStartedCapture) { ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handleCapture); /* <-- Doesn't actually playback until data is written. */ ma_atomic_exchange_32(&pDevice->sndio.isStartedCapture, MA_TRUE); } result = ((ma_sio_read_proc)pDevice->pContext->sndio.sio_read)((struct ma_sio_hdl*)pDevice->sndio.handleCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (result == 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device.", MA_FAILED_TO_SEND_DATA_TO_DEVICE); } return MA_SUCCESS; } ma_result ma_context_uninit__sndio(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_sndio); (void)pContext; return MA_SUCCESS; } ma_result ma_context_init__sndio(const ma_context_config* pConfig, ma_context* pContext) { #ifndef MA_NO_RUNTIME_LINKING const char* libsndioNames[] = { "libsndio.so" }; size_t i; for (i = 0; i < ma_countof(libsndioNames); ++i) { pContext->sndio.sndioSO = ma_dlopen(pContext, libsndioNames[i]); if (pContext->sndio.sndioSO != NULL) { break; } } if (pContext->sndio.sndioSO == NULL) { return MA_NO_BACKEND; } pContext->sndio.sio_open = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_open"); pContext->sndio.sio_close = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_close"); pContext->sndio.sio_setpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_setpar"); pContext->sndio.sio_getpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getpar"); pContext->sndio.sio_getcap = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getcap"); pContext->sndio.sio_write = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_write"); pContext->sndio.sio_read = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_read"); pContext->sndio.sio_start = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_start"); pContext->sndio.sio_stop = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_stop"); pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_initpar"); #else pContext->sndio.sio_open = sio_open; pContext->sndio.sio_close = sio_close; pContext->sndio.sio_setpar = sio_setpar; pContext->sndio.sio_getpar = sio_getpar; pContext->sndio.sio_getcap = sio_getcap; pContext->sndio.sio_write = sio_write; pContext->sndio.sio_read = sio_read; pContext->sndio.sio_start = sio_start; pContext->sndio.sio_stop = sio_stop; pContext->sndio.sio_initpar = sio_initpar; #endif pContext->onUninit = ma_context_uninit__sndio; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__sndio; pContext->onEnumDevices = ma_context_enumerate_devices__sndio; pContext->onGetDeviceInfo = ma_context_get_device_info__sndio; pContext->onDeviceInit = ma_device_init__sndio; pContext->onDeviceUninit = ma_device_uninit__sndio; pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */ pContext->onDeviceStop = ma_device_stop__sndio; pContext->onDeviceWrite = ma_device_write__sndio; pContext->onDeviceRead = ma_device_read__sndio; (void)pConfig; return MA_SUCCESS; } #endif /* sndio */ /****************************************************************************** audio(4) Backend ******************************************************************************/ #ifdef MA_HAS_AUDIO4 #include #include #include #include #include #include #include #if defined(__OpenBSD__) #include #if defined(OpenBSD) && OpenBSD >= 201709 #define MA_AUDIO4_USE_NEW_API #endif #endif void ma_construct_device_id__audio4(char* id, size_t idSize, const char* base, int deviceIndex) { size_t baseLen; ma_assert(id != NULL); ma_assert(idSize > 0); ma_assert(deviceIndex >= 0); baseLen = strlen(base); ma_assert(idSize > baseLen); ma_strcpy_s(id, idSize, base); ma_itoa_s(deviceIndex, id+baseLen, idSize-baseLen, 10); } ma_result ma_extract_device_index_from_id__audio4(const char* id, const char* base, int* pIndexOut) { size_t idLen; size_t baseLen; const char* deviceIndexStr; ma_assert(id != NULL); ma_assert(base != NULL); ma_assert(pIndexOut != NULL); idLen = strlen(id); baseLen = strlen(base); if (idLen <= baseLen) { return MA_ERROR; /* Doesn't look like the id starts with the base. */ } if (strncmp(id, base, baseLen) != 0) { return MA_ERROR; /* ID does not begin with base. */ } deviceIndexStr = id + baseLen; if (deviceIndexStr[0] == '\0') { return MA_ERROR; /* No index specified in the ID. */ } if (pIndexOut) { *pIndexOut = atoi(deviceIndexStr); } return MA_SUCCESS; } ma_bool32 ma_context_is_device_id_equal__audio4(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return ma_strcmp(pID0->audio4, pID1->audio4) == 0; } #if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */ ma_format ma_format_from_encoding__audio4(unsigned int encoding, unsigned int precision) { if (precision == 8 && (encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR_LE || encoding == AUDIO_ENCODING_ULINEAR_BE)) { return ma_format_u8; } else { if (ma_is_little_endian() && encoding == AUDIO_ENCODING_SLINEAR_LE) { if (precision == 16) { return ma_format_s16; } else if (precision == 24) { return ma_format_s24; } else if (precision == 32) { return ma_format_s32; } } else if (ma_is_big_endian() && encoding == AUDIO_ENCODING_SLINEAR_BE) { if (precision == 16) { return ma_format_s16; } else if (precision == 24) { return ma_format_s24; } else if (precision == 32) { return ma_format_s32; } } } return ma_format_unknown; /* Encoding not supported. */ } void ma_encoding_from_format__audio4(ma_format format, unsigned int* pEncoding, unsigned int* pPrecision) { ma_assert(format != ma_format_unknown); ma_assert(pEncoding != NULL); ma_assert(pPrecision != NULL); switch (format) { case ma_format_u8: { *pEncoding = AUDIO_ENCODING_ULINEAR; *pPrecision = 8; } break; case ma_format_s24: { *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE; *pPrecision = 24; } break; case ma_format_s32: { *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE; *pPrecision = 32; } break; case ma_format_s16: case ma_format_f32: default: { *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE; *pPrecision = 16; } break; } } ma_format ma_format_from_prinfo__audio4(struct audio_prinfo* prinfo) { return ma_format_from_encoding__audio4(prinfo->encoding, prinfo->precision); } #else ma_format ma_format_from_swpar__audio4(struct audio_swpar* par) { if (par->bits == 8 && par->bps == 1 && par->sig == 0) { return ma_format_u8; } if (par->bits == 16 && par->bps == 2 && par->sig == 1 && par->le == ma_is_little_endian()) { return ma_format_s16; } if (par->bits == 24 && par->bps == 3 && par->sig == 1 && par->le == ma_is_little_endian()) { return ma_format_s24; } if (par->bits == 32 && par->bps == 4 && par->sig == 1 && par->le == ma_is_little_endian()) { return ma_format_f32; } /* Format not supported. */ return ma_format_unknown; } #endif ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext, ma_device_type deviceType, int fd, ma_device_info* pInfoOut) { audio_device_t fdDevice; #if !defined(MA_AUDIO4_USE_NEW_API) int counter = 0; audio_info_t fdInfo; #else struct audio_swpar fdPar; ma_format format; #endif ma_assert(pContext != NULL); ma_assert(fd >= 0); ma_assert(pInfoOut != NULL); (void)pContext; (void)deviceType; if (ioctl(fd, AUDIO_GETDEV, &fdDevice) < 0) { return MA_ERROR; /* Failed to retrieve device info. */ } /* Name. */ ma_strcpy_s(pInfoOut->name, sizeof(pInfoOut->name), fdDevice.name); #if !defined(MA_AUDIO4_USE_NEW_API) /* Supported formats. We get this by looking at the encodings. */ for (;;) { audio_encoding_t encoding; ma_format format; ma_zero_object(&encoding); encoding.index = counter; if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) { break; } format = ma_format_from_encoding__audio4(encoding.encoding, encoding.precision); if (format != ma_format_unknown) { pInfoOut->formats[pInfoOut->formatCount++] = format; } counter += 1; } if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) { return MA_ERROR; } if (deviceType == ma_device_type_playback) { pInfoOut->minChannels = fdInfo.play.channels; pInfoOut->maxChannels = fdInfo.play.channels; pInfoOut->minSampleRate = fdInfo.play.sample_rate; pInfoOut->maxSampleRate = fdInfo.play.sample_rate; } else { pInfoOut->minChannels = fdInfo.record.channels; pInfoOut->maxChannels = fdInfo.record.channels; pInfoOut->minSampleRate = fdInfo.record.sample_rate; pInfoOut->maxSampleRate = fdInfo.record.sample_rate; } #else if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) { return MA_ERROR; } format = ma_format_from_swpar__audio4(&fdPar); if (format == ma_format_unknown) { return MA_FORMAT_NOT_SUPPORTED; } pInfoOut->formats[pInfoOut->formatCount++] = format; if (deviceType == ma_device_type_playback) { pInfoOut->minChannels = fdPar.pchan; pInfoOut->maxChannels = fdPar.pchan; } else { pInfoOut->minChannels = fdPar.rchan; pInfoOut->maxChannels = fdPar.rchan; } pInfoOut->minSampleRate = fdPar.rate; pInfoOut->maxSampleRate = fdPar.rate; #endif return MA_SUCCESS; } ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { const int maxDevices = 64; char devpath[256]; int iDevice; ma_assert(pContext != NULL); ma_assert(callback != NULL); /* Every device will be named "/dev/audioN", with a "/dev/audioctlN" equivalent. We use the "/dev/audioctlN" version here since we can open it even when another process has control of the "/dev/audioN" device. */ for (iDevice = 0; iDevice < maxDevices; ++iDevice) { struct stat st; int fd; ma_bool32 isTerminating = MA_FALSE; ma_strcpy_s(devpath, sizeof(devpath), "/dev/audioctl"); ma_itoa_s(iDevice, devpath+strlen(devpath), sizeof(devpath)-strlen(devpath), 10); if (stat(devpath, &st) < 0) { break; } /* The device exists, but we need to check if it's usable as playback and/or capture. */ /* Playback. */ if (!isTerminating) { fd = open(devpath, O_RDONLY, 0); if (fd >= 0) { /* Supports playback. */ ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice); if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_playback, fd, &deviceInfo) == MA_SUCCESS) { isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } close(fd); } } /* Capture. */ if (!isTerminating) { fd = open(devpath, O_WRONLY, 0); if (fd >= 0) { /* Supports capture. */ ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice); if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_capture, fd, &deviceInfo) == MA_SUCCESS) { isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } close(fd); } } if (isTerminating) { break; } } return MA_SUCCESS; } ma_result ma_context_get_device_info__audio4(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { int fd = -1; int deviceIndex = -1; char ctlid[256]; ma_result result; ma_assert(pContext != NULL); (void)shareMode; /* We need to open the "/dev/audioctlN" device to get the info. To do this we need to extract the number from the device ID which will be in "/dev/audioN" format. */ if (pDeviceID == NULL) { /* Default device. */ ma_strcpy_s(ctlid, sizeof(ctlid), "/dev/audioctl"); } else { /* Specific device. We need to convert from "/dev/audioN" to "/dev/audioctlN". */ result = ma_extract_device_index_from_id__audio4(pDeviceID->audio4, "/dev/audio", &deviceIndex); if (result != MA_SUCCESS) { return result; } ma_construct_device_id__audio4(ctlid, sizeof(ctlid), "/dev/audioctl", deviceIndex); } fd = open(ctlid, (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY, 0); if (fd == -1) { return MA_NO_DEVICE; } if (deviceIndex == -1) { ma_strcpy_s(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio"); } else { ma_construct_device_id__audio4(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio", deviceIndex); } result = ma_context_get_device_info_from_fd__audio4(pContext, deviceType, fd, pDeviceInfo); close(fd); return result; } void ma_device_uninit__audio4(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { close(pDevice->audio4.fdCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { close(pDevice->audio4.fdPlayback); } } ma_result ma_device_init_fd__audio4(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice) { const char* pDefaultDeviceNames[] = { "/dev/audio", "/dev/audio0" }; int fd; int fdFlags = 0; #if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */ audio_info_t fdInfo; #else struct audio_swpar fdPar; #endif ma_format internalFormat; ma_uint32 internalChannels; ma_uint32 internalSampleRate; ma_uint32 internalBufferSizeInFrames; ma_uint32 internalPeriods; ma_assert(pContext != NULL); ma_assert(pConfig != NULL); ma_assert(deviceType != ma_device_type_duplex); ma_assert(pDevice != NULL); (void)pContext; /* The first thing to do is open the file. */ if (deviceType == ma_device_type_capture) { fdFlags = O_RDONLY; } else { fdFlags = O_WRONLY; } fdFlags |= O_NONBLOCK; if ((deviceType == ma_device_type_capture && pConfig->capture.pDeviceID == NULL) || (deviceType == ma_device_type_playback && pConfig->playback.pDeviceID == NULL)) { /* Default device. */ size_t iDevice; for (iDevice = 0; iDevice < ma_countof(pDefaultDeviceNames); ++iDevice) { fd = open(pDefaultDeviceNames[iDevice], fdFlags, 0); if (fd != -1) { break; } } } else { /* Specific device. */ fd = open((deviceType == ma_device_type_capture) ? pConfig->capture.pDeviceID->audio4 : pConfig->playback.pDeviceID->audio4, fdFlags, 0); } if (fd == -1) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } #if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */ AUDIO_INITINFO(&fdInfo); /* We get the driver to do as much of the data conversion as possible. */ if (deviceType == ma_device_type_capture) { fdInfo.mode = AUMODE_RECORD; ma_encoding_from_format__audio4(pConfig->capture.format, &fdInfo.record.encoding, &fdInfo.record.precision); fdInfo.record.channels = pConfig->capture.channels; fdInfo.record.sample_rate = pConfig->sampleRate; } else { fdInfo.mode = AUMODE_PLAY; ma_encoding_from_format__audio4(pConfig->playback.format, &fdInfo.play.encoding, &fdInfo.play.precision); fdInfo.play.channels = pConfig->playback.channels; fdInfo.play.sample_rate = pConfig->sampleRate; } if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED); } if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.", MA_FORMAT_NOT_SUPPORTED); } if (deviceType == ma_device_type_capture) { internalFormat = ma_format_from_prinfo__audio4(&fdInfo.record); internalChannels = fdInfo.record.channels; internalSampleRate = fdInfo.record.sample_rate; } else { internalFormat = ma_format_from_prinfo__audio4(&fdInfo.play); internalChannels = fdInfo.play.channels; internalSampleRate = fdInfo.play.sample_rate; } if (internalFormat == ma_format_unknown) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); } /* Buffer. */ { ma_uint32 internalBufferSizeInBytes; internalBufferSizeInFrames = pConfig->bufferSizeInFrames; if (internalBufferSizeInFrames == 0) { internalBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, internalSampleRate); } internalBufferSizeInBytes = internalBufferSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels); if (internalBufferSizeInBytes < 16) { internalBufferSizeInBytes = 16; } internalPeriods = pConfig->periods; if (internalPeriods < 2) { internalPeriods = 2; } /* What miniaudio calls a fragment, audio4 calls a block. */ AUDIO_INITINFO(&fdInfo); fdInfo.hiwat = internalPeriods; fdInfo.lowat = internalPeriods-1; fdInfo.blocksize = internalBufferSizeInBytes / internalPeriods; if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED); } internalPeriods = fdInfo.hiwat; internalBufferSizeInFrames = (fdInfo.blocksize * fdInfo.hiwat) / ma_get_bytes_per_frame(internalFormat, internalChannels); } #else /* We need to retrieve the format of the device so we can know the channel count and sample rate. Then we can calculate the buffer size. */ if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.", MA_FORMAT_NOT_SUPPORTED); } internalFormat = ma_format_from_swpar__audio4(&fdPar); internalChannels = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan; internalSampleRate = fdPar.rate; if (internalFormat == ma_format_unknown) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); } /* Buffer. */ { ma_uint32 internalBufferSizeInBytes; internalBufferSizeInFrames = pConfig->bufferSizeInFrames; if (internalBufferSizeInFrames == 0) { internalBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, internalSampleRate); } /* What miniaudio calls a fragment, audio4 calls a block. */ internalBufferSizeInBytes = internalBufferSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels); if (internalBufferSizeInBytes < 16) { internalBufferSizeInBytes = 16; } fdPar.nblks = pConfig->periods; fdPar.round = internalBufferSizeInBytes / fdPar.nblks; if (ioctl(fd, AUDIO_SETPAR, &fdPar) < 0) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.", MA_FORMAT_NOT_SUPPORTED); } if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.", MA_FORMAT_NOT_SUPPORTED); } } internalFormat = ma_format_from_swpar__audio4(&fdPar); internalChannels = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan; internalSampleRate = fdPar.rate; internalPeriods = fdPar.nblks; internalBufferSizeInFrames = (fdPar.nblks * fdPar.round) / ma_get_bytes_per_frame(internalFormat, internalChannels); #endif if (internalFormat == ma_format_unknown) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED); } if (deviceType == ma_device_type_capture) { pDevice->audio4.fdCapture = fd; pDevice->capture.internalFormat = internalFormat; pDevice->capture.internalChannels = internalChannels; pDevice->capture.internalSampleRate = internalSampleRate; ma_get_standard_channel_map(ma_standard_channel_map_sound4, internalChannels, pDevice->capture.internalChannelMap); pDevice->capture.internalBufferSizeInFrames = internalBufferSizeInFrames; pDevice->capture.internalPeriods = internalPeriods; } else { pDevice->audio4.fdPlayback = fd; pDevice->playback.internalFormat = internalFormat; pDevice->playback.internalChannels = internalChannels; pDevice->playback.internalSampleRate = internalSampleRate; ma_get_standard_channel_map(ma_standard_channel_map_sound4, internalChannels, pDevice->playback.internalChannelMap); pDevice->playback.internalBufferSizeInFrames = internalBufferSizeInFrames; pDevice->playback.internalPeriods = internalPeriods; } return MA_SUCCESS; } ma_result ma_device_init__audio4(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_assert(pDevice != NULL); ma_zero_object(&pDevice->audio4); pDevice->audio4.fdCapture = -1; pDevice->audio4.fdPlayback = -1; /* The version of the operating system dictates whether or not the device is exclusive or shared. NetBSD introduced in-kernel mixing which means it's shared. All other BSD flavours are exclusive as far as I'm aware. */ #if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 800000000 /* NetBSD 8.0+ */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; } #else /* All other flavors. */ #endif if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_fd__audio4(pContext, pConfig, ma_device_type_capture, pDevice); if (result != MA_SUCCESS) { return result; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_fd__audio4(pContext, pConfig, ma_device_type_playback, pDevice); if (result != MA_SUCCESS) { if (pConfig->deviceType == ma_device_type_duplex) { close(pDevice->audio4.fdCapture); } return result; } } return MA_SUCCESS; } #if 0 ma_result ma_device_start__audio4(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (pDevice->audio4.fdCapture == -1) { return MA_INVALID_ARGS; } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->audio4.fdPlayback == -1) { return MA_INVALID_ARGS; } } return MA_SUCCESS; } #endif ma_result ma_device_stop_fd__audio4(ma_device* pDevice, int fd) { if (fd == -1) { return MA_INVALID_ARGS; } #if !defined(MA_AUDIO4_USE_NEW_API) if (ioctl(fd, AUDIO_FLUSH, 0) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } #else if (ioctl(fd, AUDIO_STOP, 0) < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } #endif return MA_SUCCESS; } ma_result ma_device_stop__audio4(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_result result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdCapture); if (result != MA_SUCCESS) { return result; } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_result result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdPlayback); if (result != MA_SUCCESS) { return result; } } return MA_SUCCESS; } ma_result ma_device_write__audio4(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount) { int result = write(pDevice->audio4.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (result < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.", MA_FAILED_TO_SEND_DATA_TO_DEVICE); } return MA_SUCCESS; } ma_result ma_device_read__audio4(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount) { int result = read(pDevice->audio4.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (result < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.", MA_FAILED_TO_READ_DATA_FROM_DEVICE); } return MA_SUCCESS; } ma_result ma_context_uninit__audio4(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_audio4); (void)pContext; return MA_SUCCESS; } ma_result ma_context_init__audio4(const ma_context_config* pConfig, ma_context* pContext) { ma_assert(pContext != NULL); (void)pConfig; pContext->onUninit = ma_context_uninit__audio4; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__audio4; pContext->onEnumDevices = ma_context_enumerate_devices__audio4; pContext->onGetDeviceInfo = ma_context_get_device_info__audio4; pContext->onDeviceInit = ma_device_init__audio4; pContext->onDeviceUninit = ma_device_uninit__audio4; pContext->onDeviceStart = NULL; pContext->onDeviceStop = ma_device_stop__audio4; pContext->onDeviceWrite = ma_device_write__audio4; pContext->onDeviceRead = ma_device_read__audio4; return MA_SUCCESS; } #endif /* audio4 */ /****************************************************************************** OSS Backend ******************************************************************************/ #ifdef MA_HAS_OSS #include #include #include #include #ifndef SNDCTL_DSP_HALT #define SNDCTL_DSP_HALT SNDCTL_DSP_RESET #endif int ma_open_temp_device__oss() { /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */ int fd = open("/dev/mixer", O_RDONLY, 0); if (fd >= 0) { return fd; } return -1; } ma_result ma_context_open_device__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, int* pfd) { const char* deviceName; int flags; ma_assert(pContext != NULL); ma_assert(pfd != NULL); (void)pContext; *pfd = -1; /* This function should only be called for playback or capture, not duplex. */ if (deviceType == ma_device_type_duplex) { return MA_INVALID_ARGS; } deviceName = "/dev/dsp"; if (pDeviceID != NULL) { deviceName = pDeviceID->oss; } flags = (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY; if (shareMode == ma_share_mode_exclusive) { flags |= O_EXCL; } *pfd = open(deviceName, flags, 0); if (*pfd == -1) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } return MA_SUCCESS; } ma_bool32 ma_context_is_device_id_equal__oss(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return ma_strcmp(pID0->oss, pID1->oss) == 0; } ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { int fd; oss_sysinfo si; int result; ma_assert(pContext != NULL); ma_assert(callback != NULL); fd = ma_open_temp_device__oss(); if (fd == -1) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND); } result = ioctl(fd, SNDCTL_SYSINFO, &si); if (result != -1) { int iAudioDevice; for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) { oss_audioinfo ai; ai.dev = iAudioDevice; result = ioctl(fd, SNDCTL_AUDIOINFO, &ai); if (result != -1) { if (ai.devnode[0] != '\0') { /* <-- Can be blank, according to documentation. */ ma_device_info deviceInfo; ma_bool32 isTerminating = MA_FALSE; ma_zero_object(&deviceInfo); /* ID */ ma_strncpy_s(deviceInfo.id.oss, sizeof(deviceInfo.id.oss), ai.devnode, (size_t)-1); /* The human readable device name should be in the "ai.handle" variable, but it can sometimes be empty in which case we just fall back to "ai.name" which is less user friendly, but usually has a value. */ if (ai.handle[0] != '\0') { ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.handle, (size_t)-1); } else { ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.name, (size_t)-1); } /* The device can be both playback and capture. */ if (!isTerminating && (ai.caps & PCM_CAP_OUTPUT) != 0) { isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } if (!isTerminating && (ai.caps & PCM_CAP_INPUT) != 0) { isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } if (isTerminating) { break; } } } } } else { close(fd); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND); } close(fd); return MA_SUCCESS; } ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_bool32 foundDevice; int fdTemp; oss_sysinfo si; int result; ma_assert(pContext != NULL); (void)shareMode; /* Handle the default device a little differently. */ if (pDeviceID == NULL) { if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } return MA_SUCCESS; } /* If we get here it means we are _not_ using the default device. */ foundDevice = MA_FALSE; fdTemp = ma_open_temp_device__oss(); if (fdTemp == -1) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND); } result = ioctl(fdTemp, SNDCTL_SYSINFO, &si); if (result != -1) { int iAudioDevice; for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) { oss_audioinfo ai; ai.dev = iAudioDevice; result = ioctl(fdTemp, SNDCTL_AUDIOINFO, &ai); if (result != -1) { if (ma_strcmp(ai.devnode, pDeviceID->oss) == 0) { /* It has the same name, so now just confirm the type. */ if ((deviceType == ma_device_type_playback && ((ai.caps & PCM_CAP_OUTPUT) != 0)) || (deviceType == ma_device_type_capture && ((ai.caps & PCM_CAP_INPUT) != 0))) { unsigned int formatMask; /* ID */ ma_strncpy_s(pDeviceInfo->id.oss, sizeof(pDeviceInfo->id.oss), ai.devnode, (size_t)-1); /* The human readable device name should be in the "ai.handle" variable, but it can sometimes be empty in which case we just fall back to "ai.name" which is less user friendly, but usually has a value. */ if (ai.handle[0] != '\0') { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.handle, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.name, (size_t)-1); } pDeviceInfo->minChannels = ai.min_channels; pDeviceInfo->maxChannels = ai.max_channels; pDeviceInfo->minSampleRate = ai.min_rate; pDeviceInfo->maxSampleRate = ai.max_rate; pDeviceInfo->formatCount = 0; if (deviceType == ma_device_type_playback) { formatMask = ai.oformats; } else { formatMask = ai.iformats; } if ((formatMask & AFMT_U8) != 0) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_u8; } if (((formatMask & AFMT_S16_LE) != 0 && ma_is_little_endian()) || (AFMT_S16_BE && ma_is_big_endian())) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s16; } if (((formatMask & AFMT_S32_LE) != 0 && ma_is_little_endian()) || (AFMT_S32_BE && ma_is_big_endian())) { pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s32; } foundDevice = MA_TRUE; break; } } } } } else { close(fdTemp); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND); } close(fdTemp); if (!foundDevice) { return MA_NO_DEVICE; } return MA_SUCCESS; } void ma_device_uninit__oss(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { close(pDevice->oss.fdCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { close(pDevice->oss.fdPlayback); } } int ma_format_to_oss(ma_format format) { int ossFormat = AFMT_U8; switch (format) { case ma_format_s16: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break; case ma_format_s24: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break; case ma_format_s32: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break; case ma_format_f32: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break; case ma_format_u8: default: ossFormat = AFMT_U8; break; } return ossFormat; } ma_format ma_format_from_oss(int ossFormat) { if (ossFormat == AFMT_U8) { return ma_format_u8; } else { if (ma_is_little_endian()) { switch (ossFormat) { case AFMT_S16_LE: return ma_format_s16; case AFMT_S32_LE: return ma_format_s32; default: return ma_format_unknown; } } else { switch (ossFormat) { case AFMT_S16_BE: return ma_format_s16; case AFMT_S32_BE: return ma_format_s32; default: return ma_format_unknown; } } } return ma_format_unknown; } ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice) { ma_result result; int ossResult; int fd; const ma_device_id* pDeviceID = NULL; ma_share_mode shareMode; int ossFormat; int ossChannels; int ossSampleRate; int ossFragment; ma_assert(pContext != NULL); ma_assert(pConfig != NULL); ma_assert(deviceType != ma_device_type_duplex); ma_assert(pDevice != NULL); (void)pContext; if (deviceType == ma_device_type_capture) { pDeviceID = pConfig->capture.pDeviceID; shareMode = pConfig->capture.shareMode; ossFormat = ma_format_to_oss(pConfig->capture.format); ossChannels = (int)pConfig->capture.channels; ossSampleRate = (int)pConfig->sampleRate; } else { pDeviceID = pConfig->playback.pDeviceID; shareMode = pConfig->playback.shareMode; ossFormat = ma_format_to_oss(pConfig->playback.format); ossChannels = (int)pConfig->playback.channels; ossSampleRate = (int)pConfig->sampleRate; } result = ma_context_open_device__oss(pContext, deviceType, pDeviceID, shareMode, &fd); if (result != MA_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* The OSS documantation is very clear about the order we should be initializing the device's properties: 1) Format 2) Channels 3) Sample rate. */ /* Format. */ ossResult = ioctl(fd, SNDCTL_DSP_SETFMT, &ossFormat); if (ossResult == -1) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format.", MA_FORMAT_NOT_SUPPORTED); } /* Channels. */ ossResult = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossChannels); if (ossResult == -1) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count.", MA_FORMAT_NOT_SUPPORTED); } /* Sample Rate. */ ossResult = ioctl(fd, SNDCTL_DSP_SPEED, &ossSampleRate); if (ossResult == -1) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate.", MA_FORMAT_NOT_SUPPORTED); } /* Buffer. The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if it should be done before or after format/channels/rate. OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual value. */ { ma_uint32 fragmentSizeInBytes; ma_uint32 bufferSizeInFrames; ma_uint32 ossFragmentSizePower; bufferSizeInFrames = pConfig->bufferSizeInFrames; if (bufferSizeInFrames == 0) { bufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, (ma_uint32)ossSampleRate); } fragmentSizeInBytes = ma_round_to_power_of_2((bufferSizeInFrames / pConfig->periods) * ma_get_bytes_per_frame(ma_format_from_oss(ossFormat), ossChannels)); if (fragmentSizeInBytes < 16) { fragmentSizeInBytes = 16; } ossFragmentSizePower = 4; fragmentSizeInBytes >>= 4; while (fragmentSizeInBytes >>= 1) { ossFragmentSizePower += 1; } ossFragment = (int)((pConfig->periods << 16) | ossFragmentSizePower); ossResult = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment); if (ossResult == -1) { close(fd); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count.", MA_FORMAT_NOT_SUPPORTED); } } /* Internal settings. */ if (deviceType == ma_device_type_capture) { pDevice->oss.fdCapture = fd; pDevice->capture.internalFormat = ma_format_from_oss(ossFormat); pDevice->capture.internalChannels = ossChannels; pDevice->capture.internalSampleRate = ossSampleRate; ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); pDevice->capture.internalPeriods = (ma_uint32)(ossFragment >> 16); pDevice->capture.internalBufferSizeInFrames = (((ma_uint32)(1 << (ossFragment & 0xFFFF))) * pDevice->capture.internalPeriods) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); if (pDevice->capture.internalFormat == ma_format_unknown) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED); } } else { pDevice->oss.fdPlayback = fd; pDevice->playback.internalFormat = ma_format_from_oss(ossFormat); pDevice->playback.internalChannels = ossChannels; pDevice->playback.internalSampleRate = ossSampleRate; ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); pDevice->playback.internalPeriods = (ma_uint32)(ossFragment >> 16); pDevice->playback.internalBufferSizeInFrames = (((ma_uint32)(1 << (ossFragment & 0xFFFF))) * pDevice->playback.internalPeriods) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); if (pDevice->playback.internalFormat == ma_format_unknown) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED); } } return MA_SUCCESS; } ma_result ma_device_init__oss(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_assert(pContext != NULL); ma_assert(pConfig != NULL); ma_assert(pDevice != NULL); ma_zero_object(&pDevice->oss); if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_fd__oss(pContext, pConfig, ma_device_type_capture, pDevice); if (result != MA_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_fd__oss(pContext, pConfig, ma_device_type_playback, pDevice); if (result != MA_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } } return MA_SUCCESS; } ma_result ma_device_stop__oss(ma_device* pDevice) { ma_assert(pDevice != NULL); /* We want to use SNDCTL_DSP_HALT. From the documentation: In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread that actually reads/writes the audio device. It must not be called by some master thread to kill the audio thread. The audio thread will not stop or get any kind of notification that the device was stopped by the master thread. The device gets stopped but the next read or write call will silently restart the device. This is actually safe in our case, because this function is only ever called from within our worker thread anyway. Just keep this in mind, though... */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { int result = ioctl(pDevice->oss.fdCapture, SNDCTL_DSP_HALT, 0); if (result == -1) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { int result = ioctl(pDevice->oss.fdPlayback, SNDCTL_DSP_HALT, 0); if (result == -1) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } } return MA_SUCCESS; } ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount) { int resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); if (resultOSS < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.", MA_FAILED_TO_SEND_DATA_TO_DEVICE); } return MA_SUCCESS; } ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount) { int resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); if (resultOSS < 0) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.", MA_FAILED_TO_READ_DATA_FROM_DEVICE); } return MA_SUCCESS; } ma_result ma_context_uninit__oss(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_oss); (void)pContext; return MA_SUCCESS; } ma_result ma_context_init__oss(const ma_context_config* pConfig, ma_context* pContext) { int fd; int ossVersion; int result; ma_assert(pContext != NULL); (void)pConfig; /* Try opening a temporary device first so we can get version information. This is closed at the end. */ fd = ma_open_temp_device__oss(); if (fd == -1) { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties.", MA_NO_BACKEND); /* Looks liks OSS isn't installed, or there are no available devices. */ } /* Grab the OSS version. */ ossVersion = 0; result = ioctl(fd, OSS_GETVERSION, &ossVersion); if (result == -1) { close(fd); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version.", MA_NO_BACKEND); } pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16); pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8); pContext->onUninit = ma_context_uninit__oss; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__oss; pContext->onEnumDevices = ma_context_enumerate_devices__oss; pContext->onGetDeviceInfo = ma_context_get_device_info__oss; pContext->onDeviceInit = ma_device_init__oss; pContext->onDeviceUninit = ma_device_uninit__oss; pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */ pContext->onDeviceStop = ma_device_stop__oss; pContext->onDeviceWrite = ma_device_write__oss; pContext->onDeviceRead = ma_device_read__oss; close(fd); return MA_SUCCESS; } #endif /* OSS */ /****************************************************************************** AAudio Backend ******************************************************************************/ #ifdef MA_HAS_AAUDIO /*#include */ #define MA_AAUDIO_UNSPECIFIED 0 typedef int32_t ma_aaudio_result_t; typedef int32_t ma_aaudio_direction_t; typedef int32_t ma_aaudio_sharing_mode_t; typedef int32_t ma_aaudio_format_t; typedef int32_t ma_aaudio_stream_state_t; typedef int32_t ma_aaudio_performance_mode_t; typedef int32_t ma_aaudio_data_callback_result_t; /* Result codes. miniaudio only cares about the success code. */ #define MA_AAUDIO_OK 0 /* Directions. */ #define MA_AAUDIO_DIRECTION_OUTPUT 0 #define MA_AAUDIO_DIRECTION_INPUT 1 /* Sharing modes. */ #define MA_AAUDIO_SHARING_MODE_EXCLUSIVE 0 #define MA_AAUDIO_SHARING_MODE_SHARED 1 /* Formats. */ #define MA_AAUDIO_FORMAT_PCM_I16 1 #define MA_AAUDIO_FORMAT_PCM_FLOAT 2 /* Stream states. */ #define MA_AAUDIO_STREAM_STATE_UNINITIALIZED 0 #define MA_AAUDIO_STREAM_STATE_UNKNOWN 1 #define MA_AAUDIO_STREAM_STATE_OPEN 2 #define MA_AAUDIO_STREAM_STATE_STARTING 3 #define MA_AAUDIO_STREAM_STATE_STARTED 4 #define MA_AAUDIO_STREAM_STATE_PAUSING 5 #define MA_AAUDIO_STREAM_STATE_PAUSED 6 #define MA_AAUDIO_STREAM_STATE_FLUSHING 7 #define MA_AAUDIO_STREAM_STATE_FLUSHED 8 #define MA_AAUDIO_STREAM_STATE_STOPPING 9 #define MA_AAUDIO_STREAM_STATE_STOPPED 10 #define MA_AAUDIO_STREAM_STATE_CLOSING 11 #define MA_AAUDIO_STREAM_STATE_CLOSED 12 #define MA_AAUDIO_STREAM_STATE_DISCONNECTED 13 /* Performance modes. */ #define MA_AAUDIO_PERFORMANCE_MODE_NONE 10 #define MA_AAUDIO_PERFORMANCE_MODE_POWER_SAVING 11 #define MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY 12 /* Callback results. */ #define MA_AAUDIO_CALLBACK_RESULT_CONTINUE 0 #define MA_AAUDIO_CALLBACK_RESULT_STOP 1 /* Objects. */ typedef struct ma_AAudioStreamBuilder_t* ma_AAudioStreamBuilder; typedef struct ma_AAudioStream_t* ma_AAudioStream; typedef ma_aaudio_data_callback_result_t (*ma_AAudioStream_dataCallback)(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t numFrames); typedef ma_aaudio_result_t (* MA_PFN_AAudio_createStreamBuilder) (ma_AAudioStreamBuilder** ppBuilder); typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_delete) (ma_AAudioStreamBuilder* pBuilder); typedef void (* MA_PFN_AAudioStreamBuilder_setDeviceId) (ma_AAudioStreamBuilder* pBuilder, int32_t deviceId); typedef void (* MA_PFN_AAudioStreamBuilder_setDirection) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_direction_t direction); typedef void (* MA_PFN_AAudioStreamBuilder_setSharingMode) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_sharing_mode_t sharingMode); typedef void (* MA_PFN_AAudioStreamBuilder_setFormat) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_format_t format); typedef void (* MA_PFN_AAudioStreamBuilder_setChannelCount) (ma_AAudioStreamBuilder* pBuilder, int32_t channelCount); typedef void (* MA_PFN_AAudioStreamBuilder_setSampleRate) (ma_AAudioStreamBuilder* pBuilder, int32_t sampleRate); typedef void (* MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)(ma_AAudioStreamBuilder* pBuilder, int32_t numFrames); typedef void (* MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback) (ma_AAudioStreamBuilder* pBuilder, int32_t numFrames); typedef void (* MA_PFN_AAudioStreamBuilder_setDataCallback) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_dataCallback callback, void* pUserData); typedef void (* MA_PFN_AAudioStreamBuilder_setPerformanceMode) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_performance_mode_t mode); typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_openStream) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream); typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_close) (ma_AAudioStream* pStream); typedef ma_aaudio_stream_state_t (* MA_PFN_AAudioStream_getState) (ma_AAudioStream* pStream); typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_waitForStateChange) (ma_AAudioStream* pStream, ma_aaudio_stream_state_t inputState, ma_aaudio_stream_state_t* pNextState, int64_t timeoutInNanoseconds); typedef ma_aaudio_format_t (* MA_PFN_AAudioStream_getFormat) (ma_AAudioStream* pStream); typedef int32_t (* MA_PFN_AAudioStream_getChannelCount) (ma_AAudioStream* pStream); typedef int32_t (* MA_PFN_AAudioStream_getSampleRate) (ma_AAudioStream* pStream); typedef int32_t (* MA_PFN_AAudioStream_getBufferCapacityInFrames) (ma_AAudioStream* pStream); typedef int32_t (* MA_PFN_AAudioStream_getFramesPerDataCallback) (ma_AAudioStream* pStream); typedef int32_t (* MA_PFN_AAudioStream_getFramesPerBurst) (ma_AAudioStream* pStream); typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_requestStart) (ma_AAudioStream* pStream); typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_requestStop) (ma_AAudioStream* pStream); ma_result ma_result_from_aaudio(ma_aaudio_result_t resultAA) { switch (resultAA) { case MA_AAUDIO_OK: return MA_SUCCESS; default: break; } return MA_ERROR; } ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount) { ma_device* pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_capture(pDevice, frameCount, pAudioData, &pDevice->aaudio.duplexRB); } else { ma_device__send_frames_to_client(pDevice, frameCount, pAudioData); /* Send directly to the client. */ } (void)pStream; return MA_AAUDIO_CALLBACK_RESULT_CONTINUE; } ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount) { ma_device* pDevice = (ma_device*)pUserData; ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_playback(pDevice, frameCount, pAudioData, &pDevice->aaudio.duplexRB); } else { ma_device__read_frames_from_client(pDevice, frameCount, pAudioData); /* Read directly from the client. */ } (void)pStream; return MA_AAUDIO_CALLBACK_RESULT_CONTINUE; } ma_result ma_open_stream__aaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, const ma_device_config* pConfig, const ma_device* pDevice, ma_AAudioStream** ppStream) { ma_AAudioStreamBuilder* pBuilder; ma_aaudio_result_t resultAA; ma_assert(deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */ *ppStream = NULL; resultAA = ((MA_PFN_AAudio_createStreamBuilder)pContext->aaudio.AAudio_createStreamBuilder)(&pBuilder); if (resultAA != MA_AAUDIO_OK) { return ma_result_from_aaudio(resultAA); } if (pDeviceID != NULL) { ((MA_PFN_AAudioStreamBuilder_setDeviceId)pContext->aaudio.AAudioStreamBuilder_setDeviceId)(pBuilder, pDeviceID->aaudio); } ((MA_PFN_AAudioStreamBuilder_setDirection)pContext->aaudio.AAudioStreamBuilder_setDirection)(pBuilder, (deviceType == ma_device_type_playback) ? MA_AAUDIO_DIRECTION_OUTPUT : MA_AAUDIO_DIRECTION_INPUT); ((MA_PFN_AAudioStreamBuilder_setSharingMode)pContext->aaudio.AAudioStreamBuilder_setSharingMode)(pBuilder, (shareMode == ma_share_mode_shared) ? MA_AAUDIO_SHARING_MODE_SHARED : MA_AAUDIO_SHARING_MODE_EXCLUSIVE); if (pConfig != NULL) { ma_uint32 bufferCapacityInFrames; if (pDevice == NULL || !pDevice->usingDefaultSampleRate) { ((MA_PFN_AAudioStreamBuilder_setSampleRate)pContext->aaudio.AAudioStreamBuilder_setSampleRate)(pBuilder, pConfig->sampleRate); } if (deviceType == ma_device_type_capture) { if (pDevice == NULL || !pDevice->capture.usingDefaultChannels) { ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pConfig->capture.channels); } if (pDevice == NULL || !pDevice->capture.usingDefaultFormat) { ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pConfig->capture.format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT); } } else { if (pDevice == NULL || !pDevice->playback.usingDefaultChannels) { ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pConfig->playback.channels); } if (pDevice == NULL || !pDevice->playback.usingDefaultFormat) { ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pConfig->playback.format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT); } } bufferCapacityInFrames = pConfig->bufferSizeInFrames; if (bufferCapacityInFrames == 0) { bufferCapacityInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, pConfig->sampleRate); } ((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder, bufferCapacityInFrames); ((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder, bufferCapacityInFrames / pConfig->periods); if (deviceType == ma_device_type_capture) { ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_capture__aaudio, (void*)pDevice); } else { ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_playback__aaudio, (void*)pDevice); } /* Not sure how this affects things, but since there's a mapping between miniaudio's performance profiles and AAudio's performance modes, let go ahead and set it. */ ((MA_PFN_AAudioStreamBuilder_setPerformanceMode)pContext->aaudio.AAudioStreamBuilder_setPerformanceMode)(pBuilder, (pConfig->performanceProfile == ma_performance_profile_low_latency) ? MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY : MA_AAUDIO_PERFORMANCE_MODE_NONE); } resultAA = ((MA_PFN_AAudioStreamBuilder_openStream)pContext->aaudio.AAudioStreamBuilder_openStream)(pBuilder, ppStream); if (resultAA != MA_AAUDIO_OK) { *ppStream = NULL; ((MA_PFN_AAudioStreamBuilder_delete)pContext->aaudio.AAudioStreamBuilder_delete)(pBuilder); return ma_result_from_aaudio(resultAA); } ((MA_PFN_AAudioStreamBuilder_delete)pContext->aaudio.AAudioStreamBuilder_delete)(pBuilder); return MA_SUCCESS; } ma_result ma_close_stream__aaudio(ma_context* pContext, ma_AAudioStream* pStream) { return ma_result_from_aaudio(((MA_PFN_AAudioStream_close)pContext->aaudio.AAudioStream_close)(pStream)); } ma_bool32 ma_has_default_device__aaudio(ma_context* pContext, ma_device_type deviceType) { /* The only way to know this is to try creating a stream. */ ma_AAudioStream* pStream; ma_result result = ma_open_stream__aaudio(pContext, deviceType, NULL, ma_share_mode_shared, NULL, NULL, &pStream); if (result != MA_SUCCESS) { return MA_FALSE; } ma_close_stream__aaudio(pContext, pStream); return MA_TRUE; } ma_result ma_wait_for_simple_state_transition__aaudio(ma_context* pContext, ma_AAudioStream* pStream, ma_aaudio_stream_state_t oldState, ma_aaudio_stream_state_t newState) { ma_aaudio_stream_state_t actualNewState; ma_aaudio_result_t resultAA = ((MA_PFN_AAudioStream_waitForStateChange)pContext->aaudio.AAudioStream_waitForStateChange)(pStream, oldState, &actualNewState, 5000000000); /* 5 second timeout. */ if (resultAA != MA_AAUDIO_OK) { return ma_result_from_aaudio(resultAA); } if (newState != actualNewState) { return MA_ERROR; /* Failed to transition into the expected state. */ } return MA_SUCCESS; } ma_bool32 ma_context_is_device_id_equal__aaudio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return pID0->aaudio == pID1->aaudio; } ma_result ma_context_enumerate_devices__aaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_bool32 cbResult = MA_TRUE; ma_assert(pContext != NULL); ma_assert(callback != NULL); /* Unfortunately AAudio does not have an enumeration API. Therefore I'm only going to report default devices, but only if it can instantiate a stream. */ /* Playback. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED; ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); if (ma_has_default_device__aaudio(pContext, ma_device_type_playback)) { cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } } /* Capture. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED; ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); if (ma_has_default_device__aaudio(pContext, ma_device_type_capture)) { cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } } return MA_SUCCESS; } ma_result ma_context_get_device_info__aaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_AAudioStream* pStream; ma_result result; ma_assert(pContext != NULL); /* No exclusive mode with AAudio. */ if (shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } /* ID */ if (pDeviceID != NULL) { pDeviceInfo->id.aaudio = pDeviceID->aaudio; } else { pDeviceInfo->id.aaudio = MA_AAUDIO_UNSPECIFIED; } /* Name */ if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } /* We'll need to open the device to get accurate sample rate and channel count information. */ result = ma_open_stream__aaudio(pContext, deviceType, pDeviceID, shareMode, NULL, NULL, &pStream); if (result != MA_SUCCESS) { return result; } pDeviceInfo->minChannels = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)(pStream); pDeviceInfo->maxChannels = pDeviceInfo->minChannels; pDeviceInfo->minSampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)(pStream); pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate; ma_close_stream__aaudio(pContext, pStream); pStream = NULL; /* AAudio supports s16 and f32. */ pDeviceInfo->formatCount = 2; pDeviceInfo->formats[0] = ma_format_s16; pDeviceInfo->formats[1] = ma_format_f32; return MA_SUCCESS; } void ma_device_uninit__aaudio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); pDevice->aaudio.pStreamCapture = NULL; } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); pDevice->aaudio.pStreamPlayback = NULL; } if (pDevice->type == ma_device_type_duplex) { ma_pcm_rb_uninit(&pDevice->aaudio.duplexRB); } } ma_result ma_device_init__aaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result; ma_assert(pDevice != NULL); /* No exclusive mode with AAudio. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; } /* We first need to try opening the stream. */ if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { int32_t framesPerPeriod; result = ma_open_stream__aaudio(pContext, ma_device_type_capture, pConfig->capture.pDeviceID, pConfig->capture.shareMode, pConfig, pDevice, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture); if (result != MA_SUCCESS) { return result; /* Failed to open the AAudio stream. */ } pDevice->capture.internalFormat = (((MA_PFN_AAudioStream_getFormat)pContext->aaudio.AAudioStream_getFormat)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture) == MA_AAUDIO_FORMAT_PCM_I16) ? ma_format_s16 : ma_format_f32; pDevice->capture.internalChannels = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture); pDevice->capture.internalSampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture); ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); /* <-- Cannot find info on channel order, so assuming a default. */ pDevice->capture.internalBufferSizeInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pContext->aaudio.AAudioStream_getBufferCapacityInFrames)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture); /* TODO: When synchronous reading and writing is supported, use AAudioStream_getFramesPerBurst() instead of AAudioStream_getFramesPerDataCallback(). Keep using AAudioStream_getFramesPerDataCallback() for asynchronous mode, though. */ framesPerPeriod = ((MA_PFN_AAudioStream_getFramesPerDataCallback)pContext->aaudio.AAudioStream_getFramesPerDataCallback)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture); if (framesPerPeriod > 0) { pDevice->capture.internalPeriods = 1; } else { pDevice->capture.internalPeriods = pDevice->capture.internalBufferSizeInFrames / framesPerPeriod; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { int32_t framesPerPeriod; result = ma_open_stream__aaudio(pContext, ma_device_type_playback, pConfig->playback.pDeviceID, pConfig->playback.shareMode, pConfig, pDevice, (ma_AAudioStream**)&pDevice->aaudio.pStreamPlayback); if (result != MA_SUCCESS) { return result; /* Failed to open the AAudio stream. */ } pDevice->playback.internalFormat = (((MA_PFN_AAudioStream_getFormat)pContext->aaudio.AAudioStream_getFormat)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback) == MA_AAUDIO_FORMAT_PCM_I16) ? ma_format_s16 : ma_format_f32; pDevice->playback.internalChannels = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); pDevice->playback.internalSampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); /* <-- Cannot find info on channel order, so assuming a default. */ pDevice->playback.internalBufferSizeInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pContext->aaudio.AAudioStream_getBufferCapacityInFrames)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); framesPerPeriod = ((MA_PFN_AAudioStream_getFramesPerDataCallback)pContext->aaudio.AAudioStream_getFramesPerDataCallback)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); if (framesPerPeriod > 0) { pDevice->playback.internalPeriods = 1; } else { pDevice->playback.internalPeriods = pDevice->playback.internalBufferSizeInFrames / framesPerPeriod; } } if (pConfig->deviceType == ma_device_type_duplex) { ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalBufferSizeInFrames); ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->aaudio.duplexRB); if (result != MA_SUCCESS) { if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); } return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[AAudio] Failed to initialize ring buffer.", result); } } return MA_SUCCESS; } ma_result ma_device_start_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream) { ma_aaudio_result_t resultAA; ma_aaudio_stream_state_t currentState; ma_assert(pDevice != NULL); resultAA = ((MA_PFN_AAudioStream_requestStart)pDevice->pContext->aaudio.AAudioStream_requestStart)(pStream); if (resultAA != MA_AAUDIO_OK) { return ma_result_from_aaudio(resultAA); } /* Do we actually need to wait for the device to transition into it's started state? */ /* The device should be in either a starting or started state. If it's not set to started we need to wait for it to transition. It should go from starting to started. */ currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream); if (currentState != MA_AAUDIO_STREAM_STATE_STARTED) { ma_result result; if (currentState != MA_AAUDIO_STREAM_STATE_STARTING) { return MA_ERROR; /* Expecting the stream to be a starting or started state. */ } result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STARTED); if (result != MA_SUCCESS) { return result; } } return MA_SUCCESS; } ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream) { ma_aaudio_result_t resultAA; ma_aaudio_stream_state_t currentState; ma_assert(pDevice != NULL); resultAA = ((MA_PFN_AAudioStream_requestStop)pDevice->pContext->aaudio.AAudioStream_requestStop)(pStream); if (resultAA != MA_AAUDIO_OK) { return ma_result_from_aaudio(resultAA); } /* The device should be in either a stopping or stopped state. If it's not set to started we need to wait for it to transition. It should go from stopping to stopped. */ currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream); if (currentState != MA_AAUDIO_STREAM_STATE_STOPPED) { ma_result result; if (currentState != MA_AAUDIO_STREAM_STATE_STOPPING) { return MA_ERROR; /* Expecting the stream to be a stopping or stopped state. */ } result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STOPPED); if (result != MA_SUCCESS) { return result; } } return MA_SUCCESS; } ma_result ma_device_start__aaudio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); if (result != MA_SUCCESS) { return result; } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); if (result != MA_SUCCESS) { if (pDevice->type == ma_device_type_duplex) { ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); } return result; } } return MA_SUCCESS; } ma_result ma_device_stop__aaudio(ma_device* pDevice) { ma_stop_proc onStop; ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); if (result != MA_SUCCESS) { return result; } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); if (result != MA_SUCCESS) { return result; } } onStop = pDevice->onStop; if (onStop) { onStop(pDevice); } return MA_SUCCESS; } ma_result ma_context_uninit__aaudio(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_aaudio); ma_dlclose(pContext, pContext->aaudio.hAAudio); pContext->aaudio.hAAudio = NULL; return MA_SUCCESS; } ma_result ma_context_init__aaudio(const ma_context_config* pConfig, ma_context* pContext) { const char* libNames[] = { "libaaudio.so" }; size_t i; for (i = 0; i < ma_countof(libNames); ++i) { pContext->aaudio.hAAudio = ma_dlopen(pContext, libNames[i]); if (pContext->aaudio.hAAudio != NULL) { break; } } if (pContext->aaudio.hAAudio == NULL) { return MA_FAILED_TO_INIT_BACKEND; } pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudio_createStreamBuilder"); pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete"); pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId"); pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection"); pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode"); pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat"); pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount"); pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate"); pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames"); pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback"); pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback"); pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode"); pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream"); pContext->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_close"); pContext->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getState"); pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange"); pContext->aaudio.AAudioStream_getFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFormat"); pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getChannelCount"); pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getSampleRate"); pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames"); pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback"); pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst"); pContext->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStart"); pContext->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStop"); pContext->isBackendAsynchronous = MA_TRUE; pContext->onUninit = ma_context_uninit__aaudio; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__aaudio; pContext->onEnumDevices = ma_context_enumerate_devices__aaudio; pContext->onGetDeviceInfo = ma_context_get_device_info__aaudio; pContext->onDeviceInit = ma_device_init__aaudio; pContext->onDeviceUninit = ma_device_uninit__aaudio; pContext->onDeviceStart = ma_device_start__aaudio; pContext->onDeviceStop = ma_device_stop__aaudio; (void)pConfig; return MA_SUCCESS; } #endif /* AAudio */ /****************************************************************************** OpenSL|ES Backend ******************************************************************************/ #ifdef MA_HAS_OPENSL #include #ifdef MA_ANDROID #include #endif /* OpenSL|ES has one-per-application objects :( */ SLObjectItf g_maEngineObjectSL = NULL; SLEngineItf g_maEngineSL = NULL; ma_uint32 g_maOpenSLInitCounter = 0; #define MA_OPENSL_OBJ(p) (*((SLObjectItf)(p))) #define MA_OPENSL_OUTPUTMIX(p) (*((SLOutputMixItf)(p))) #define MA_OPENSL_PLAY(p) (*((SLPlayItf)(p))) #define MA_OPENSL_RECORD(p) (*((SLRecordItf)(p))) #ifdef MA_ANDROID #define MA_OPENSL_BUFFERQUEUE(p) (*((SLAndroidSimpleBufferQueueItf)(p))) #else #define MA_OPENSL_BUFFERQUEUE(p) (*((SLBufferQueueItf)(p))) #endif /* Converts an individual OpenSL-style channel identifier (SL_SPEAKER_FRONT_LEFT, etc.) to miniaudio. */ ma_uint8 ma_channel_id_to_ma__opensl(SLuint32 id) { switch (id) { case SL_SPEAKER_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT; case SL_SPEAKER_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT; case SL_SPEAKER_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER; case SL_SPEAKER_LOW_FREQUENCY: return MA_CHANNEL_LFE; case SL_SPEAKER_BACK_LEFT: return MA_CHANNEL_BACK_LEFT; case SL_SPEAKER_BACK_RIGHT: return MA_CHANNEL_BACK_RIGHT; case SL_SPEAKER_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER; case SL_SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER; case SL_SPEAKER_BACK_CENTER: return MA_CHANNEL_BACK_CENTER; case SL_SPEAKER_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT; case SL_SPEAKER_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT; case SL_SPEAKER_TOP_CENTER: return MA_CHANNEL_TOP_CENTER; case SL_SPEAKER_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT; case SL_SPEAKER_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER; case SL_SPEAKER_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT; case SL_SPEAKER_TOP_BACK_LEFT: return MA_CHANNEL_TOP_BACK_LEFT; case SL_SPEAKER_TOP_BACK_CENTER: return MA_CHANNEL_TOP_BACK_CENTER; case SL_SPEAKER_TOP_BACK_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT; default: return 0; } } /* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to OpenSL-style. */ SLuint32 ma_channel_id_to_opensl(ma_uint8 id) { switch (id) { case MA_CHANNEL_MONO: return SL_SPEAKER_FRONT_CENTER; case MA_CHANNEL_FRONT_LEFT: return SL_SPEAKER_FRONT_LEFT; case MA_CHANNEL_FRONT_RIGHT: return SL_SPEAKER_FRONT_RIGHT; case MA_CHANNEL_FRONT_CENTER: return SL_SPEAKER_FRONT_CENTER; case MA_CHANNEL_LFE: return SL_SPEAKER_LOW_FREQUENCY; case MA_CHANNEL_BACK_LEFT: return SL_SPEAKER_BACK_LEFT; case MA_CHANNEL_BACK_RIGHT: return SL_SPEAKER_BACK_RIGHT; case MA_CHANNEL_FRONT_LEFT_CENTER: return SL_SPEAKER_FRONT_LEFT_OF_CENTER; case MA_CHANNEL_FRONT_RIGHT_CENTER: return SL_SPEAKER_FRONT_RIGHT_OF_CENTER; case MA_CHANNEL_BACK_CENTER: return SL_SPEAKER_BACK_CENTER; case MA_CHANNEL_SIDE_LEFT: return SL_SPEAKER_SIDE_LEFT; case MA_CHANNEL_SIDE_RIGHT: return SL_SPEAKER_SIDE_RIGHT; case MA_CHANNEL_TOP_CENTER: return SL_SPEAKER_TOP_CENTER; case MA_CHANNEL_TOP_FRONT_LEFT: return SL_SPEAKER_TOP_FRONT_LEFT; case MA_CHANNEL_TOP_FRONT_CENTER: return SL_SPEAKER_TOP_FRONT_CENTER; case MA_CHANNEL_TOP_FRONT_RIGHT: return SL_SPEAKER_TOP_FRONT_RIGHT; case MA_CHANNEL_TOP_BACK_LEFT: return SL_SPEAKER_TOP_BACK_LEFT; case MA_CHANNEL_TOP_BACK_CENTER: return SL_SPEAKER_TOP_BACK_CENTER; case MA_CHANNEL_TOP_BACK_RIGHT: return SL_SPEAKER_TOP_BACK_RIGHT; default: return 0; } } /* Converts a channel mapping to an OpenSL-style channel mask. */ SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel channelMap[MA_MAX_CHANNELS], ma_uint32 channels) { SLuint32 channelMask = 0; ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { channelMask |= ma_channel_id_to_opensl(channelMap[iChannel]); } return channelMask; } /* Converts an OpenSL-style channel mask to a miniaudio channel map. */ void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { if (channels == 1 && channelMask == 0) { channelMap[0] = MA_CHANNEL_MONO; } else if (channels == 2 && channelMask == 0) { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; } else { if (channels == 1 && (channelMask & SL_SPEAKER_FRONT_CENTER) != 0) { channelMap[0] = MA_CHANNEL_MONO; } else { /* Just iterate over each bit. */ ma_uint32 iChannel = 0; ma_uint32 iBit; for (iBit = 0; iBit < 32; ++iBit) { SLuint32 bitValue = (channelMask & (1UL << iBit)); if (bitValue != 0) { /* The bit is set. */ channelMap[iChannel] = ma_channel_id_to_ma__opensl(bitValue); iChannel += 1; } } } } } SLuint32 ma_round_to_standard_sample_rate__opensl(SLuint32 samplesPerSec) { if (samplesPerSec <= SL_SAMPLINGRATE_8) { return SL_SAMPLINGRATE_8; } if (samplesPerSec <= SL_SAMPLINGRATE_11_025) { return SL_SAMPLINGRATE_11_025; } if (samplesPerSec <= SL_SAMPLINGRATE_12) { return SL_SAMPLINGRATE_12; } if (samplesPerSec <= SL_SAMPLINGRATE_16) { return SL_SAMPLINGRATE_16; } if (samplesPerSec <= SL_SAMPLINGRATE_22_05) { return SL_SAMPLINGRATE_22_05; } if (samplesPerSec <= SL_SAMPLINGRATE_24) { return SL_SAMPLINGRATE_24; } if (samplesPerSec <= SL_SAMPLINGRATE_32) { return SL_SAMPLINGRATE_32; } if (samplesPerSec <= SL_SAMPLINGRATE_44_1) { return SL_SAMPLINGRATE_44_1; } if (samplesPerSec <= SL_SAMPLINGRATE_48) { return SL_SAMPLINGRATE_48; } /* Android doesn't support more than 48000. */ #ifndef MA_ANDROID if (samplesPerSec <= SL_SAMPLINGRATE_64) { return SL_SAMPLINGRATE_64; } if (samplesPerSec <= SL_SAMPLINGRATE_88_2) { return SL_SAMPLINGRATE_88_2; } if (samplesPerSec <= SL_SAMPLINGRATE_96) { return SL_SAMPLINGRATE_96; } if (samplesPerSec <= SL_SAMPLINGRATE_192) { return SL_SAMPLINGRATE_192; } #endif return SL_SAMPLINGRATE_16; } ma_bool32 ma_context_is_device_id_equal__opensl(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return pID0->opensl == pID1->opensl; } ma_result ma_context_enumerate_devices__opensl(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_bool32 cbResult; ma_assert(pContext != NULL); ma_assert(callback != NULL); ma_assert(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to enumerate devices. */ if (g_maOpenSLInitCounter == 0) { return MA_INVALID_OPERATION; } /* TODO: Test Me. This is currently untested, so for now we are just returning default devices. */ #if 0 && !defined(MA_ANDROID) ma_bool32 isTerminated = MA_FALSE; SLuint32 pDeviceIDs[128]; SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]); SLAudioIODeviceCapabilitiesItf deviceCaps; SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps); if (resultSL != SL_RESULT_SUCCESS) { /* The interface may not be supported so just report a default device. */ goto return_default_device; } /* Playback */ if (!isTerminated) { resultSL = (*deviceCaps)->GetAvailableAudioOutputs(deviceCaps, &deviceCount, pDeviceIDs); if (resultSL != SL_RESULT_SUCCESS) { return MA_NO_DEVICE; } for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); deviceInfo.id.opensl = pDeviceIDs[iDevice]; SLAudioOutputDescriptor desc; resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc); if (resultSL == SL_RESULT_SUCCESS) { ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.pDeviceName, (size_t)-1); ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); if (cbResult == MA_FALSE) { isTerminated = MA_TRUE; break; } } } } /* Capture */ if (!isTerminated) { resultSL = (*deviceCaps)->GetAvailableAudioInputs(deviceCaps, &deviceCount, pDeviceIDs); if (resultSL != SL_RESULT_SUCCESS) { return MA_NO_DEVICE; } for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); deviceInfo.id.opensl = pDeviceIDs[iDevice]; SLAudioInputDescriptor desc; resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc); if (resultSL == SL_RESULT_SUCCESS) { ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.deviceName, (size_t)-1); ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); if (cbResult == MA_FALSE) { isTerminated = MA_TRUE; break; } } } } return MA_SUCCESS; #else goto return_default_device; #endif return_default_device:; cbResult = MA_TRUE; /* Playback. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } /* Capture. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } return MA_SUCCESS; } ma_result ma_context_get_device_info__opensl(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_assert(pContext != NULL); ma_assert(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to get device info. */ if (g_maOpenSLInitCounter == 0) { return MA_INVALID_OPERATION; } /* No exclusive mode with OpenSL|ES. */ if (shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } /* TODO: Test Me. This is currently untested, so for now we are just returning default devices. */ #if 0 && !defined(MA_ANDROID) SLAudioIODeviceCapabilitiesItf deviceCaps; SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps); if (resultSL != SL_RESULT_SUCCESS) { /* The interface may not be supported so just report a default device. */ goto return_default_device; } if (deviceType == ma_device_type_playback) { SLAudioOutputDescriptor desc; resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, pDeviceID->opensl, &desc); if (resultSL != SL_RESULT_SUCCESS) { return MA_NO_DEVICE; } ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.pDeviceName, (size_t)-1); } else { SLAudioInputDescriptor desc; resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, pDeviceID->opensl, &desc); if (resultSL != SL_RESULT_SUCCESS) { return MA_NO_DEVICE; } ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.deviceName, (size_t)-1); } goto return_detailed_info; #else goto return_default_device; #endif return_default_device: if (pDeviceID != NULL) { if ((deviceType == ma_device_type_playback && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOOUTPUT) || (deviceType == ma_device_type_capture && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOINPUT)) { return MA_NO_DEVICE; /* Don't know the device. */ } } /* Name / Description */ if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } goto return_detailed_info; return_detailed_info: /* For now we're just outputting a set of values that are supported by the API but not necessarily supported by the device natively. Later on we should work on this so that it more closely reflects the device's actual native format. */ pDeviceInfo->minChannels = 1; pDeviceInfo->maxChannels = 2; pDeviceInfo->minSampleRate = 8000; pDeviceInfo->maxSampleRate = 48000; pDeviceInfo->formatCount = 2; pDeviceInfo->formats[0] = ma_format_u8; pDeviceInfo->formats[1] = ma_format_s16; #if defined(MA_ANDROID) && __ANDROID_API__ >= 21 pDeviceInfo->formats[pDeviceInfo->formatCount] = ma_format_f32; pDeviceInfo->formatCount += 1; #endif return MA_SUCCESS; } #ifdef MA_ANDROID /*void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, SLuint32 eventFlags, const void* pBuffer, SLuint32 bufferSize, SLuint32 dataUsed, void* pContext)*/ void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData) { ma_device* pDevice = (ma_device*)pUserData; size_t periodSizeInBytes; ma_uint8* pBuffer; SLresult resultSL; ma_assert(pDevice != NULL); (void)pBufferQueue; /* For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this, but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :( */ /* Don't do anything if the device is not started. */ if (pDevice->state != MA_STATE_STARTED) { return; } periodSizeInBytes = (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods) * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); pBuffer = pDevice->opensl.pBufferCapture + (pDevice->opensl.currentBufferIndexCapture * periodSizeInBytes); if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_capture(pDevice, (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods), pBuffer, &pDevice->opensl.duplexRB); } else { ma_device__send_frames_to_client(pDevice, (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods), pBuffer); } resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pBuffer, periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { return; } pDevice->opensl.currentBufferIndexCapture = (pDevice->opensl.currentBufferIndexCapture + 1) % pDevice->capture.internalPeriods; } void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData) { ma_device* pDevice = (ma_device*)pUserData; size_t periodSizeInBytes; ma_uint8* pBuffer; SLresult resultSL; ma_assert(pDevice != NULL); (void)pBufferQueue; /* Don't do anything if the device is not started. */ if (pDevice->state != MA_STATE_STARTED) { return; } periodSizeInBytes = (pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods) * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes); if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_playback(pDevice, (pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods), pBuffer, &pDevice->opensl.duplexRB); } else { ma_device__read_frames_from_client(pDevice, (pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods), pBuffer); } resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pBuffer, periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { return; } pDevice->opensl.currentBufferIndexPlayback = (pDevice->opensl.currentBufferIndexPlayback + 1) % pDevice->playback.internalPeriods; } #endif void ma_device_uninit__opensl(ma_device* pDevice) { ma_assert(pDevice != NULL); ma_assert(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it before uninitializing the device. */ if (g_maOpenSLInitCounter == 0) { return; } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (pDevice->opensl.pAudioRecorderObj) { MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj); } ma_free(pDevice->opensl.pBufferCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->opensl.pAudioPlayerObj) { MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioPlayerObj); } if (pDevice->opensl.pOutputMixObj) { MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj); } ma_free(pDevice->opensl.pBufferPlayback); } if (pDevice->type == ma_device_type_duplex) { ma_pcm_rb_uninit(&pDevice->opensl.duplexRB); } } #if defined(MA_ANDROID) && __ANDROID_API__ >= 21 typedef SLAndroidDataFormat_PCM_EX ma_SLDataFormat_PCM; #else typedef SLDataFormat_PCM ma_SLDataFormat_PCM; #endif ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* channelMap, ma_SLDataFormat_PCM* pDataFormat) { #if defined(MA_ANDROID) && __ANDROID_API__ >= 21 if (format == ma_format_f32) { pDataFormat->formatType = SL_ANDROID_DATAFORMAT_PCM_EX; pDataFormat->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; } else { pDataFormat->formatType = SL_DATAFORMAT_PCM; } #else pDataFormat->formatType = SL_DATAFORMAT_PCM; #endif pDataFormat->numChannels = channels; ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate * 1000); /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */ pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format)*8; pDataFormat->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels); pDataFormat->endianness = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; /* Android has a few restrictions on the format as documented here: https://developer.android.com/ndk/guides/audio/opensl-for-android.html - Only mono and stereo is supported. - Only u8 and s16 formats are supported. - Maximum sample rate of 48000. */ #ifdef MA_ANDROID if (pDataFormat->numChannels > 2) { pDataFormat->numChannels = 2; } #if __ANDROID_API__ >= 21 if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) { /* It's floating point. */ ma_assert(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT); if (pDataFormat->bitsPerSample > 32) { pDataFormat->bitsPerSample = 32; } } else { if (pDataFormat->bitsPerSample > 16) { pDataFormat->bitsPerSample = 16; } } #else if (pDataFormat->bitsPerSample > 16) { pDataFormat->bitsPerSample = 16; } #endif if (((SLDataFormat_PCM*)pDataFormat)->samplesPerSec > SL_SAMPLINGRATE_48) { ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = SL_SAMPLINGRATE_48; } #endif pDataFormat->containerSize = pDataFormat->bitsPerSample; /* Always tightly packed for now. */ return MA_SUCCESS; } ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pDataFormat, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap) { ma_bool32 isFloatingPoint = MA_FALSE; #if defined(MA_ANDROID) && __ANDROID_API__ >= 21 if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) { ma_assert(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT); isFloatingPoint = MA_TRUE; } #endif if (isFloatingPoint) { if (pDataFormat->bitsPerSample == 32) { *pFormat = ma_format_f32; } } else { if (pDataFormat->bitsPerSample == 8) { *pFormat = ma_format_u8; } else if (pDataFormat->bitsPerSample == 16) { *pFormat = ma_format_s16; } else if (pDataFormat->bitsPerSample == 24) { *pFormat = ma_format_s24; } else if (pDataFormat->bitsPerSample == 32) { *pFormat = ma_format_s32; } } *pChannels = pDataFormat->numChannels; *pSampleRate = ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec / 1000; ma_channel_mask_to_channel_map__opensl(pDataFormat->channelMask, pDataFormat->numChannels, pChannelMap); return MA_SUCCESS; } ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { #ifdef MA_ANDROID SLDataLocator_AndroidSimpleBufferQueue queue; SLresult resultSL; ma_uint32 bufferSizeInFrames; size_t bufferSizeInBytes; const SLInterfaceID itfIDs1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE}; #endif (void)pContext; ma_assert(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to initialize a new device. */ if (g_maOpenSLInitCounter == 0) { return MA_INVALID_OPERATION; } /* For now, only supporting Android implementations of OpenSL|ES since that's the only one I've been able to test with and I currently depend on Android-specific extensions (simple buffer queues). */ #ifdef MA_ANDROID /* No exclusive mode with OpenSL|ES. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; } /* Now we can start initializing the device properly. */ ma_assert(pDevice != NULL); ma_zero_object(&pDevice->opensl); queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; queue.numBuffers = pConfig->periods; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { ma_SLDataFormat_PCM pcm; SLDataLocator_IODevice locatorDevice; SLDataSource source; SLDataSink sink; ma_SLDataFormat_PCM_init__opensl(pConfig->capture.format, pConfig->capture.channels, pConfig->sampleRate, pConfig->capture.channelMap, &pcm); locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE; locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT; locatorDevice.deviceID = (pConfig->capture.pDeviceID == NULL) ? SL_DEFAULTDEVICEID_AUDIOINPUT : pConfig->capture.pDeviceID->opensl; locatorDevice.device = NULL; source.pLocator = &locatorDevice; source.pFormat = NULL; sink.pLocator = &queue; sink.pFormat = (SLDataFormat_PCM*)&pcm; resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ pcm.formatType = SL_DATAFORMAT_PCM; pcm.numChannels = 1; ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */ pcm.bitsPerSample = 16; pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */ pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); } if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_RECORD, &pDevice->opensl.pAudioRecorder) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, ma_buffer_queue_callback_capture__opensl_android, pDevice) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* The internal format is determined by the "pcm" object. */ ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->capture.internalFormat, &pDevice->capture.internalChannels, &pDevice->capture.internalSampleRate, pDevice->capture.internalChannelMap); /* Buffer. */ bufferSizeInFrames = pConfig->bufferSizeInFrames; if (bufferSizeInFrames == 0) { bufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, pDevice->capture.internalSampleRate); } pDevice->capture.internalPeriods = pConfig->periods; pDevice->capture.internalBufferSizeInFrames = (bufferSizeInFrames / pDevice->capture.internalPeriods) * pDevice->capture.internalPeriods; pDevice->opensl.currentBufferIndexCapture = 0; bufferSizeInBytes = pDevice->capture.internalBufferSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); pDevice->opensl.pBufferCapture = (ma_uint8*)ma_malloc(bufferSizeInBytes); if (pDevice->opensl.pBufferCapture == NULL) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY); } MA_ZERO_MEMORY(pDevice->opensl.pBufferCapture, bufferSizeInBytes); } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_SLDataFormat_PCM pcm; SLDataSource source; SLDataLocator_OutputMix outmixLocator; SLDataSink sink; ma_SLDataFormat_PCM_init__opensl(pConfig->playback.format, pConfig->playback.channels, pConfig->sampleRate, pConfig->playback.channelMap, &pcm); resultSL = (*g_maEngineSL)->CreateOutputMix(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL); if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE)) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* Set the output device. */ if (pConfig->playback.pDeviceID != NULL) { SLuint32 deviceID_OpenSL = pConfig->playback.pDeviceID->opensl; MA_OPENSL_OUTPUTMIX(pDevice->opensl.pOutputMix)->ReRoute((SLOutputMixItf)pDevice->opensl.pOutputMix, 1, &deviceID_OpenSL); } source.pLocator = &queue; source.pFormat = (SLDataFormat_PCM*)&pcm; outmixLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX; outmixLocator.outputMix = (SLObjectItf)pDevice->opensl.pOutputMixObj; sink.pLocator = &outmixLocator; sink.pFormat = NULL; resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ pcm.formatType = SL_DATAFORMAT_PCM; pcm.numChannels = 2; ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; pcm.bitsPerSample = 16; pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */ pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); } if (resultSL != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_PLAY, &pDevice->opensl.pAudioPlayer) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } if (MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, ma_buffer_queue_callback_playback__opensl_android, pDevice) != SL_RESULT_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } /* The internal format is determined by the "pcm" object. */ ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->playback.internalFormat, &pDevice->playback.internalChannels, &pDevice->playback.internalSampleRate, pDevice->playback.internalChannelMap); /* Buffer. */ bufferSizeInFrames = pConfig->bufferSizeInFrames; if (bufferSizeInFrames == 0) { bufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, pDevice->playback.internalSampleRate); } pDevice->playback.internalPeriods = pConfig->periods; pDevice->playback.internalBufferSizeInFrames = (bufferSizeInFrames / pDevice->playback.internalPeriods) * pDevice->playback.internalPeriods; pDevice->opensl.currentBufferIndexPlayback = 0; bufferSizeInBytes = pDevice->playback.internalBufferSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); pDevice->opensl.pBufferPlayback = (ma_uint8*)ma_malloc(bufferSizeInBytes); if (pDevice->opensl.pBufferPlayback == NULL) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY); } MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes); } if (pConfig->deviceType == ma_device_type_duplex) { ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalBufferSizeInFrames); ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->opensl.duplexRB); if (result != MA_SUCCESS) { ma_device_uninit__opensl(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to initialize ring buffer.", result); } } return MA_SUCCESS; #else return MA_NO_BACKEND; /* Non-Android implementations are not supported. */ #endif } ma_result ma_device_start__opensl(ma_device* pDevice) { SLresult resultSL; size_t periodSizeInBytes; ma_uint32 iPeriod; ma_assert(pDevice != NULL); ma_assert(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to start the device. */ if (g_maOpenSLInitCounter == 0) { return MA_INVALID_OPERATION; } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING); if (resultSL != SL_RESULT_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device.", MA_FAILED_TO_START_BACKEND_DEVICE); } periodSizeInBytes = (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods) * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) { resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.", MA_FAILED_TO_START_BACKEND_DEVICE); } } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_PLAYING); if (resultSL != SL_RESULT_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device.", MA_FAILED_TO_START_BACKEND_DEVICE); } /* In playback mode (no duplex) we need to load some initial buffers. In duplex mode we need to enqueu silent buffers. */ if (pDevice->type == ma_device_type_duplex) { MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, pDevice->playback.internalBufferSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); } else { ma_device__read_frames_from_client(pDevice, pDevice->playback.internalBufferSizeInFrames, pDevice->opensl.pBufferPlayback); } periodSizeInBytes = (pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods) * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) { resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pDevice->opensl.pBufferPlayback + (periodSizeInBytes * iPeriod), periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device.", MA_FAILED_TO_START_BACKEND_DEVICE); } } } return MA_SUCCESS; } ma_result ma_device_stop__opensl(ma_device* pDevice) { SLresult resultSL; ma_stop_proc onStop; ma_assert(pDevice != NULL); ma_assert(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it before stopping/uninitializing the device. */ if (g_maOpenSLInitCounter == 0) { return MA_INVALID_OPERATION; } /* TODO: Wait until all buffers have been processed. Hint: Maybe SLAndroidSimpleBufferQueue::GetState() could be used in a loop? */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); if (resultSL != SL_RESULT_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); if (resultSL != SL_RESULT_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device.", MA_FAILED_TO_STOP_BACKEND_DEVICE); } MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback); } /* Make sure the client is aware that the device has stopped. There may be an OpenSL|ES callback for this, but I haven't found it. */ onStop = pDevice->onStop; if (onStop) { onStop(pDevice); } return MA_SUCCESS; } ma_result ma_context_uninit__opensl(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_opensl); (void)pContext; /* Uninit global data. */ if (g_maOpenSLInitCounter > 0) { if (ma_atomic_decrement_32(&g_maOpenSLInitCounter) == 0) { (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL); } } return MA_SUCCESS; } ma_result ma_context_init__opensl(const ma_context_config* pConfig, ma_context* pContext) { ma_assert(pContext != NULL); (void)pConfig; /* Initialize global data first if applicable. */ if (ma_atomic_increment_32(&g_maOpenSLInitCounter) == 1) { SLresult resultSL = slCreateEngine(&g_maEngineObjectSL, 0, NULL, 0, NULL, NULL); if (resultSL != SL_RESULT_SUCCESS) { ma_atomic_decrement_32(&g_maOpenSLInitCounter); return MA_NO_BACKEND; } (*g_maEngineObjectSL)->Realize(g_maEngineObjectSL, SL_BOOLEAN_FALSE); resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_ENGINE, &g_maEngineSL); if (resultSL != SL_RESULT_SUCCESS) { (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL); ma_atomic_decrement_32(&g_maOpenSLInitCounter); return MA_NO_BACKEND; } } pContext->isBackendAsynchronous = MA_TRUE; pContext->onUninit = ma_context_uninit__opensl; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__opensl; pContext->onEnumDevices = ma_context_enumerate_devices__opensl; pContext->onGetDeviceInfo = ma_context_get_device_info__opensl; pContext->onDeviceInit = ma_device_init__opensl; pContext->onDeviceUninit = ma_device_uninit__opensl; pContext->onDeviceStart = ma_device_start__opensl; pContext->onDeviceStop = ma_device_stop__opensl; return MA_SUCCESS; } #endif /* OpenSL|ES */ /****************************************************************************** Web Audio Backend ******************************************************************************/ #ifdef MA_HAS_WEBAUDIO #include ma_bool32 ma_is_capture_supported__webaudio() { return EM_ASM_INT({ return (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined); }, 0) != 0; /* Must pass in a dummy argument for C99 compatibility. */ } #ifdef __cplusplus extern "C" { #endif EMSCRIPTEN_KEEPALIVE void ma_device_process_pcm_frames_capture__webaudio(ma_device* pDevice, int frameCount, float* pFrames) { if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_capture(pDevice, (ma_uint32)frameCount, pFrames, &pDevice->webaudio.duplexRB); } else { ma_device__send_frames_to_client(pDevice, (ma_uint32)frameCount, pFrames); /* Send directly to the client. */ } } EMSCRIPTEN_KEEPALIVE void ma_device_process_pcm_frames_playback__webaudio(ma_device* pDevice, int frameCount, float* pFrames) { if (pDevice->type == ma_device_type_duplex) { ma_device__handle_duplex_callback_playback(pDevice, (ma_uint32)frameCount, pFrames, &pDevice->webaudio.duplexRB); } else { ma_device__read_frames_from_client(pDevice, (ma_uint32)frameCount, pFrames); /* Read directly from the device. */ } } #ifdef __cplusplus } #endif ma_bool32 ma_context_is_device_id_equal__webaudio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1) { ma_assert(pContext != NULL); ma_assert(pID0 != NULL); ma_assert(pID1 != NULL); (void)pContext; return ma_strcmp(pID0->webaudio, pID1->webaudio) == 0; } ma_result ma_context_enumerate_devices__webaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_bool32 cbResult = MA_TRUE; ma_assert(pContext != NULL); ma_assert(callback != NULL); /* Only supporting default devices for now. */ /* Playback. */ if (cbResult) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); } /* Capture. */ if (cbResult) { if (ma_is_capture_supported__webaudio()) { ma_device_info deviceInfo; ma_zero_object(&deviceInfo); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); } } return MA_SUCCESS; } ma_result ma_context_get_device_info__webaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_assert(pContext != NULL); /* No exclusive mode with Web Audio. */ if (shareMode == ma_share_mode_exclusive) { return MA_SHARE_MODE_NOT_SUPPORTED; } if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) { return MA_NO_DEVICE; } ma_zero_memory(pDeviceInfo->id.webaudio, sizeof(pDeviceInfo->id.webaudio)); /* Only supporting default devices for now. */ if (deviceType == ma_device_type_playback) { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); } else { ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); } /* Web Audio can support any number of channels and sample rates. It only supports f32 formats, however. */ pDeviceInfo->minChannels = 1; pDeviceInfo->maxChannels = MA_MAX_CHANNELS; if (pDeviceInfo->maxChannels > 32) { pDeviceInfo->maxChannels = 32; /* Maximum output channel count is 32 for createScriptProcessor() (JavaScript). */ } /* We can query the sample rate by just using a temporary audio context. */ pDeviceInfo->minSampleRate = EM_ASM_INT({ try { var temp = new (window.AudioContext || window.webkitAudioContext)(); var sampleRate = temp.sampleRate; temp.close(); return sampleRate; } catch(e) { return 0; } }, 0); /* Must pass in a dummy argument for C99 compatibility. */ pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate; if (pDeviceInfo->minSampleRate == 0) { return MA_NO_DEVICE; } /* Web Audio only supports f32. */ pDeviceInfo->formatCount = 1; pDeviceInfo->formats[0] = ma_format_f32; return MA_SUCCESS; } void ma_device_uninit_by_index__webaudio(ma_device* pDevice, ma_device_type deviceType, int deviceIndex) { ma_assert(pDevice != NULL); EM_ASM({ var device = miniaudio.get_device_by_index($0); /* Make sure all nodes are disconnected and marked for collection. */ if (device.scriptNode !== undefined) { device.scriptNode.onaudioprocess = function(e) {}; /* We want to reset the callback to ensure it doesn't get called after AudioContext.close() has returned. Shouldn't happen since we're disconnecting, but just to be safe... */ device.scriptNode.disconnect(); device.scriptNode = undefined; } if (device.streamNode !== undefined) { device.streamNode.disconnect(); device.streamNode = undefined; } /* Stop the device. I think there is a chance the callback could get fired after calling this, hence why we want to clear the callback before closing. */ device.webaudio.close(); device.webaudio = undefined; /* Can't forget to free the intermediary buffer. This is the buffer that's shared between JavaScript and C. */ if (device.intermediaryBuffer !== undefined) { Module._free(device.intermediaryBuffer); device.intermediaryBuffer = undefined; device.intermediaryBufferView = undefined; device.intermediaryBufferSizeInBytes = undefined; } /* Make sure the device is untracked so the slot can be reused later. */ miniaudio.untrack_device_by_index($0); }, deviceIndex, deviceType); } void ma_device_uninit__webaudio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback); } if (pDevice->type == ma_device_type_duplex) { ma_pcm_rb_uninit(&pDevice->webaudio.duplexRB); } } ma_result ma_device_init_by_type__webaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice) { int deviceIndex; ma_uint32 internalBufferSizeInFrames; ma_assert(pContext != NULL); ma_assert(pConfig != NULL); ma_assert(deviceType != ma_device_type_duplex); ma_assert(pDevice != NULL); if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) { return MA_NO_DEVICE; } /* Try calculating an appropriate buffer size. */ internalBufferSizeInFrames = pConfig->bufferSizeInFrames; if (internalBufferSizeInFrames == 0) { internalBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, pConfig->sampleRate); } /* The size of the buffer must be a power of 2 and between 256 and 16384. */ if (internalBufferSizeInFrames < 256) { internalBufferSizeInFrames = 256; } else if (internalBufferSizeInFrames > 16384) { internalBufferSizeInFrames = 16384; } else { internalBufferSizeInFrames = ma_next_power_of_2(internalBufferSizeInFrames); } /* We create the device on the JavaScript side and reference it using an index. We use this to make it possible to reference the device between JavaScript and C. */ deviceIndex = EM_ASM_INT({ var channels = $0; var sampleRate = $1; var bufferSize = $2; /* In PCM frames. */ var isCapture = $3; var pDevice = $4; if (typeof(miniaudio) === 'undefined') { return -1; /* Context not initialized. */ } var device = {}; /* The AudioContext must be created in a suspended state. */ device.webaudio = new (window.AudioContext || window.webkitAudioContext)({sampleRate:sampleRate}); device.webaudio.suspend(); /* We need an intermediary buffer which we use for JavaScript and C interop. This buffer stores interleaved f32 PCM data. Because it's passed between JavaScript and C it needs to be allocated and freed using Module._malloc() and Module._free(). */ device.intermediaryBufferSizeInBytes = channels * bufferSize * 4; device.intermediaryBuffer = Module._malloc(device.intermediaryBufferSizeInBytes); device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes); /* Both playback and capture devices use a ScriptProcessorNode for performing per-sample operations. ScriptProcessorNode is actually deprecated so this is likely to be temporary. The way this works for playback is very simple. You just set a callback that's periodically fired, just like a normal audio callback function. But apparently this design is "flawed" and is now deprecated in favour of something called AudioWorklets which _forces_ you to load a _separate_ .js file at run time... nice... Hopefully ScriptProcessorNode will continue to work for years to come, but this may need to change to use AudioSourceBufferNode instead, which I think is what Emscripten uses for it's built-in SDL implementation. I'll be avoiding that insane AudioWorklet API like the plague... For capture it is a bit unintuitive. We use the ScriptProccessorNode _only_ to get the raw PCM data. It is connected to an AudioContext just like the playback case, however we just output silence to the AudioContext instead of passing any real data. It would make more sense to me to use the MediaRecorder API, but unfortunately you need to specify a MIME time (Opus, Vorbis, etc.) for the binary blob that's returned to the client, but I've been unable to figure out how to get this as raw PCM. The closes I can think is to use the MIME type for WAV files and just parse it, but I don't know how well this would work. Although ScriptProccessorNode is deprecated, in practice it seems to have pretty good browser support so I'm leaving it like this for now. If anything knows how I could get raw PCM data using the MediaRecorder API please let me know! */ device.scriptNode = device.webaudio.createScriptProcessor(bufferSize, channels, channels); if (isCapture) { device.scriptNode.onaudioprocess = function(e) { if (device.intermediaryBuffer === undefined) { return; /* This means the device has been uninitialized. */ } /* Make sure silence it output to the AudioContext destination. Not doing this will cause sound to come out of the speakers! */ for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { e.outputBuffer.getChannelData(iChannel).fill(0.0); } /* There are some situations where we may want to send silence to the client. */ var sendSilence = false; if (device.streamNode === undefined) { sendSilence = true; } /* Sanity check. This will never happen, right? */ if (e.inputBuffer.numberOfChannels != channels) { console.log("Capture: Channel count mismatch. " + e.inputBufer.numberOfChannels + " != " + channels + ". Sending silence."); sendSilence = true; } /* This looped design guards against the situation where e.inputBuffer is a different size to the original buffer size. Should never happen in practice. */ var totalFramesProcessed = 0; while (totalFramesProcessed < e.inputBuffer.length) { var framesRemaining = e.inputBuffer.length - totalFramesProcessed; var framesToProcess = framesRemaining; if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) { framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4); } /* We need to do the reverse of the playback case. We need to interleave the input data and copy it into the intermediary buffer. Then we send it to the client. */ if (sendSilence) { device.intermediaryBufferView.fill(0.0); } else { for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) { for (var iChannel = 0; iChannel < e.inputBuffer.numberOfChannels; ++iChannel) { device.intermediaryBufferView[iFrame*channels + iChannel] = e.inputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame]; } } } /* Send data to the client from our intermediary buffer. */ ccall("ma_device_process_pcm_frames_capture__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]); totalFramesProcessed += framesToProcess; } }; navigator.mediaDevices.getUserMedia({audio:true, video:false}) .then(function(stream) { device.streamNode = device.webaudio.createMediaStreamSource(stream); device.streamNode.connect(device.scriptNode); device.scriptNode.connect(device.webaudio.destination); }) .catch(function(error) { /* I think this should output silence... */ device.scriptNode.connect(device.webaudio.destination); }); } else { device.scriptNode.onaudioprocess = function(e) { if (device.intermediaryBuffer === undefined) { return; /* This means the device has been uninitialized. */ } var outputSilence = false; /* Sanity check. This will never happen, right? */ if (e.outputBuffer.numberOfChannels != channels) { console.log("Playback: Channel count mismatch. " + e.outputBufer.numberOfChannels + " != " + channels + ". Outputting silence."); outputSilence = true; return; } /* This looped design guards against the situation where e.outputBuffer is a different size to the original buffer size. Should never happen in practice. */ var totalFramesProcessed = 0; while (totalFramesProcessed < e.outputBuffer.length) { var framesRemaining = e.outputBuffer.length - totalFramesProcessed; var framesToProcess = framesRemaining; if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) { framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4); } /* Read data from the client into our intermediary buffer. */ ccall("ma_device_process_pcm_frames_playback__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]); /* At this point we'll have data in our intermediary buffer which we now need to deinterleave and copy over to the output buffers. */ if (outputSilence) { for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { e.outputBuffer.getChannelData(iChannel).fill(0.0); } } else { for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) { e.outputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame] = device.intermediaryBufferView[iFrame*channels + iChannel]; } } } totalFramesProcessed += framesToProcess; } }; device.scriptNode.connect(device.webaudio.destination); } return miniaudio.track_device(device); }, (deviceType == ma_device_type_capture) ? pConfig->capture.channels : pConfig->playback.channels, pConfig->sampleRate, internalBufferSizeInFrames, deviceType == ma_device_type_capture, pDevice); if (deviceIndex < 0) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } if (deviceType == ma_device_type_capture) { pDevice->webaudio.indexCapture = deviceIndex; pDevice->capture.internalFormat = ma_format_f32; pDevice->capture.internalChannels = pConfig->capture.channels; ma_get_standard_channel_map(ma_standard_channel_map_webaudio, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); pDevice->capture.internalSampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); pDevice->capture.internalBufferSizeInFrames = internalBufferSizeInFrames; pDevice->capture.internalPeriods = 1; } else { pDevice->webaudio.indexPlayback = deviceIndex; pDevice->playback.internalFormat = ma_format_f32; pDevice->playback.internalChannels = pConfig->playback.channels; ma_get_standard_channel_map(ma_standard_channel_map_webaudio, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); pDevice->playback.internalSampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); pDevice->playback.internalBufferSizeInFrames = internalBufferSizeInFrames; pDevice->playback.internalPeriods = 1; } return MA_SUCCESS; } ma_result ma_device_init__webaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result; /* No exclusive mode with Web Audio. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; } if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { result = ma_device_init_by_type__webaudio(pContext, pConfig, ma_device_type_capture, pDevice); if (result != MA_SUCCESS) { return result; } } if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { result = ma_device_init_by_type__webaudio(pContext, pConfig, ma_device_type_playback, pDevice); if (result != MA_SUCCESS) { if (pConfig->deviceType == ma_device_type_duplex) { ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture); } return result; } } /* We need a ring buffer for moving data from the capture device to the playback device. The capture callback is the producer and the playback callback is the consumer. The buffer needs to be large enough to hold internalBufferSizeInFrames based on the external sample rate. */ if (pConfig->deviceType == ma_device_type_duplex) { ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalBufferSizeInFrames) * 2; result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->webaudio.duplexRB); if (result != MA_SUCCESS) { if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback); } return result; } } return MA_SUCCESS; } ma_result ma_device_start__webaudio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { EM_ASM({ miniaudio.get_device_by_index($0).webaudio.resume(); }, pDevice->webaudio.indexCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { EM_ASM({ miniaudio.get_device_by_index($0).webaudio.resume(); }, pDevice->webaudio.indexPlayback); } return MA_SUCCESS; } ma_result ma_device_stop__webaudio(ma_device* pDevice) { ma_assert(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { EM_ASM({ miniaudio.get_device_by_index($0).webaudio.suspend(); }, pDevice->webaudio.indexCapture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { EM_ASM({ miniaudio.get_device_by_index($0).webaudio.suspend(); }, pDevice->webaudio.indexPlayback); } ma_stop_proc onStop = pDevice->onStop; if (onStop) { onStop(pDevice); } return MA_SUCCESS; } ma_result ma_context_uninit__webaudio(ma_context* pContext) { ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_webaudio); /* Nothing needs to be done here. */ (void)pContext; return MA_SUCCESS; } ma_result ma_context_init__webaudio(const ma_context_config* pConfig, ma_context* pContext) { int resultFromJS; ma_assert(pContext != NULL); /* Here is where our global JavaScript object is initialized. */ resultFromJS = EM_ASM_INT({ if ((window.AudioContext || window.webkitAudioContext) === undefined) { return 0; /* Web Audio not supported. */ } if (typeof(miniaudio) === 'undefined') { miniaudio = {}; miniaudio.devices = []; /* Device cache for mapping devices to indexes for JavaScript/C interop. */ miniaudio.track_device = function(device) { /* Try inserting into a free slot first. */ for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) { if (miniaudio.devices[iDevice] == null) { miniaudio.devices[iDevice] = device; return iDevice; } } /* Getting here means there is no empty slots in the array so we just push to the end. */ miniaudio.devices.push(device); return miniaudio.devices.length - 1; }; miniaudio.untrack_device_by_index = function(deviceIndex) { /* We just set the device's slot to null. The slot will get reused in the next call to ma_track_device. */ miniaudio.devices[deviceIndex] = null; /* Trim the array if possible. */ while (miniaudio.devices.length > 0) { if (miniaudio.devices[miniaudio.devices.length-1] == null) { miniaudio.devices.pop(); } else { break; } } }; miniaudio.untrack_device = function(device) { for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) { if (miniaudio.devices[iDevice] == device) { return miniaudio.untrack_device_by_index(iDevice); } } }; miniaudio.get_device_by_index = function(deviceIndex) { return miniaudio.devices[deviceIndex]; }; } return 1; }, 0); /* Must pass in a dummy argument for C99 compatibility. */ if (resultFromJS != 1) { return MA_FAILED_TO_INIT_BACKEND; } pContext->isBackendAsynchronous = MA_TRUE; pContext->onUninit = ma_context_uninit__webaudio; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__webaudio; pContext->onEnumDevices = ma_context_enumerate_devices__webaudio; pContext->onGetDeviceInfo = ma_context_get_device_info__webaudio; pContext->onDeviceInit = ma_device_init__webaudio; pContext->onDeviceUninit = ma_device_uninit__webaudio; pContext->onDeviceStart = ma_device_start__webaudio; pContext->onDeviceStop = ma_device_stop__webaudio; (void)pConfig; /* Unused. */ return MA_SUCCESS; } #endif /* Web Audio */ ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint32 channels) { /* A blank channel map should be allowed, in which case it should use an appropriate default which will depend on context. */ if (channelMap[0] != MA_CHANNEL_NONE) { ma_uint32 iChannel; if (channels == 0) { return MA_FALSE; /* No channels. */ } /* A channel cannot be present in the channel map more than once. */ for (iChannel = 0; iChannel < channels; ++iChannel) { ma_uint32 jChannel; for (jChannel = iChannel + 1; jChannel < channels; ++jChannel) { if (channelMap[iChannel] == channelMap[jChannel]) { return MA_FALSE; } } } } return MA_TRUE; } void ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType) { ma_assert(pDevice != NULL); if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { if (pDevice->capture.usingDefaultFormat) { pDevice->capture.format = pDevice->capture.internalFormat; } if (pDevice->capture.usingDefaultChannels) { pDevice->capture.channels = pDevice->capture.internalChannels; } if (pDevice->capture.usingDefaultChannelMap) { if (pDevice->capture.internalChannels == pDevice->capture.channels) { ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels); } else { ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->capture.channels, pDevice->capture.channelMap); } } } if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { if (pDevice->playback.usingDefaultFormat) { pDevice->playback.format = pDevice->playback.internalFormat; } if (pDevice->playback.usingDefaultChannels) { pDevice->playback.channels = pDevice->playback.internalChannels; } if (pDevice->playback.usingDefaultChannelMap) { if (pDevice->playback.internalChannels == pDevice->playback.channels) { ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels); } else { ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->playback.channels, pDevice->playback.channelMap); } } } if (pDevice->usingDefaultSampleRate) { if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { pDevice->sampleRate = pDevice->capture.internalSampleRate; } else { pDevice->sampleRate = pDevice->playback.internalSampleRate; } } /* PCM converters. */ if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { /* Converting from internal device format to public format. */ ma_pcm_converter_config converterConfig = ma_pcm_converter_config_init_new(); converterConfig.neverConsumeEndOfInput = MA_TRUE; converterConfig.pUserData = pDevice; converterConfig.formatIn = pDevice->capture.internalFormat; converterConfig.channelsIn = pDevice->capture.internalChannels; converterConfig.sampleRateIn = pDevice->capture.internalSampleRate; ma_channel_map_copy(converterConfig.channelMapIn, pDevice->capture.internalChannelMap, pDevice->capture.internalChannels); converterConfig.formatOut = pDevice->capture.format; converterConfig.channelsOut = pDevice->capture.channels; converterConfig.sampleRateOut = pDevice->sampleRate; ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, pDevice->capture.channels); converterConfig.onRead = ma_device__pcm_converter__on_read_from_buffer_capture; ma_pcm_converter_init(&converterConfig, &pDevice->capture.converter); } if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { /* Converting from public format to device format. */ ma_pcm_converter_config converterConfig = ma_pcm_converter_config_init_new(); converterConfig.neverConsumeEndOfInput = MA_TRUE; converterConfig.pUserData = pDevice; converterConfig.formatIn = pDevice->playback.format; converterConfig.channelsIn = pDevice->playback.channels; converterConfig.sampleRateIn = pDevice->sampleRate; ma_channel_map_copy(converterConfig.channelMapIn, pDevice->playback.channelMap, pDevice->playback.channels); converterConfig.formatOut = pDevice->playback.internalFormat; converterConfig.channelsOut = pDevice->playback.internalChannels; converterConfig.sampleRateOut = pDevice->playback.internalSampleRate; ma_channel_map_copy(converterConfig.channelMapOut, pDevice->playback.internalChannelMap, pDevice->playback.internalChannels); if (deviceType == ma_device_type_playback) { if (pDevice->type == ma_device_type_playback) { converterConfig.onRead = ma_device__on_read_from_client; } else { converterConfig.onRead = ma_device__pcm_converter__on_read_from_buffer_playback; } } else { converterConfig.onRead = ma_device__pcm_converter__on_read_from_buffer_playback; } ma_pcm_converter_init(&converterConfig, &pDevice->playback.converter); } } ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) { ma_device* pDevice = (ma_device*)pData; ma_assert(pDevice != NULL); #ifdef MA_WIN32 ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE); #endif /* When the device is being initialized it's initial state is set to MA_STATE_UNINITIALIZED. Before returning from ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker thread to signal an event to know when the worker thread is ready for action. */ ma_device__set_state(pDevice, MA_STATE_STOPPED); ma_event_signal(&pDevice->stopEvent); for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */ ma_stop_proc onStop; /* We wait on an event to know when something has requested that the device be started and the main loop entered. */ ma_event_wait(&pDevice->wakeupEvent); /* Default result code. */ pDevice->workResult = MA_SUCCESS; /* If the reason for the wake up is that we are terminating, just break from the loop. */ if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) { break; } /* Getting to this point means the device is wanting to get started. The function that has requested that the device be started will be waiting on an event (pDevice->startEvent) which means we need to make sure we signal the event in both the success and error case. It's important that the state of the device is set _before_ signaling the event. */ ma_assert(ma_device__get_state(pDevice) == MA_STATE_STARTING); /* Make sure the state is set appropriately. */ ma_device__set_state(pDevice, MA_STATE_STARTED); ma_event_signal(&pDevice->startEvent); if (pDevice->pContext->onDeviceMainLoop != NULL) { pDevice->pContext->onDeviceMainLoop(pDevice); } else { ma_uint32 periodSizeInFrames; /* When a device is using miniaudio's generic worker thread they must implement onDeviceRead or onDeviceWrite, depending on the device type. */ ma_assert( (pDevice->type == ma_device_type_playback && pDevice->pContext->onDeviceWrite != NULL) || (pDevice->type == ma_device_type_capture && pDevice->pContext->onDeviceRead != NULL) || (pDevice->type == ma_device_type_duplex && pDevice->pContext->onDeviceWrite != NULL && pDevice->pContext->onDeviceRead != NULL) ); if (pDevice->type == ma_device_type_capture) { ma_assert(pDevice->capture.internalBufferSizeInFrames >= pDevice->capture.internalPeriods); periodSizeInFrames = pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods; } else if (pDevice->type == ma_device_type_playback) { ma_assert(pDevice->playback.internalBufferSizeInFrames >= pDevice->playback.internalPeriods); periodSizeInFrames = pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods; } else { ma_assert(pDevice->capture.internalBufferSizeInFrames >= pDevice->capture.internalPeriods); ma_assert(pDevice->playback.internalBufferSizeInFrames >= pDevice->playback.internalPeriods); periodSizeInFrames = ma_min( pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods ); } /* With the blocking API, the device is started automatically in read()/write(). All we need to do is enter the loop and just keep reading or writing based on the period size. */ /* Main Loop */ ma_assert(periodSizeInFrames >= 1); while (ma_device__get_state(pDevice) == MA_STATE_STARTED) { ma_result result = MA_SUCCESS; ma_uint32 totalFramesProcessed = 0; if (pDevice->type == ma_device_type_duplex) { /* The process is device_read -> convert -> callback -> convert -> device_write. */ ma_uint8 captureDeviceData[4096]; ma_uint32 captureDeviceDataCapInFrames = sizeof(captureDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); while (totalFramesProcessed < periodSizeInFrames) { ma_device_callback_proc onData; ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesToProcess = framesRemaining; if (framesToProcess > captureDeviceDataCapInFrames) { framesToProcess = captureDeviceDataCapInFrames; } result = pDevice->pContext->onDeviceRead(pDevice, captureDeviceData, framesToProcess); if (result != MA_SUCCESS) { break; } onData = pDevice->onData; if (onData != NULL) { pDevice->capture._dspFrameCount = framesToProcess; pDevice->capture._dspFrames = captureDeviceData; /* We need to process every input frame. */ for (;;) { ma_uint8 capturedData[4096]; /* In capture.format/channels format */ ma_uint8 playbackData[4096]; /* In playback.format/channels format */ ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames); ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing); if (capturedFramesToProcess == 0) { break; /* Don't fire the data callback with zero frames. */ } onData(pDevice, playbackData, capturedData, capturedFramesToProcess); /* At this point the playbackData buffer should be holding data that needs to be written to the device. */ pDevice->playback._dspFrameCount = capturedFramesToProcess; pDevice->playback._dspFrames = playbackData; for (;;) { ma_uint8 playbackDeviceData[4096]; ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames); if (playbackDeviceFramesCount == 0) { break; } result = pDevice->pContext->onDeviceWrite(pDevice, playbackDeviceData, playbackDeviceFramesCount); if (result != MA_SUCCESS) { break; } if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) { break; } } if (capturedFramesToProcess < capturedFramesToTryProcessing) { break; } /* In case an error happened from onDeviceWrite()... */ if (result != MA_SUCCESS) { break; } } } totalFramesProcessed += framesToProcess; } } else { ma_uint8 buffer[4096]; ma_uint32 bufferSizeInFrames; if (pDevice->type == ma_device_type_capture) { bufferSizeInFrames = sizeof(buffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); } else { bufferSizeInFrames = sizeof(buffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); } while (totalFramesProcessed < periodSizeInFrames) { ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed; ma_uint32 framesToProcess = framesRemaining; if (framesToProcess > bufferSizeInFrames) { framesToProcess = bufferSizeInFrames; } if (pDevice->type == ma_device_type_playback) { ma_device__read_frames_from_client(pDevice, framesToProcess, buffer); result = pDevice->pContext->onDeviceWrite(pDevice, buffer, framesToProcess); } else { result = pDevice->pContext->onDeviceRead(pDevice, buffer, framesToProcess); ma_device__send_frames_to_client(pDevice, framesToProcess, buffer); } totalFramesProcessed += framesToProcess; } } /* Get out of the loop if read()/write() returned an error. It probably means the device has been stopped. */ if (result != MA_SUCCESS) { break; } } } /* Getting here means we have broken from the main loop which happens the application has requested that device be stopped. Note that this may have actually already happened above if the device was lost and miniaudio has attempted to re-initialize the device. In this case we don't want to be doing this a second time. */ if (ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED) { if (pDevice->pContext->onDeviceStop) { pDevice->pContext->onDeviceStop(pDevice); } } /* After the device has stopped, make sure an event is posted. */ onStop = pDevice->onStop; if (onStop) { onStop(pDevice); } /* A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. Note that it's possible that the device has been uninitialized which means we need to _not_ change the status to stopped. We cannot go from an uninitialized state to stopped state. */ if (ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED) { ma_device__set_state(pDevice, MA_STATE_STOPPED); ma_event_signal(&pDevice->stopEvent); } } /* Make sure we aren't continuously waiting on a stop event. */ ma_event_signal(&pDevice->stopEvent); /* <-- Is this still needed? */ #ifdef MA_WIN32 ma_CoUninitialize(pDevice->pContext); #endif return (ma_thread_result)0; } /* Helper for determining whether or not the given device is initialized. */ ma_bool32 ma_device__is_initialized(ma_device* pDevice) { if (pDevice == NULL) { return MA_FALSE; } return ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED; } #ifdef MA_WIN32 ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext) { ma_CoUninitialize(pContext); ma_dlclose(pContext, pContext->win32.hUser32DLL); ma_dlclose(pContext, pContext->win32.hOle32DLL); ma_dlclose(pContext, pContext->win32.hAdvapi32DLL); return MA_SUCCESS; } ma_result ma_context_init_backend_apis__win32(ma_context* pContext) { #ifdef MA_WIN32_DESKTOP /* Ole32.dll */ pContext->win32.hOle32DLL = ma_dlopen(pContext, "ole32.dll"); if (pContext->win32.hOle32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitializeEx"); pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoUninitialize"); pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoCreateInstance"); pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoTaskMemFree"); pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "PropVariantClear"); pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "StringFromGUID2"); /* User32.dll */ pContext->win32.hUser32DLL = ma_dlopen(pContext, "user32.dll"); if (pContext->win32.hUser32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetForegroundWindow"); pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetDesktopWindow"); /* Advapi32.dll */ pContext->win32.hAdvapi32DLL = ma_dlopen(pContext, "advapi32.dll"); if (pContext->win32.hAdvapi32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegCloseKey"); pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); #endif ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); return MA_SUCCESS; } #else ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext) { #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING) ma_dlclose(pContext, pContext->posix.pthreadSO); #else (void)pContext; #endif return MA_SUCCESS; } ma_result ma_context_init_backend_apis__nix(ma_context* pContext) { /* pthread */ #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING) const char* libpthreadFileNames[] = { "libpthread.so", "libpthread.so.0", "libpthread.dylib" }; size_t i; for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) { pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]); if (pContext->posix.pthreadSO != NULL) { break; } } if (pContext->posix.pthreadSO == NULL) { return MA_FAILED_TO_INIT_BACKEND; } pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create"); pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join"); pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init"); pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy"); pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock"); pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock"); pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init"); pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy"); pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait"); pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal"); pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init"); pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy"); pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy"); pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam"); pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam"); #else pContext->posix.pthread_create = (ma_proc)pthread_create; pContext->posix.pthread_join = (ma_proc)pthread_join; pContext->posix.pthread_mutex_init = (ma_proc)pthread_mutex_init; pContext->posix.pthread_mutex_destroy = (ma_proc)pthread_mutex_destroy; pContext->posix.pthread_mutex_lock = (ma_proc)pthread_mutex_lock; pContext->posix.pthread_mutex_unlock = (ma_proc)pthread_mutex_unlock; pContext->posix.pthread_cond_init = (ma_proc)pthread_cond_init; pContext->posix.pthread_cond_destroy = (ma_proc)pthread_cond_destroy; pContext->posix.pthread_cond_wait = (ma_proc)pthread_cond_wait; pContext->posix.pthread_cond_signal = (ma_proc)pthread_cond_signal; pContext->posix.pthread_attr_init = (ma_proc)pthread_attr_init; pContext->posix.pthread_attr_destroy = (ma_proc)pthread_attr_destroy; #if !defined(__EMSCRIPTEN__) pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy; pContext->posix.pthread_attr_getschedparam = (ma_proc)pthread_attr_getschedparam; pContext->posix.pthread_attr_setschedparam = (ma_proc)pthread_attr_setschedparam; #endif #endif return MA_SUCCESS; } #endif ma_result ma_context_init_backend_apis(ma_context* pContext) { ma_result result; #ifdef MA_WIN32 result = ma_context_init_backend_apis__win32(pContext); #else result = ma_context_init_backend_apis__nix(pContext); #endif return result; } ma_result ma_context_uninit_backend_apis(ma_context* pContext) { ma_result result; #ifdef MA_WIN32 result = ma_context_uninit_backend_apis__win32(pContext); #else result = ma_context_uninit_backend_apis__nix(pContext); #endif return result; } ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext) { return pContext->isBackendAsynchronous; } ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext) { ma_result result; ma_context_config config; ma_backend defaultBackends[ma_backend_null+1]; ma_uint32 iBackend; ma_backend* pBackendsToIterate; ma_uint32 backendsToIterateCount; if (pContext == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pContext); /* Always make sure the config is set first to ensure properties are available as soon as possible. */ if (pConfig != NULL) { config = *pConfig; } else { config = ma_context_config_init(); } pContext->logCallback = config.logCallback; pContext->threadPriority = config.threadPriority; pContext->pUserData = config.pUserData; /* Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. */ result = ma_context_init_backend_apis(pContext); if (result != MA_SUCCESS) { return result; } for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) { defaultBackends[iBackend] = (ma_backend)iBackend; } pBackendsToIterate = (ma_backend*)backends; backendsToIterateCount = backendCount; if (pBackendsToIterate == NULL) { pBackendsToIterate = (ma_backend*)defaultBackends; backendsToIterateCount = ma_countof(defaultBackends); } ma_assert(pBackendsToIterate != NULL); for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) { ma_backend backend = pBackendsToIterate[iBackend]; result = MA_NO_BACKEND; switch (backend) { #ifdef MA_HAS_WASAPI case ma_backend_wasapi: { result = ma_context_init__wasapi(&config, pContext); } break; #endif #ifdef MA_HAS_DSOUND case ma_backend_dsound: { result = ma_context_init__dsound(&config, pContext); } break; #endif #ifdef MA_HAS_WINMM case ma_backend_winmm: { result = ma_context_init__winmm(&config, pContext); } break; #endif #ifdef MA_HAS_ALSA case ma_backend_alsa: { result = ma_context_init__alsa(&config, pContext); } break; #endif #ifdef MA_HAS_PULSEAUDIO case ma_backend_pulseaudio: { result = ma_context_init__pulse(&config, pContext); } break; #endif #ifdef MA_HAS_JACK case ma_backend_jack: { result = ma_context_init__jack(&config, pContext); } break; #endif #ifdef MA_HAS_COREAUDIO case ma_backend_coreaudio: { result = ma_context_init__coreaudio(&config, pContext); } break; #endif #ifdef MA_HAS_SNDIO case ma_backend_sndio: { result = ma_context_init__sndio(&config, pContext); } break; #endif #ifdef MA_HAS_AUDIO4 case ma_backend_audio4: { result = ma_context_init__audio4(&config, pContext); } break; #endif #ifdef MA_HAS_OSS case ma_backend_oss: { result = ma_context_init__oss(&config, pContext); } break; #endif #ifdef MA_HAS_AAUDIO case ma_backend_aaudio: { result = ma_context_init__aaudio(&config, pContext); } break; #endif #ifdef MA_HAS_OPENSL case ma_backend_opensl: { result = ma_context_init__opensl(&config, pContext); } break; #endif #ifdef MA_HAS_WEBAUDIO case ma_backend_webaudio: { result = ma_context_init__webaudio(&config, pContext); } break; #endif #ifdef MA_HAS_NULL case ma_backend_null: { result = ma_context_init__null(&config, pContext); } break; #endif default: break; } /* If this iteration was successful, return. */ if (result == MA_SUCCESS) { result = ma_mutex_init(pContext, &pContext->deviceEnumLock); if (result != MA_SUCCESS) { ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.", MA_FAILED_TO_CREATE_MUTEX); } result = ma_mutex_init(pContext, &pContext->deviceInfoLock); if (result != MA_SUCCESS) { ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.", MA_FAILED_TO_CREATE_MUTEX); } #ifdef MA_DEBUG_OUTPUT printf("[miniaudio] Endian: %s\n", ma_is_little_endian() ? "LE" : "BE"); printf("[miniaudio] SSE2: %s\n", ma_has_sse2() ? "YES" : "NO"); printf("[miniaudio] AVX2: %s\n", ma_has_avx2() ? "YES" : "NO"); printf("[miniaudio] AVX512F: %s\n", ma_has_avx512f() ? "YES" : "NO"); printf("[miniaudio] NEON: %s\n", ma_has_neon() ? "YES" : "NO"); #endif pContext->backend = backend; return result; } } /* If we get here it means an error occurred. */ ma_zero_object(pContext); /* Safety. */ return MA_NO_BACKEND; } ma_result ma_context_uninit(ma_context* pContext) { if (pContext == NULL) { return MA_INVALID_ARGS; } pContext->onUninit(pContext); ma_mutex_uninit(&pContext->deviceEnumLock); ma_mutex_uninit(&pContext->deviceInfoLock); ma_free(pContext->pDeviceInfos); ma_context_uninit_backend_apis(pContext); return MA_SUCCESS; } ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) { ma_result result; if (pContext == NULL || pContext->onEnumDevices == NULL || callback == NULL) { return MA_INVALID_ARGS; } ma_mutex_lock(&pContext->deviceEnumLock); { result = pContext->onEnumDevices(pContext, callback, pUserData); } ma_mutex_unlock(&pContext->deviceEnumLock); return result; } ma_bool32 ma_context_get_devices__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData) { /* We need to insert the device info into our main internal buffer. Where it goes depends on the device type. If it's a capture device it's just appended to the end. If it's a playback device it's inserted just before the first capture device. */ /* First make sure we have room. Since the number of devices we add to the list is usually relatively small I've decided to use a simple fixed size increment for buffer expansion. */ const ma_uint32 bufferExpansionCount = 2; const ma_uint32 totalDeviceInfoCount = pContext->playbackDeviceInfoCount + pContext->captureDeviceInfoCount; if (pContext->deviceInfoCapacity >= totalDeviceInfoCount) { ma_uint32 newCapacity = totalDeviceInfoCount + bufferExpansionCount; ma_device_info* pNewInfos = (ma_device_info*)ma_realloc(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity); if (pNewInfos == NULL) { return MA_FALSE; /* Out of memory. */ } pContext->pDeviceInfos = pNewInfos; pContext->deviceInfoCapacity = newCapacity; } if (deviceType == ma_device_type_playback) { /* Playback. Insert just before the first capture device. */ /* The first thing to do is move all of the capture devices down a slot. */ ma_uint32 iFirstCaptureDevice = pContext->playbackDeviceInfoCount; size_t iCaptureDevice; for (iCaptureDevice = totalDeviceInfoCount; iCaptureDevice > iFirstCaptureDevice; --iCaptureDevice) { pContext->pDeviceInfos[iCaptureDevice] = pContext->pDeviceInfos[iCaptureDevice-1]; } /* Now just insert where the first capture device was before moving it down a slot. */ pContext->pDeviceInfos[iFirstCaptureDevice] = *pInfo; pContext->playbackDeviceInfoCount += 1; } else { /* Capture. Insert at the end. */ pContext->pDeviceInfos[totalDeviceInfoCount] = *pInfo; pContext->captureDeviceInfoCount += 1; } (void)pUserData; return MA_TRUE; } ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount) { ma_result result; /* Safety. */ if (ppPlaybackDeviceInfos != NULL) *ppPlaybackDeviceInfos = NULL; if (pPlaybackDeviceCount != NULL) *pPlaybackDeviceCount = 0; if (ppCaptureDeviceInfos != NULL) *ppCaptureDeviceInfos = NULL; if (pCaptureDeviceCount != NULL) *pCaptureDeviceCount = 0; if (pContext == NULL || pContext->onEnumDevices == NULL) { return MA_INVALID_ARGS; } /* Note that we don't use ma_context_enumerate_devices() here because we want to do locking at a higher level. */ ma_mutex_lock(&pContext->deviceEnumLock); { /* Reset everything first. */ pContext->playbackDeviceInfoCount = 0; pContext->captureDeviceInfoCount = 0; /* Now enumerate over available devices. */ result = pContext->onEnumDevices(pContext, ma_context_get_devices__enum_callback, NULL); if (result == MA_SUCCESS) { /* Playback devices. */ if (ppPlaybackDeviceInfos != NULL) { *ppPlaybackDeviceInfos = pContext->pDeviceInfos; } if (pPlaybackDeviceCount != NULL) { *pPlaybackDeviceCount = pContext->playbackDeviceInfoCount; } /* Capture devices. */ if (ppCaptureDeviceInfos != NULL) { *ppCaptureDeviceInfos = pContext->pDeviceInfos + pContext->playbackDeviceInfoCount; /* Capture devices come after playback devices. */ } if (pCaptureDeviceCount != NULL) { *pCaptureDeviceCount = pContext->captureDeviceInfoCount; } } } ma_mutex_unlock(&pContext->deviceEnumLock); return result; } ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) { ma_device_info deviceInfo; /* NOTE: Do not clear pDeviceInfo on entry. The reason is the pDeviceID may actually point to pDeviceInfo->id which will break things. */ if (pContext == NULL || pDeviceInfo == NULL) { return MA_INVALID_ARGS; } ma_zero_object(&deviceInfo); /* Help the backend out by copying over the device ID if we have one. */ if (pDeviceID != NULL) { ma_copy_memory(&deviceInfo.id, pDeviceID, sizeof(*pDeviceID)); } /* The backend may have an optimized device info retrieval function. If so, try that first. */ if (pContext->onGetDeviceInfo != NULL) { ma_result result; ma_mutex_lock(&pContext->deviceInfoLock); { result = pContext->onGetDeviceInfo(pContext, deviceType, pDeviceID, shareMode, &deviceInfo); } ma_mutex_unlock(&pContext->deviceInfoLock); /* Clamp ranges. */ deviceInfo.minChannels = ma_max(deviceInfo.minChannels, MA_MIN_CHANNELS); deviceInfo.maxChannels = ma_min(deviceInfo.maxChannels, MA_MAX_CHANNELS); deviceInfo.minSampleRate = ma_max(deviceInfo.minSampleRate, MA_MIN_SAMPLE_RATE); deviceInfo.maxSampleRate = ma_min(deviceInfo.maxSampleRate, MA_MAX_SAMPLE_RATE); *pDeviceInfo = deviceInfo; return result; } /* Getting here means onGetDeviceInfo has not been set. */ return MA_ERROR; } ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result; ma_device_config config; if (pContext == NULL) { return ma_device_init_ex(NULL, 0, NULL, pConfig, pDevice); } if (pDevice == NULL) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); } if (pConfig == NULL) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pConfig == NULL).", MA_INVALID_ARGS); } /* We need to make a copy of the config so we can set default values if they were left unset in the input config. */ config = *pConfig; /* Basic config validation. */ if (config.deviceType != ma_device_type_playback && config.deviceType != ma_device_type_capture && config.deviceType != ma_device_type_duplex) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Device type is invalid. Make sure the device type has been set in the config.", MA_INVALID_DEVICE_CONFIG); } if (config.deviceType == ma_device_type_capture || config.deviceType == ma_device_type_duplex) { if (config.capture.channels > MA_MAX_CHANNELS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Capture channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG); } if (!ma__is_channel_map_valid(config.capture.channelMap, config.capture.channels)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Capture channel map is invalid.", MA_INVALID_DEVICE_CONFIG); } } if (config.deviceType == ma_device_type_playback || config.deviceType == ma_device_type_duplex) { if (config.playback.channels > MA_MAX_CHANNELS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Playback channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG); } if (!ma__is_channel_map_valid(config.playback.channelMap, config.playback.channels)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Playback channel map is invalid.", MA_INVALID_DEVICE_CONFIG); } } ma_zero_object(pDevice); pDevice->pContext = pContext; /* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */ pDevice->pUserData = config.pUserData; pDevice->onData = config.dataCallback; pDevice->onStop = config.stopCallback; if (((ma_uintptr)pDevice % sizeof(pDevice)) != 0) { if (pContext->logCallback) { pContext->logCallback(pContext, pDevice, MA_LOG_LEVEL_WARNING, "WARNING: ma_device_init() called for a device that is not properly aligned. Thread safety is not supported."); } } /* When passing in 0 for the format/channels/rate/chmap it means the device will be using whatever is chosen by the backend. If everything is set to defaults it means the format conversion pipeline will run on a fast path where data transfer is just passed straight through to the backend. */ if (config.sampleRate == 0) { config.sampleRate = MA_DEFAULT_SAMPLE_RATE; pDevice->usingDefaultSampleRate = MA_TRUE; } if (config.capture.format == ma_format_unknown) { config.capture.format = MA_DEFAULT_FORMAT; pDevice->capture.usingDefaultFormat = MA_TRUE; } if (config.capture.channels == 0) { config.capture.channels = MA_DEFAULT_CHANNELS; pDevice->capture.usingDefaultChannels = MA_TRUE; } if (config.capture.channelMap[0] == MA_CHANNEL_NONE) { pDevice->capture.usingDefaultChannelMap = MA_TRUE; } if (config.playback.format == ma_format_unknown) { config.playback.format = MA_DEFAULT_FORMAT; pDevice->playback.usingDefaultFormat = MA_TRUE; } if (config.playback.channels == 0) { config.playback.channels = MA_DEFAULT_CHANNELS; pDevice->playback.usingDefaultChannels = MA_TRUE; } if (config.playback.channelMap[0] == MA_CHANNEL_NONE) { pDevice->playback.usingDefaultChannelMap = MA_TRUE; } /* Default buffer size. */ if (config.bufferSizeInMilliseconds == 0 && config.bufferSizeInFrames == 0) { config.bufferSizeInMilliseconds = (config.performanceProfile == ma_performance_profile_low_latency) ? MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY : MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE; pDevice->usingDefaultBufferSize = MA_TRUE; } /* Default periods. */ if (config.periods == 0) { config.periods = MA_DEFAULT_PERIODS; pDevice->usingDefaultPeriods = MA_TRUE; } /* Must have at least 3 periods for full-duplex mode. The idea is that the playback and capture positions hang out in the middle period, with the surrounding periods acting as a buffer in case the capture and playback devices get's slightly out of sync. */ if (config.deviceType == ma_device_type_duplex && config.periods < 3) { config.periods = 3; } pDevice->type = config.deviceType; pDevice->sampleRate = config.sampleRate; pDevice->capture.shareMode = config.capture.shareMode; pDevice->capture.format = config.capture.format; pDevice->capture.channels = config.capture.channels; ma_channel_map_copy(pDevice->capture.channelMap, config.capture.channelMap, config.capture.channels); pDevice->playback.shareMode = config.playback.shareMode; pDevice->playback.format = config.playback.format; pDevice->playback.channels = config.playback.channels; ma_channel_map_copy(pDevice->playback.channelMap, config.playback.channelMap, config.playback.channels); /* The internal format, channel count and sample rate can be modified by the backend. */ pDevice->capture.internalFormat = pDevice->capture.format; pDevice->capture.internalChannels = pDevice->capture.channels; pDevice->capture.internalSampleRate = pDevice->sampleRate; ma_channel_map_copy(pDevice->capture.internalChannelMap, pDevice->capture.channelMap, pDevice->capture.channels); pDevice->playback.internalFormat = pDevice->playback.format; pDevice->playback.internalChannels = pDevice->playback.channels; pDevice->playback.internalSampleRate = pDevice->sampleRate; ma_channel_map_copy(pDevice->playback.internalChannelMap, pDevice->playback.channelMap, pDevice->playback.channels); if (ma_mutex_init(pContext, &pDevice->lock) != MA_SUCCESS) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", MA_FAILED_TO_CREATE_MUTEX); } /* When the device is started, the worker thread is the one that does the actual startup of the backend device. We use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device. Each of these semaphores is released internally by the worker thread when the work is completed. The start semaphore is also used to wake up the worker thread. */ if (ma_event_init(pContext, &pDevice->wakeupEvent) != MA_SUCCESS) { ma_mutex_uninit(&pDevice->lock); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", MA_FAILED_TO_CREATE_EVENT); } if (ma_event_init(pContext, &pDevice->startEvent) != MA_SUCCESS) { ma_event_uninit(&pDevice->wakeupEvent); ma_mutex_uninit(&pDevice->lock); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", MA_FAILED_TO_CREATE_EVENT); } if (ma_event_init(pContext, &pDevice->stopEvent) != MA_SUCCESS) { ma_event_uninit(&pDevice->startEvent); ma_event_uninit(&pDevice->wakeupEvent); ma_mutex_uninit(&pDevice->lock); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", MA_FAILED_TO_CREATE_EVENT); } result = pContext->onDeviceInit(pContext, &config, pDevice); if (result != MA_SUCCESS) { return MA_NO_BACKEND; /* The error message will have been posted with ma_post_error() by the source of the error so don't bother calling it here. */ } ma_device__post_init_setup(pDevice, pConfig->deviceType); /* If the backend did not fill out a name for the device, try a generic method. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (pDevice->capture.name[0] == '\0') { if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_capture, config.capture.pDeviceID, pDevice->capture.name, sizeof(pDevice->capture.name)) != MA_SUCCESS) { ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), (config.capture.pDeviceID == NULL) ? MA_DEFAULT_CAPTURE_DEVICE_NAME : "Capture Device", (size_t)-1); } } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->playback.name[0] == '\0') { if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_playback, config.playback.pDeviceID, pDevice->playback.name, sizeof(pDevice->playback.name)) != MA_SUCCESS) { ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), (config.playback.pDeviceID == NULL) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : "Playback Device", (size_t)-1); } } } /* Some backends don't require the worker thread. */ if (!ma_context_is_backend_asynchronous(pContext)) { /* The worker thread. */ if (ma_thread_create(pContext, &pDevice->thread, ma_worker_thread, pDevice) != MA_SUCCESS) { ma_device_uninit(pDevice); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", MA_FAILED_TO_CREATE_THREAD); } /* Wait for the worker thread to put the device into it's stopped state for real. */ ma_event_wait(&pDevice->stopEvent); } else { ma_device__set_state(pDevice, MA_STATE_STOPPED); } #ifdef MA_DEBUG_OUTPUT printf("[%s]\n", ma_get_backend_name(pDevice->pContext->backend)); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { printf(" %s (%s)\n", pDevice->capture.name, "Capture"); printf(" Format: %s -> %s\n", ma_get_format_name(pDevice->capture.format), ma_get_format_name(pDevice->capture.internalFormat)); printf(" Channels: %d -> %d\n", pDevice->capture.channels, pDevice->capture.internalChannels); printf(" Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->capture.internalSampleRate); printf(" Buffer Size: %d/%d (%d)\n", pDevice->capture.internalBufferSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods)); printf(" Conversion:\n"); printf(" Pre Format Conversion: %s\n", pDevice->capture.converter.isPreFormatConversionRequired ? "YES" : "NO"); printf(" Post Format Conversion: %s\n", pDevice->capture.converter.isPostFormatConversionRequired ? "YES" : "NO"); printf(" Channel Routing: %s\n", pDevice->capture.converter.isChannelRoutingRequired ? "YES" : "NO"); printf(" SRC: %s\n", pDevice->capture.converter.isSRCRequired ? "YES" : "NO"); printf(" Channel Routing at Start: %s\n", pDevice->capture.converter.isChannelRoutingAtStart ? "YES" : "NO"); printf(" Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO"); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { printf(" %s (%s)\n", pDevice->playback.name, "Playback"); printf(" Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat)); printf(" Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels); printf(" Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate); printf(" Buffer Size: %d/%d (%d)\n", pDevice->playback.internalBufferSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods)); printf(" Conversion:\n"); printf(" Pre Format Conversion: %s\n", pDevice->playback.converter.isPreFormatConversionRequired ? "YES" : "NO"); printf(" Post Format Conversion: %s\n", pDevice->playback.converter.isPostFormatConversionRequired ? "YES" : "NO"); printf(" Channel Routing: %s\n", pDevice->playback.converter.isChannelRoutingRequired ? "YES" : "NO"); printf(" SRC: %s\n", pDevice->playback.converter.isSRCRequired ? "YES" : "NO"); printf(" Channel Routing at Start: %s\n", pDevice->playback.converter.isChannelRoutingAtStart ? "YES" : "NO"); printf(" Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO"); } #endif ma_assert(ma_device__get_state(pDevice) == MA_STATE_STOPPED); return MA_SUCCESS; } ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pContextConfig, const ma_device_config* pConfig, ma_device* pDevice) { ma_result result; ma_context* pContext; ma_backend defaultBackends[ma_backend_null+1]; ma_uint32 iBackend; ma_backend* pBackendsToIterate; ma_uint32 backendsToIterateCount; if (pConfig == NULL) { return MA_INVALID_ARGS; } pContext = (ma_context*)ma_malloc(sizeof(*pContext)); if (pContext == NULL) { return MA_OUT_OF_MEMORY; } for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) { defaultBackends[iBackend] = (ma_backend)iBackend; } pBackendsToIterate = (ma_backend*)backends; backendsToIterateCount = backendCount; if (pBackendsToIterate == NULL) { pBackendsToIterate = (ma_backend*)defaultBackends; backendsToIterateCount = ma_countof(defaultBackends); } result = MA_NO_BACKEND; for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) { result = ma_context_init(&pBackendsToIterate[iBackend], 1, pContextConfig, pContext); if (result == MA_SUCCESS) { result = ma_device_init(pContext, pConfig, pDevice); if (result == MA_SUCCESS) { break; /* Success. */ } else { ma_context_uninit(pContext); /* Failure. */ } } } if (result != MA_SUCCESS) { ma_free(pContext); return result; } pDevice->isOwnerOfContext = MA_TRUE; return result; } void ma_device_uninit(ma_device* pDevice) { if (!ma_device__is_initialized(pDevice)) { return; } /* Make sure the device is stopped first. The backends will probably handle this naturally, but I like to do it explicitly for my own sanity. */ if (ma_device_is_started(pDevice)) { ma_device_stop(pDevice); } /* Putting the device into an uninitialized state will make the worker thread return. */ ma_device__set_state(pDevice, MA_STATE_UNINITIALIZED); /* Wake up the worker thread and wait for it to properly terminate. */ if (!ma_context_is_backend_asynchronous(pDevice->pContext)) { ma_event_signal(&pDevice->wakeupEvent); ma_thread_wait(&pDevice->thread); } pDevice->pContext->onDeviceUninit(pDevice); ma_event_uninit(&pDevice->stopEvent); ma_event_uninit(&pDevice->startEvent); ma_event_uninit(&pDevice->wakeupEvent); ma_mutex_uninit(&pDevice->lock); if (pDevice->isOwnerOfContext) { ma_context_uninit(pDevice->pContext); ma_free(pDevice->pContext); } ma_zero_object(pDevice); } void ma_device_set_stop_callback(ma_device* pDevice, ma_stop_proc proc) { if (pDevice == NULL) { return; } ma_atomic_exchange_ptr(&pDevice->onStop, proc); } ma_result ma_device_start(ma_device* pDevice) { ma_result result; if (pDevice == NULL) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); } if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED); } /* Starting the device doesn't do anything in synchronous mode because in that case it's started automatically with ma_device_write() and ma_device_read(). It's best to return an error so that the application can be aware that it's not doing it right. */ if (!ma_device__is_async(pDevice)) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called in synchronous mode. This should only be used in asynchronous/callback mode.", MA_DEVICE_NOT_INITIALIZED); } result = MA_ERROR; ma_mutex_lock(&pDevice->lock); { /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a stopped or paused state. */ ma_assert(ma_device__get_state(pDevice) == MA_STATE_STOPPED); ma_device__set_state(pDevice, MA_STATE_STARTING); /* Asynchronous backends need to be handled differently. */ if (ma_context_is_backend_asynchronous(pDevice->pContext)) { result = pDevice->pContext->onDeviceStart(pDevice); if (result == MA_SUCCESS) { ma_device__set_state(pDevice, MA_STATE_STARTED); } } else { /* Synchronous backends are started by signaling an event that's being waited on in the worker thread. We first wake up the thread and then wait for the start event. */ ma_event_signal(&pDevice->wakeupEvent); /* Wait for the worker thread to finish starting the device. Note that the worker thread will be the one who puts the device into the started state. Don't call ma_device__set_state() here. */ ma_event_wait(&pDevice->startEvent); result = pDevice->workResult; } } ma_mutex_unlock(&pDevice->lock); return result; } ma_result ma_device_stop(ma_device* pDevice) { ma_result result; if (pDevice == NULL) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS); } if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) { return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED); } /* Stopping is slightly different for synchronous mode. In this case it just tells the driver to stop the internal processing of the device. Also, stopping in synchronous mode does not require state checking. */ if (!ma_device__is_async(pDevice)) { if (pDevice->pContext->onDeviceStop) { return pDevice->pContext->onDeviceStop(pDevice); } } result = MA_ERROR; ma_mutex_lock(&pDevice->lock); { /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */ ma_assert(ma_device__get_state(pDevice) == MA_STATE_STARTED); ma_device__set_state(pDevice, MA_STATE_STOPPING); /* There's no need to wake up the thread like we do when starting. */ /* Asynchronous backends need to be handled differently. */ if (ma_context_is_backend_asynchronous(pDevice->pContext)) { if (pDevice->pContext->onDeviceStop) { result = pDevice->pContext->onDeviceStop(pDevice); } else { result = MA_SUCCESS; } ma_device__set_state(pDevice, MA_STATE_STOPPED); } else { /* Synchronous backends. */ /* We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be the one who puts the device into the stopped state. Don't call ma_device__set_state() here. */ ma_event_wait(&pDevice->stopEvent); result = MA_SUCCESS; } } ma_mutex_unlock(&pDevice->lock); return result; } ma_bool32 ma_device_is_started(ma_device* pDevice) { if (pDevice == NULL) { return MA_FALSE; } return ma_device__get_state(pDevice) == MA_STATE_STARTED; } ma_context_config ma_context_config_init() { ma_context_config config; ma_zero_object(&config); return config; } ma_device_config ma_device_config_init(ma_device_type deviceType) { ma_device_config config; ma_zero_object(&config); config.deviceType = deviceType; return config; } #endif /* MA_NO_DEVICE_IO */ void ma_get_standard_channel_map_microsoft(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { /* Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */ switch (channels) { case 1: { channelMap[0] = MA_CHANNEL_MONO; } break; case 2: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; } break; case 3: /* Not defined, but best guess. */ { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { #ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP /* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */ channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_BACK_CENTER; #else /* Quad. */ channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; #endif } break; case 5: /* Not defined, but best guess. */ { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_BACK_LEFT; channelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_LFE; channelMap[4] = MA_CHANNEL_SIDE_LEFT; channelMap[5] = MA_CHANNEL_SIDE_RIGHT; } break; case 7: /* Not defined, but best guess. */ { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_LFE; channelMap[4] = MA_CHANNEL_BACK_CENTER; channelMap[5] = MA_CHANNEL_SIDE_LEFT; channelMap[6] = MA_CHANNEL_SIDE_RIGHT; } break; case 8: default: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_LFE; channelMap[4] = MA_CHANNEL_BACK_LEFT; channelMap[5] = MA_CHANNEL_BACK_RIGHT; channelMap[6] = MA_CHANNEL_SIDE_LEFT; channelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); } } } void ma_get_standard_channel_map_alsa(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { switch (channels) { case 1: { channelMap[0] = MA_CHANNEL_MONO; } break; case 2: { channelMap[0] = MA_CHANNEL_LEFT; channelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; channelMap[5] = MA_CHANNEL_LFE; } break; case 7: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; channelMap[5] = MA_CHANNEL_LFE; channelMap[6] = MA_CHANNEL_BACK_CENTER; } break; case 8: default: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; channelMap[5] = MA_CHANNEL_LFE; channelMap[6] = MA_CHANNEL_SIDE_LEFT; channelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); } } } void ma_get_standard_channel_map_rfc3551(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { switch (channels) { case 1: { channelMap[0] = MA_CHANNEL_MONO; } break; case 2: { channelMap[0] = MA_CHANNEL_LEFT; channelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_CENTER; channelMap[2] = MA_CHANNEL_FRONT_RIGHT; channelMap[3] = MA_CHANNEL_BACK_CENTER; } break; case 5: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_BACK_LEFT; channelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_SIDE_LEFT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_FRONT_RIGHT; channelMap[4] = MA_CHANNEL_SIDE_RIGHT; channelMap[5] = MA_CHANNEL_BACK_CENTER; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; for (iChannel = 6; iChannel < MA_MAX_CHANNELS; ++iChannel) { channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); } } } void ma_get_standard_channel_map_flac(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { switch (channels) { case 1: { channelMap[0] = MA_CHANNEL_MONO; } break; case 2: { channelMap[0] = MA_CHANNEL_LEFT; channelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_BACK_LEFT; channelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_LFE; channelMap[4] = MA_CHANNEL_BACK_LEFT; channelMap[5] = MA_CHANNEL_BACK_RIGHT; } break; case 7: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_LFE; channelMap[4] = MA_CHANNEL_BACK_CENTER; channelMap[5] = MA_CHANNEL_SIDE_LEFT; channelMap[6] = MA_CHANNEL_SIDE_RIGHT; } break; case 8: default: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; channelMap[3] = MA_CHANNEL_LFE; channelMap[4] = MA_CHANNEL_BACK_LEFT; channelMap[5] = MA_CHANNEL_BACK_RIGHT; channelMap[6] = MA_CHANNEL_SIDE_LEFT; channelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); } } } void ma_get_standard_channel_map_vorbis(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { /* In Vorbis' type 0 channel mapping, the first two channels are not always the standard left/right - it will have the center speaker where the right usually goes. Why?! */ switch (channels) { case 1: { channelMap[0] = MA_CHANNEL_MONO; } break; case 2: { channelMap[0] = MA_CHANNEL_LEFT; channelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_CENTER; channelMap[2] = MA_CHANNEL_FRONT_RIGHT; } break; case 4: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_CENTER; channelMap[2] = MA_CHANNEL_FRONT_RIGHT; channelMap[3] = MA_CHANNEL_BACK_LEFT; channelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_CENTER; channelMap[2] = MA_CHANNEL_FRONT_RIGHT; channelMap[3] = MA_CHANNEL_BACK_LEFT; channelMap[4] = MA_CHANNEL_BACK_RIGHT; channelMap[5] = MA_CHANNEL_LFE; } break; case 7: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_CENTER; channelMap[2] = MA_CHANNEL_FRONT_RIGHT; channelMap[3] = MA_CHANNEL_SIDE_LEFT; channelMap[4] = MA_CHANNEL_SIDE_RIGHT; channelMap[5] = MA_CHANNEL_BACK_CENTER; channelMap[6] = MA_CHANNEL_LFE; } break; case 8: default: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_CENTER; channelMap[2] = MA_CHANNEL_FRONT_RIGHT; channelMap[3] = MA_CHANNEL_SIDE_LEFT; channelMap[4] = MA_CHANNEL_SIDE_RIGHT; channelMap[5] = MA_CHANNEL_BACK_LEFT; channelMap[6] = MA_CHANNEL_BACK_RIGHT; channelMap[7] = MA_CHANNEL_LFE; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); } } } void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { switch (channels) { case 1: { channelMap[0] = MA_CHANNEL_MONO; } break; case 2: { channelMap[0] = MA_CHANNEL_LEFT; channelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_CENTER; } break; case 4: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; channelMap[5] = MA_CHANNEL_LFE; } break; case 7: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; channelMap[5] = MA_CHANNEL_BACK_CENTER; channelMap[6] = MA_CHANNEL_LFE; } break; case 8: default: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; channelMap[5] = MA_CHANNEL_LFE; channelMap[6] = MA_CHANNEL_SIDE_LEFT; channelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); } } } void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { switch (channels) { case 1: { channelMap[0] = MA_CHANNEL_MONO; } break; case 2: { channelMap[0] = MA_CHANNEL_LEFT; channelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: default: { channelMap[0] = MA_CHANNEL_FRONT_LEFT; channelMap[1] = MA_CHANNEL_FRONT_RIGHT; channelMap[2] = MA_CHANNEL_BACK_LEFT; channelMap[3] = MA_CHANNEL_BACK_RIGHT; channelMap[4] = MA_CHANNEL_FRONT_CENTER; channelMap[5] = MA_CHANNEL_LFE; } break; } /* Remainder. */ if (channels > 6) { ma_uint32 iChannel; for (iChannel = 6; iChannel < MA_MAX_CHANNELS; ++iChannel) { channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); } } } void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) { switch (standardChannelMap) { case ma_standard_channel_map_alsa: { ma_get_standard_channel_map_alsa(channels, channelMap); } break; case ma_standard_channel_map_rfc3551: { ma_get_standard_channel_map_rfc3551(channels, channelMap); } break; case ma_standard_channel_map_flac: { ma_get_standard_channel_map_flac(channels, channelMap); } break; case ma_standard_channel_map_vorbis: { ma_get_standard_channel_map_vorbis(channels, channelMap); } break; case ma_standard_channel_map_sound4: { ma_get_standard_channel_map_sound4(channels, channelMap); } break; case ma_standard_channel_map_sndio: { ma_get_standard_channel_map_sndio(channels, channelMap); } break; case ma_standard_channel_map_microsoft: default: { ma_get_standard_channel_map_microsoft(channels, channelMap); } break; } } void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels) { if (pOut != NULL && pIn != NULL && channels > 0) { ma_copy_memory(pOut, pIn, sizeof(*pOut) * channels); } } ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS]) { if (channelMap == NULL) { return MA_FALSE; } /* A channel count of 0 is invalid. */ if (channels == 0) { return MA_FALSE; } /* It does not make sense to have a mono channel when there is more than 1 channel. */ if (channels > 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { if (channelMap[iChannel] == MA_CHANNEL_MONO) { return MA_FALSE; } } } return MA_TRUE; } ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel channelMapA[MA_MAX_CHANNELS], const ma_channel channelMapB[MA_MAX_CHANNELS]) { ma_uint32 iChannel; if (channelMapA == channelMapB) { return MA_FALSE; } if (channels == 0 || channels > MA_MAX_CHANNELS) { return MA_FALSE; } for (iChannel = 0; iChannel < channels; ++iChannel) { if (channelMapA[iChannel] != channelMapB[iChannel]) { return MA_FALSE; } } return MA_TRUE; } ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS]) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { if (channelMap[iChannel] != MA_CHANNEL_NONE) { return MA_FALSE; } } return MA_TRUE; } ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS], ma_channel channelPosition) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { if (channelMap[iChannel] == channelPosition) { return MA_TRUE; } } return MA_FALSE; } /************************************************************************************************************************************************************** Format Conversion. **************************************************************************************************************************************************************/ void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes) { #if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX ma_copy_memory(dst, src, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { ma_uint64 bytesToCopyNow = sizeInBytes; if (bytesToCopyNow > MA_SIZE_MAX) { bytesToCopyNow = MA_SIZE_MAX; } ma_copy_memory(dst, src, (size_t)bytesToCopyNow); /* Safe cast to size_t. */ sizeInBytes -= bytesToCopyNow; dst = ( void*)(( ma_uint8*)dst + bytesToCopyNow); src = (const void*)((const ma_uint8*)src + bytesToCopyNow); } #endif } void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes) { #if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX ma_zero_memory(dst, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { ma_uint64 bytesToZeroNow = sizeInBytes; if (bytesToZeroNow > MA_SIZE_MAX) { bytesToZeroNow = MA_SIZE_MAX; } ma_zero_memory(dst, (size_t)bytesToZeroNow); /* Safe cast to size_t. */ sizeInBytes -= bytesToZeroNow; dst = (void*)((ma_uint8*)dst + bytesToZeroNow); } #endif } /* u8 */ void ma_pcm_u8_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { (void)ditherMode; ma_copy_memory_64(dst, src, count * sizeof(ma_uint8)); } void ma_pcm_u8_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_int16* dst_s16 = (ma_int16*)dst; const ma_uint8* src_u8 = (const ma_uint8*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int16 x = src_u8[i]; x = x - 128; x = x << 8; dst_s16[i] = x; } (void)ditherMode; } void ma_pcm_u8_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_u8_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_u8_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_u8_to_s16__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s16__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_u8_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_u8_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode); #else ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_u8_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint8* dst_s24 = (ma_uint8*)dst; const ma_uint8* src_u8 = (const ma_uint8*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int16 x = src_u8[i]; x = x - 128; dst_s24[i*3+0] = 0; dst_s24[i*3+1] = 0; dst_s24[i*3+2] = (ma_uint8)((ma_int8)x); } (void)ditherMode; } void ma_pcm_u8_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_u8_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_u8_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_u8_to_s24__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s24__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_u8_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_u8_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode); #else ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_u8_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_int32* dst_s32 = (ma_int32*)dst; const ma_uint8* src_u8 = (const ma_uint8*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int32 x = src_u8[i]; x = x - 128; x = x << 24; dst_s32[i] = x; } (void)ditherMode; } void ma_pcm_u8_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_u8_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_u8_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_u8_to_s32__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s32__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_u8_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_u8_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode); #else ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_u8_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { float* dst_f32 = (float*)dst; const ma_uint8* src_u8 = (const ma_uint8*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { float x = (float)src_u8[i]; x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */ x = x - 1; /* 0..2 to -1..1 */ dst_f32[i] = x; } (void)ditherMode; } void ma_pcm_u8_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_u8_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_u8_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_u8_to_f32__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_f32__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_u8_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_u8_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode); #else ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_interleave_u8__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_uint8* dst_u8 = (ma_uint8*)dst; const ma_uint8** src_u8 = (const ma_uint8**)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame]; } } } void ma_pcm_interleave_u8__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_uint8* dst_u8 = (ma_uint8*)dst; const ma_uint8** src_u8 = (const ma_uint8**)src; if (channels == 1) { ma_copy_memory_64(dst, src[0], frameCount * sizeof(ma_uint8)); } else if (channels == 2) { ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { dst_u8[iFrame*2 + 0] = src_u8[0][iFrame]; dst_u8[iFrame*2 + 1] = src_u8[1][iFrame]; } } else { ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame]; } } } } void ma_pcm_interleave_u8(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_interleave_u8__reference(dst, src, frameCount, channels); #else ma_pcm_interleave_u8__optimized(dst, src, frameCount, channels); #endif } void ma_pcm_deinterleave_u8__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_uint8** dst_u8 = (ma_uint8**)dst; const ma_uint8* src_u8 = (const ma_uint8*)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_u8[iChannel][iFrame] = src_u8[iFrame*channels + iChannel]; } } } void ma_pcm_deinterleave_u8__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels); } void ma_pcm_deinterleave_u8(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels); #else ma_pcm_deinterleave_u8__optimized(dst, src, frameCount, channels); #endif } /* s16 */ void ma_pcm_s16_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint8* dst_u8 = (ma_uint8*)dst; const ma_int16* src_s16 = (const ma_int16*)src; if (ditherMode == ma_dither_mode_none) { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int16 x = src_s16[i]; x = x >> 8; x = x + 128; dst_u8[i] = (ma_uint8)x; } } else { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int16 x = src_s16[i]; /* Dither. Don't overflow. */ ma_int32 dither = ma_dither_s32(ditherMode, -0x80, 0x7F); if ((x + dither) <= 0x7FFF) { x = (ma_int16)(x + dither); } else { x = 0x7FFF; } x = x >> 8; x = x + 128; dst_u8[i] = (ma_uint8)x; } } } void ma_pcm_s16_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s16_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s16_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s16_to_u8__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_u8__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s16_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s16_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode); #else ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s16_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { (void)ditherMode; ma_copy_memory_64(dst, src, count * sizeof(ma_int16)); } void ma_pcm_s16_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint8* dst_s24 = (ma_uint8*)dst; const ma_int16* src_s16 = (const ma_int16*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { dst_s24[i*3+0] = 0; dst_s24[i*3+1] = (ma_uint8)(src_s16[i] & 0xFF); dst_s24[i*3+2] = (ma_uint8)(src_s16[i] >> 8); } (void)ditherMode; } void ma_pcm_s16_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s16_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s16_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s16_to_s24__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s24__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s16_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s16_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode); #else ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s16_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_int32* dst_s32 = (ma_int32*)dst; const ma_int16* src_s16 = (const ma_int16*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { dst_s32[i] = src_s16[i] << 16; } (void)ditherMode; } void ma_pcm_s16_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s16_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s16_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s16_to_s32__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s32__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s16_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s16_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode); #else ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s16_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { float* dst_f32 = (float*)dst; const ma_int16* src_s16 = (const ma_int16*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { float x = (float)src_s16[i]; #if 0 /* The accurate way. */ x = x + 32768.0f; /* -32768..32767 to 0..65535 */ x = x * 0.00003051804379339284f; /* 0..65536 to 0..2 */ x = x - 1; /* 0..2 to -1..1 */ #else /* The fast way. */ x = x * 0.000030517578125f; /* -32768..32767 to -1..0.999969482421875 */ #endif dst_f32[i] = x; } (void)ditherMode; } void ma_pcm_s16_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s16_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s16_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s16_to_f32__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_f32__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s16_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s16_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode); #else ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_interleave_s16__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_int16* dst_s16 = (ma_int16*)dst; const ma_int16** src_s16 = (const ma_int16**)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_s16[iFrame*channels + iChannel] = src_s16[iChannel][iFrame]; } } } void ma_pcm_interleave_s16__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_interleave_s16__reference(dst, src, frameCount, channels); } void ma_pcm_interleave_s16(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_interleave_s16__reference(dst, src, frameCount, channels); #else ma_pcm_interleave_s16__optimized(dst, src, frameCount, channels); #endif } void ma_pcm_deinterleave_s16__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_int16** dst_s16 = (ma_int16**)dst; const ma_int16* src_s16 = (const ma_int16*)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_s16[iChannel][iFrame] = src_s16[iFrame*channels + iChannel]; } } } void ma_pcm_deinterleave_s16__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels); } void ma_pcm_deinterleave_s16(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels); #else ma_pcm_deinterleave_s16__optimized(dst, src, frameCount, channels); #endif } /* s24 */ void ma_pcm_s24_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint8* dst_u8 = (ma_uint8*)dst; const ma_uint8* src_s24 = (const ma_uint8*)src; if (ditherMode == ma_dither_mode_none) { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int8 x = (ma_int8)src_s24[i*3 + 2] + 128; dst_u8[i] = (ma_uint8)x; } } else { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int32 x = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24); /* Dither. Don't overflow. */ ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF); if ((ma_int64)x + dither <= 0x7FFFFFFF) { x = x + dither; } else { x = 0x7FFFFFFF; } x = x >> 24; x = x + 128; dst_u8[i] = (ma_uint8)x; } } } void ma_pcm_s24_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s24_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s24_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s24_to_u8__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_u8__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s24_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s24_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode); #else ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s24_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_int16* dst_s16 = (ma_int16*)dst; const ma_uint8* src_s24 = (const ma_uint8*)src; if (ditherMode == ma_dither_mode_none) { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_uint16 dst_lo = ((ma_uint16)src_s24[i*3 + 1]); ma_uint16 dst_hi = ((ma_uint16)src_s24[i*3 + 2]) << 8; dst_s16[i] = (ma_int16)dst_lo | dst_hi; } } else { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int32 x = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24); /* Dither. Don't overflow. */ ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF); if ((ma_int64)x + dither <= 0x7FFFFFFF) { x = x + dither; } else { x = 0x7FFFFFFF; } x = x >> 16; dst_s16[i] = (ma_int16)x; } } } void ma_pcm_s24_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s24_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s24_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s24_to_s16__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s16__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s24_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s24_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode); #else ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s24_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { (void)ditherMode; ma_copy_memory_64(dst, src, count * 3); } void ma_pcm_s24_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_int32* dst_s32 = (ma_int32*)dst; const ma_uint8* src_s24 = (const ma_uint8*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { dst_s32[i] = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24); } (void)ditherMode; } void ma_pcm_s24_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s24_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s24_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s24_to_s32__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s32__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s24_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s24_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode); #else ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s24_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { float* dst_f32 = (float*)dst; const ma_uint8* src_s24 = (const ma_uint8*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { float x = (float)(((ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24)) >> 8); #if 0 /* The accurate way. */ x = x + 8388608.0f; /* -8388608..8388607 to 0..16777215 */ x = x * 0.00000011920929665621f; /* 0..16777215 to 0..2 */ x = x - 1; /* 0..2 to -1..1 */ #else /* The fast way. */ x = x * 0.00000011920928955078125f; /* -8388608..8388607 to -1..0.999969482421875 */ #endif dst_f32[i] = x; } (void)ditherMode; } void ma_pcm_s24_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s24_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s24_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s24_to_f32__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_f32__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s24_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s24_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode); #else ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_interleave_s24__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_uint8* dst8 = (ma_uint8*)dst; const ma_uint8** src8 = (const ma_uint8**)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst8[iFrame*3*channels + iChannel*3 + 0] = src8[iChannel][iFrame*3 + 0]; dst8[iFrame*3*channels + iChannel*3 + 1] = src8[iChannel][iFrame*3 + 1]; dst8[iFrame*3*channels + iChannel*3 + 2] = src8[iChannel][iFrame*3 + 2]; } } } void ma_pcm_interleave_s24__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_interleave_s24__reference(dst, src, frameCount, channels); } void ma_pcm_interleave_s24(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_interleave_s24__reference(dst, src, frameCount, channels); #else ma_pcm_interleave_s24__optimized(dst, src, frameCount, channels); #endif } void ma_pcm_deinterleave_s24__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_uint8** dst8 = (ma_uint8**)dst; const ma_uint8* src8 = (const ma_uint8*)src; ma_uint32 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst8[iChannel][iFrame*3 + 0] = src8[iFrame*3*channels + iChannel*3 + 0]; dst8[iChannel][iFrame*3 + 1] = src8[iFrame*3*channels + iChannel*3 + 1]; dst8[iChannel][iFrame*3 + 2] = src8[iFrame*3*channels + iChannel*3 + 2]; } } } void ma_pcm_deinterleave_s24__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels); } void ma_pcm_deinterleave_s24(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels); #else ma_pcm_deinterleave_s24__optimized(dst, src, frameCount, channels); #endif } /* s32 */ void ma_pcm_s32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint8* dst_u8 = (ma_uint8*)dst; const ma_int32* src_s32 = (const ma_int32*)src; if (ditherMode == ma_dither_mode_none) { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int32 x = src_s32[i]; x = x >> 24; x = x + 128; dst_u8[i] = (ma_uint8)x; } } else { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int32 x = src_s32[i]; /* Dither. Don't overflow. */ ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF); if ((ma_int64)x + dither <= 0x7FFFFFFF) { x = x + dither; } else { x = 0x7FFFFFFF; } x = x >> 24; x = x + 128; dst_u8[i] = (ma_uint8)x; } } } void ma_pcm_s32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s32_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s32_to_u8__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_u8__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode); #else ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_int16* dst_s16 = (ma_int16*)dst; const ma_int32* src_s32 = (const ma_int32*)src; if (ditherMode == ma_dither_mode_none) { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int32 x = src_s32[i]; x = x >> 16; dst_s16[i] = (ma_int16)x; } } else { ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int32 x = src_s32[i]; /* Dither. Don't overflow. */ ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF); if ((ma_int64)x + dither <= 0x7FFFFFFF) { x = x + dither; } else { x = 0x7FFFFFFF; } x = x >> 16; dst_s16[i] = (ma_int16)x; } } } void ma_pcm_s32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s32_to_s16__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s16__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode); #else ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint8* dst_s24 = (ma_uint8*)dst; const ma_int32* src_s32 = (const ma_int32*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { ma_uint32 x = (ma_uint32)src_s32[i]; dst_s24[i*3+0] = (ma_uint8)((x & 0x0000FF00) >> 8); dst_s24[i*3+1] = (ma_uint8)((x & 0x00FF0000) >> 16); dst_s24[i*3+2] = (ma_uint8)((x & 0xFF000000) >> 24); } (void)ditherMode; /* No dithering for s32 -> s24. */ } void ma_pcm_s32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s32_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s32_to_s24__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s24__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode); #else ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_s32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { (void)ditherMode; ma_copy_memory_64(dst, src, count * sizeof(ma_int32)); } void ma_pcm_s32_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { float* dst_f32 = (float*)dst; const ma_int32* src_s32 = (const ma_int32*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { double x = src_s32[i]; #if 0 x = x + 2147483648.0; x = x * 0.0000000004656612873077392578125; x = x - 1; #else x = x / 2147483648.0; #endif dst_f32[i] = (float)x; } (void)ditherMode; /* No dithering for s32 -> f32. */ } void ma_pcm_s32_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_s32_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_s32_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_s32_to_f32__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_f32__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_s32_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_s32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode); #else ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_interleave_s32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_int32* dst_s32 = (ma_int32*)dst; const ma_int32** src_s32 = (const ma_int32**)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_s32[iFrame*channels + iChannel] = src_s32[iChannel][iFrame]; } } } void ma_pcm_interleave_s32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_interleave_s32__reference(dst, src, frameCount, channels); } void ma_pcm_interleave_s32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_interleave_s32__reference(dst, src, frameCount, channels); #else ma_pcm_interleave_s32__optimized(dst, src, frameCount, channels); #endif } void ma_pcm_deinterleave_s32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_int32** dst_s32 = (ma_int32**)dst; const ma_int32* src_s32 = (const ma_int32*)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_s32[iChannel][iFrame] = src_s32[iFrame*channels + iChannel]; } } } void ma_pcm_deinterleave_s32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels); } void ma_pcm_deinterleave_s32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels); #else ma_pcm_deinterleave_s32__optimized(dst, src, frameCount, channels); #endif } /* f32 */ void ma_pcm_f32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint64 i; ma_uint8* dst_u8 = (ma_uint8*)dst; const float* src_f32 = (const float*)src; float ditherMin = 0; float ditherMax = 0; if (ditherMode != ma_dither_mode_none) { ditherMin = 1.0f / -128; ditherMax = 1.0f / 127; } for (i = 0; i < count; i += 1) { float x = src_f32[i]; x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax); x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ x = x + 1; /* -1..1 to 0..2 */ x = x * 127.5f; /* 0..2 to 0..255 */ dst_u8[i] = (ma_uint8)x; } } void ma_pcm_f32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_f32_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_f32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_f32_to_u8__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_u8__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_f32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_f32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode); #else ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_f32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint64 i; ma_int16* dst_s16 = (ma_int16*)dst; const float* src_f32 = (const float*)src; float ditherMin = 0; float ditherMax = 0; if (ditherMode != ma_dither_mode_none) { ditherMin = 1.0f / -32768; ditherMax = 1.0f / 32767; } for (i = 0; i < count; i += 1) { float x = src_f32[i]; x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax); x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ #if 0 /* The accurate way. */ x = x + 1; /* -1..1 to 0..2 */ x = x * 32767.5f; /* 0..2 to 0..65535 */ x = x - 32768.0f; /* 0...65535 to -32768..32767 */ #else /* The fast way. */ x = x * 32767.0f; /* -1..1 to -32767..32767 */ #endif dst_s16[i] = (ma_int16)x; } } void ma_pcm_f32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint64 i; ma_uint64 i4; ma_uint64 count4; ma_int16* dst_s16 = (ma_int16*)dst; const float* src_f32 = (const float*)src; float ditherMin = 0; float ditherMax = 0; if (ditherMode != ma_dither_mode_none) { ditherMin = 1.0f / -32768; ditherMax = 1.0f / 32767; } /* Unrolled. */ i = 0; count4 = count >> 2; for (i4 = 0; i4 < count4; i4 += 1) { float d0 = ma_dither_f32(ditherMode, ditherMin, ditherMax); float d1 = ma_dither_f32(ditherMode, ditherMin, ditherMax); float d2 = ma_dither_f32(ditherMode, ditherMin, ditherMax); float d3 = ma_dither_f32(ditherMode, ditherMin, ditherMax); float x0 = src_f32[i+0]; float x1 = src_f32[i+1]; float x2 = src_f32[i+2]; float x3 = src_f32[i+3]; x0 = x0 + d0; x1 = x1 + d1; x2 = x2 + d2; x3 = x3 + d3; x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0)); x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1)); x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2)); x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3)); x0 = x0 * 32767.0f; x1 = x1 * 32767.0f; x2 = x2 * 32767.0f; x3 = x3 * 32767.0f; dst_s16[i+0] = (ma_int16)x0; dst_s16[i+1] = (ma_int16)x1; dst_s16[i+2] = (ma_int16)x2; dst_s16[i+3] = (ma_int16)x3; i += 4; } /* Leftover. */ for (; i < count; i += 1) { float x = src_f32[i]; x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax); x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ x = x * 32767.0f; /* -1..1 to -32767..32767 */ dst_s16[i] = (ma_int16)x; } } #if defined(MA_SUPPORT_SSE2) void ma_pcm_f32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint64 i; ma_uint64 i8; ma_uint64 count8; ma_int16* dst_s16; const float* src_f32; float ditherMin; float ditherMax; /* Both the input and output buffers need to be aligned to 16 bytes. */ if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 0)) { ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); return; } dst_s16 = (ma_int16*)dst; src_f32 = (const float*)src; ditherMin = 0; ditherMax = 0; if (ditherMode != ma_dither_mode_none) { ditherMin = 1.0f / -32768; ditherMax = 1.0f / 32767; } i = 0; /* SSE2. SSE allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */ count8 = count >> 3; for (i8 = 0; i8 < count8; i8 += 1) { __m128 d0; __m128 d1; __m128 x0; __m128 x1; if (ditherMode == ma_dither_mode_none) { d0 = _mm_set1_ps(0); d1 = _mm_set1_ps(0); } else if (ditherMode == ma_dither_mode_rectangle) { d0 = _mm_set_ps( ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax) ); d1 = _mm_set_ps( ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax) ); } else { d0 = _mm_set_ps( ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax) ); d1 = _mm_set_ps( ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax) ); } x0 = *((__m128*)(src_f32 + i) + 0); x1 = *((__m128*)(src_f32 + i) + 1); x0 = _mm_add_ps(x0, d0); x1 = _mm_add_ps(x1, d1); x0 = _mm_mul_ps(x0, _mm_set1_ps(32767.0f)); x1 = _mm_mul_ps(x1, _mm_set1_ps(32767.0f)); _mm_stream_si128(((__m128i*)(dst_s16 + i)), _mm_packs_epi32(_mm_cvttps_epi32(x0), _mm_cvttps_epi32(x1))); i += 8; } /* Leftover. */ for (; i < count; i += 1) { float x = src_f32[i]; x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax); x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ x = x * 32767.0f; /* -1..1 to -32767..32767 */ dst_s16[i] = (ma_int16)x; } } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_f32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint64 i; ma_uint64 i16; ma_uint64 count16; ma_int16* dst_s16; const float* src_f32; float ditherMin; float ditherMax; /* Both the input and output buffers need to be aligned to 32 bytes. */ if ((((ma_uintptr)dst & 31) != 0) || (((ma_uintptr)src & 31) != 0)) { ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); return; } dst_s16 = (ma_int16*)dst; src_f32 = (const float*)src; ditherMin = 0; ditherMax = 0; if (ditherMode != ma_dither_mode_none) { ditherMin = 1.0f / -32768; ditherMax = 1.0f / 32767; } i = 0; /* AVX2. AVX2 allows us to output 16 s16's at a time which means our loop is unrolled 16 times. */ count16 = count >> 4; for (i16 = 0; i16 < count16; i16 += 1) { __m256 d0; __m256 d1; __m256 x0; __m256 x1; __m256i i0; __m256i i1; __m256i p0; __m256i p1; __m256i r; if (ditherMode == ma_dither_mode_none) { d0 = _mm256_set1_ps(0); d1 = _mm256_set1_ps(0); } else if (ditherMode == ma_dither_mode_rectangle) { d0 = _mm256_set_ps( ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax) ); d1 = _mm256_set_ps( ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax), ma_dither_f32_rectangle(ditherMin, ditherMax) ); } else { d0 = _mm256_set_ps( ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax) ); d1 = _mm256_set_ps( ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax), ma_dither_f32_triangle(ditherMin, ditherMax) ); } x0 = *((__m256*)(src_f32 + i) + 0); x1 = *((__m256*)(src_f32 + i) + 1); x0 = _mm256_add_ps(x0, d0); x1 = _mm256_add_ps(x1, d1); x0 = _mm256_mul_ps(x0, _mm256_set1_ps(32767.0f)); x1 = _mm256_mul_ps(x1, _mm256_set1_ps(32767.0f)); /* Computing the final result is a little more complicated for AVX2 than SSE2. */ i0 = _mm256_cvttps_epi32(x0); i1 = _mm256_cvttps_epi32(x1); p0 = _mm256_permute2x128_si256(i0, i1, 0 | 32); p1 = _mm256_permute2x128_si256(i0, i1, 1 | 48); r = _mm256_packs_epi32(p0, p1); _mm256_stream_si256(((__m256i*)(dst_s16 + i)), r); i += 16; } /* Leftover. */ for (; i < count; i += 1) { float x = src_f32[i]; x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax); x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ x = x * 32767.0f; /* -1..1 to -32767..32767 */ dst_s16[i] = (ma_int16)x; } } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_f32_to_s16__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { /* TODO: Convert this from AVX to AVX-512. */ ma_pcm_f32_to_s16__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint64 i; ma_uint64 i8; ma_uint64 count8; ma_int16* dst_s16; const float* src_f32; float ditherMin; float ditherMax; /* Both the input and output buffers need to be aligned to 16 bytes. */ if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 0)) { ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); return; } dst_s16 = (ma_int16*)dst; src_f32 = (const float*)src; ditherMin = 0; ditherMax = 0; if (ditherMode != ma_dither_mode_none) { ditherMin = 1.0f / -32768; ditherMax = 1.0f / 32767; } i = 0; /* NEON. NEON allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */ count8 = count >> 3; for (i8 = 0; i8 < count8; i8 += 1) { float32x4_t d0; float32x4_t d1; float32x4_t x0; float32x4_t x1; int32x4_t i0; int32x4_t i1; if (ditherMode == ma_dither_mode_none) { d0 = vmovq_n_f32(0); d1 = vmovq_n_f32(0); } else if (ditherMode == ma_dither_mode_rectangle) { float d0v[4]; d0v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax); d0v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax); d0v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax); d0v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax); d0 = vld1q_f32(d0v); float d1v[4]; d1v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax); d1v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax); d1v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax); d1v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax); d1 = vld1q_f32(d1v); } else { float d0v[4]; d0v[0] = ma_dither_f32_triangle(ditherMin, ditherMax); d0v[1] = ma_dither_f32_triangle(ditherMin, ditherMax); d0v[2] = ma_dither_f32_triangle(ditherMin, ditherMax); d0v[3] = ma_dither_f32_triangle(ditherMin, ditherMax); d0 = vld1q_f32(d0v); float d1v[4]; d1v[0] = ma_dither_f32_triangle(ditherMin, ditherMax); d1v[1] = ma_dither_f32_triangle(ditherMin, ditherMax); d1v[2] = ma_dither_f32_triangle(ditherMin, ditherMax); d1v[3] = ma_dither_f32_triangle(ditherMin, ditherMax); d1 = vld1q_f32(d1v); } x0 = *((float32x4_t*)(src_f32 + i) + 0); x1 = *((float32x4_t*)(src_f32 + i) + 1); x0 = vaddq_f32(x0, d0); x1 = vaddq_f32(x1, d1); x0 = vmulq_n_f32(x0, 32767.0f); x1 = vmulq_n_f32(x1, 32767.0f); i0 = vcvtq_s32_f32(x0); i1 = vcvtq_s32_f32(x1); *((int16x8_t*)(dst_s16 + i)) = vcombine_s16(vqmovn_s32(i0), vqmovn_s32(i1)); i += 8; } /* Leftover. */ for (; i < count; i += 1) { float x = src_f32[i]; x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax); x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ x = x * 32767.0f; /* -1..1 to -32767..32767 */ dst_s16[i] = (ma_int16)x; } } #endif void ma_pcm_f32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s16__reference(dst, src, count, ditherMode); #else ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_f32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_uint8* dst_s24 = (ma_uint8*)dst; const float* src_f32 = (const float*)src; ma_uint64 i; for (i = 0; i < count; i += 1) { ma_int32 r; float x = src_f32[i]; x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ #if 0 /* The accurate way. */ x = x + 1; /* -1..1 to 0..2 */ x = x * 8388607.5f; /* 0..2 to 0..16777215 */ x = x - 8388608.0f; /* 0..16777215 to -8388608..8388607 */ #else /* The fast way. */ x = x * 8388607.0f; /* -1..1 to -8388607..8388607 */ #endif r = (ma_int32)x; dst_s24[(i*3)+0] = (ma_uint8)((r & 0x0000FF) >> 0); dst_s24[(i*3)+1] = (ma_uint8)((r & 0x00FF00) >> 8); dst_s24[(i*3)+2] = (ma_uint8)((r & 0xFF0000) >> 16); } (void)ditherMode; /* No dithering for f32 -> s24. */ } void ma_pcm_f32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_f32_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_f32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_f32_to_s24__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s24__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_f32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_f32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode); #else ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_f32_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_int32* dst_s32 = (ma_int32*)dst; const float* src_f32 = (const float*)src; ma_uint32 i; for (i = 0; i < count; i += 1) { double x = src_f32[i]; x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ #if 0 /* The accurate way. */ x = x + 1; /* -1..1 to 0..2 */ x = x * 2147483647.5; /* 0..2 to 0..4294967295 */ x = x - 2147483648.0; /* 0...4294967295 to -2147483648..2147483647 */ #else /* The fast way. */ x = x * 2147483647.0; /* -1..1 to -2147483647..2147483647 */ #endif dst_s32[i] = (ma_int32)x; } (void)ditherMode; /* No dithering for f32 -> s32. */ } void ma_pcm_f32_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode); } #if defined(MA_SUPPORT_SSE2) void ma_pcm_f32_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX2) void ma_pcm_f32_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_AVX512) void ma_pcm_f32_to_s32__avx512(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s32__avx2(dst, src, count, ditherMode); } #endif #if defined(MA_SUPPORT_NEON) void ma_pcm_f32_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); } #endif void ma_pcm_f32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode); #else ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); #endif } void ma_pcm_f32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { (void)ditherMode; ma_copy_memory_64(dst, src, count * sizeof(float)); } void ma_pcm_interleave_f32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { float* dst_f32 = (float*)dst; const float** src_f32 = (const float**)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_f32[iFrame*channels + iChannel] = src_f32[iChannel][iFrame]; } } } void ma_pcm_interleave_f32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_interleave_f32__reference(dst, src, frameCount, channels); } void ma_pcm_interleave_f32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_interleave_f32__reference(dst, src, frameCount, channels); #else ma_pcm_interleave_f32__optimized(dst, src, frameCount, channels); #endif } void ma_pcm_deinterleave_f32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { float** dst_f32 = (float**)dst; const float* src_f32 = (const float*)src; ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; iChannel += 1) { dst_f32[iChannel][iFrame] = src_f32[iFrame*channels + iChannel]; } } } void ma_pcm_deinterleave_f32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels); } void ma_pcm_deinterleave_f32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) { #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels); #else ma_pcm_deinterleave_f32__optimized(dst, src, frameCount, channels); #endif } void ma_format_converter_init_callbacks__default(ma_format_converter* pConverter) { ma_assert(pConverter != NULL); switch (pConverter->config.formatIn) { case ma_format_u8: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_u8_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_u8_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_u8_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_u8_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_u8_to_f32; } } break; case ma_format_s16: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s16_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s16_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s16_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s16_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s16_to_f32; } } break; case ma_format_s24: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s24_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s24_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s24_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s24_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s24_to_f32; } } break; case ma_format_s32: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s32_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s32_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s32_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s32_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s32_to_f32; } } break; case ma_format_f32: default: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_f32_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_f32_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_f32_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_f32_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_f32_to_f32; } } break; } } #if defined(MA_SUPPORT_SSE2) void ma_format_converter_init_callbacks__sse2(ma_format_converter* pConverter) { ma_assert(pConverter != NULL); switch (pConverter->config.formatIn) { case ma_format_u8: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_u8_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_u8_to_s16__sse2; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_u8_to_s24__sse2; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_u8_to_s32__sse2; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_u8_to_f32__sse2; } } break; case ma_format_s16: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s16_to_u8__sse2; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s16_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s16_to_s24__sse2; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s16_to_s32__sse2; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s16_to_f32__sse2; } } break; case ma_format_s24: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s24_to_u8__sse2; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s24_to_s16__sse2; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s24_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s24_to_s32__sse2; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s24_to_f32__sse2; } } break; case ma_format_s32: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s32_to_u8__sse2; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s32_to_s16__sse2; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s32_to_s24__sse2; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s32_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s32_to_f32__sse2; } } break; case ma_format_f32: default: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_f32_to_u8__sse2; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_f32_to_s16__sse2; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_f32_to_s24__sse2; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_f32_to_s32__sse2; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_f32_to_f32; } } break; } } #endif #if defined(MA_SUPPORT_AVX2) void ma_format_converter_init_callbacks__avx2(ma_format_converter* pConverter) { ma_assert(pConverter != NULL); switch (pConverter->config.formatIn) { case ma_format_u8: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_u8_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_u8_to_s16__avx2; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_u8_to_s24__avx2; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_u8_to_s32__avx2; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_u8_to_f32__avx2; } } break; case ma_format_s16: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s16_to_u8__avx2; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s16_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s16_to_s24__avx2; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s16_to_s32__avx2; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s16_to_f32__avx2; } } break; case ma_format_s24: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s24_to_u8__avx2; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s24_to_s16__avx2; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s24_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s24_to_s32__avx2; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s24_to_f32__avx2; } } break; case ma_format_s32: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s32_to_u8__avx2; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s32_to_s16__avx2; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s32_to_s24__avx2; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s32_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s32_to_f32__avx2; } } break; case ma_format_f32: default: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_f32_to_u8__avx2; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_f32_to_s16__avx2; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_f32_to_s24__avx2; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_f32_to_s32__avx2; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_f32_to_f32; } } break; } } #endif #if defined(MA_SUPPORT_AVX512) void ma_format_converter_init_callbacks__avx512(ma_format_converter* pConverter) { ma_assert(pConverter != NULL); switch (pConverter->config.formatIn) { case ma_format_u8: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_u8_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_u8_to_s16__avx512; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_u8_to_s24__avx512; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_u8_to_s32__avx512; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_u8_to_f32__avx512; } } break; case ma_format_s16: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s16_to_u8__avx512; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s16_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s16_to_s24__avx512; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s16_to_s32__avx512; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s16_to_f32__avx512; } } break; case ma_format_s24: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s24_to_u8__avx512; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s24_to_s16__avx512; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s24_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s24_to_s32__avx512; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s24_to_f32__avx512; } } break; case ma_format_s32: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s32_to_u8__avx512; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s32_to_s16__avx512; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s32_to_s24__avx512; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s32_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s32_to_f32__avx512; } } break; case ma_format_f32: default: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_f32_to_u8__avx512; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_f32_to_s16__avx512; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_f32_to_s24__avx512; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_f32_to_s32__avx512; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_f32_to_f32; } } break; } } #endif #if defined(MA_SUPPORT_NEON) void ma_format_converter_init_callbacks__neon(ma_format_converter* pConverter) { ma_assert(pConverter != NULL); switch (pConverter->config.formatIn) { case ma_format_u8: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_u8_to_u8; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_u8_to_s16__neon; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_u8_to_s24__neon; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_u8_to_s32__neon; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_u8_to_f32__neon; } } break; case ma_format_s16: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s16_to_u8__neon; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s16_to_s16; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s16_to_s24__neon; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s16_to_s32__neon; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s16_to_f32__neon; } } break; case ma_format_s24: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s24_to_u8__neon; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s24_to_s16__neon; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s24_to_s24; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s24_to_s32__neon; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s24_to_f32__neon; } } break; case ma_format_s32: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_s32_to_u8__neon; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_s32_to_s16__neon; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_s32_to_s24__neon; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_s32_to_s32; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_s32_to_f32__neon; } } break; case ma_format_f32: default: { if (pConverter->config.formatOut == ma_format_u8) { pConverter->onConvertPCM = ma_pcm_f32_to_u8__neon; } else if (pConverter->config.formatOut == ma_format_s16) { pConverter->onConvertPCM = ma_pcm_f32_to_s16__neon; } else if (pConverter->config.formatOut == ma_format_s24) { pConverter->onConvertPCM = ma_pcm_f32_to_s24__neon; } else if (pConverter->config.formatOut == ma_format_s32) { pConverter->onConvertPCM = ma_pcm_f32_to_s32__neon; } else if (pConverter->config.formatOut == ma_format_f32) { pConverter->onConvertPCM = ma_pcm_f32_to_f32; } } break; } } #endif ma_result ma_format_converter_init(const ma_format_converter_config* pConfig, ma_format_converter* pConverter) { if (pConverter == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pConverter); if (pConfig == NULL) { return MA_INVALID_ARGS; } pConverter->config = *pConfig; /* SIMD */ pConverter->useSSE2 = ma_has_sse2() && !pConfig->noSSE2; pConverter->useAVX2 = ma_has_avx2() && !pConfig->noAVX2; pConverter->useAVX512 = ma_has_avx512f() && !pConfig->noAVX512; pConverter->useNEON = ma_has_neon() && !pConfig->noNEON; #if defined(MA_SUPPORT_AVX512) if (pConverter->useAVX512) { ma_format_converter_init_callbacks__avx512(pConverter); } else #endif #if defined(MA_SUPPORT_AVX2) if (pConverter->useAVX2) { ma_format_converter_init_callbacks__avx2(pConverter); } else #endif #if defined(MA_SUPPORT_SSE2) if (pConverter->useSSE2) { ma_format_converter_init_callbacks__sse2(pConverter); } else #endif #if defined(MA_SUPPORT_NEON) if (pConverter->useNEON) { ma_format_converter_init_callbacks__neon(pConverter); } else #endif { ma_format_converter_init_callbacks__default(pConverter); } switch (pConfig->formatOut) { case ma_format_u8: { pConverter->onInterleavePCM = ma_pcm_interleave_u8; pConverter->onDeinterleavePCM = ma_pcm_deinterleave_u8; } break; case ma_format_s16: { pConverter->onInterleavePCM = ma_pcm_interleave_s16; pConverter->onDeinterleavePCM = ma_pcm_deinterleave_s16; } break; case ma_format_s24: { pConverter->onInterleavePCM = ma_pcm_interleave_s24; pConverter->onDeinterleavePCM = ma_pcm_deinterleave_s24; } break; case ma_format_s32: { pConverter->onInterleavePCM = ma_pcm_interleave_s32; pConverter->onDeinterleavePCM = ma_pcm_deinterleave_s32; } break; case ma_format_f32: default: { pConverter->onInterleavePCM = ma_pcm_interleave_f32; pConverter->onDeinterleavePCM = ma_pcm_deinterleave_f32; } break; } return MA_SUCCESS; } ma_uint64 ma_format_converter_read(ma_format_converter* pConverter, ma_uint64 frameCount, void* pFramesOut, void* pUserData) { ma_uint64 totalFramesRead; ma_uint32 sampleSizeIn; ma_uint32 sampleSizeOut; ma_uint32 frameSizeOut; ma_uint8* pNextFramesOut; if (pConverter == NULL || pFramesOut == NULL) { return 0; } totalFramesRead = 0; sampleSizeIn = ma_get_bytes_per_sample(pConverter->config.formatIn); sampleSizeOut = ma_get_bytes_per_sample(pConverter->config.formatOut); /*frameSizeIn = sampleSizeIn * pConverter->config.channels;*/ frameSizeOut = sampleSizeOut * pConverter->config.channels; pNextFramesOut = (ma_uint8*)pFramesOut; if (pConverter->config.onRead != NULL) { /* Input data is interleaved. */ if (pConverter->config.formatIn == pConverter->config.formatOut) { /* Pass through. */ while (totalFramesRead < frameCount) { ma_uint32 framesJustRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > 0xFFFFFFFF) { framesToReadRightNow = 0xFFFFFFFF; } framesJustRead = (ma_uint32)pConverter->config.onRead(pConverter, (ma_uint32)framesToReadRightNow, pNextFramesOut, pUserData); if (framesJustRead == 0) { break; } totalFramesRead += framesJustRead; pNextFramesOut += framesJustRead * frameSizeOut; if (framesJustRead < framesToReadRightNow) { break; } } } else { /* Conversion required. */ ma_uint32 maxFramesToReadAtATime; MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 temp[MA_MAX_CHANNELS * MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128]; ma_assert(sizeof(temp) <= 0xFFFFFFFF); maxFramesToReadAtATime = sizeof(temp) / sampleSizeIn / pConverter->config.channels; while (totalFramesRead < frameCount) { ma_uint32 framesJustRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > maxFramesToReadAtATime) { framesToReadRightNow = maxFramesToReadAtATime; } framesJustRead = (ma_uint32)pConverter->config.onRead(pConverter, (ma_uint32)framesToReadRightNow, temp, pUserData); if (framesJustRead == 0) { break; } pConverter->onConvertPCM(pNextFramesOut, temp, framesJustRead*pConverter->config.channels, pConverter->config.ditherMode); totalFramesRead += framesJustRead; pNextFramesOut += framesJustRead * frameSizeOut; if (framesJustRead < framesToReadRightNow) { break; } } } } else { /* Input data is deinterleaved. If a conversion is required we need to do an intermediary step. */ void* ppTempSamplesOfOutFormat[MA_MAX_CHANNELS]; size_t splitBufferSizeOut; ma_uint32 maxFramesToReadAtATime; MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 tempSamplesOfOutFormat[MA_MAX_CHANNELS * MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128]; ma_assert(sizeof(tempSamplesOfOutFormat) <= 0xFFFFFFFF); ma_split_buffer(tempSamplesOfOutFormat, sizeof(tempSamplesOfOutFormat), pConverter->config.channels, MA_SIMD_ALIGNMENT, (void**)&ppTempSamplesOfOutFormat, &splitBufferSizeOut); maxFramesToReadAtATime = (ma_uint32)(splitBufferSizeOut / sampleSizeIn); while (totalFramesRead < frameCount) { ma_uint32 framesJustRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > maxFramesToReadAtATime) { framesToReadRightNow = maxFramesToReadAtATime; } if (pConverter->config.formatIn == pConverter->config.formatOut) { /* Only interleaving. */ framesJustRead = (ma_uint32)pConverter->config.onReadDeinterleaved(pConverter, (ma_uint32)framesToReadRightNow, ppTempSamplesOfOutFormat, pUserData); if (framesJustRead == 0) { break; } } else { /* Interleaving + Conversion. Convert first, then interleave. */ void* ppTempSamplesOfInFormat[MA_MAX_CHANNELS]; size_t splitBufferSizeIn; ma_uint32 iChannel; MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 tempSamplesOfInFormat[MA_MAX_CHANNELS * MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128]; ma_split_buffer(tempSamplesOfInFormat, sizeof(tempSamplesOfInFormat), pConverter->config.channels, MA_SIMD_ALIGNMENT, (void**)&ppTempSamplesOfInFormat, &splitBufferSizeIn); if (framesToReadRightNow > (splitBufferSizeIn / sampleSizeIn)) { framesToReadRightNow = (splitBufferSizeIn / sampleSizeIn); } framesJustRead = (ma_uint32)pConverter->config.onReadDeinterleaved(pConverter, (ma_uint32)framesToReadRightNow, ppTempSamplesOfInFormat, pUserData); if (framesJustRead == 0) { break; } for (iChannel = 0; iChannel < pConverter->config.channels; iChannel += 1) { pConverter->onConvertPCM(ppTempSamplesOfOutFormat[iChannel], ppTempSamplesOfInFormat[iChannel], framesJustRead, pConverter->config.ditherMode); } } pConverter->onInterleavePCM(pNextFramesOut, (const void**)ppTempSamplesOfOutFormat, framesJustRead, pConverter->config.channels); totalFramesRead += framesJustRead; pNextFramesOut += framesJustRead * frameSizeOut; if (framesJustRead < framesToReadRightNow) { break; } } } return totalFramesRead; } ma_uint64 ma_format_converter_read_deinterleaved(ma_format_converter* pConverter, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData) { ma_uint64 totalFramesRead; ma_uint32 sampleSizeIn; ma_uint32 sampleSizeOut; ma_uint8* ppNextSamplesOut[MA_MAX_CHANNELS]; if (pConverter == NULL || ppSamplesOut == NULL) { return 0; } totalFramesRead = 0; sampleSizeIn = ma_get_bytes_per_sample(pConverter->config.formatIn); sampleSizeOut = ma_get_bytes_per_sample(pConverter->config.formatOut); ma_copy_memory(ppNextSamplesOut, ppSamplesOut, sizeof(void*) * pConverter->config.channels); if (pConverter->config.onRead != NULL) { /* Input data is interleaved. */ ma_uint32 maxFramesToReadAtATime; MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 tempSamplesOfOutFormat[MA_MAX_CHANNELS * MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128]; ma_assert(sizeof(tempSamplesOfOutFormat) <= 0xFFFFFFFF); maxFramesToReadAtATime = sizeof(tempSamplesOfOutFormat) / sampleSizeIn / pConverter->config.channels; while (totalFramesRead < frameCount) { ma_uint32 iChannel; ma_uint32 framesJustRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > maxFramesToReadAtATime) { framesToReadRightNow = maxFramesToReadAtATime; } if (pConverter->config.formatIn == pConverter->config.formatOut) { /* Only de-interleaving. */ framesJustRead = (ma_uint32)pConverter->config.onRead(pConverter, (ma_uint32)framesToReadRightNow, tempSamplesOfOutFormat, pUserData); if (framesJustRead == 0) { break; } } else { /* De-interleaving + Conversion. Convert first, then de-interleave. */ MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 tempSamplesOfInFormat[sizeof(tempSamplesOfOutFormat)]; framesJustRead = (ma_uint32)pConverter->config.onRead(pConverter, (ma_uint32)framesToReadRightNow, tempSamplesOfInFormat, pUserData); if (framesJustRead == 0) { break; } pConverter->onConvertPCM(tempSamplesOfOutFormat, tempSamplesOfInFormat, framesJustRead * pConverter->config.channels, pConverter->config.ditherMode); } pConverter->onDeinterleavePCM((void**)ppNextSamplesOut, tempSamplesOfOutFormat, framesJustRead, pConverter->config.channels); totalFramesRead += framesJustRead; for (iChannel = 0; iChannel < pConverter->config.channels; ++iChannel) { ppNextSamplesOut[iChannel] += framesJustRead * sampleSizeOut; } if (framesJustRead < framesToReadRightNow) { break; } } } else { /* Input data is deinterleaved. */ if (pConverter->config.formatIn == pConverter->config.formatOut) { /* Pass through. */ while (totalFramesRead < frameCount) { ma_uint32 iChannel; ma_uint32 framesJustRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > 0xFFFFFFFF) { framesToReadRightNow = 0xFFFFFFFF; } framesJustRead = (ma_uint32)pConverter->config.onReadDeinterleaved(pConverter, (ma_uint32)framesToReadRightNow, (void**)ppNextSamplesOut, pUserData); if (framesJustRead == 0) { break; } totalFramesRead += framesJustRead; for (iChannel = 0; iChannel < pConverter->config.channels; ++iChannel) { ppNextSamplesOut[iChannel] += framesJustRead * sampleSizeOut; } if (framesJustRead < framesToReadRightNow) { break; } } } else { /* Conversion required. */ void* ppTemp[MA_MAX_CHANNELS]; size_t splitBufferSize; ma_uint32 maxFramesToReadAtATime; MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 temp[MA_MAX_CHANNELS][MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128]; ma_assert(sizeof(temp) <= 0xFFFFFFFF); ma_split_buffer(temp, sizeof(temp), pConverter->config.channels, MA_SIMD_ALIGNMENT, (void**)&ppTemp, &splitBufferSize); maxFramesToReadAtATime = (ma_uint32)(splitBufferSize / sampleSizeIn); while (totalFramesRead < frameCount) { ma_uint32 iChannel; ma_uint32 framesJustRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > maxFramesToReadAtATime) { framesToReadRightNow = maxFramesToReadAtATime; } framesJustRead = (ma_uint32)pConverter->config.onReadDeinterleaved(pConverter, (ma_uint32)framesToReadRightNow, ppTemp, pUserData); if (framesJustRead == 0) { break; } for (iChannel = 0; iChannel < pConverter->config.channels; iChannel += 1) { pConverter->onConvertPCM(ppNextSamplesOut[iChannel], ppTemp[iChannel], framesJustRead, pConverter->config.ditherMode); ppNextSamplesOut[iChannel] += framesJustRead * sampleSizeOut; } totalFramesRead += framesJustRead; if (framesJustRead < framesToReadRightNow) { break; } } } } return totalFramesRead; } ma_format_converter_config ma_format_converter_config_init_new() { ma_format_converter_config config; ma_zero_object(&config); return config; } ma_format_converter_config ma_format_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channels, ma_format_converter_read_proc onRead, void* pUserData) { ma_format_converter_config config = ma_format_converter_config_init_new(); config.formatIn = formatIn; config.formatOut = formatOut; config.channels = channels; config.onRead = onRead; config.onReadDeinterleaved = NULL; config.pUserData = pUserData; return config; } ma_format_converter_config ma_format_converter_config_init_deinterleaved(ma_format formatIn, ma_format formatOut, ma_uint32 channels, ma_format_converter_read_deinterleaved_proc onReadDeinterleaved, void* pUserData) { ma_format_converter_config config = ma_format_converter_config_init(formatIn, formatOut, channels, NULL, pUserData); config.onReadDeinterleaved = onReadDeinterleaved; return config; } /************************************************************************************************************************************************************** Channel Routing **************************************************************************************************************************************************************/ /* -X = Left, +X = Right -Y = Bottom, +Y = Top -Z = Front, +Z = Back */ typedef struct { float x; float y; float z; } ma_vec3; static MA_INLINE ma_vec3 ma_vec3f(float x, float y, float z) { ma_vec3 r; r.x = x; r.y = y; r.z = z; return r; } static MA_INLINE ma_vec3 ma_vec3_add(ma_vec3 a, ma_vec3 b) { return ma_vec3f( a.x + b.x, a.y + b.y, a.z + b.z ); } static MA_INLINE ma_vec3 ma_vec3_sub(ma_vec3 a, ma_vec3 b) { return ma_vec3f( a.x - b.x, a.y - b.y, a.z - b.z ); } static MA_INLINE ma_vec3 ma_vec3_mul(ma_vec3 a, ma_vec3 b) { return ma_vec3f( a.x * b.x, a.y * b.y, a.z * b.z ); } static MA_INLINE ma_vec3 ma_vec3_div(ma_vec3 a, ma_vec3 b) { return ma_vec3f( a.x / b.x, a.y / b.y, a.z / b.z ); } static MA_INLINE float ma_vec3_dot(ma_vec3 a, ma_vec3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; } static MA_INLINE float ma_vec3_length2(ma_vec3 a) { return ma_vec3_dot(a, a); } static MA_INLINE float ma_vec3_length(ma_vec3 a) { return (float)sqrt(ma_vec3_length2(a)); } static MA_INLINE ma_vec3 ma_vec3_normalize(ma_vec3 a) { float len = 1 / ma_vec3_length(a); ma_vec3 r; r.x = a.x * len; r.y = a.y * len; r.z = a.z * len; return r; } static MA_INLINE float ma_vec3_distance(ma_vec3 a, ma_vec3 b) { return ma_vec3_length(ma_vec3_sub(a, b)); } #define MA_PLANE_LEFT 0 #define MA_PLANE_RIGHT 1 #define MA_PLANE_FRONT 2 #define MA_PLANE_BACK 3 #define MA_PLANE_BOTTOM 4 #define MA_PLANE_TOP 5 float g_maChannelPlaneRatios[MA_CHANNEL_POSITION_COUNT][6] = { { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_NONE */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_MONO */ { 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_LEFT */ { 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_RIGHT */ { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_CENTER */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_LFE */ { 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_LEFT */ { 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_RIGHT */ { 0.25f, 0.0f, 0.75f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_LEFT_CENTER */ { 0.0f, 0.25f, 0.75f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_RIGHT_CENTER */ { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_CENTER */ { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_SIDE_LEFT */ { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_SIDE_RIGHT */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, /* MA_CHANNEL_TOP_CENTER */ { 0.33f, 0.0f, 0.33f, 0.0f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_FRONT_LEFT */ { 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f}, /* MA_CHANNEL_TOP_FRONT_CENTER */ { 0.0f, 0.33f, 0.33f, 0.0f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_FRONT_RIGHT */ { 0.33f, 0.0f, 0.0f, 0.33f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_BACK_LEFT */ { 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f}, /* MA_CHANNEL_TOP_BACK_CENTER */ { 0.0f, 0.33f, 0.0f, 0.33f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_BACK_RIGHT */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_0 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_1 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_2 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_3 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_4 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_5 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_6 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_7 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_8 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_9 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_10 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_11 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_12 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_13 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_14 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_15 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_16 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_17 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_18 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_19 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_20 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_21 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_22 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_23 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_24 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_25 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_26 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_27 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_28 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_29 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_30 */ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_31 */ }; float ma_calculate_channel_position_planar_weight(ma_channel channelPositionA, ma_channel channelPositionB) { /* Imagine the following simplified example: You have a single input speaker which is the front/left speaker which you want to convert to the following output configuration: - front/left - side/left - back/left The front/left output is easy - it the same speaker position so it receives the full contribution of the front/left input. The amount of contribution to apply to the side/left and back/left speakers, however, is a bit more complicated. Imagine the front/left speaker as emitting audio from two planes - the front plane and the left plane. You can think of the front/left speaker emitting half of it's total volume from the front, and the other half from the left. Since part of it's volume is being emitted from the left side, and the side/left and back/left channels also emit audio from the left plane, one would expect that they would receive some amount of contribution from front/left speaker. The amount of contribution depends on how many planes are shared between the two speakers. Note that in the examples below I've added a top/front/left speaker as an example just to show how the math works across 3 spatial dimensions. The first thing to do is figure out how each speaker's volume is spread over each of plane: - front/left: 2 planes (front and left) = 1/2 = half it's total volume on each plane - side/left: 1 plane (left only) = 1/1 = entire volume from left plane - back/left: 2 planes (back and left) = 1/2 = half it's total volume on each plane - top/front/left: 3 planes (top, front and left) = 1/3 = one third it's total volume on each plane The amount of volume each channel contributes to each of it's planes is what controls how much it is willing to given and take to other channels on the same plane. The volume that is willing to the given by one channel is multiplied by the volume that is willing to be taken by the other to produce the final contribution. */ /* Contribution = Sum(Volume to Give * Volume to Take) */ float contribution = g_maChannelPlaneRatios[channelPositionA][0] * g_maChannelPlaneRatios[channelPositionB][0] + g_maChannelPlaneRatios[channelPositionA][1] * g_maChannelPlaneRatios[channelPositionB][1] + g_maChannelPlaneRatios[channelPositionA][2] * g_maChannelPlaneRatios[channelPositionB][2] + g_maChannelPlaneRatios[channelPositionA][3] * g_maChannelPlaneRatios[channelPositionB][3] + g_maChannelPlaneRatios[channelPositionA][4] * g_maChannelPlaneRatios[channelPositionB][4] + g_maChannelPlaneRatios[channelPositionA][5] * g_maChannelPlaneRatios[channelPositionB][5]; return contribution; } float ma_channel_router__calculate_input_channel_planar_weight(const ma_channel_router* pRouter, ma_channel channelPositionIn, ma_channel channelPositionOut) { ma_assert(pRouter != NULL); (void)pRouter; return ma_calculate_channel_position_planar_weight(channelPositionIn, channelPositionOut); } ma_bool32 ma_channel_router__is_spatial_channel_position(const ma_channel_router* pRouter, ma_channel channelPosition) { int i; ma_assert(pRouter != NULL); (void)pRouter; if (channelPosition == MA_CHANNEL_NONE || channelPosition == MA_CHANNEL_MONO || channelPosition == MA_CHANNEL_LFE) { return MA_FALSE; } for (i = 0; i < 6; ++i) { if (g_maChannelPlaneRatios[channelPosition][i] != 0) { return MA_TRUE; } } return MA_FALSE; } ma_result ma_channel_router_init(const ma_channel_router_config* pConfig, ma_channel_router* pRouter) { ma_uint32 iChannelIn; ma_uint32 iChannelOut; if (pRouter == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pRouter); if (pConfig == NULL) { return MA_INVALID_ARGS; } if (pConfig->onReadDeinterleaved == NULL) { return MA_INVALID_ARGS; } if (!ma_channel_map_valid(pConfig->channelsIn, pConfig->channelMapIn)) { return MA_INVALID_ARGS; /* Invalid input channel map. */ } if (!ma_channel_map_valid(pConfig->channelsOut, pConfig->channelMapOut)) { return MA_INVALID_ARGS; /* Invalid output channel map. */ } pRouter->config = *pConfig; /* SIMD */ pRouter->useSSE2 = ma_has_sse2() && !pConfig->noSSE2; pRouter->useAVX2 = ma_has_avx2() && !pConfig->noAVX2; pRouter->useAVX512 = ma_has_avx512f() && !pConfig->noAVX512; pRouter->useNEON = ma_has_neon() && !pConfig->noNEON; /* If the input and output channels and channel maps are the same we should use a passthrough. */ if (pRouter->config.channelsIn == pRouter->config.channelsOut) { if (ma_channel_map_equal(pRouter->config.channelsIn, pRouter->config.channelMapIn, pRouter->config.channelMapOut)) { pRouter->isPassthrough = MA_TRUE; } if (ma_channel_map_blank(pRouter->config.channelsIn, pRouter->config.channelMapIn) || ma_channel_map_blank(pRouter->config.channelsOut, pRouter->config.channelMapOut)) { pRouter->isPassthrough = MA_TRUE; } } /* Here is where we do a bit of pre-processing to know how each channel should be combined to make up the output. Rules: 1) If it's a passthrough, do nothing - it's just a simple memcpy(). 2) If the channel counts are the same and every channel position in the input map is present in the output map, use a simple shuffle. An example might be different 5.1 channel layouts. 3) Otherwise channels are blended based on spatial locality. */ if (!pRouter->isPassthrough) { if (pRouter->config.channelsIn == pRouter->config.channelsOut) { ma_bool32 areAllChannelPositionsPresent = MA_TRUE; for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { ma_bool32 isInputChannelPositionInOutput = MA_FALSE; for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { if (pRouter->config.channelMapIn[iChannelIn] == pRouter->config.channelMapOut[iChannelOut]) { isInputChannelPositionInOutput = MA_TRUE; break; } } if (!isInputChannelPositionInOutput) { areAllChannelPositionsPresent = MA_FALSE; break; } } if (areAllChannelPositionsPresent) { pRouter->isSimpleShuffle = MA_TRUE; /* All the router will be doing is rearranging channels which means all we need to do is use a shuffling table which is just a mapping between the index of the input channel to the index of the output channel. */ for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { if (pRouter->config.channelMapIn[iChannelIn] == pRouter->config.channelMapOut[iChannelOut]) { pRouter->shuffleTable[iChannelIn] = (ma_uint8)iChannelOut; break; } } } } } } /* Here is where weights are calculated. Note that we calculate the weights at all times, even when using a passthrough and simple shuffling. We use different algorithms for calculating weights depending on our mixing mode. In simple mode we don't do any blending (except for converting between mono, which is done in a later step). Instead we just map 1:1 matching channels. In this mode, if no channels in the input channel map correspond to anything in the output channel map, nothing will be heard! */ /* In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping. */ for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { ma_channel channelPosIn = pRouter->config.channelMapIn[iChannelIn]; for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { ma_channel channelPosOut = pRouter->config.channelMapOut[iChannelOut]; if (channelPosIn == channelPosOut) { pRouter->config.weights[iChannelIn][iChannelOut] = 1; } } } /* The mono channel is accumulated on all other channels, except LFE. Make sure in this loop we exclude output mono channels since they were handled in the pass above. */ for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { ma_channel channelPosIn = pRouter->config.channelMapIn[iChannelIn]; if (channelPosIn == MA_CHANNEL_MONO) { for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { ma_channel channelPosOut = pRouter->config.channelMapOut[iChannelOut]; if (channelPosOut != MA_CHANNEL_NONE && channelPosOut != MA_CHANNEL_MONO && channelPosOut != MA_CHANNEL_LFE) { pRouter->config.weights[iChannelIn][iChannelOut] = 1; } } } } /* The output mono channel is the average of all non-none, non-mono and non-lfe input channels. */ { ma_uint32 len = 0; for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { ma_channel channelPosIn = pRouter->config.channelMapIn[iChannelIn]; if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) { len += 1; } } if (len > 0) { float monoWeight = 1.0f / len; for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { ma_channel channelPosOut = pRouter->config.channelMapOut[iChannelOut]; if (channelPosOut == MA_CHANNEL_MONO) { for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { ma_channel channelPosIn = pRouter->config.channelMapIn[iChannelIn]; if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) { pRouter->config.weights[iChannelIn][iChannelOut] += monoWeight; } } } } } } /* Input and output channels that are not present on the other side need to be blended in based on spatial locality. */ switch (pRouter->config.mixingMode) { case ma_channel_mix_mode_rectangular: { /* Unmapped input channels. */ for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { ma_channel channelPosIn = pRouter->config.channelMapIn[iChannelIn]; if (ma_channel_router__is_spatial_channel_position(pRouter, channelPosIn)) { if (!ma_channel_map_contains_channel_position(pRouter->config.channelsOut, pRouter->config.channelMapOut, channelPosIn)) { for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { ma_channel channelPosOut = pRouter->config.channelMapOut[iChannelOut]; if (ma_channel_router__is_spatial_channel_position(pRouter, channelPosOut)) { float weight = 0; if (pRouter->config.mixingMode == ma_channel_mix_mode_planar_blend) { weight = ma_channel_router__calculate_input_channel_planar_weight(pRouter, channelPosIn, channelPosOut); } /* Only apply the weight if we haven't already got some contribution from the respective channels. */ if (pRouter->config.weights[iChannelIn][iChannelOut] == 0) { pRouter->config.weights[iChannelIn][iChannelOut] = weight; } } } } } } /* Unmapped output channels. */ for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { ma_channel channelPosOut = pRouter->config.channelMapOut[iChannelOut]; if (ma_channel_router__is_spatial_channel_position(pRouter, channelPosOut)) { if (!ma_channel_map_contains_channel_position(pRouter->config.channelsIn, pRouter->config.channelMapIn, channelPosOut)) { for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { ma_channel channelPosIn = pRouter->config.channelMapIn[iChannelIn]; if (ma_channel_router__is_spatial_channel_position(pRouter, channelPosIn)) { float weight = 0; if (pRouter->config.mixingMode == ma_channel_mix_mode_planar_blend) { weight = ma_channel_router__calculate_input_channel_planar_weight(pRouter, channelPosIn, channelPosOut); } /* Only apply the weight if we haven't already got some contribution from the respective channels. */ if (pRouter->config.weights[iChannelIn][iChannelOut] == 0) { pRouter->config.weights[iChannelIn][iChannelOut] = weight; } } } } } } } break; case ma_channel_mix_mode_custom_weights: case ma_channel_mix_mode_simple: default: { /* Fallthrough. */ } break; } return MA_SUCCESS; } static MA_INLINE ma_bool32 ma_channel_router__can_use_sse2(ma_channel_router* pRouter, const float* pSamplesOut, const float* pSamplesIn) { return pRouter->useSSE2 && (((ma_uintptr)pSamplesOut & 15) == 0) && (((ma_uintptr)pSamplesIn & 15) == 0); } static MA_INLINE ma_bool32 ma_channel_router__can_use_avx2(ma_channel_router* pRouter, const float* pSamplesOut, const float* pSamplesIn) { return pRouter->useAVX2 && (((ma_uintptr)pSamplesOut & 31) == 0) && (((ma_uintptr)pSamplesIn & 31) == 0); } static MA_INLINE ma_bool32 ma_channel_router__can_use_avx512(ma_channel_router* pRouter, const float* pSamplesOut, const float* pSamplesIn) { return pRouter->useAVX512 && (((ma_uintptr)pSamplesOut & 63) == 0) && (((ma_uintptr)pSamplesIn & 63) == 0); } static MA_INLINE ma_bool32 ma_channel_router__can_use_neon(ma_channel_router* pRouter, const float* pSamplesOut, const float* pSamplesIn) { return pRouter->useNEON && (((ma_uintptr)pSamplesOut & 15) == 0) && (((ma_uintptr)pSamplesIn & 15) == 0); } void ma_channel_router__do_routing(ma_channel_router* pRouter, ma_uint64 frameCount, float** ppSamplesOut, const float** ppSamplesIn) { ma_uint32 iChannelIn; ma_uint32 iChannelOut; ma_assert(pRouter != NULL); ma_assert(pRouter->isPassthrough == MA_FALSE); if (pRouter->isSimpleShuffle) { /* A shuffle is just a re-arrangement of channels and does not require any arithmetic. */ ma_assert(pRouter->config.channelsIn == pRouter->config.channelsOut); for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { iChannelOut = pRouter->shuffleTable[iChannelIn]; ma_copy_memory_64(ppSamplesOut[iChannelOut], ppSamplesIn[iChannelIn], frameCount * sizeof(float)); } } else { /* This is the more complicated case. Each of the output channels is accumulated with 0 or more input channels. */ /* Clear. */ for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { ma_zero_memory_64(ppSamplesOut[iChannelOut], frameCount * sizeof(float)); } /* Accumulate. */ for (iChannelIn = 0; iChannelIn < pRouter->config.channelsIn; ++iChannelIn) { for (iChannelOut = 0; iChannelOut < pRouter->config.channelsOut; ++iChannelOut) { ma_uint64 iFrame = 0; #if defined(MA_SUPPORT_NEON) if (ma_channel_router__can_use_neon(pRouter, ppSamplesOut[iChannelOut], ppSamplesIn[iChannelIn])) { float32x4_t weight = vmovq_n_f32(pRouter->config.weights[iChannelIn][iChannelOut]); ma_uint64 frameCount4 = frameCount/4; ma_uint64 iFrame4; for (iFrame4 = 0; iFrame4 < frameCount4; iFrame4 += 1) { float32x4_t* pO = (float32x4_t*)ppSamplesOut[iChannelOut] + iFrame4; float32x4_t* pI = (float32x4_t*)ppSamplesIn [iChannelIn ] + iFrame4; *pO = vaddq_f32(*pO, vmulq_f32(*pI, weight)); } iFrame += frameCount4*4; } else #endif #if defined(MA_SUPPORT_AVX512) if (ma_channel_router__can_use_avx512(pRouter, ppSamplesOut[iChannelOut], ppSamplesIn[iChannelIn])) { __m512 weight = _mm512_set1_ps(pRouter->config.weights[iChannelIn][iChannelOut]); ma_uint64 frameCount16 = frameCount/16; ma_uint64 iFrame16; for (iFrame16 = 0; iFrame16 < frameCount16; iFrame16 += 1) { __m512* pO = (__m512*)ppSamplesOut[iChannelOut] + iFrame16; __m512* pI = (__m512*)ppSamplesIn [iChannelIn ] + iFrame16; *pO = _mm512_add_ps(*pO, _mm512_mul_ps(*pI, weight)); } iFrame += frameCount16*16; } else #endif #if defined(MA_SUPPORT_AVX2) if (ma_channel_router__can_use_avx2(pRouter, ppSamplesOut[iChannelOut], ppSamplesIn[iChannelIn])) { __m256 weight = _mm256_set1_ps(pRouter->config.weights[iChannelIn][iChannelOut]); ma_uint64 frameCount8 = frameCount/8; ma_uint64 iFrame8; for (iFrame8 = 0; iFrame8 < frameCount8; iFrame8 += 1) { __m256* pO = (__m256*)ppSamplesOut[iChannelOut] + iFrame8; __m256* pI = (__m256*)ppSamplesIn [iChannelIn ] + iFrame8; *pO = _mm256_add_ps(*pO, _mm256_mul_ps(*pI, weight)); } iFrame += frameCount8*8; } else #endif #if defined(MA_SUPPORT_SSE2) if (ma_channel_router__can_use_sse2(pRouter, ppSamplesOut[iChannelOut], ppSamplesIn[iChannelIn])) { __m128 weight = _mm_set1_ps(pRouter->config.weights[iChannelIn][iChannelOut]); ma_uint64 frameCount4 = frameCount/4; ma_uint64 iFrame4; for (iFrame4 = 0; iFrame4 < frameCount4; iFrame4 += 1) { __m128* pO = (__m128*)ppSamplesOut[iChannelOut] + iFrame4; __m128* pI = (__m128*)ppSamplesIn [iChannelIn ] + iFrame4; *pO = _mm_add_ps(*pO, _mm_mul_ps(*pI, weight)); } iFrame += frameCount4*4; } else #endif { /* Reference. */ float weight0 = pRouter->config.weights[iChannelIn][iChannelOut]; float weight1 = pRouter->config.weights[iChannelIn][iChannelOut]; float weight2 = pRouter->config.weights[iChannelIn][iChannelOut]; float weight3 = pRouter->config.weights[iChannelIn][iChannelOut]; ma_uint64 frameCount4 = frameCount/4; ma_uint64 iFrame4; for (iFrame4 = 0; iFrame4 < frameCount4; iFrame4 += 1) { ppSamplesOut[iChannelOut][iFrame+0] += ppSamplesIn[iChannelIn][iFrame+0] * weight0; ppSamplesOut[iChannelOut][iFrame+1] += ppSamplesIn[iChannelIn][iFrame+1] * weight1; ppSamplesOut[iChannelOut][iFrame+2] += ppSamplesIn[iChannelIn][iFrame+2] * weight2; ppSamplesOut[iChannelOut][iFrame+3] += ppSamplesIn[iChannelIn][iFrame+3] * weight3; iFrame += 4; } } /* Leftover. */ for (; iFrame < frameCount; ++iFrame) { ppSamplesOut[iChannelOut][iFrame] += ppSamplesIn[iChannelIn][iFrame] * pRouter->config.weights[iChannelIn][iChannelOut]; } } } } } ma_uint64 ma_channel_router_read_deinterleaved(ma_channel_router* pRouter, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData) { if (pRouter == NULL || ppSamplesOut == NULL) { return 0; } /* Fast path for a passthrough. */ if (pRouter->isPassthrough) { if (frameCount <= 0xFFFFFFFF) { return (ma_uint32)pRouter->config.onReadDeinterleaved(pRouter, (ma_uint32)frameCount, ppSamplesOut, pUserData); } else { float* ppNextSamplesOut[MA_MAX_CHANNELS]; ma_uint64 totalFramesRead; ma_copy_memory(ppNextSamplesOut, ppSamplesOut, sizeof(float*) * pRouter->config.channelsOut); totalFramesRead = 0; while (totalFramesRead < frameCount) { ma_uint32 iChannel; ma_uint32 framesJustRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > 0xFFFFFFFF) { framesToReadRightNow = 0xFFFFFFFF; } framesJustRead = (ma_uint32)pRouter->config.onReadDeinterleaved(pRouter, (ma_uint32)framesToReadRightNow, (void**)ppNextSamplesOut, pUserData); if (framesJustRead == 0) { break; } totalFramesRead += framesJustRead; if (framesJustRead < framesToReadRightNow) { break; } for (iChannel = 0; iChannel < pRouter->config.channelsOut; ++iChannel) { ppNextSamplesOut[iChannel] += framesJustRead; } } return totalFramesRead; } } /* Slower path for a non-passthrough. */ { float* ppNextSamplesOut[MA_MAX_CHANNELS]; float* ppTemp[MA_MAX_CHANNELS]; size_t maxBytesToReadPerFrameEachIteration; size_t maxFramesToReadEachIteration; ma_uint64 totalFramesRead; MA_ALIGN(MA_SIMD_ALIGNMENT) float temp[MA_MAX_CHANNELS * 256]; ma_assert(sizeof(temp) <= 0xFFFFFFFF); ma_copy_memory(ppNextSamplesOut, ppSamplesOut, sizeof(float*) * pRouter->config.channelsOut); ma_split_buffer(temp, sizeof(temp), pRouter->config.channelsIn, MA_SIMD_ALIGNMENT, (void**)&ppTemp, &maxBytesToReadPerFrameEachIteration); maxFramesToReadEachIteration = maxBytesToReadPerFrameEachIteration/sizeof(float); totalFramesRead = 0; while (totalFramesRead < frameCount) { ma_uint32 iChannel; ma_uint32 framesJustRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > maxFramesToReadEachIteration) { framesToReadRightNow = maxFramesToReadEachIteration; } framesJustRead = pRouter->config.onReadDeinterleaved(pRouter, (ma_uint32)framesToReadRightNow, (void**)ppTemp, pUserData); if (framesJustRead == 0) { break; } ma_channel_router__do_routing(pRouter, framesJustRead, (float**)ppNextSamplesOut, (const float**)ppTemp); /* <-- Real work is done here. */ totalFramesRead += framesJustRead; if (totalFramesRead < frameCount) { for (iChannel = 0; iChannel < pRouter->config.channelsIn; iChannel += 1) { ppNextSamplesOut[iChannel] += framesJustRead; } } if (framesJustRead < framesToReadRightNow) { break; } } return totalFramesRead; } } ma_channel_router_config ma_channel_router_config_init(ma_uint32 channelsIn, const ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint32 channelsOut, const ma_channel channelMapOut[MA_MAX_CHANNELS], ma_channel_mix_mode mixingMode, ma_channel_router_read_deinterleaved_proc onRead, void* pUserData) { ma_channel_router_config config; ma_uint32 iChannel; ma_zero_object(&config); config.channelsIn = channelsIn; for (iChannel = 0; iChannel < channelsIn; ++iChannel) { config.channelMapIn[iChannel] = channelMapIn[iChannel]; } config.channelsOut = channelsOut; for (iChannel = 0; iChannel < channelsOut; ++iChannel) { config.channelMapOut[iChannel] = channelMapOut[iChannel]; } config.mixingMode = mixingMode; config.onReadDeinterleaved = onRead; config.pUserData = pUserData; return config; } /************************************************************************************************************************************************************** SRC **************************************************************************************************************************************************************/ #define ma_floorf(x) ((float)floor((double)(x))) #define ma_sinf(x) ((float)sin((double)(x))) #define ma_cosf(x) ((float)cos((double)(x))) static MA_INLINE double ma_sinc(double x) { if (x != 0) { return sin(MA_PI_D*x) / (MA_PI_D*x); } else { return 1; } } #define ma_sincf(x) ((float)ma_sinc((double)(x))) ma_uint64 ma_src_read_deinterleaved__passthrough(ma_src* pSRC, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData); ma_uint64 ma_src_read_deinterleaved__linear(ma_src* pSRC, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData); ma_uint64 ma_src_read_deinterleaved__sinc(ma_src* pSRC, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData); void ma_src__build_sinc_table__sinc(ma_src* pSRC) { ma_uint32 i; ma_assert(pSRC != NULL); pSRC->sinc.table[0] = 1.0f; for (i = 1; i < ma_countof(pSRC->sinc.table); i += 1) { double x = i*MA_PI_D / MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION; pSRC->sinc.table[i] = (float)(sin(x)/x); } } void ma_src__build_sinc_table__rectangular(ma_src* pSRC) { /* This is the same as the base sinc table. */ ma_src__build_sinc_table__sinc(pSRC); } void ma_src__build_sinc_table__hann(ma_src* pSRC) { ma_uint32 i; ma_src__build_sinc_table__sinc(pSRC); for (i = 0; i < ma_countof(pSRC->sinc.table); i += 1) { double x = pSRC->sinc.table[i]; double N = MA_SRC_SINC_MAX_WINDOW_WIDTH*2; double n = ((double)(i) / MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION) + MA_SRC_SINC_MAX_WINDOW_WIDTH; double w = 0.5 * (1 - cos((2*MA_PI_D*n) / (N))); pSRC->sinc.table[i] = (float)(x * w); } } ma_result ma_src_init(const ma_src_config* pConfig, ma_src* pSRC) { if (pSRC == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pSRC); if (pConfig == NULL || pConfig->onReadDeinterleaved == NULL) { return MA_INVALID_ARGS; } if (pConfig->channels == 0 || pConfig->channels > MA_MAX_CHANNELS) { return MA_INVALID_ARGS; } pSRC->config = *pConfig; /* SIMD */ pSRC->useSSE2 = ma_has_sse2() && !pConfig->noSSE2; pSRC->useAVX2 = ma_has_avx2() && !pConfig->noAVX2; pSRC->useAVX512 = ma_has_avx512f() && !pConfig->noAVX512; pSRC->useNEON = ma_has_neon() && !pConfig->noNEON; if (pSRC->config.algorithm == ma_src_algorithm_sinc) { /* Make sure the window width within bounds. */ if (pSRC->config.sinc.windowWidth == 0) { pSRC->config.sinc.windowWidth = MA_SRC_SINC_DEFAULT_WINDOW_WIDTH; } if (pSRC->config.sinc.windowWidth < MA_SRC_SINC_MIN_WINDOW_WIDTH) { pSRC->config.sinc.windowWidth = MA_SRC_SINC_MIN_WINDOW_WIDTH; } if (pSRC->config.sinc.windowWidth > MA_SRC_SINC_MAX_WINDOW_WIDTH) { pSRC->config.sinc.windowWidth = MA_SRC_SINC_MAX_WINDOW_WIDTH; } /* Set up the lookup table. */ switch (pSRC->config.sinc.windowFunction) { case ma_src_sinc_window_function_hann: ma_src__build_sinc_table__hann(pSRC); break; case ma_src_sinc_window_function_rectangular: ma_src__build_sinc_table__rectangular(pSRC); break; default: return MA_INVALID_ARGS; /* <-- Hitting this means the window function is unknown to miniaudio. */ } } return MA_SUCCESS; } ma_result ma_src_set_sample_rate(ma_src* pSRC, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) { if (pSRC == NULL) { return MA_INVALID_ARGS; } /* Must have a sample rate of > 0. */ if (sampleRateIn == 0 || sampleRateOut == 0) { return MA_INVALID_ARGS; } ma_atomic_exchange_32(&pSRC->config.sampleRateIn, sampleRateIn); ma_atomic_exchange_32(&pSRC->config.sampleRateOut, sampleRateOut); return MA_SUCCESS; } ma_uint64 ma_src_read_deinterleaved(ma_src* pSRC, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData) { ma_src_algorithm algorithm; if (pSRC == NULL || frameCount == 0 || ppSamplesOut == NULL) { return 0; } algorithm = pSRC->config.algorithm; /* Can use a function pointer for this. */ switch (algorithm) { case ma_src_algorithm_none: return ma_src_read_deinterleaved__passthrough(pSRC, frameCount, ppSamplesOut, pUserData); case ma_src_algorithm_linear: return ma_src_read_deinterleaved__linear( pSRC, frameCount, ppSamplesOut, pUserData); case ma_src_algorithm_sinc: return ma_src_read_deinterleaved__sinc( pSRC, frameCount, ppSamplesOut, pUserData); default: break; } /* Should never get here. */ return 0; } ma_uint64 ma_src_read_deinterleaved__passthrough(ma_src* pSRC, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData) { if (frameCount <= 0xFFFFFFFF) { return pSRC->config.onReadDeinterleaved(pSRC, (ma_uint32)frameCount, ppSamplesOut, pUserData); } else { ma_uint32 iChannel; ma_uint64 totalFramesRead; float* ppNextSamplesOut[MA_MAX_CHANNELS]; for (iChannel = 0; iChannel < pSRC->config.channels; ++iChannel) { ppNextSamplesOut[iChannel] = (float*)ppSamplesOut[iChannel]; } totalFramesRead = 0; while (totalFramesRead < frameCount) { ma_uint32 framesJustRead; ma_uint64 framesRemaining = frameCount - totalFramesRead; ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > 0xFFFFFFFF) { framesToReadRightNow = 0xFFFFFFFF; } framesJustRead = (ma_uint32)pSRC->config.onReadDeinterleaved(pSRC, (ma_uint32)framesToReadRightNow, (void**)ppNextSamplesOut, pUserData); if (framesJustRead == 0) { break; } totalFramesRead += framesJustRead; for (iChannel = 0; iChannel < pSRC->config.channels; ++iChannel) { ppNextSamplesOut[iChannel] += framesJustRead; } if (framesJustRead < framesToReadRightNow) { break; } } return totalFramesRead; } } ma_uint64 ma_src_read_deinterleaved__linear(ma_src* pSRC, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData) { float* ppNextSamplesOut[MA_MAX_CHANNELS]; float factor; ma_uint32 maxFrameCountPerChunkIn; ma_uint64 totalFramesRead; ma_assert(pSRC != NULL); ma_assert(frameCount > 0); ma_assert(ppSamplesOut != NULL); ma_copy_memory(ppNextSamplesOut, ppSamplesOut, sizeof(void*) * pSRC->config.channels); factor = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; maxFrameCountPerChunkIn = ma_countof(pSRC->linear.input[0]); totalFramesRead = 0; while (totalFramesRead < frameCount) { ma_uint32 iChannel; float tBeg; float tEnd; float tAvailable; float tNext; float* ppSamplesFromClient[MA_MAX_CHANNELS]; ma_uint32 iNextFrame; ma_uint32 maxOutputFramesToRead; ma_uint32 maxOutputFramesToRead4; ma_uint32 framesToReadFromClient; ma_uint32 framesReadFromClient; ma_uint64 framesRemaining = frameCount - totalFramesRead; ma_uint64 framesToRead = framesRemaining; if (framesToRead > 16384) { framesToRead = 16384; /* <-- Keep this small because we're using 32-bit floats for calculating sample positions and I don't want to run out of precision with huge sample counts. */ } /* Read Input Data */ tBeg = pSRC->linear.timeIn; tEnd = tBeg + ((ma_int64)framesToRead*factor); /* Cast to int64 required for VC6. */ framesToReadFromClient = (ma_uint32)(tEnd) + 1 + 1; /* +1 to make tEnd 1-based and +1 because we always need to an extra sample for interpolation. */ if (framesToReadFromClient >= maxFrameCountPerChunkIn) { framesToReadFromClient = maxFrameCountPerChunkIn; } for (iChannel = 0; iChannel < pSRC->config.channels; ++iChannel) { ppSamplesFromClient[iChannel] = pSRC->linear.input[iChannel] + pSRC->linear.leftoverFrames; } framesReadFromClient = 0; if (framesToReadFromClient > pSRC->linear.leftoverFrames) { framesReadFromClient = (ma_uint32)pSRC->config.onReadDeinterleaved(pSRC, (ma_uint32)framesToReadFromClient - pSRC->linear.leftoverFrames, (void**)ppSamplesFromClient, pUserData); } framesReadFromClient += pSRC->linear.leftoverFrames; /* <-- You can sort of think of it as though we've re-read the leftover samples from the client. */ if (framesReadFromClient < 2) { break; } for (iChannel = 0; iChannel < pSRC->config.channels; ++iChannel) { ppSamplesFromClient[iChannel] = pSRC->linear.input[iChannel]; } /* Write Output Data */ /* At this point we have a bunch of frames that the client has given to us for processing. From this we can determine the maximum number of output frames that can be processed from this input. We want to output as many samples as possible from our input data. */ tAvailable = framesReadFromClient - tBeg - 1; /* Subtract 1 because the last input sample is needed for interpolation and cannot be included in the output sample count calculation. */ maxOutputFramesToRead = (ma_uint32)(tAvailable / factor); if (maxOutputFramesToRead == 0) { maxOutputFramesToRead = 1; } if (maxOutputFramesToRead > framesToRead) { maxOutputFramesToRead = (ma_uint32)framesToRead; } /* Output frames are always read in groups of 4 because I'm planning on using this as a reference for some SIMD-y stuff later. */ maxOutputFramesToRead4 = maxOutputFramesToRead/4; for (iChannel = 0; iChannel < pSRC->config.channels; ++iChannel) { ma_uint32 iFrameOut; float t0 = pSRC->linear.timeIn + factor*0; float t1 = pSRC->linear.timeIn + factor*1; float t2 = pSRC->linear.timeIn + factor*2; float t3 = pSRC->linear.timeIn + factor*3; float t; for (iFrameOut = 0; iFrameOut < maxOutputFramesToRead4; iFrameOut += 1) { float iPrevSample0 = (float)floor(t0); float iPrevSample1 = (float)floor(t1); float iPrevSample2 = (float)floor(t2); float iPrevSample3 = (float)floor(t3); float iNextSample0 = iPrevSample0 + 1; float iNextSample1 = iPrevSample1 + 1; float iNextSample2 = iPrevSample2 + 1; float iNextSample3 = iPrevSample3 + 1; float alpha0 = t0 - iPrevSample0; float alpha1 = t1 - iPrevSample1; float alpha2 = t2 - iPrevSample2; float alpha3 = t3 - iPrevSample3; float prevSample0 = ppSamplesFromClient[iChannel][(ma_uint32)iPrevSample0]; float prevSample1 = ppSamplesFromClient[iChannel][(ma_uint32)iPrevSample1]; float prevSample2 = ppSamplesFromClient[iChannel][(ma_uint32)iPrevSample2]; float prevSample3 = ppSamplesFromClient[iChannel][(ma_uint32)iPrevSample3]; float nextSample0 = ppSamplesFromClient[iChannel][(ma_uint32)iNextSample0]; float nextSample1 = ppSamplesFromClient[iChannel][(ma_uint32)iNextSample1]; float nextSample2 = ppSamplesFromClient[iChannel][(ma_uint32)iNextSample2]; float nextSample3 = ppSamplesFromClient[iChannel][(ma_uint32)iNextSample3]; ppNextSamplesOut[iChannel][iFrameOut*4 + 0] = ma_mix_f32_fast(prevSample0, nextSample0, alpha0); ppNextSamplesOut[iChannel][iFrameOut*4 + 1] = ma_mix_f32_fast(prevSample1, nextSample1, alpha1); ppNextSamplesOut[iChannel][iFrameOut*4 + 2] = ma_mix_f32_fast(prevSample2, nextSample2, alpha2); ppNextSamplesOut[iChannel][iFrameOut*4 + 3] = ma_mix_f32_fast(prevSample3, nextSample3, alpha3); t0 += factor*4; t1 += factor*4; t2 += factor*4; t3 += factor*4; } t = pSRC->linear.timeIn + (factor*maxOutputFramesToRead4*4); for (iFrameOut = (maxOutputFramesToRead4*4); iFrameOut < maxOutputFramesToRead; iFrameOut += 1) { float iPrevSample = (float)floor(t); float iNextSample = iPrevSample + 1; float alpha = t - iPrevSample; float prevSample; float nextSample; ma_assert(iPrevSample < ma_countof(pSRC->linear.input[iChannel])); ma_assert(iNextSample < ma_countof(pSRC->linear.input[iChannel])); prevSample = ppSamplesFromClient[iChannel][(ma_uint32)iPrevSample]; nextSample = ppSamplesFromClient[iChannel][(ma_uint32)iNextSample]; ppNextSamplesOut[iChannel][iFrameOut] = ma_mix_f32_fast(prevSample, nextSample, alpha); t += factor; } ppNextSamplesOut[iChannel] += maxOutputFramesToRead; } totalFramesRead += maxOutputFramesToRead; /* Residual */ tNext = pSRC->linear.timeIn + (maxOutputFramesToRead*factor); pSRC->linear.timeIn = tNext; ma_assert(tNext <= framesReadFromClient+1); iNextFrame = (ma_uint32)floor(tNext); pSRC->linear.leftoverFrames = framesReadFromClient - iNextFrame; pSRC->linear.timeIn = tNext - iNextFrame; for (iChannel = 0; iChannel < pSRC->config.channels; ++iChannel) { ma_uint32 iFrame; for (iFrame = 0; iFrame < pSRC->linear.leftoverFrames; ++iFrame) { float sample = ppSamplesFromClient[iChannel][framesReadFromClient-pSRC->linear.leftoverFrames + iFrame]; ppSamplesFromClient[iChannel][iFrame] = sample; } } /* Exit the loop if we've found everything from the client. */ if (framesReadFromClient < framesToReadFromClient) { break; } } return totalFramesRead; } ma_src_config ma_src_config_init_new() { ma_src_config config; ma_zero_object(&config); return config; } ma_src_config ma_src_config_init(ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_uint32 channels, ma_src_read_deinterleaved_proc onReadDeinterleaved, void* pUserData) { ma_src_config config = ma_src_config_init_new(); config.sampleRateIn = sampleRateIn; config.sampleRateOut = sampleRateOut; config.channels = channels; config.onReadDeinterleaved = onReadDeinterleaved; config.pUserData = pUserData; return config; } /************************************************************************************************************************************************************** Sinc Sample Rate Conversion =========================== The sinc SRC algorithm uses a windowed sinc to perform interpolation of samples. Currently, miniaudio's implementation supports rectangular and Hann window methods. Whenever an output sample is being computed, it looks at a sub-section of the input samples. I've called this sub-section in the code below the "window", which I realize is a bit ambigous with the mathematical "window", but it works for me when I need to conceptualize things in my head. The window is made up of two halves. The first half contains past input samples (initialized to zero), and the second half contains future input samples. As time moves forward and input samples are consumed, the window moves forward. The larger the window, the better the quality at the expense of slower processing. The window is limited the range [MA_SRC_SINC_MIN_WINDOW_WIDTH, MA_SRC_SINC_MAX_WINDOW_WIDTH] and defaults to MA_SRC_SINC_DEFAULT_WINDOW_WIDTH. Input samples are cached for efficiency (to prevent frequently requesting tiny numbers of samples from the client). When the window gets to the end of the cache, it's moved back to the start, and more samples are read from the client. If the client has no more data to give, the cache is filled with zeros and the last of the input samples will be consumed. Once the last of the input samples have been consumed, no more samples will be output. When reading output samples, we always first read whatever is already in the input cache. Only when the cache has been fully consumed do we read more data from the client. To access samples in the input buffer you do so relative to the window. When the window itself is at position 0, the first item in the buffer is accessed with "windowPos + windowWidth". Generally, to access any sample relative to the window you do "windowPos + windowWidth + sampleIndexRelativeToWindow". **************************************************************************************************************************************************************/ /* Comment this to disable interpolation of table lookups. Less accurate, but faster. */ #define MA_USE_SINC_TABLE_INTERPOLATION /* Retrieves a sample from the input buffer's window. Values >= 0 retrieve future samples. Negative values return past samples. */ static MA_INLINE float ma_src_sinc__get_input_sample_from_window(const ma_src* pSRC, ma_uint32 channel, ma_uint32 windowPosInSamples, ma_int32 sampleIndex) { ma_assert(pSRC != NULL); ma_assert(channel < pSRC->config.channels); ma_assert(sampleIndex >= -(ma_int32)pSRC->config.sinc.windowWidth); ma_assert(sampleIndex < (ma_int32)pSRC->config.sinc.windowWidth); /* The window should always be contained within the input cache. */ ma_assert(windowPosInSamples < ma_countof(pSRC->sinc.input[0]) - pSRC->config.sinc.windowWidth); return pSRC->sinc.input[channel][windowPosInSamples + pSRC->config.sinc.windowWidth + sampleIndex]; } static MA_INLINE float ma_src_sinc__interpolation_factor(const ma_src* pSRC, float x) { float xabs; ma_int32 ixabs; ma_assert(pSRC != NULL); xabs = (float)fabs(x); xabs = xabs * MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION; ixabs = (ma_int32)xabs; #if defined(MA_USE_SINC_TABLE_INTERPOLATION) { float a = xabs - ixabs; return ma_mix_f32_fast(pSRC->sinc.table[ixabs], pSRC->sinc.table[ixabs+1], a); } #else return pSRC->sinc.table[ixabs]; #endif } #if defined(MA_SUPPORT_SSE2) static MA_INLINE __m128 ma_fabsf_sse2(__m128 x) { return _mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF)), x); } static MA_INLINE __m128 ma_truncf_sse2(__m128 x) { return _mm_cvtepi32_ps(_mm_cvttps_epi32(x)); } static MA_INLINE __m128 ma_src_sinc__interpolation_factor__sse2(const ma_src* pSRC, __m128 x) { __m128 resolution128; __m128 xabs; __m128i ixabs; __m128 lo; __m128 hi; __m128 a; __m128 r; int* ixabsv; resolution128 = _mm_set1_ps(MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION); xabs = ma_fabsf_sse2(x); xabs = _mm_mul_ps(xabs, resolution128); ixabs = _mm_cvttps_epi32(xabs); ixabsv = (int*)&ixabs; lo = _mm_set_ps( pSRC->sinc.table[ixabsv[3]], pSRC->sinc.table[ixabsv[2]], pSRC->sinc.table[ixabsv[1]], pSRC->sinc.table[ixabsv[0]] ); hi = _mm_set_ps( pSRC->sinc.table[ixabsv[3]+1], pSRC->sinc.table[ixabsv[2]+1], pSRC->sinc.table[ixabsv[1]+1], pSRC->sinc.table[ixabsv[0]+1] ); a = _mm_sub_ps(xabs, _mm_cvtepi32_ps(ixabs)); r = ma_mix_f32_fast__sse2(lo, hi, a); return r; } #endif #if defined(MA_SUPPORT_AVX2) static MA_INLINE __m256 ma_fabsf_avx2(__m256 x) { return _mm256_and_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0x7FFFFFFF)), x); } #if 0 static MA_INLINE __m256 ma_src_sinc__interpolation_factor__avx2(const ma_src* pSRC, __m256 x) { __m256 resolution256 = _mm256_set1_ps(MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION); __m256 xabs = ma_fabsf_avx2(x); xabs = _mm256_mul_ps(xabs, resolution256); __m256i ixabs = _mm256_cvttps_epi32(xabs); __m256 a = _mm256_sub_ps(xabs, _mm256_cvtepi32_ps(ixabs)); int* ixabsv = (int*)&ixabs; __m256 lo = _mm256_set_ps( pSRC->sinc.table[ixabsv[7]], pSRC->sinc.table[ixabsv[6]], pSRC->sinc.table[ixabsv[5]], pSRC->sinc.table[ixabsv[4]], pSRC->sinc.table[ixabsv[3]], pSRC->sinc.table[ixabsv[2]], pSRC->sinc.table[ixabsv[1]], pSRC->sinc.table[ixabsv[0]] ); __m256 hi = _mm256_set_ps( pSRC->sinc.table[ixabsv[7]+1], pSRC->sinc.table[ixabsv[6]+1], pSRC->sinc.table[ixabsv[5]+1], pSRC->sinc.table[ixabsv[4]+1], pSRC->sinc.table[ixabsv[3]+1], pSRC->sinc.table[ixabsv[2]+1], pSRC->sinc.table[ixabsv[1]+1], pSRC->sinc.table[ixabsv[0]+1] ); __m256 r = ma_mix_f32_fast__avx2(lo, hi, a); return r; } #endif #endif #if defined(MA_SUPPORT_NEON) static MA_INLINE float32x4_t ma_fabsf_neon(float32x4_t x) { return vabdq_f32(vmovq_n_f32(0), x); } static MA_INLINE float32x4_t ma_src_sinc__interpolation_factor__neon(const ma_src* pSRC, float32x4_t x) { float32x4_t xabs; int32x4_t ixabs; float32x4_t a float32x4_t r int* ixabsv; float lo[4]; float hi[4]; xabs = ma_fabsf_neon(x); xabs = vmulq_n_f32(xabs, MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION); ixabs = vcvtq_s32_f32(xabs); ixabsv = (int*)&ixabs; lo[0] = pSRC->sinc.table[ixabsv[0]]; lo[1] = pSRC->sinc.table[ixabsv[1]]; lo[2] = pSRC->sinc.table[ixabsv[2]]; lo[3] = pSRC->sinc.table[ixabsv[3]]; hi[0] = pSRC->sinc.table[ixabsv[0]+1]; hi[1] = pSRC->sinc.table[ixabsv[1]+1]; hi[2] = pSRC->sinc.table[ixabsv[2]+1]; hi[3] = pSRC->sinc.table[ixabsv[3]+1]; a = vsubq_f32(xabs, vcvtq_f32_s32(ixabs)); r = ma_mix_f32_fast__neon(vld1q_f32(lo), vld1q_f32(hi), a); return r; } #endif ma_uint64 ma_src_read_deinterleaved__sinc(ma_src* pSRC, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData) { float factor; float inverseFactor; ma_int32 windowWidth; ma_int32 windowWidth2; ma_int32 windowWidthSIMD; ma_int32 windowWidthSIMD2; float* ppNextSamplesOut[MA_MAX_CHANNELS]; float _windowSamplesUnaligned[MA_SRC_SINC_MAX_WINDOW_WIDTH*2 + MA_SIMD_ALIGNMENT]; float* windowSamples; float _iWindowFUnaligned[MA_SRC_SINC_MAX_WINDOW_WIDTH*2 + MA_SIMD_ALIGNMENT]; float* iWindowF; ma_int32 i; ma_uint64 totalOutputFramesRead; ma_assert(pSRC != NULL); ma_assert(frameCount > 0); ma_assert(ppSamplesOut != NULL); factor = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; inverseFactor = 1/factor; windowWidth = (ma_int32)pSRC->config.sinc.windowWidth; windowWidth2 = windowWidth*2; /* There are cases where it's actually more efficient to increase the window width so that it's aligned with the respective SIMD pipeline being used. */ windowWidthSIMD = windowWidth; if (pSRC->useNEON) { windowWidthSIMD = (windowWidthSIMD + 1) & ~(1); } else if (pSRC->useAVX512) { windowWidthSIMD = (windowWidthSIMD + 7) & ~(7); } else if (pSRC->useAVX2) { windowWidthSIMD = (windowWidthSIMD + 3) & ~(3); } else if (pSRC->useSSE2) { windowWidthSIMD = (windowWidthSIMD + 1) & ~(1); } windowWidthSIMD2 = windowWidthSIMD*2; (void)windowWidthSIMD2; /* <-- Silence a warning when SIMD is disabled. */ ma_copy_memory(ppNextSamplesOut, ppSamplesOut, sizeof(void*) * pSRC->config.channels); windowSamples = (float*)(((ma_uintptr)_windowSamplesUnaligned + MA_SIMD_ALIGNMENT-1) & ~(MA_SIMD_ALIGNMENT-1)); ma_zero_memory(windowSamples, MA_SRC_SINC_MAX_WINDOW_WIDTH*2 * sizeof(float)); iWindowF = (float*)(((ma_uintptr)_iWindowFUnaligned + MA_SIMD_ALIGNMENT-1) & ~(MA_SIMD_ALIGNMENT-1)); ma_zero_memory(iWindowF, MA_SRC_SINC_MAX_WINDOW_WIDTH*2 * sizeof(float)); for (i = 0; i < windowWidth2; ++i) { iWindowF[i] = (float)(i - windowWidth); } totalOutputFramesRead = 0; while (totalOutputFramesRead < frameCount) { ma_uint32 maxInputSamplesAvailableInCache; float timeInBeg; float timeInEnd; ma_uint64 maxOutputFramesToRead; ma_uint64 outputFramesRemaining; ma_uint64 outputFramesToRead; ma_uint32 iChannel; ma_uint32 prevWindowPosInSamples; ma_uint32 availableOutputFrames; /* The maximum number of frames we can read this iteration depends on how many input samples we have available to us. This is the number of input samples between the end of the window and the end of the cache. */ maxInputSamplesAvailableInCache = ma_countof(pSRC->sinc.input[0]) - (pSRC->config.sinc.windowWidth*2) - pSRC->sinc.windowPosInSamples; if (maxInputSamplesAvailableInCache > pSRC->sinc.inputFrameCount) { maxInputSamplesAvailableInCache = pSRC->sinc.inputFrameCount; } /* Never consume the tail end of the input data if requested. */ if (pSRC->config.neverConsumeEndOfInput) { if (maxInputSamplesAvailableInCache >= pSRC->config.sinc.windowWidth) { maxInputSamplesAvailableInCache -= pSRC->config.sinc.windowWidth; } else { maxInputSamplesAvailableInCache = 0; } } timeInBeg = pSRC->sinc.timeIn; timeInEnd = (float)(pSRC->sinc.windowPosInSamples + maxInputSamplesAvailableInCache); ma_assert(timeInBeg >= 0); ma_assert(timeInBeg <= timeInEnd); maxOutputFramesToRead = (ma_uint64)(((timeInEnd - timeInBeg) * inverseFactor)); outputFramesRemaining = frameCount - totalOutputFramesRead; outputFramesToRead = outputFramesRemaining; if (outputFramesToRead > maxOutputFramesToRead) { outputFramesToRead = maxOutputFramesToRead; } for (iChannel = 0; iChannel < pSRC->config.channels; iChannel += 1) { /* Do SRC. */ float timeIn = timeInBeg; ma_uint32 iSample; for (iSample = 0; iSample < outputFramesToRead; iSample += 1) { float sampleOut = 0; float iTimeInF = ma_floorf(timeIn); ma_uint32 iTimeIn = (ma_uint32)iTimeInF; ma_int32 iWindow = 0; float tScalar; /* Pre-load the window samples into an aligned buffer to begin with. Need to put these into an aligned buffer to make SIMD easier. */ windowSamples[0] = 0; /* <-- The first sample is always zero. */ for (i = 1; i < windowWidth2; ++i) { windowSamples[i] = pSRC->sinc.input[iChannel][iTimeIn + i]; } #if defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX512) if (pSRC->useAVX2 || pSRC->useAVX512) { __m256i ixabs[MA_SRC_SINC_MAX_WINDOW_WIDTH*2/8]; __m256 a[MA_SRC_SINC_MAX_WINDOW_WIDTH*2/8]; __m256 resolution256; __m256 t; __m256 r; ma_int32 windowWidth8; ma_int32 iWindow8; resolution256 = _mm256_set1_ps(MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION); t = _mm256_set1_ps((timeIn - iTimeInF)); r = _mm256_set1_ps(0); windowWidth8 = windowWidthSIMD2 >> 3; for (iWindow8 = 0; iWindow8 < windowWidth8; iWindow8 += 1) { __m256 w = *((__m256*)iWindowF + iWindow8); __m256 xabs = _mm256_sub_ps(t, w); xabs = ma_fabsf_avx2(xabs); xabs = _mm256_mul_ps(xabs, resolution256); ixabs[iWindow8] = _mm256_cvttps_epi32(xabs); a[iWindow8] = _mm256_sub_ps(xabs, _mm256_cvtepi32_ps(ixabs[iWindow8])); } for (iWindow8 = 0; iWindow8 < windowWidth8; iWindow8 += 1) { int* ixabsv = (int*)&ixabs[iWindow8]; __m256 lo = _mm256_set_ps( pSRC->sinc.table[ixabsv[7]], pSRC->sinc.table[ixabsv[6]], pSRC->sinc.table[ixabsv[5]], pSRC->sinc.table[ixabsv[4]], pSRC->sinc.table[ixabsv[3]], pSRC->sinc.table[ixabsv[2]], pSRC->sinc.table[ixabsv[1]], pSRC->sinc.table[ixabsv[0]] ); __m256 hi = _mm256_set_ps( pSRC->sinc.table[ixabsv[7]+1], pSRC->sinc.table[ixabsv[6]+1], pSRC->sinc.table[ixabsv[5]+1], pSRC->sinc.table[ixabsv[4]+1], pSRC->sinc.table[ixabsv[3]+1], pSRC->sinc.table[ixabsv[2]+1], pSRC->sinc.table[ixabsv[1]+1], pSRC->sinc.table[ixabsv[0]+1] ); __m256 s = *((__m256*)windowSamples + iWindow8); r = _mm256_add_ps(r, _mm256_mul_ps(s, ma_mix_f32_fast__avx2(lo, hi, a[iWindow8]))); } /* Horizontal add. */ __m256 x = _mm256_hadd_ps(r, _mm256_permute2f128_ps(r, r, 1)); x = _mm256_hadd_ps(x, x); x = _mm256_hadd_ps(x, x); sampleOut += _mm_cvtss_f32(_mm256_castps256_ps128(x)); iWindow += windowWidth8 * 8; } else #endif #if defined(MA_SUPPORT_SSE2) if (pSRC->useSSE2) { __m128 t = _mm_set1_ps((timeIn - iTimeInF)); __m128 r = _mm_set1_ps(0); ma_int32 windowWidth4 = windowWidthSIMD2 >> 2; ma_int32 iWindow4; for (iWindow4 = 0; iWindow4 < windowWidth4; iWindow4 += 1) { __m128* s = (__m128*)windowSamples + iWindow4; __m128* w = (__m128*)iWindowF + iWindow4; __m128 a = ma_src_sinc__interpolation_factor__sse2(pSRC, _mm_sub_ps(t, *w)); r = _mm_add_ps(r, _mm_mul_ps(*s, a)); } sampleOut += ((float*)(&r))[0]; sampleOut += ((float*)(&r))[1]; sampleOut += ((float*)(&r))[2]; sampleOut += ((float*)(&r))[3]; iWindow += windowWidth4 * 4; } else #endif #if defined(MA_SUPPORT_NEON) if (pSRC->useNEON) { float32x4_t t = vmovq_n_f32((timeIn - iTimeInF)); float32x4_t r = vmovq_n_f32(0); ma_int32 windowWidth4 = windowWidthSIMD2 >> 2; ma_int32 iWindow4; for (iWindow4 = 0; iWindow4 < windowWidth4; iWindow4 += 1) { float32x4_t* s = (float32x4_t*)windowSamples + iWindow4; float32x4_t* w = (float32x4_t*)iWindowF + iWindow4; float32x4_t a = ma_src_sinc__interpolation_factor__neon(pSRC, vsubq_f32(t, *w)); r = vaddq_f32(r, vmulq_f32(*s, a)); } sampleOut += ((float*)(&r))[0]; sampleOut += ((float*)(&r))[1]; sampleOut += ((float*)(&r))[2]; sampleOut += ((float*)(&r))[3]; iWindow += windowWidth4 * 4; } else #endif { iWindow += 1; /* The first one is a dummy for SIMD alignment purposes. Skip it. */ } /* Non-SIMD/Reference implementation. */ tScalar = (timeIn - iTimeIn); for (; iWindow < windowWidth2; iWindow += 1) { float s = windowSamples[iWindow]; float w = iWindowF[iWindow]; float a = ma_src_sinc__interpolation_factor(pSRC, (tScalar - w)); float r = s * a; sampleOut += r; } ppNextSamplesOut[iChannel][iSample] = (float)sampleOut; timeIn += factor; } ppNextSamplesOut[iChannel] += outputFramesToRead; } totalOutputFramesRead += outputFramesToRead; prevWindowPosInSamples = pSRC->sinc.windowPosInSamples; pSRC->sinc.timeIn += ((ma_int64)outputFramesToRead * factor); /* Cast to int64 required for VC6. */ pSRC->sinc.windowPosInSamples = (ma_uint32)pSRC->sinc.timeIn; pSRC->sinc.inputFrameCount -= pSRC->sinc.windowPosInSamples - prevWindowPosInSamples; /* If the window has reached a point where we cannot read a whole output sample it needs to be moved back to the start. */ availableOutputFrames = (ma_uint32)((timeInEnd - pSRC->sinc.timeIn) * inverseFactor); if (availableOutputFrames == 0) { size_t samplesToMove = ma_countof(pSRC->sinc.input[0]) - pSRC->sinc.windowPosInSamples; pSRC->sinc.timeIn -= ma_floorf(pSRC->sinc.timeIn); pSRC->sinc.windowPosInSamples = 0; /* Move everything from the end of the cache up to the front. */ for (iChannel = 0; iChannel < pSRC->config.channels; iChannel += 1) { memmove(pSRC->sinc.input[iChannel], pSRC->sinc.input[iChannel] + ma_countof(pSRC->sinc.input[iChannel]) - samplesToMove, samplesToMove * sizeof(*pSRC->sinc.input[iChannel])); } } /* Read more data from the client if required. */ if (pSRC->isEndOfInputLoaded) { pSRC->isEndOfInputLoaded = MA_FALSE; break; } /* Everything beyond this point is reloading. If we're at the end of the input data we do _not_ want to try reading any more in this function call. If the caller wants to keep trying, they can reload their internal data sources and call this function again. We should never be */ ma_assert(pSRC->isEndOfInputLoaded == MA_FALSE); if (pSRC->sinc.inputFrameCount <= pSRC->config.sinc.windowWidth || availableOutputFrames == 0) { float* ppInputDst[MA_MAX_CHANNELS] = {0}; ma_uint32 framesToReadFromClient; ma_uint32 framesReadFromClient; ma_uint32 leftoverFrames; for (iChannel = 0; iChannel < pSRC->config.channels; iChannel += 1) { ppInputDst[iChannel] = pSRC->sinc.input[iChannel] + pSRC->config.sinc.windowWidth + pSRC->sinc.inputFrameCount; } /* Now read data from the client. */ framesToReadFromClient = ma_countof(pSRC->sinc.input[0]) - (pSRC->config.sinc.windowWidth + pSRC->sinc.inputFrameCount); framesReadFromClient = 0; if (framesToReadFromClient > 0) { framesReadFromClient = pSRC->config.onReadDeinterleaved(pSRC, framesToReadFromClient, (void**)ppInputDst, pUserData); } if (framesReadFromClient != framesToReadFromClient) { pSRC->isEndOfInputLoaded = MA_TRUE; } else { pSRC->isEndOfInputLoaded = MA_FALSE; } if (framesReadFromClient != 0) { pSRC->sinc.inputFrameCount += framesReadFromClient; } else { /* We couldn't get anything more from the client. If no more output samples can be computed from the available input samples we need to return. */ if (pSRC->config.neverConsumeEndOfInput) { if ((pSRC->sinc.inputFrameCount * inverseFactor) <= pSRC->config.sinc.windowWidth) { break; } } else { if ((pSRC->sinc.inputFrameCount * inverseFactor) < 1) { break; } } } /* Anything left over in the cache must be set to zero. */ leftoverFrames = ma_countof(pSRC->sinc.input[0]) - (pSRC->config.sinc.windowWidth + pSRC->sinc.inputFrameCount); if (leftoverFrames > 0) { for (iChannel = 0; iChannel < pSRC->config.channels; iChannel += 1) { ma_zero_memory(pSRC->sinc.input[iChannel] + pSRC->config.sinc.windowWidth + pSRC->sinc.inputFrameCount, leftoverFrames * sizeof(float)); } } } } return totalOutputFramesRead; } /************************************************************************************************************************************************************** Format Conversion **************************************************************************************************************************************************************/ void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode) { if (formatOut == formatIn) { ma_copy_memory_64(pOut, pIn, sampleCount * ma_get_bytes_per_sample(formatOut)); return; } switch (formatIn) { case ma_format_u8: { switch (formatOut) { case ma_format_s16: ma_pcm_u8_to_s16(pOut, pIn, sampleCount, ditherMode); return; case ma_format_s24: ma_pcm_u8_to_s24(pOut, pIn, sampleCount, ditherMode); return; case ma_format_s32: ma_pcm_u8_to_s32(pOut, pIn, sampleCount, ditherMode); return; case ma_format_f32: ma_pcm_u8_to_f32(pOut, pIn, sampleCount, ditherMode); return; default: break; } } break; case ma_format_s16: { switch (formatOut) { case ma_format_u8: ma_pcm_s16_to_u8( pOut, pIn, sampleCount, ditherMode); return; case ma_format_s24: ma_pcm_s16_to_s24(pOut, pIn, sampleCount, ditherMode); return; case ma_format_s32: ma_pcm_s16_to_s32(pOut, pIn, sampleCount, ditherMode); return; case ma_format_f32: ma_pcm_s16_to_f32(pOut, pIn, sampleCount, ditherMode); return; default: break; } } break; case ma_format_s24: { switch (formatOut) { case ma_format_u8: ma_pcm_s24_to_u8( pOut, pIn, sampleCount, ditherMode); return; case ma_format_s16: ma_pcm_s24_to_s16(pOut, pIn, sampleCount, ditherMode); return; case ma_format_s32: ma_pcm_s24_to_s32(pOut, pIn, sampleCount, ditherMode); return; case ma_format_f32: ma_pcm_s24_to_f32(pOut, pIn, sampleCount, ditherMode); return; default: break; } } break; case ma_format_s32: { switch (formatOut) { case ma_format_u8: ma_pcm_s32_to_u8( pOut, pIn, sampleCount, ditherMode); return; case ma_format_s16: ma_pcm_s32_to_s16(pOut, pIn, sampleCount, ditherMode); return; case ma_format_s24: ma_pcm_s32_to_s24(pOut, pIn, sampleCount, ditherMode); return; case ma_format_f32: ma_pcm_s32_to_f32(pOut, pIn, sampleCount, ditherMode); return; default: break; } } break; case ma_format_f32: { switch (formatOut) { case ma_format_u8: ma_pcm_f32_to_u8( pOut, pIn, sampleCount, ditherMode); return; case ma_format_s16: ma_pcm_f32_to_s16(pOut, pIn, sampleCount, ditherMode); return; case ma_format_s24: ma_pcm_f32_to_s24(pOut, pIn, sampleCount, ditherMode); return; case ma_format_s32: ma_pcm_f32_to_s32(pOut, pIn, sampleCount, ditherMode); return; default: break; } } break; default: break; } } void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames) { if (pInterleavedPCMFrames == NULL || ppDeinterleavedPCMFrames == NULL) { return; /* Invalid args. */ } /* For efficiency we do this per format. */ switch (format) { case ma_format_s16: { const ma_int16* pSrcS16 = (const ma_int16*)pInterleavedPCMFrames; ma_uint64 iPCMFrame; for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { ma_int16* pDstS16 = (ma_int16*)ppDeinterleavedPCMFrames[iChannel]; pDstS16[iPCMFrame] = pSrcS16[iPCMFrame*channels+iChannel]; } } } break; case ma_format_f32: { const float* pSrcF32 = (const float*)pInterleavedPCMFrames; ma_uint64 iPCMFrame; for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { float* pDstF32 = (float*)ppDeinterleavedPCMFrames[iChannel]; pDstF32[iPCMFrame] = pSrcF32[iPCMFrame*channels+iChannel]; } } } break; default: { ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format); ma_uint64 iPCMFrame; for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { void* pDst = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes); const void* pSrc = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes); memcpy(pDst, pSrc, sampleSizeInBytes); } } } break; } } void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames) { switch (format) { case ma_format_s16: { ma_int16* pDstS16 = (ma_int16*)pInterleavedPCMFrames; ma_uint64 iPCMFrame; for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { const ma_int16* pSrcS16 = (const ma_int16*)ppDeinterleavedPCMFrames[iChannel]; pDstS16[iPCMFrame*channels+iChannel] = pSrcS16[iPCMFrame]; } } } break; case ma_format_f32: { float* pDstF32 = (float*)pInterleavedPCMFrames; ma_uint64 iPCMFrame; for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { const float* pSrcF32 = (const float*)ppDeinterleavedPCMFrames[iChannel]; pDstF32[iPCMFrame*channels+iChannel] = pSrcF32[iPCMFrame]; } } } break; default: { ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format); ma_uint64 iPCMFrame; for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { void* pDst = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes); const void* pSrc = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes); memcpy(pDst, pSrc, sampleSizeInBytes); } } } break; } } typedef struct { ma_pcm_converter* pDSP; void* pUserDataForClient; } ma_pcm_converter_callback_data; ma_uint32 ma_pcm_converter__pre_format_converter_on_read(ma_format_converter* pConverter, ma_uint32 frameCount, void* pFramesOut, void* pUserData) { ma_pcm_converter_callback_data* pData; ma_pcm_converter* pDSP; (void)pConverter; pData = (ma_pcm_converter_callback_data*)pUserData; ma_assert(pData != NULL); pDSP = pData->pDSP; ma_assert(pDSP != NULL); return pDSP->onRead(pDSP, pFramesOut, frameCount, pData->pUserDataForClient); } ma_uint32 ma_pcm_converter__post_format_converter_on_read(ma_format_converter* pConverter, ma_uint32 frameCount, void* pFramesOut, void* pUserData) { ma_pcm_converter_callback_data* pData; ma_pcm_converter* pDSP; (void)pConverter; pData = (ma_pcm_converter_callback_data*)pUserData; ma_assert(pData != NULL); pDSP = pData->pDSP; ma_assert(pDSP != NULL); /* When this version of this callback is used it means we're reading directly from the client. */ ma_assert(pDSP->isPreFormatConversionRequired == MA_FALSE); ma_assert(pDSP->isChannelRoutingRequired == MA_FALSE); ma_assert(pDSP->isSRCRequired == MA_FALSE); return pDSP->onRead(pDSP, pFramesOut, frameCount, pData->pUserDataForClient); } ma_uint32 ma_pcm_converter__post_format_converter_on_read_deinterleaved(ma_format_converter* pConverter, ma_uint32 frameCount, void** ppSamplesOut, void* pUserData) { ma_pcm_converter_callback_data* pData; ma_pcm_converter* pDSP; (void)pConverter; pData = (ma_pcm_converter_callback_data*)pUserData; ma_assert(pData != NULL); pDSP = pData->pDSP; ma_assert(pDSP != NULL); if (!pDSP->isChannelRoutingAtStart) { return (ma_uint32)ma_channel_router_read_deinterleaved(&pDSP->channelRouter, frameCount, ppSamplesOut, pUserData); } else { if (pDSP->isSRCRequired) { return (ma_uint32)ma_src_read_deinterleaved(&pDSP->src, frameCount, ppSamplesOut, pUserData); } else { return (ma_uint32)ma_channel_router_read_deinterleaved(&pDSP->channelRouter, frameCount, ppSamplesOut, pUserData); } } } ma_uint32 ma_pcm_converter__src_on_read_deinterleaved(ma_src* pSRC, ma_uint32 frameCount, void** ppSamplesOut, void* pUserData) { ma_pcm_converter_callback_data* pData; ma_pcm_converter* pDSP; (void)pSRC; pData = (ma_pcm_converter_callback_data*)pUserData; ma_assert(pData != NULL); pDSP = pData->pDSP; ma_assert(pDSP != NULL); /* If the channel routing stage is at the front we need to read from that. Otherwise we read from the pre format converter. */ if (pDSP->isChannelRoutingAtStart) { return (ma_uint32)ma_channel_router_read_deinterleaved(&pDSP->channelRouter, frameCount, ppSamplesOut, pUserData); } else { return (ma_uint32)ma_format_converter_read_deinterleaved(&pDSP->formatConverterIn, frameCount, ppSamplesOut, pUserData); } } ma_uint32 ma_pcm_converter__channel_router_on_read_deinterleaved(ma_channel_router* pRouter, ma_uint32 frameCount, void** ppSamplesOut, void* pUserData) { ma_pcm_converter_callback_data* pData; ma_pcm_converter* pDSP; (void)pRouter; pData = (ma_pcm_converter_callback_data*)pUserData; ma_assert(pData != NULL); pDSP = pData->pDSP; ma_assert(pDSP != NULL); /* If the channel routing stage is at the front of the pipeline we read from the pre format converter. Otherwise we read from the sample rate converter. */ if (pDSP->isChannelRoutingAtStart) { return (ma_uint32)ma_format_converter_read_deinterleaved(&pDSP->formatConverterIn, frameCount, ppSamplesOut, pUserData); } else { if (pDSP->isSRCRequired) { return (ma_uint32)ma_src_read_deinterleaved(&pDSP->src, frameCount, ppSamplesOut, pUserData); } else { return (ma_uint32)ma_format_converter_read_deinterleaved(&pDSP->formatConverterIn, frameCount, ppSamplesOut, pUserData); } } } ma_result ma_pcm_converter_init(const ma_pcm_converter_config* pConfig, ma_pcm_converter* pDSP) { ma_result result; if (pDSP == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pDSP); pDSP->onRead = pConfig->onRead; pDSP->pUserData = pConfig->pUserData; pDSP->isDynamicSampleRateAllowed = pConfig->allowDynamicSampleRate; /* In general, this is the pipeline used for data conversion. Note that this can actually change which is explained later. Pre Format Conversion -> Sample Rate Conversion -> Channel Routing -> Post Format Conversion Pre Format Conversion --------------------- This is where the sample data is converted to a format that's usable by the later stages in the pipeline. Input data is converted to deinterleaved floating-point. Channel Routing --------------- Channel routing is where stereo is converted to 5.1, mono is converted to stereo, etc. This stage depends on the pre format conversion stage. Sample Rate Conversion ---------------------- Sample rate conversion depends on the pre format conversion stage and as the name implies performs sample rate conversion. Post Format Conversion ---------------------- This stage is where our deinterleaved floating-point data from the previous stages are converted to the requested output format. Optimizations ------------- Sometimes the conversion pipeline is rearranged for efficiency. The first obvious optimization is to eliminate unnecessary stages in the pipeline. When no channel routing nor sample rate conversion is necessary, the entire pipeline is optimized down to just this: Post Format Conversion When sample rate conversion is not unnecessary: Pre Format Conversion -> Channel Routing -> Post Format Conversion When channel routing is unnecessary: Pre Format Conversion -> Sample Rate Conversion -> Post Format Conversion A slightly less obvious optimization is used depending on whether or not we are increasing or decreasing the number of channels. Because everything in the pipeline works on a per-channel basis, the efficiency of the pipeline is directly proportionate to the number of channels that need to be processed. Therefore, it's can be more efficient to move the channel conversion stage to an earlier or later stage. When the channel count is being reduced, we move the channel conversion stage to the start of the pipeline so that later stages can work on a smaller number of channels at a time. Otherwise, we move the channel conversion stage to the end of the pipeline. When reducing the channel count, the pipeline will look like this: Pre Format Conversion -> Channel Routing -> Sample Rate Conversion -> Post Format Conversion Notice how the Channel Routing and Sample Rate Conversion stages are swapped so that the SRC stage has less data to process. */ /* First we need to determine what's required and what's not. */ if (pConfig->sampleRateIn != pConfig->sampleRateOut || pConfig->allowDynamicSampleRate) { pDSP->isSRCRequired = MA_TRUE; } if (pConfig->channelsIn != pConfig->channelsOut || !ma_channel_map_equal(pConfig->channelsIn, pConfig->channelMapIn, pConfig->channelMapOut)) { pDSP->isChannelRoutingRequired = MA_TRUE; } /* If neither a sample rate conversion nor channel conversion is necessary we can skip the pre format conversion. */ if (!pDSP->isSRCRequired && !pDSP->isChannelRoutingRequired) { /* We don't need a pre format conversion stage, but we may still need a post format conversion stage. */ if (pConfig->formatIn != pConfig->formatOut) { pDSP->isPostFormatConversionRequired = MA_TRUE; } } else { pDSP->isPreFormatConversionRequired = MA_TRUE; pDSP->isPostFormatConversionRequired = MA_TRUE; } /* Use a passthrough if none of the stages are being used. */ if (!pDSP->isPreFormatConversionRequired && !pDSP->isPostFormatConversionRequired && !pDSP->isChannelRoutingRequired && !pDSP->isSRCRequired) { pDSP->isPassthrough = MA_TRUE; } /* Move the channel conversion stage to the start of the pipeline if we are reducing the channel count. */ if (pConfig->channelsOut < pConfig->channelsIn) { pDSP->isChannelRoutingAtStart = MA_TRUE; } /* We always initialize every stage of the pipeline regardless of whether or not the stage is used because it simplifies a few things when it comes to dynamically changing properties post-initialization. */ result = MA_SUCCESS; /* Pre format conversion. */ { ma_format_converter_config preFormatConverterConfig = ma_format_converter_config_init( pConfig->formatIn, ma_format_f32, pConfig->channelsIn, ma_pcm_converter__pre_format_converter_on_read, pDSP ); preFormatConverterConfig.ditherMode = pConfig->ditherMode; preFormatConverterConfig.noSSE2 = pConfig->noSSE2; preFormatConverterConfig.noAVX2 = pConfig->noAVX2; preFormatConverterConfig.noAVX512 = pConfig->noAVX512; preFormatConverterConfig.noNEON = pConfig->noNEON; result = ma_format_converter_init(&preFormatConverterConfig, &pDSP->formatConverterIn); if (result != MA_SUCCESS) { return result; } } /* Post format conversion. The exact configuration for this depends on whether or not we are reading data directly from the client or from an earlier stage in the pipeline. */ { ma_format_converter_config postFormatConverterConfig = ma_format_converter_config_init_new(); postFormatConverterConfig.formatIn = pConfig->formatIn; postFormatConverterConfig.formatOut = pConfig->formatOut; postFormatConverterConfig.channels = pConfig->channelsOut; postFormatConverterConfig.ditherMode = pConfig->ditherMode; postFormatConverterConfig.noSSE2 = pConfig->noSSE2; postFormatConverterConfig.noAVX2 = pConfig->noAVX2; postFormatConverterConfig.noAVX512 = pConfig->noAVX512; postFormatConverterConfig.noNEON = pConfig->noNEON; if (pDSP->isPreFormatConversionRequired) { postFormatConverterConfig.onReadDeinterleaved = ma_pcm_converter__post_format_converter_on_read_deinterleaved; postFormatConverterConfig.formatIn = ma_format_f32; } else { postFormatConverterConfig.onRead = ma_pcm_converter__post_format_converter_on_read; } result = ma_format_converter_init(&postFormatConverterConfig, &pDSP->formatConverterOut); if (result != MA_SUCCESS) { return result; } } /* SRC */ { ma_src_config srcConfig = ma_src_config_init( pConfig->sampleRateIn, pConfig->sampleRateOut, ((pConfig->channelsIn < pConfig->channelsOut) ? pConfig->channelsIn : pConfig->channelsOut), ma_pcm_converter__src_on_read_deinterleaved, pDSP ); srcConfig.algorithm = pConfig->srcAlgorithm; srcConfig.neverConsumeEndOfInput = pConfig->neverConsumeEndOfInput; srcConfig.noSSE2 = pConfig->noSSE2; srcConfig.noAVX2 = pConfig->noAVX2; srcConfig.noAVX512 = pConfig->noAVX512; srcConfig.noNEON = pConfig->noNEON; ma_copy_memory(&srcConfig.sinc, &pConfig->sinc, sizeof(pConfig->sinc)); result = ma_src_init(&srcConfig, &pDSP->src); if (result != MA_SUCCESS) { return result; } } /* Channel conversion */ { ma_channel_router_config routerConfig = ma_channel_router_config_init( pConfig->channelsIn, pConfig->channelMapIn, pConfig->channelsOut, pConfig->channelMapOut, pConfig->channelMixMode, ma_pcm_converter__channel_router_on_read_deinterleaved, pDSP); routerConfig.noSSE2 = pConfig->noSSE2; routerConfig.noAVX2 = pConfig->noAVX2; routerConfig.noAVX512 = pConfig->noAVX512; routerConfig.noNEON = pConfig->noNEON; result = ma_channel_router_init(&routerConfig, &pDSP->channelRouter); if (result != MA_SUCCESS) { return result; } } return MA_SUCCESS; } ma_result ma_pcm_converter_refresh_sample_rate(ma_pcm_converter* pDSP) { /* The SRC stage will already have been initialized so we can just set it there. */ ma_src_set_sample_rate(&pDSP->src, pDSP->src.config.sampleRateIn, pDSP->src.config.sampleRateOut); return MA_SUCCESS; } ma_result ma_pcm_converter_set_input_sample_rate(ma_pcm_converter* pDSP, ma_uint32 sampleRateIn) { if (pDSP == NULL) { return MA_INVALID_ARGS; } /* Must have a sample rate of > 0. */ if (sampleRateIn == 0) { return MA_INVALID_ARGS; } /* Must have been initialized with allowDynamicSampleRate. */ if (!pDSP->isDynamicSampleRateAllowed) { return MA_INVALID_OPERATION; } ma_atomic_exchange_32(&pDSP->src.config.sampleRateIn, sampleRateIn); return ma_pcm_converter_refresh_sample_rate(pDSP); } ma_result ma_pcm_converter_set_output_sample_rate(ma_pcm_converter* pDSP, ma_uint32 sampleRateOut) { if (pDSP == NULL) { return MA_INVALID_ARGS; } /* Must have a sample rate of > 0. */ if (sampleRateOut == 0) { return MA_INVALID_ARGS; } /* Must have been initialized with allowDynamicSampleRate. */ if (!pDSP->isDynamicSampleRateAllowed) { return MA_INVALID_OPERATION; } ma_atomic_exchange_32(&pDSP->src.config.sampleRateOut, sampleRateOut); return ma_pcm_converter_refresh_sample_rate(pDSP); } ma_result ma_pcm_converter_set_sample_rate(ma_pcm_converter* pDSP, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) { if (pDSP == NULL) { return MA_INVALID_ARGS; } /* Must have a sample rate of > 0. */ if (sampleRateIn == 0 || sampleRateOut == 0) { return MA_INVALID_ARGS; } /* Must have been initialized with allowDynamicSampleRate. */ if (!pDSP->isDynamicSampleRateAllowed) { return MA_INVALID_OPERATION; } ma_atomic_exchange_32(&pDSP->src.config.sampleRateIn, sampleRateIn); ma_atomic_exchange_32(&pDSP->src.config.sampleRateOut, sampleRateOut); return ma_pcm_converter_refresh_sample_rate(pDSP); } ma_uint64 ma_pcm_converter_read(ma_pcm_converter* pDSP, void* pFramesOut, ma_uint64 frameCount) { ma_pcm_converter_callback_data data; if (pDSP == NULL || pFramesOut == NULL) { return 0; } /* Fast path. */ if (pDSP->isPassthrough) { if (frameCount <= 0xFFFFFFFF) { return (ma_uint32)pDSP->onRead(pDSP, pFramesOut, (ma_uint32)frameCount, pDSP->pUserData); } else { ma_uint8* pNextFramesOut = (ma_uint8*)pFramesOut; ma_uint64 totalFramesRead = 0; while (totalFramesRead < frameCount) { ma_uint32 framesRead; ma_uint64 framesRemaining = (frameCount - totalFramesRead); ma_uint64 framesToReadRightNow = framesRemaining; if (framesToReadRightNow > 0xFFFFFFFF) { framesToReadRightNow = 0xFFFFFFFF; } framesRead = pDSP->onRead(pDSP, pNextFramesOut, (ma_uint32)framesToReadRightNow, pDSP->pUserData); if (framesRead == 0) { break; } pNextFramesOut += framesRead * pDSP->channelRouter.config.channelsOut * ma_get_bytes_per_sample(pDSP->formatConverterOut.config.formatOut); totalFramesRead += framesRead; } return totalFramesRead; } } /* Slower path. The real work is done here. To do this all we need to do is read from the last stage in the pipeline. */ ma_assert(pDSP->isPostFormatConversionRequired == MA_TRUE); data.pDSP = pDSP; data.pUserDataForClient = pDSP->pUserData; return ma_format_converter_read(&pDSP->formatConverterOut, frameCount, pFramesOut, &data); } typedef struct { const void* pDataIn; ma_format formatIn; ma_uint32 channelsIn; ma_uint64 totalFrameCount; ma_uint64 iNextFrame; ma_bool32 isFeedingZeros; /* When set to true, feeds the DSP zero samples. */ } ma_convert_frames__data; ma_uint32 ma_convert_frames__on_read(ma_pcm_converter* pDSP, void* pFramesOut, ma_uint32 frameCount, void* pUserData) { ma_convert_frames__data* pData; ma_uint32 framesToRead; ma_uint64 framesRemaining; ma_uint32 frameSizeInBytes; (void)pDSP; pData = (ma_convert_frames__data*)pUserData; ma_assert(pData != NULL); ma_assert(pData->totalFrameCount >= pData->iNextFrame); framesToRead = frameCount; framesRemaining = (pData->totalFrameCount - pData->iNextFrame); if (framesToRead > framesRemaining) { framesToRead = (ma_uint32)framesRemaining; } frameSizeInBytes = ma_get_bytes_per_frame(pData->formatIn, pData->channelsIn); if (!pData->isFeedingZeros) { ma_copy_memory(pFramesOut, (const ma_uint8*)pData->pDataIn + (frameSizeInBytes * pData->iNextFrame), frameSizeInBytes * framesToRead); } else { ma_zero_memory(pFramesOut, frameSizeInBytes * framesToRead); } pData->iNextFrame += framesToRead; return framesToRead; } ma_pcm_converter_config ma_pcm_converter_config_init_new() { ma_pcm_converter_config config; ma_zero_object(&config); return config; } ma_pcm_converter_config ma_pcm_converter_config_init(ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, ma_pcm_converter_read_proc onRead, void* pUserData) { return ma_pcm_converter_config_init_ex(formatIn, channelsIn, sampleRateIn, NULL, formatOut, channelsOut, sampleRateOut, NULL, onRead, pUserData); } ma_pcm_converter_config ma_pcm_converter_config_init_ex(ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_channel channelMapIn[MA_MAX_CHANNELS], ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, ma_channel channelMapOut[MA_MAX_CHANNELS], ma_pcm_converter_read_proc onRead, void* pUserData) { ma_pcm_converter_config config; ma_zero_object(&config); config.formatIn = formatIn; config.channelsIn = channelsIn; config.sampleRateIn = sampleRateIn; config.formatOut = formatOut; config.channelsOut = channelsOut; config.sampleRateOut = sampleRateOut; if (channelMapIn != NULL) { ma_copy_memory(config.channelMapIn, channelMapIn, sizeof(config.channelMapIn)); } if (channelMapOut != NULL) { ma_copy_memory(config.channelMapOut, channelMapOut, sizeof(config.channelMapOut)); } config.onRead = onRead; config.pUserData = pUserData; return config; } ma_uint64 ma_convert_frames(void* pOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void* pIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_uint64 frameCount) { ma_channel channelMapOut[MA_MAX_CHANNELS]; ma_channel channelMapIn[MA_MAX_CHANNELS]; ma_get_standard_channel_map(ma_standard_channel_map_default, channelsOut, channelMapOut); ma_get_standard_channel_map(ma_standard_channel_map_default, channelsIn, channelMapIn); return ma_convert_frames_ex(pOut, formatOut, channelsOut, sampleRateOut, channelMapOut, pIn, formatIn, channelsIn, sampleRateIn, channelMapIn, frameCount); } ma_uint64 ma_convert_frames_ex(void* pOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, ma_channel channelMapOut[MA_MAX_CHANNELS], const void* pIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint64 frameCount) { ma_uint64 frameCountOut; ma_convert_frames__data data; ma_pcm_converter_config converterConfig; ma_pcm_converter converter; ma_uint64 totalFramesRead; if (frameCount == 0) { return 0; } frameCountOut = ma_calculate_frame_count_after_src(sampleRateOut, sampleRateIn, frameCount); if (pOut == NULL) { return frameCountOut; } data.pDataIn = pIn; data.formatIn = formatIn; data.channelsIn = channelsIn; data.totalFrameCount = frameCount; data.iNextFrame = 0; data.isFeedingZeros = MA_FALSE; ma_zero_object(&converterConfig); converterConfig.formatIn = formatIn; converterConfig.channelsIn = channelsIn; converterConfig.sampleRateIn = sampleRateIn; if (channelMapIn != NULL) { ma_channel_map_copy(converterConfig.channelMapIn, channelMapIn, channelsIn); } else { ma_get_standard_channel_map(ma_standard_channel_map_default, converterConfig.channelsIn, converterConfig.channelMapIn); } converterConfig.formatOut = formatOut; converterConfig.channelsOut = channelsOut; converterConfig.sampleRateOut = sampleRateOut; if (channelMapOut != NULL) { ma_channel_map_copy(converterConfig.channelMapOut, channelMapOut, channelsOut); } else { ma_get_standard_channel_map(ma_standard_channel_map_default, converterConfig.channelsOut, converterConfig.channelMapOut); } converterConfig.onRead = ma_convert_frames__on_read; converterConfig.pUserData = &data; if (ma_pcm_converter_init(&converterConfig, &converter) != MA_SUCCESS) { return 0; } /* Always output our computed frame count. There is a chance the sample rate conversion routine may not output the last sample due to precision issues with 32-bit floats, in which case we should feed the DSP zero samples so it can generate that last frame. */ totalFramesRead = ma_pcm_converter_read(&converter, pOut, frameCountOut); if (totalFramesRead < frameCountOut) { ma_uint32 bpf = ma_get_bytes_per_frame(formatIn, channelsIn); data.isFeedingZeros = MA_TRUE; data.totalFrameCount = ((ma_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF; /* C89 does not support 64-bit constants so need to instead construct it like this. Annoying... */ /*data.totalFrameCount = 0xFFFFFFFFFFFFFFFF;*/ data.pDataIn = NULL; while (totalFramesRead < frameCountOut) { ma_uint64 framesToRead; ma_uint64 framesJustRead; framesToRead = (frameCountOut - totalFramesRead); ma_assert(framesToRead > 0); framesJustRead = ma_pcm_converter_read(&converter, ma_offset_ptr(pOut, totalFramesRead * bpf), framesToRead); totalFramesRead += framesJustRead; if (framesJustRead < framesToRead) { break; } } /* At this point we should have output every sample, but just to be super duper sure, just fill the rest with zeros. */ if (totalFramesRead < frameCountOut) { ma_zero_memory_64(ma_offset_ptr(pOut, totalFramesRead * bpf), ((frameCountOut - totalFramesRead) * bpf)); totalFramesRead = frameCountOut; } } ma_assert(totalFramesRead == frameCountOut); return totalFramesRead; } /************************************************************************************************************************************************************** Ring Buffer **************************************************************************************************************************************************************/ MA_INLINE ma_uint32 ma_rb__extract_offset_in_bytes(ma_uint32 encodedOffset) { return encodedOffset & 0x7FFFFFFF; } MA_INLINE ma_uint32 ma_rb__extract_offset_loop_flag(ma_uint32 encodedOffset) { return encodedOffset & 0x80000000; } MA_INLINE void* ma_rb__get_read_ptr(ma_rb* pRB) { ma_assert(pRB != NULL); return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(pRB->encodedReadOffset)); } MA_INLINE void* ma_rb__get_write_ptr(ma_rb* pRB) { ma_assert(pRB != NULL); return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(pRB->encodedWriteOffset)); } MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag) { return offsetLoopFlag | offsetInBytes; } MA_INLINE void ma_rb__deconstruct_offset(ma_uint32 encodedOffset, ma_uint32* pOffsetInBytes, ma_uint32* pOffsetLoopFlag) { ma_assert(pOffsetInBytes != NULL); ma_assert(pOffsetLoopFlag != NULL); *pOffsetInBytes = ma_rb__extract_offset_in_bytes(encodedOffset); *pOffsetLoopFlag = ma_rb__extract_offset_loop_flag(encodedOffset); } ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void* pOptionalPreallocatedBuffer, ma_rb* pRB) { const ma_uint32 maxSubBufferSize = 0x7FFFFFFF - (MA_SIMD_ALIGNMENT-1); if (pRB == NULL) { return MA_INVALID_ARGS; } if (subbufferSizeInBytes == 0 || subbufferCount == 0) { return MA_INVALID_ARGS; } if (subbufferSizeInBytes > maxSubBufferSize) { return MA_INVALID_ARGS; /* Maximum buffer size is ~2GB. The most significant bit is a flag for use internally. */ } ma_zero_object(pRB); pRB->subbufferSizeInBytes = (ma_uint32)subbufferSizeInBytes; pRB->subbufferCount = (ma_uint32)subbufferCount; if (pOptionalPreallocatedBuffer != NULL) { pRB->subbufferStrideInBytes = (ma_uint32)subbufferStrideInBytes; pRB->pBuffer = pOptionalPreallocatedBuffer; } else { size_t bufferSizeInBytes; /* Here is where we allocate our own buffer. We always want to align this to MA_SIMD_ALIGNMENT for future SIMD optimization opportunity. To do this we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT. */ pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT; bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes; pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT); if (pRB->pBuffer == NULL) { return MA_OUT_OF_MEMORY; } ma_zero_memory(pRB->pBuffer, bufferSizeInBytes); pRB->ownsBuffer = MA_TRUE; } return MA_SUCCESS; } ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, ma_rb* pRB) { return ma_rb_init_ex(bufferSizeInBytes, 1, 0, pOptionalPreallocatedBuffer, pRB); } void ma_rb_uninit(ma_rb* pRB) { if (pRB == NULL) { return; } if (pRB->ownsBuffer) { ma_aligned_free(pRB->pBuffer); } } ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut) { ma_uint32 writeOffset; ma_uint32 writeOffsetInBytes; ma_uint32 writeOffsetLoopFlag; ma_uint32 readOffset; ma_uint32 readOffsetInBytes; ma_uint32 readOffsetLoopFlag; size_t bytesAvailable; size_t bytesRequested; if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) { return MA_INVALID_ARGS; } /* The returned buffer should never move ahead of the write pointer. */ writeOffset = pRB->encodedWriteOffset; ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); readOffset = pRB->encodedReadOffset; ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); /* The number of bytes available depends on whether or not the read and write pointers are on the same loop iteration. If so, we can only read up to the write pointer. If not, we can only read up to the end of the buffer. */ if (readOffsetLoopFlag == writeOffsetLoopFlag) { bytesAvailable = writeOffsetInBytes - readOffsetInBytes; } else { bytesAvailable = pRB->subbufferSizeInBytes - readOffsetInBytes; } bytesRequested = *pSizeInBytes; if (bytesRequested > bytesAvailable) { bytesRequested = bytesAvailable; } *pSizeInBytes = bytesRequested; (*ppBufferOut) = ma_rb__get_read_ptr(pRB); return MA_SUCCESS; } ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut) { ma_uint32 readOffset; ma_uint32 readOffsetInBytes; ma_uint32 readOffsetLoopFlag; ma_uint32 newReadOffsetInBytes; ma_uint32 newReadOffsetLoopFlag; if (pRB == NULL) { return MA_INVALID_ARGS; } /* Validate the buffer. */ if (pBufferOut != ma_rb__get_read_ptr(pRB)) { return MA_INVALID_ARGS; } readOffset = pRB->encodedReadOffset; ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */ newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + sizeInBytes); if (newReadOffsetInBytes > pRB->subbufferSizeInBytes) { return MA_INVALID_ARGS; /* <-- sizeInBytes will cause the read offset to overflow. */ } /* Move the read pointer back to the start if necessary. */ newReadOffsetLoopFlag = readOffsetLoopFlag; if (newReadOffsetInBytes == pRB->subbufferSizeInBytes) { newReadOffsetInBytes = 0; newReadOffsetLoopFlag ^= 0x80000000; } ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetLoopFlag, newReadOffsetInBytes)); return MA_SUCCESS; } ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut) { ma_uint32 readOffset; ma_uint32 readOffsetInBytes; ma_uint32 readOffsetLoopFlag; ma_uint32 writeOffset; ma_uint32 writeOffsetInBytes; ma_uint32 writeOffsetLoopFlag; size_t bytesAvailable; size_t bytesRequested; if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) { return MA_INVALID_ARGS; } /* The returned buffer should never overtake the read buffer. */ readOffset = pRB->encodedReadOffset; ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); writeOffset = pRB->encodedWriteOffset; ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); /* In the case of writing, if the write pointer and the read pointer are on the same loop iteration we can only write up to the end of the buffer. Otherwise we can only write up to the read pointer. The write pointer should never overtake the read pointer. */ if (writeOffsetLoopFlag == readOffsetLoopFlag) { bytesAvailable = pRB->subbufferSizeInBytes - writeOffsetInBytes; } else { bytesAvailable = readOffsetInBytes - writeOffsetInBytes; } bytesRequested = *pSizeInBytes; if (bytesRequested > bytesAvailable) { bytesRequested = bytesAvailable; } *pSizeInBytes = bytesRequested; *ppBufferOut = ma_rb__get_write_ptr(pRB); /* Clear the buffer if desired. */ if (pRB->clearOnWriteAcquire) { ma_zero_memory(*ppBufferOut, *pSizeInBytes); } return MA_SUCCESS; } ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut) { ma_uint32 writeOffset; ma_uint32 writeOffsetInBytes; ma_uint32 writeOffsetLoopFlag; ma_uint32 newWriteOffsetInBytes; ma_uint32 newWriteOffsetLoopFlag; if (pRB == NULL) { return MA_INVALID_ARGS; } /* Validate the buffer. */ if (pBufferOut != ma_rb__get_write_ptr(pRB)) { return MA_INVALID_ARGS; } writeOffset = pRB->encodedWriteOffset; ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */ newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + sizeInBytes); if (newWriteOffsetInBytes > pRB->subbufferSizeInBytes) { return MA_INVALID_ARGS; /* <-- sizeInBytes will cause the read offset to overflow. */ } /* Move the read pointer back to the start if necessary. */ newWriteOffsetLoopFlag = writeOffsetLoopFlag; if (newWriteOffsetInBytes == pRB->subbufferSizeInBytes) { newWriteOffsetInBytes = 0; newWriteOffsetLoopFlag ^= 0x80000000; } ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetLoopFlag, newWriteOffsetInBytes)); return MA_SUCCESS; } ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes) { ma_uint32 readOffset; ma_uint32 readOffsetInBytes; ma_uint32 readOffsetLoopFlag; ma_uint32 writeOffset; ma_uint32 writeOffsetInBytes; ma_uint32 writeOffsetLoopFlag; ma_uint32 newReadOffsetInBytes; ma_uint32 newReadOffsetLoopFlag; if (pRB == NULL || offsetInBytes > pRB->subbufferSizeInBytes) { return MA_INVALID_ARGS; } readOffset = pRB->encodedReadOffset; ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); writeOffset = pRB->encodedWriteOffset; ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); newReadOffsetInBytes = readOffsetInBytes; newReadOffsetLoopFlag = readOffsetLoopFlag; /* We cannot go past the write buffer. */ if (readOffsetLoopFlag == writeOffsetLoopFlag) { if ((readOffsetInBytes + offsetInBytes) > writeOffsetInBytes) { newReadOffsetInBytes = writeOffsetInBytes; } else { newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes); } } else { /* May end up looping. */ if ((readOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) { newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes; newReadOffsetLoopFlag ^= 0x80000000; /* <-- Looped. */ } else { newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes); } } ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag)); return MA_SUCCESS; } ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes) { ma_uint32 readOffset; ma_uint32 readOffsetInBytes; ma_uint32 readOffsetLoopFlag; ma_uint32 writeOffset; ma_uint32 writeOffsetInBytes; ma_uint32 writeOffsetLoopFlag; ma_uint32 newWriteOffsetInBytes; ma_uint32 newWriteOffsetLoopFlag; if (pRB == NULL) { return MA_INVALID_ARGS; } readOffset = pRB->encodedReadOffset; ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); writeOffset = pRB->encodedWriteOffset; ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); newWriteOffsetInBytes = writeOffsetInBytes; newWriteOffsetLoopFlag = writeOffsetLoopFlag; /* We cannot go past the write buffer. */ if (readOffsetLoopFlag == writeOffsetLoopFlag) { /* May end up looping. */ if ((writeOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) { newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes; newWriteOffsetLoopFlag ^= 0x80000000; /* <-- Looped. */ } else { newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes); } } else { if ((writeOffsetInBytes + offsetInBytes) > readOffsetInBytes) { newWriteOffsetInBytes = readOffsetInBytes; } else { newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes); } } ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag)); return MA_SUCCESS; } ma_int32 ma_rb_pointer_distance(ma_rb* pRB) { ma_uint32 readOffset; ma_uint32 readOffsetInBytes; ma_uint32 readOffsetLoopFlag; ma_uint32 writeOffset; ma_uint32 writeOffsetInBytes; ma_uint32 writeOffsetLoopFlag; if (pRB == NULL) { return 0; } readOffset = pRB->encodedReadOffset; ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); writeOffset = pRB->encodedWriteOffset; ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); if (readOffsetLoopFlag == writeOffsetLoopFlag) { return writeOffsetInBytes - readOffsetInBytes; } else { return writeOffsetInBytes + (pRB->subbufferSizeInBytes - readOffsetInBytes); } } size_t ma_rb_get_subbuffer_size(ma_rb* pRB) { if (pRB == NULL) { return 0; } return pRB->subbufferSizeInBytes; } size_t ma_rb_get_subbuffer_stride(ma_rb* pRB) { if (pRB == NULL) { return 0; } if (pRB->subbufferStrideInBytes == 0) { return (size_t)pRB->subbufferSizeInBytes; } return (size_t)pRB->subbufferStrideInBytes; } size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex) { if (pRB == NULL) { return 0; } return subbufferIndex * ma_rb_get_subbuffer_stride(pRB); } void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer) { if (pRB == NULL) { return NULL; } return ma_offset_ptr(pBuffer, ma_rb_get_subbuffer_offset(pRB, subbufferIndex)); } static MA_INLINE ma_uint32 ma_pcm_rb_get_bpf(ma_pcm_rb* pRB) { ma_assert(pRB != NULL); return ma_get_bytes_per_frame(pRB->format, pRB->channels); } ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, ma_pcm_rb* pRB) { ma_uint32 bpf; ma_result result; if (pRB == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pRB); bpf = ma_get_bytes_per_frame(format, channels); if (bpf == 0) { return MA_INVALID_ARGS; } result = ma_rb_init_ex(subbufferSizeInFrames*bpf, subbufferCount, subbufferStrideInFrames*bpf, pOptionalPreallocatedBuffer, &pRB->rb); if (result != MA_SUCCESS) { return result; } pRB->format = format; pRB->channels = channels; return MA_SUCCESS; } ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void* pOptionalPreallocatedBuffer, ma_pcm_rb* pRB) { return ma_pcm_rb_init_ex(format, channels, bufferSizeInFrames, 1, 0, pOptionalPreallocatedBuffer, pRB); } void ma_pcm_rb_uninit(ma_pcm_rb* pRB) { if (pRB == NULL) { return; } ma_rb_uninit(&pRB->rb); } ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut) { size_t sizeInBytes; ma_result result; if (pRB == NULL || pSizeInFrames == NULL) { return MA_INVALID_ARGS; } sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB); result = ma_rb_acquire_read(&pRB->rb, &sizeInBytes, ppBufferOut); if (result != MA_SUCCESS) { return result; } *pSizeInFrames = (ma_uint32)(sizeInBytes / (size_t)ma_pcm_rb_get_bpf(pRB)); return MA_SUCCESS; } ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut) { if (pRB == NULL) { return MA_INVALID_ARGS; } return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut); } ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut) { size_t sizeInBytes; ma_result result; if (pRB == NULL) { return MA_INVALID_ARGS; } sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB); result = ma_rb_acquire_write(&pRB->rb, &sizeInBytes, ppBufferOut); if (result != MA_SUCCESS) { return result; } *pSizeInFrames = (ma_uint32)(sizeInBytes / ma_pcm_rb_get_bpf(pRB)); return MA_SUCCESS; } ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut) { if (pRB == NULL) { return MA_INVALID_ARGS; } return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut); } ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames) { if (pRB == NULL) { return MA_INVALID_ARGS; } return ma_rb_seek_read(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB)); } ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames) { if (pRB == NULL) { return MA_INVALID_ARGS; } return ma_rb_seek_write(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB)); } ma_int32 ma_pcm_rb_pointer_disance(ma_pcm_rb* pRB) { if (pRB == NULL) { return MA_INVALID_ARGS; } return ma_rb_pointer_distance(&pRB->rb) / ma_pcm_rb_get_bpf(pRB); } ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB) { if (pRB == NULL) { return 0; } return (ma_uint32)(ma_rb_get_subbuffer_size(&pRB->rb) / ma_pcm_rb_get_bpf(pRB)); } ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB) { if (pRB == NULL) { return 0; } return (ma_uint32)(ma_rb_get_subbuffer_stride(&pRB->rb) / ma_pcm_rb_get_bpf(pRB)); } ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex) { if (pRB == NULL) { return 0; } return (ma_uint32)(ma_rb_get_subbuffer_offset(&pRB->rb, subbufferIndex) / ma_pcm_rb_get_bpf(pRB)); } void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer) { if (pRB == NULL) { return NULL; } return ma_rb_get_subbuffer_ptr(&pRB->rb, subbufferIndex, pBuffer); } /************************************************************************************************************************************************************** Miscellaneous Helpers **************************************************************************************************************************************************************/ void* ma_malloc(size_t sz) { return MA_MALLOC(sz); } void* ma_realloc(void* p, size_t sz) { return MA_REALLOC(p, sz); } void ma_free(void* p) { MA_FREE(p); } void* ma_aligned_malloc(size_t sz, size_t alignment) { size_t extraBytes; void* pUnaligned; void* pAligned; if (alignment == 0) { return 0; } extraBytes = alignment-1 + sizeof(void*); pUnaligned = ma_malloc(sz + extraBytes); if (pUnaligned == NULL) { return NULL; } pAligned = (void*)(((ma_uintptr)pUnaligned + extraBytes) & ~((ma_uintptr)(alignment-1))); ((void**)pAligned)[-1] = pUnaligned; return pAligned; } void ma_aligned_free(void* p) { ma_free(((void**)p)[-1]); } const char* ma_get_format_name(ma_format format) { switch (format) { case ma_format_unknown: return "Unknown"; case ma_format_u8: return "8-bit Unsigned Integer"; case ma_format_s16: return "16-bit Signed Integer"; case ma_format_s24: return "24-bit Signed Integer (Tightly Packed)"; case ma_format_s32: return "32-bit Signed Integer"; case ma_format_f32: return "32-bit IEEE Floating Point"; default: return "Invalid"; } } void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels) { ma_uint32 i; for (i = 0; i < channels; ++i) { pOut[i] = ma_mix_f32(pInA[i], pInB[i], factor); } } ma_uint32 ma_get_bytes_per_sample(ma_format format) { ma_uint32 sizes[] = { 0, /* unknown */ 1, /* u8 */ 2, /* s16 */ 3, /* s24 */ 4, /* s32 */ 4, /* f32 */ }; return sizes[format]; } /************************************************************************************************************************************************************** Decoding **************************************************************************************************************************************************************/ #ifndef MA_NO_DECODING size_t ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) { size_t bytesRead; ma_assert(pDecoder != NULL); ma_assert(pBufferOut != NULL); bytesRead = pDecoder->onRead(pDecoder, pBufferOut, bytesToRead); pDecoder->readPointer += bytesRead; return bytesRead; } ma_bool32 ma_decoder_seek_bytes(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin) { ma_bool32 wasSuccessful; ma_assert(pDecoder != NULL); wasSuccessful = pDecoder->onSeek(pDecoder, byteOffset, origin); if (wasSuccessful) { if (origin == ma_seek_origin_start) { pDecoder->readPointer = (ma_uint64)byteOffset; } else { pDecoder->readPointer += byteOffset; } } return wasSuccessful; } ma_bool32 ma_decoder_seek_bytes_64(ma_decoder* pDecoder, ma_uint64 byteOffset, ma_seek_origin origin) { ma_assert(pDecoder != NULL); if (origin == ma_seek_origin_start) { ma_uint64 bytesToSeekThisIteration = 0x7FFFFFFF; if (bytesToSeekThisIteration > byteOffset) { bytesToSeekThisIteration = byteOffset; } if (!ma_decoder_seek_bytes(pDecoder, (int)bytesToSeekThisIteration, ma_seek_origin_start)) { return MA_FALSE; } byteOffset -= bytesToSeekThisIteration; } /* Getting here means we need to seek relative to the current position. */ while (byteOffset > 0) { ma_uint64 bytesToSeekThisIteration = 0x7FFFFFFF; if (bytesToSeekThisIteration > byteOffset) { bytesToSeekThisIteration = byteOffset; } if (!ma_decoder_seek_bytes(pDecoder, (int)bytesToSeekThisIteration, ma_seek_origin_current)) { return MA_FALSE; } byteOffset -= bytesToSeekThisIteration; } return MA_TRUE; } ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate) { ma_decoder_config config; ma_zero_object(&config); config.format = outputFormat; config.channels = outputChannels; config.sampleRate = outputSampleRate; ma_get_standard_channel_map(ma_standard_channel_map_default, config.channels, config.channelMap); return config; } ma_decoder_config ma_decoder_config_init_copy(const ma_decoder_config* pConfig) { ma_decoder_config config; if (pConfig != NULL) { config = *pConfig; } else { ma_zero_object(&config); } return config; } ma_result ma_decoder__init_dsp(ma_decoder* pDecoder, const ma_decoder_config* pConfig, ma_pcm_converter_read_proc onRead) { ma_pcm_converter_config dspConfig; ma_assert(pDecoder != NULL); /* Output format. */ if (pConfig->format == ma_format_unknown) { pDecoder->outputFormat = pDecoder->internalFormat; } else { pDecoder->outputFormat = pConfig->format; } if (pConfig->channels == 0) { pDecoder->outputChannels = pDecoder->internalChannels; } else { pDecoder->outputChannels = pConfig->channels; } if (pConfig->sampleRate == 0) { pDecoder->outputSampleRate = pDecoder->internalSampleRate; } else { pDecoder->outputSampleRate = pConfig->sampleRate; } if (ma_channel_map_blank(pDecoder->outputChannels, pConfig->channelMap)) { ma_get_standard_channel_map(ma_standard_channel_map_default, pDecoder->outputChannels, pDecoder->outputChannelMap); } else { ma_copy_memory(pDecoder->outputChannelMap, pConfig->channelMap, sizeof(pConfig->channelMap)); } /* DSP. */ dspConfig = ma_pcm_converter_config_init_ex( pDecoder->internalFormat, pDecoder->internalChannels, pDecoder->internalSampleRate, pDecoder->internalChannelMap, pDecoder->outputFormat, pDecoder->outputChannels, pDecoder->outputSampleRate, pDecoder->outputChannelMap, onRead, pDecoder); dspConfig.channelMixMode = pConfig->channelMixMode; dspConfig.ditherMode = pConfig->ditherMode; dspConfig.srcAlgorithm = pConfig->srcAlgorithm; dspConfig.sinc = pConfig->src.sinc; return ma_pcm_converter_init(&dspConfig, &pDecoder->dsp); } /* WAV */ #ifdef dr_wav_h #define MA_HAS_WAV size_t ma_decoder_internal_on_read__wav(void* pUserData, void* pBufferOut, size_t bytesToRead) { ma_decoder* pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead); } drwav_bool32 ma_decoder_internal_on_seek__wav(void* pUserData, int offset, drwav_seek_origin origin) { ma_decoder* pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); return ma_decoder_seek_bytes(pDecoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); } ma_uint32 ma_decoder_internal_on_read_pcm_frames__wav(ma_pcm_converter* pDSP, void* pSamplesOut, ma_uint32 frameCount, void* pUserData) { ma_decoder* pDecoder; drwav* pWav; (void)pDSP; pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); pWav = (drwav*)pDecoder->pInternalDecoder; ma_assert(pWav != NULL); switch (pDecoder->internalFormat) { case ma_format_s16: return (ma_uint32)drwav_read_pcm_frames_s16(pWav, frameCount, (drwav_int16*)pSamplesOut); case ma_format_s32: return (ma_uint32)drwav_read_pcm_frames_s32(pWav, frameCount, (drwav_int32*)pSamplesOut); case ma_format_f32: return (ma_uint32)drwav_read_pcm_frames_f32(pWav, frameCount, (float*)pSamplesOut); default: break; } /* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */ ma_assert(MA_FALSE); return 0; } ma_result ma_decoder_internal_on_seek_to_pcm_frame__wav(ma_decoder* pDecoder, ma_uint64 frameIndex) { drwav* pWav; drwav_bool32 result; pWav = (drwav*)pDecoder->pInternalDecoder; ma_assert(pWav != NULL); result = drwav_seek_to_pcm_frame(pWav, frameIndex); if (result) { return MA_SUCCESS; } else { return MA_ERROR; } } ma_result ma_decoder_internal_on_uninit__wav(ma_decoder* pDecoder) { drwav_close((drwav*)pDecoder->pInternalDecoder); return MA_SUCCESS; } ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__wav(ma_decoder* pDecoder) { return ((drwav*)pDecoder->pInternalDecoder)->totalPCMFrameCount; } ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { drwav* pWav; ma_result result; ma_assert(pConfig != NULL); ma_assert(pDecoder != NULL); /* Try opening the decoder first. */ pWav = drwav_open(ma_decoder_internal_on_read__wav, ma_decoder_internal_on_seek__wav, pDecoder); if (pWav == NULL) { return MA_ERROR; } /* If we get here it means we successfully initialized the WAV decoder. We can now initialize the rest of the ma_decoder. */ pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__wav; pDecoder->onUninit = ma_decoder_internal_on_uninit__wav; pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__wav; pDecoder->pInternalDecoder = pWav; /* Try to be as optimal as possible for the internal format. If miniaudio does not support a format we will fall back to f32. */ pDecoder->internalFormat = ma_format_unknown; switch (pWav->translatedFormatTag) { case DR_WAVE_FORMAT_PCM: { if (pWav->bitsPerSample == 8) { pDecoder->internalFormat = ma_format_s16; } else if (pWav->bitsPerSample == 16) { pDecoder->internalFormat = ma_format_s16; } else if (pWav->bitsPerSample == 32) { pDecoder->internalFormat = ma_format_s32; } } break; case DR_WAVE_FORMAT_IEEE_FLOAT: { if (pWav->bitsPerSample == 32) { pDecoder->internalFormat = ma_format_f32; } } break; case DR_WAVE_FORMAT_ALAW: case DR_WAVE_FORMAT_MULAW: case DR_WAVE_FORMAT_ADPCM: case DR_WAVE_FORMAT_DVI_ADPCM: { pDecoder->internalFormat = ma_format_s16; } break; } if (pDecoder->internalFormat == ma_format_unknown) { pDecoder->internalFormat = ma_format_f32; } pDecoder->internalChannels = pWav->channels; pDecoder->internalSampleRate = pWav->sampleRate; ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDecoder->internalChannels, pDecoder->internalChannelMap); result = ma_decoder__init_dsp(pDecoder, pConfig, ma_decoder_internal_on_read_pcm_frames__wav); if (result != MA_SUCCESS) { drwav_close(pWav); return result; } return MA_SUCCESS; } #endif /* FLAC */ #ifdef dr_flac_h #define MA_HAS_FLAC size_t ma_decoder_internal_on_read__flac(void* pUserData, void* pBufferOut, size_t bytesToRead) { ma_decoder* pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead); } drflac_bool32 ma_decoder_internal_on_seek__flac(void* pUserData, int offset, drflac_seek_origin origin) { ma_decoder* pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); return ma_decoder_seek_bytes(pDecoder, offset, (origin == drflac_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); } ma_uint32 ma_decoder_internal_on_read_pcm_frames__flac(ma_pcm_converter* pDSP, void* pSamplesOut, ma_uint32 frameCount, void* pUserData) { ma_decoder* pDecoder; drflac* pFlac; (void)pDSP; pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); pFlac = (drflac*)pDecoder->pInternalDecoder; ma_assert(pFlac != NULL); switch (pDecoder->internalFormat) { case ma_format_s16: return (ma_uint32)drflac_read_pcm_frames_s16(pFlac, frameCount, (drflac_int16*)pSamplesOut); case ma_format_s32: return (ma_uint32)drflac_read_pcm_frames_s32(pFlac, frameCount, (drflac_int32*)pSamplesOut); case ma_format_f32: return (ma_uint32)drflac_read_pcm_frames_f32(pFlac, frameCount, (float*)pSamplesOut); default: break; } /* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */ ma_assert(MA_FALSE); return 0; } ma_result ma_decoder_internal_on_seek_to_pcm_frame__flac(ma_decoder* pDecoder, ma_uint64 frameIndex) { drflac* pFlac; drflac_bool32 result; pFlac = (drflac*)pDecoder->pInternalDecoder; ma_assert(pFlac != NULL); result = drflac_seek_to_pcm_frame(pFlac, frameIndex); if (result) { return MA_SUCCESS; } else { return MA_ERROR; } } ma_result ma_decoder_internal_on_uninit__flac(ma_decoder* pDecoder) { drflac_close((drflac*)pDecoder->pInternalDecoder); return MA_SUCCESS; } ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__flac(ma_decoder* pDecoder) { return ((drflac*)pDecoder->pInternalDecoder)->totalPCMFrameCount; } ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { drflac* pFlac; ma_result result; ma_assert(pConfig != NULL); ma_assert(pDecoder != NULL); /* Try opening the decoder first. */ pFlac = drflac_open(ma_decoder_internal_on_read__flac, ma_decoder_internal_on_seek__flac, pDecoder); if (pFlac == NULL) { return MA_ERROR; } /* If we get here it means we successfully initialized the FLAC decoder. We can now initialize the rest of the ma_decoder. */ pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__flac; pDecoder->onUninit = ma_decoder_internal_on_uninit__flac; pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__flac; pDecoder->pInternalDecoder = pFlac; /* dr_flac supports reading as s32, s16 and f32. Try to do a one-to-one mapping if possible, but fall back to s32 if not. s32 is the "native" FLAC format since it's the only one that's truly lossless. */ pDecoder->internalFormat = ma_format_s32; if (pConfig->format == ma_format_s16) { pDecoder->internalFormat = ma_format_s16; } else if (pConfig->format == ma_format_f32) { pDecoder->internalFormat = ma_format_f32; } pDecoder->internalChannels = pFlac->channels; pDecoder->internalSampleRate = pFlac->sampleRate; ma_get_standard_channel_map(ma_standard_channel_map_flac, pDecoder->internalChannels, pDecoder->internalChannelMap); result = ma_decoder__init_dsp(pDecoder, pConfig, ma_decoder_internal_on_read_pcm_frames__flac); if (result != MA_SUCCESS) { drflac_close(pFlac); return result; } return MA_SUCCESS; } #endif /* Vorbis */ #ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H #define MA_HAS_VORBIS /* The size in bytes of each chunk of data to read from the Vorbis stream. */ #define MA_VORBIS_DATA_CHUNK_SIZE 4096 typedef struct { stb_vorbis* pInternalVorbis; ma_uint8* pData; size_t dataSize; size_t dataCapacity; ma_uint32 framesConsumed; /* The number of frames consumed in ppPacketData. */ ma_uint32 framesRemaining; /* The number of frames remaining in ppPacketData. */ float** ppPacketData; } ma_vorbis_decoder; ma_uint32 ma_vorbis_decoder_read_pcm_frames(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, void* pSamplesOut, ma_uint32 frameCount) { float* pSamplesOutF; ma_uint32 totalFramesRead; ma_assert(pVorbis != NULL); ma_assert(pDecoder != NULL); pSamplesOutF = (float*)pSamplesOut; totalFramesRead = 0; while (frameCount > 0) { /* Read from the in-memory buffer first. */ while (pVorbis->framesRemaining > 0 && frameCount > 0) { ma_uint32 iChannel; for (iChannel = 0; iChannel < pDecoder->internalChannels; ++iChannel) { pSamplesOutF[0] = pVorbis->ppPacketData[iChannel][pVorbis->framesConsumed]; pSamplesOutF += 1; } pVorbis->framesConsumed += 1; pVorbis->framesRemaining -= 1; frameCount -= 1; totalFramesRead += 1; } if (frameCount == 0) { break; } ma_assert(pVorbis->framesRemaining == 0); /* We've run out of cached frames, so decode the next packet and continue iteration. */ do { int samplesRead; int consumedDataSize; if (pVorbis->dataSize > INT_MAX) { break; /* Too big. */ } samplesRead = 0; consumedDataSize = stb_vorbis_decode_frame_pushdata(pVorbis->pInternalVorbis, pVorbis->pData, (int)pVorbis->dataSize, NULL, (float***)&pVorbis->ppPacketData, &samplesRead); if (consumedDataSize != 0) { size_t leftoverDataSize = (pVorbis->dataSize - (size_t)consumedDataSize); size_t i; for (i = 0; i < leftoverDataSize; ++i) { pVorbis->pData[i] = pVorbis->pData[i + consumedDataSize]; } pVorbis->dataSize = leftoverDataSize; pVorbis->framesConsumed = 0; pVorbis->framesRemaining = samplesRead; break; } else { /* Need more data. If there's any room in the existing buffer allocation fill that first. Otherwise expand. */ size_t bytesRead; if (pVorbis->dataCapacity == pVorbis->dataSize) { /* No room. Expand. */ size_t newCap = pVorbis->dataCapacity + MA_VORBIS_DATA_CHUNK_SIZE; ma_uint8* pNewData; pNewData = (ma_uint8*)ma_realloc(pVorbis->pData, newCap); if (pNewData == NULL) { return totalFramesRead; /* Out of memory. */ } pVorbis->pData = pNewData; pVorbis->dataCapacity = newCap; } /* Fill in a chunk. */ bytesRead = ma_decoder_read_bytes(pDecoder, pVorbis->pData + pVorbis->dataSize, (pVorbis->dataCapacity - pVorbis->dataSize)); if (bytesRead == 0) { return totalFramesRead; /* Error reading more data. */ } pVorbis->dataSize += bytesRead; } } while (MA_TRUE); } return totalFramesRead; } ma_result ma_vorbis_decoder_seek_to_pcm_frame(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, ma_uint64 frameIndex) { float buffer[4096]; ma_assert(pVorbis != NULL); ma_assert(pDecoder != NULL); /* This is terribly inefficient because stb_vorbis does not have a good seeking solution with it's push API. Currently this just performs a full decode right from the start of the stream. Later on I'll need to write a layer that goes through all of the Ogg pages until we find the one containing the sample we need. Then we know exactly where to seek for stb_vorbis. */ if (!ma_decoder_seek_bytes(pDecoder, 0, ma_seek_origin_start)) { return MA_ERROR; } stb_vorbis_flush_pushdata(pVorbis->pInternalVorbis); pVorbis->framesConsumed = 0; pVorbis->framesRemaining = 0; pVorbis->dataSize = 0; while (frameIndex > 0) { ma_uint32 framesRead; ma_uint32 framesToRead = ma_countof(buffer)/pDecoder->internalChannels; if (framesToRead > frameIndex) { framesToRead = (ma_uint32)frameIndex; } framesRead = ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, buffer, framesToRead); if (framesRead == 0) { return MA_ERROR; } frameIndex -= framesRead; } return MA_SUCCESS; } ma_result ma_decoder_internal_on_seek_to_pcm_frame__vorbis(ma_decoder* pDecoder, ma_uint64 frameIndex) { ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder; ma_assert(pVorbis != NULL); return ma_vorbis_decoder_seek_to_pcm_frame(pVorbis, pDecoder, frameIndex); } ma_result ma_decoder_internal_on_uninit__vorbis(ma_decoder* pDecoder) { ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder; ma_assert(pVorbis != NULL); stb_vorbis_close(pVorbis->pInternalVorbis); ma_free(pVorbis->pData); ma_free(pVorbis); return MA_SUCCESS; } ma_uint32 ma_decoder_internal_on_read_pcm_frames__vorbis(ma_pcm_converter* pDSP, void* pSamplesOut, ma_uint32 frameCount, void* pUserData) { ma_decoder* pDecoder; ma_vorbis_decoder* pVorbis; (void)pDSP; pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); ma_assert(pDecoder->internalFormat == ma_format_f32); pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder; ma_assert(pVorbis != NULL); return ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, pSamplesOut, frameCount); } ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__vorbis(ma_decoder* pDecoder) { /* No good way to do this with Vorbis. */ (void)pDecoder; return 0; } ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result; stb_vorbis* pInternalVorbis = NULL; size_t dataSize = 0; size_t dataCapacity = 0; ma_uint8* pData = NULL; stb_vorbis_info vorbisInfo; size_t vorbisDataSize; ma_vorbis_decoder* pVorbis; ma_assert(pConfig != NULL); ma_assert(pDecoder != NULL); /* We grow the buffer in chunks. */ do { /* Allocate memory for a new chunk. */ ma_uint8* pNewData; size_t bytesRead; int vorbisError = 0; int consumedDataSize = 0; dataCapacity += MA_VORBIS_DATA_CHUNK_SIZE; pNewData = (ma_uint8*)ma_realloc(pData, dataCapacity); if (pNewData == NULL) { ma_free(pData); return MA_OUT_OF_MEMORY; } pData = pNewData; /* Fill in a chunk. */ bytesRead = ma_decoder_read_bytes(pDecoder, pData + dataSize, (dataCapacity - dataSize)); if (bytesRead == 0) { return MA_ERROR; } dataSize += bytesRead; if (dataSize > INT_MAX) { return MA_ERROR; /* Too big. */ } pInternalVorbis = stb_vorbis_open_pushdata(pData, (int)dataSize, &consumedDataSize, &vorbisError, NULL); if (pInternalVorbis != NULL) { /* If we get here it means we were able to open the stb_vorbis decoder. There may be some leftover bytes in our buffer, so we need to move those bytes down to the front of the buffer since they'll be needed for future decoding. */ size_t leftoverDataSize = (dataSize - (size_t)consumedDataSize); size_t i; for (i = 0; i < leftoverDataSize; ++i) { pData[i] = pData[i + consumedDataSize]; } dataSize = leftoverDataSize; break; /* Success. */ } else { if (vorbisError == VORBIS_need_more_data) { continue; } else { return MA_ERROR; /* Failed to open the stb_vorbis decoder. */ } } } while (MA_TRUE); /* If we get here it means we successfully opened the Vorbis decoder. */ vorbisInfo = stb_vorbis_get_info(pInternalVorbis); /* Don't allow more than MA_MAX_CHANNELS channels. */ if (vorbisInfo.channels > MA_MAX_CHANNELS) { stb_vorbis_close(pInternalVorbis); ma_free(pData); return MA_ERROR; /* Too many channels. */ } vorbisDataSize = sizeof(ma_vorbis_decoder) + sizeof(float)*vorbisInfo.max_frame_size; pVorbis = (ma_vorbis_decoder*)ma_malloc(vorbisDataSize); if (pVorbis == NULL) { stb_vorbis_close(pInternalVorbis); ma_free(pData); return MA_OUT_OF_MEMORY; } ma_zero_memory(pVorbis, vorbisDataSize); pVorbis->pInternalVorbis = pInternalVorbis; pVorbis->pData = pData; pVorbis->dataSize = dataSize; pVorbis->dataCapacity = dataCapacity; pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__vorbis; pDecoder->onUninit = ma_decoder_internal_on_uninit__vorbis; pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__vorbis; pDecoder->pInternalDecoder = pVorbis; /* The internal format is always f32. */ pDecoder->internalFormat = ma_format_f32; pDecoder->internalChannels = vorbisInfo.channels; pDecoder->internalSampleRate = vorbisInfo.sample_rate; ma_get_standard_channel_map(ma_standard_channel_map_vorbis, pDecoder->internalChannels, pDecoder->internalChannelMap); result = ma_decoder__init_dsp(pDecoder, pConfig, ma_decoder_internal_on_read_pcm_frames__vorbis); if (result != MA_SUCCESS) { stb_vorbis_close(pVorbis->pInternalVorbis); ma_free(pVorbis->pData); ma_free(pVorbis); return result; } return MA_SUCCESS; } #endif /* MP3 */ #ifdef dr_mp3_h #define MA_HAS_MP3 size_t ma_decoder_internal_on_read__mp3(void* pUserData, void* pBufferOut, size_t bytesToRead) { ma_decoder* pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead); } drmp3_bool32 ma_decoder_internal_on_seek__mp3(void* pUserData, int offset, drmp3_seek_origin origin) { ma_decoder* pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); return ma_decoder_seek_bytes(pDecoder, offset, (origin == drmp3_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); } ma_uint32 ma_decoder_internal_on_read_pcm_frames__mp3(ma_pcm_converter* pDSP, void* pSamplesOut, ma_uint32 frameCount, void* pUserData) { ma_decoder* pDecoder; drmp3* pMP3; (void)pDSP; pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); ma_assert(pDecoder->internalFormat == ma_format_f32); pMP3 = (drmp3*)pDecoder->pInternalDecoder; ma_assert(pMP3 != NULL); return (ma_uint32)drmp3_read_pcm_frames_f32(pMP3, frameCount, (float*)pSamplesOut); } ma_result ma_decoder_internal_on_seek_to_pcm_frame__mp3(ma_decoder* pDecoder, ma_uint64 frameIndex) { drmp3* pMP3; drmp3_bool32 result; pMP3 = (drmp3*)pDecoder->pInternalDecoder; ma_assert(pMP3 != NULL); result = drmp3_seek_to_pcm_frame(pMP3, frameIndex); if (result) { return MA_SUCCESS; } else { return MA_ERROR; } } ma_result ma_decoder_internal_on_uninit__mp3(ma_decoder* pDecoder) { drmp3_uninit((drmp3*)pDecoder->pInternalDecoder); ma_free(pDecoder->pInternalDecoder); return MA_SUCCESS; } ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__mp3(ma_decoder* pDecoder) { return drmp3_get_pcm_frame_count((drmp3*)pDecoder->pInternalDecoder); } ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { drmp3* pMP3; drmp3_config mp3Config; ma_result result; ma_assert(pConfig != NULL); ma_assert(pDecoder != NULL); pMP3 = (drmp3*)ma_malloc(sizeof(*pMP3)); if (pMP3 == NULL) { return MA_OUT_OF_MEMORY; } /* Try opening the decoder first. MP3 can have variable sample rates (it's per frame/packet). We therefore need to use some smarts to determine the most appropriate internal sample rate. These are the rules we're going to use: Sample Rates 1) If an output sample rate is specified in pConfig we just use that. Otherwise; 2) Fall back to 44100. The internal channel count is always stereo, and the internal format is always f32. */ ma_zero_object(&mp3Config); mp3Config.outputChannels = 2; mp3Config.outputSampleRate = (pConfig->sampleRate != 0) ? pConfig->sampleRate : 44100; if (!drmp3_init(pMP3, ma_decoder_internal_on_read__mp3, ma_decoder_internal_on_seek__mp3, pDecoder, &mp3Config)) { return MA_ERROR; } /* If we get here it means we successfully initialized the MP3 decoder. We can now initialize the rest of the ma_decoder. */ pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__mp3; pDecoder->onUninit = ma_decoder_internal_on_uninit__mp3; pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__mp3; pDecoder->pInternalDecoder = pMP3; /* Internal format. */ pDecoder->internalFormat = ma_format_f32; pDecoder->internalChannels = pMP3->channels; pDecoder->internalSampleRate = pMP3->sampleRate; ma_get_standard_channel_map(ma_standard_channel_map_default, pDecoder->internalChannels, pDecoder->internalChannelMap); result = ma_decoder__init_dsp(pDecoder, pConfig, ma_decoder_internal_on_read_pcm_frames__mp3); if (result != MA_SUCCESS) { ma_free(pMP3); return result; } return MA_SUCCESS; } #endif /* Raw */ ma_uint32 ma_decoder_internal_on_read_pcm_frames__raw(ma_pcm_converter* pDSP, void* pSamplesOut, ma_uint32 frameCount, void* pUserData) { ma_decoder* pDecoder; ma_uint32 bpf; (void)pDSP; pDecoder = (ma_decoder*)pUserData; ma_assert(pDecoder != NULL); /* For raw decoding we just read directly from the decoder's callbacks. */ bpf = ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels); return (ma_uint32)ma_decoder_read_bytes(pDecoder, pSamplesOut, frameCount * bpf) / bpf; } ma_result ma_decoder_internal_on_seek_to_pcm_frame__raw(ma_decoder* pDecoder, ma_uint64 frameIndex) { ma_bool32 result = MA_FALSE; ma_uint64 totalBytesToSeek; ma_assert(pDecoder != NULL); if (pDecoder->onSeek == NULL) { return MA_ERROR; } /* The callback uses a 32 bit integer whereas we use a 64 bit unsigned integer. We just need to continuously seek until we're at the correct position. */ totalBytesToSeek = frameIndex * ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels); if (totalBytesToSeek < 0x7FFFFFFF) { /* Simple case. */ result = ma_decoder_seek_bytes(pDecoder, (int)(frameIndex * ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels)), ma_seek_origin_start); } else { /* Complex case. Start by doing a seek relative to the start. Then keep looping using offset seeking. */ result = ma_decoder_seek_bytes(pDecoder, 0x7FFFFFFF, ma_seek_origin_start); if (result == MA_TRUE) { totalBytesToSeek -= 0x7FFFFFFF; while (totalBytesToSeek > 0) { ma_uint64 bytesToSeekThisIteration = totalBytesToSeek; if (bytesToSeekThisIteration > 0x7FFFFFFF) { bytesToSeekThisIteration = 0x7FFFFFFF; } result = ma_decoder_seek_bytes(pDecoder, (int)bytesToSeekThisIteration, ma_seek_origin_current); if (result != MA_TRUE) { break; } totalBytesToSeek -= bytesToSeekThisIteration; } } } if (result) { return MA_SUCCESS; } else { return MA_ERROR; } } ma_result ma_decoder_internal_on_uninit__raw(ma_decoder* pDecoder) { (void)pDecoder; return MA_SUCCESS; } ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__raw(ma_decoder* pDecoder) { (void)pDecoder; return 0; } ma_result ma_decoder_init_raw__internal(const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder) { ma_result result; ma_assert(pConfigIn != NULL); ma_assert(pConfigOut != NULL); ma_assert(pDecoder != NULL); pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__raw; pDecoder->onUninit = ma_decoder_internal_on_uninit__raw; pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__raw; /* Internal format. */ pDecoder->internalFormat = pConfigIn->format; pDecoder->internalChannels = pConfigIn->channels; pDecoder->internalSampleRate = pConfigIn->sampleRate; ma_channel_map_copy(pDecoder->internalChannelMap, pConfigIn->channelMap, pConfigIn->channels); result = ma_decoder__init_dsp(pDecoder, pConfigOut, ma_decoder_internal_on_read_pcm_frames__raw); if (result != MA_SUCCESS) { return result; } return MA_SUCCESS; } ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_assert(pConfig != NULL); if (pDecoder == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pDecoder); if (onRead == NULL || onSeek == NULL) { return MA_INVALID_ARGS; } pDecoder->onRead = onRead; pDecoder->onSeek = onSeek; pDecoder->pUserData = pUserData; (void)pConfig; return MA_SUCCESS; } ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); if (result != MA_SUCCESS) { return result; } #ifdef MA_HAS_WAV return ma_decoder_init_wav__internal(&config, pDecoder); #else return MA_NO_BACKEND; #endif } ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); if (result != MA_SUCCESS) { return result; } #ifdef MA_HAS_FLAC return ma_decoder_init_flac__internal(&config, pDecoder); #else return MA_NO_BACKEND; #endif } ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); if (result != MA_SUCCESS) { return result; } #ifdef MA_HAS_VORBIS return ma_decoder_init_vorbis__internal(&config, pDecoder); #else return MA_NO_BACKEND; #endif } ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); if (result != MA_SUCCESS) { return result; } #ifdef MA_HAS_MP3 return ma_decoder_init_mp3__internal(&config, pDecoder); #else return MA_NO_BACKEND; #endif } ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfigOut); result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); if (result != MA_SUCCESS) { return result; } return ma_decoder_init_raw__internal(pConfigIn, &config, pDecoder); } ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result = MA_NO_BACKEND; ma_assert(pConfig != NULL); ma_assert(pDecoder != NULL); /* Silence some warnings in the case that we don't have any decoder backends enabled. */ (void)onRead; (void)onSeek; (void)pUserData; (void)pConfig; (void)pDecoder; /* We use trial and error to open a decoder. */ #ifdef MA_HAS_WAV if (result != MA_SUCCESS) { result = ma_decoder_init_wav__internal(pConfig, pDecoder); if (result != MA_SUCCESS) { onSeek(pDecoder, 0, ma_seek_origin_start); } } #endif #ifdef MA_HAS_FLAC if (result != MA_SUCCESS) { result = ma_decoder_init_flac__internal(pConfig, pDecoder); if (result != MA_SUCCESS) { onSeek(pDecoder, 0, ma_seek_origin_start); } } #endif #ifdef MA_HAS_VORBIS if (result != MA_SUCCESS) { result = ma_decoder_init_vorbis__internal(pConfig, pDecoder); if (result != MA_SUCCESS) { onSeek(pDecoder, 0, ma_seek_origin_start); } } #endif #ifdef MA_HAS_MP3 if (result != MA_SUCCESS) { result = ma_decoder_init_mp3__internal(pConfig, pDecoder); if (result != MA_SUCCESS) { onSeek(pDecoder, 0, ma_seek_origin_start); } } #endif if (result != MA_SUCCESS) { return result; } return result; } ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder); if (result != MA_SUCCESS) { return result; } return ma_decoder_init__internal(onRead, onSeek, pUserData, &config, pDecoder); } size_t ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) { size_t bytesRemaining; ma_assert(pDecoder->memory.dataSize >= pDecoder->memory.currentReadPos); bytesRemaining = pDecoder->memory.dataSize - pDecoder->memory.currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } if (bytesToRead > 0) { ma_copy_memory(pBufferOut, pDecoder->memory.pData + pDecoder->memory.currentReadPos, bytesToRead); pDecoder->memory.currentReadPos += bytesToRead; } return bytesToRead; } ma_bool32 ma_decoder__on_seek_memory(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin) { if (origin == ma_seek_origin_current) { if (byteOffset > 0) { if (pDecoder->memory.currentReadPos + byteOffset > pDecoder->memory.dataSize) { byteOffset = (int)(pDecoder->memory.dataSize - pDecoder->memory.currentReadPos); /* Trying to seek too far forward. */ } } else { if (pDecoder->memory.currentReadPos < (size_t)-byteOffset) { byteOffset = -(int)pDecoder->memory.currentReadPos; /* Trying to seek too far backwards. */ } } /* This will never underflow thanks to the clamps above. */ pDecoder->memory.currentReadPos += byteOffset; } else { if ((ma_uint32)byteOffset <= pDecoder->memory.dataSize) { pDecoder->memory.currentReadPos = byteOffset; } else { pDecoder->memory.currentReadPos = pDecoder->memory.dataSize; /* Trying to seek too far forward. */ } } return MA_TRUE; } ma_result ma_decoder__preinit_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result = ma_decoder__preinit(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, pConfig, pDecoder); if (result != MA_SUCCESS) { return result; } if (pData == NULL || dataSize == 0) { return MA_INVALID_ARGS; } pDecoder->memory.pData = (const ma_uint8*)pData; pDecoder->memory.dataSize = dataSize; pDecoder->memory.currentReadPos = 0; (void)pConfig; return MA_SUCCESS; } ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); if (result != MA_SUCCESS) { return result; } return ma_decoder_init__internal(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, &config, pDecoder); } ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); if (result != MA_SUCCESS) { return result; } #ifdef MA_HAS_WAV return ma_decoder_init_wav__internal(&config, pDecoder); #else return MA_NO_BACKEND; #endif } ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); if (result != MA_SUCCESS) { return result; } #ifdef MA_HAS_FLAC return ma_decoder_init_flac__internal(&config, pDecoder); #else return MA_NO_BACKEND; #endif } ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); if (result != MA_SUCCESS) { return result; } #ifdef MA_HAS_VORBIS return ma_decoder_init_vorbis__internal(&config, pDecoder); #else return MA_NO_BACKEND; #endif } ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */ result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); if (result != MA_SUCCESS) { return result; } #ifdef MA_HAS_MP3 return ma_decoder_init_mp3__internal(&config, pDecoder); #else return MA_NO_BACKEND; #endif } ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder) { ma_decoder_config config; ma_result result; config = ma_decoder_config_init_copy(pConfigOut); /* Make sure the config is not NULL. */ result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder); if (result != MA_SUCCESS) { return result; } return ma_decoder_init_raw__internal(pConfigIn, &config, pDecoder); } #ifndef MA_NO_STDIO #include #if !defined(_MSC_VER) && !defined(__DMC__) #include /* For strcasecmp(). */ #endif const char* ma_path_file_name(const char* path) { const char* fileName; if (path == NULL) { return NULL; } fileName = path; /* We just loop through the path until we find the last slash. */ while (path[0] != '\0') { if (path[0] == '/' || path[0] == '\\') { fileName = path; } path += 1; } /* At this point the file name is sitting on a slash, so just move forward. */ while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) { fileName += 1; } return fileName; } const char* ma_path_extension(const char* path) { const char* extension; const char* lastOccurance; if (path == NULL) { path = ""; } extension = ma_path_file_name(path); lastOccurance = NULL; /* Just find the last '.' and return. */ while (extension[0] != '\0') { if (extension[0] == '.') { extension += 1; lastOccurance = extension; } extension += 1; } return (lastOccurance != NULL) ? lastOccurance : extension; } ma_bool32 ma_path_extension_equal(const char* path, const char* extension) { const char* ext1; const char* ext2; if (path == NULL || extension == NULL) { return MA_FALSE; } ext1 = extension; ext2 = ma_path_extension(path); #if defined(_MSC_VER) || defined(__DMC__) return _stricmp(ext1, ext2) == 0; #else return strcasecmp(ext1, ext2) == 0; #endif } size_t ma_decoder__on_read_stdio(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) { return fread(pBufferOut, 1, bytesToRead, (FILE*)pDecoder->pUserData); } ma_bool32 ma_decoder__on_seek_stdio(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin) { return fseek((FILE*)pDecoder->pUserData, byteOffset, (origin == ma_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } ma_result ma_decoder__preinit_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { FILE* pFile; if (pDecoder == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pDecoder); if (pFilePath == NULL || pFilePath[0] == '\0') { return MA_INVALID_ARGS; } #if defined(_MSC_VER) && _MSC_VER >= 1400 if (fopen_s(&pFile, pFilePath, "rb") != 0) { return MA_ERROR; } #else pFile = fopen(pFilePath, "rb"); if (pFile == NULL) { return MA_ERROR; } #endif /* We need to manually set the user data so the calls to ma_decoder__on_seek_stdio() succeed. */ pDecoder->pUserData = pFile; (void)pConfig; return MA_SUCCESS; } ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder); /* This sets pDecoder->pUserData to a FILE*. */ if (result != MA_SUCCESS) { return result; } /* WAV */ if (ma_path_extension_equal(pFilePath, "wav")) { result = ma_decoder_init_wav(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); if (result == MA_SUCCESS) { return MA_SUCCESS; } ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start); } /* FLAC */ if (ma_path_extension_equal(pFilePath, "flac")) { result = ma_decoder_init_flac(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); if (result == MA_SUCCESS) { return MA_SUCCESS; } ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start); } /* MP3 */ if (ma_path_extension_equal(pFilePath, "mp3")) { result = ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); if (result == MA_SUCCESS) { return MA_SUCCESS; } ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start); } /* Trial and error. */ return ma_decoder_init(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); } ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder); if (result != MA_SUCCESS) { return result; } return ma_decoder_init_wav(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); } ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder); if (result != MA_SUCCESS) { return result; } return ma_decoder_init_flac(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); } ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder); if (result != MA_SUCCESS) { return result; } return ma_decoder_init_vorbis(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); } ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder); if (result != MA_SUCCESS) { return result; } return ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); } #endif ma_result ma_decoder_uninit(ma_decoder* pDecoder) { if (pDecoder == NULL) { return MA_INVALID_ARGS; } if (pDecoder->onUninit) { pDecoder->onUninit(pDecoder); } #ifndef MA_NO_STDIO /* If we have a file handle, close it. */ if (pDecoder->onRead == ma_decoder__on_read_stdio) { fclose((FILE*)pDecoder->pUserData); } #endif return MA_SUCCESS; } ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder) { if (pDecoder == NULL) { return 0; } if (pDecoder->onGetLengthInPCMFrames) { return pDecoder->onGetLengthInPCMFrames(pDecoder); } return 0; } ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) { if (pDecoder == NULL) { return 0; } return ma_pcm_converter_read(&pDecoder->dsp, pFramesOut, frameCount); } ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex) { if (pDecoder == NULL) { return 0; } if (pDecoder->onSeekToPCMFrame) { return pDecoder->onSeekToPCMFrame(pDecoder, frameIndex); } /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */ return MA_INVALID_ARGS; } ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_decoder_config* pConfigOut, ma_uint64* pFrameCountOut, void** ppPCMFramesOut) { ma_uint64 totalFrameCount; ma_uint64 bpf; ma_uint64 dataCapInFrames; void* pPCMFramesOut; ma_assert(pDecoder != NULL); totalFrameCount = 0; bpf = ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels); /* The frame count is unknown until we try reading. Thus, we just run in a loop. */ dataCapInFrames = 0; pPCMFramesOut = NULL; for (;;) { ma_uint64 frameCountToTryReading; ma_uint64 framesJustRead; /* Make room if there's not enough. */ if (totalFrameCount == dataCapInFrames) { void* pNewPCMFramesOut; ma_uint64 newDataCapInFrames = dataCapInFrames*2; if (newDataCapInFrames == 0) { newDataCapInFrames = 4096; } if ((newDataCapInFrames * bpf) > MA_SIZE_MAX) { ma_free(pPCMFramesOut); return MA_TOO_LARGE; } pNewPCMFramesOut = (void*)ma_realloc(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf)); if (pNewPCMFramesOut == NULL) { ma_free(pPCMFramesOut); return MA_OUT_OF_MEMORY; } dataCapInFrames = newDataCapInFrames; pPCMFramesOut = pNewPCMFramesOut; } frameCountToTryReading = dataCapInFrames - totalFrameCount; ma_assert(frameCountToTryReading > 0); framesJustRead = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading); totalFrameCount += framesJustRead; if (framesJustRead < frameCountToTryReading) { break; } } if (pConfigOut != NULL) { pConfigOut->format = pDecoder->outputFormat; pConfigOut->channels = pDecoder->outputChannels; pConfigOut->sampleRate = pDecoder->outputSampleRate; ma_channel_map_copy(pConfigOut->channelMap, pDecoder->outputChannelMap, pDecoder->outputChannels); } if (ppPCMFramesOut != NULL) { *ppPCMFramesOut = pPCMFramesOut; } else { ma_free(pPCMFramesOut); } if (pFrameCountOut != NULL) { *pFrameCountOut = totalFrameCount; } ma_decoder_uninit(pDecoder); return MA_SUCCESS; } #ifndef MA_NO_STDIO ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut) { ma_decoder_config config; ma_decoder decoder; ma_result result; if (pFrameCountOut != NULL) { *pFrameCountOut = 0; } if (ppPCMFramesOut != NULL) { *ppPCMFramesOut = NULL; } if (pFilePath == NULL) { return MA_INVALID_ARGS; } config = ma_decoder_config_init_copy(pConfig); result = ma_decoder_init_file(pFilePath, &config, &decoder); if (result != MA_SUCCESS) { return result; } return ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut); } #endif ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut) { ma_decoder_config config; ma_decoder decoder; ma_result result; if (pFrameCountOut != NULL) { *pFrameCountOut = 0; } if (ppPCMFramesOut != NULL) { *ppPCMFramesOut = NULL; } if (pData == NULL || dataSize == 0) { return MA_INVALID_ARGS; } config = ma_decoder_config_init_copy(pConfig); result = ma_decoder_init_memory(pData, dataSize, &config, &decoder); if (result != MA_SUCCESS) { return result; } return ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut); } #endif /* MA_NO_DECODING */ /************************************************************************************************************************************************************** Generation **************************************************************************************************************************************************************/ ma_result ma_sine_wave_init(double amplitude, double periodsPerSecond, ma_uint32 sampleRate, ma_sine_wave* pSineWave) { if (pSineWave == NULL) { return MA_INVALID_ARGS; } ma_zero_object(pSineWave); if (amplitude == 0 || periodsPerSecond == 0) { return MA_INVALID_ARGS; } if (amplitude > 1) { amplitude = 1; } if (amplitude < -1) { amplitude = -1; } pSineWave->amplitude = amplitude; pSineWave->periodsPerSecond = periodsPerSecond; pSineWave->delta = MA_TAU_D / sampleRate; pSineWave->time = 0; return MA_SUCCESS; } ma_uint64 ma_sine_wave_read_f32(ma_sine_wave* pSineWave, ma_uint64 count, float* pSamples) { return ma_sine_wave_read_f32_ex(pSineWave, count, 1, ma_stream_layout_interleaved, &pSamples); } ma_uint64 ma_sine_wave_read_f32_ex(ma_sine_wave* pSineWave, ma_uint64 frameCount, ma_uint32 channels, ma_stream_layout layout, float** ppFrames) { if (pSineWave == NULL) { return 0; } if (ppFrames != NULL) { ma_uint64 iFrame; for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_uint32 iChannel; float s = (float)(sin(pSineWave->time * pSineWave->periodsPerSecond) * pSineWave->amplitude); pSineWave->time += pSineWave->delta; if (layout == ma_stream_layout_interleaved) { for (iChannel = 0; iChannel < channels; iChannel += 1) { ppFrames[0][iFrame*channels + iChannel] = s; } } else { for (iChannel = 0; iChannel < channels; iChannel += 1) { ppFrames[iChannel][iFrame] = s; } } } } else { pSineWave->time += pSineWave->delta * (ma_int64)frameCount; /* Cast to int64 required for VC6. */ } return frameCount; } #if defined(_MSC_VER) #pragma warning(pop) #endif #endif /* MINIAUDIO_IMPLEMENTATION */ /* BACKEND IMPLEMENTATION GUIDLINES ================================ Context ------- - Run-time linking if possible. - Set whether or not it's an asynchronous backend Device ------ - If a full-duplex device is requested and the backend does not support full duplex devices, have ma_device_init__[backend]() return MA_DEVICE_TYPE_NOT_SUPPORTED. - If exclusive mode is requested, but the backend does not support it, return MA_SHARE_MODE_NOT_SUPPORTED. If practical, try not to fall back to a different share mode - give the client exactly what they asked for. Some backends, such as ALSA, may not have a practical way to distinguish between the two. - If pDevice->usingDefault* is set, prefer the device's native value if the backend supports it. Otherwise use the relevant value from the config. - If the configs buffer size in frames is 0, set it based on the buffer size in milliseconds, keeping in mind to handle the case when the default sample rate is being used where practical. - Backends must set the following members of pDevice before returning successfully from ma_device_init__[backend](): - internalFormat - internalChannels - internalSampleRate - internalChannelMap - bufferSizeInFrames - periods */ /* REVISION HISTORY ================ v0.9.5 - 2019-05-21 - Add logging to ma_dlopen() and ma_dlsym(). - Add ma_decoder_get_length_in_pcm_frames(). - Fix a bug with capture on the OpenSL|ES backend. - Fix a bug with the ALSA backend where a device would not restart after being stopped. v0.9.4 - 2019-05-06 - Add support for C89. With this change, miniaudio should compile clean with GCC/Clang with "-std=c89 -ansi -pedantic" and Microsoft copmilers back to VC6. Other compilers should also work, but have not been tested. v0.9.3 - 2019-04-19 - Fix compiler errors on GCC when compiling with -std=c99. v0.9.2 - 2019-04-08 - Add support for per-context user data. - Fix a potential bug with context configs. - Fix some bugs with PulseAudio. v0.9.1 - 2019-03-17 - Fix a bug where the output buffer is not getting zeroed out before calling the data callback. This happens when the device is running in passthrough mode (not doing any data conversion). - Fix an issue where the data callback is getting called too frequently on the WASAPI and DirectSound backends. - Fix error on the UWP build. - Fix a build error on Apple platforms. v0.9 - 2019-03-06 - Rebranded to "miniaudio". All namespaces have been renamed from "mal" to "ma". - API CHANGE: ma_device_init() and ma_device_config_init() have changed significantly: - The device type, device ID and user data pointer have moved from ma_device_init() to the config. - All variations of ma_device_config_init_*() have been removed in favor of just ma_device_config_init(). - ma_device_config_init() now takes only one parameter which is the device type. All other properties need to be set on the returned object directly. - The onDataCallback and onStopCallback members of ma_device_config have been renamed to "dataCallback" and "stopCallback". - The ID of the physical device is now split into two: one for the playback device and the other for the capture device. This is required for full-duplex. These are named "pPlaybackDeviceID" and "pCaptureDeviceID". - API CHANGE: The data callback has changed. It now uses a unified callback for all device types rather than being separate for each. It now takes two pointers - one containing input data and the other output data. This design in required for full-duplex. The return value is now void instead of the number of frames written. The new callback looks like the following: void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - API CHANGE: Remove the log callback parameter from ma_context_config_init(). With this change, ma_context_config_init() now takes no parameters and the log callback is set via the structure directly. The new policy for config initialization is that only mandatory settings are passed in to *_config_init(). The "onLog" member of ma_context_config has been renamed to "logCallback". - API CHANGE: Remove ma_device_get_buffer_size_in_bytes(). - API CHANGE: Rename decoding APIs to "pcm_frames" convention. - mal_decoder_read() -> ma_decoder_read_pcm_frames() - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame() - API CHANGE: Rename sine wave reading APIs to f32 convention. - mal_sine_wave_read() -> ma_sine_wave_read_f32() - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex() - API CHANGE: Remove some deprecated APIs - mal_device_set_recv_callback() - mal_device_set_send_callback() - mal_src_set_input_sample_rate() - mal_src_set_output_sample_rate() - API CHANGE: Add log level to the log callback. New signature: - void on_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) - API CHANGE: Changes to result codes. Constants have changed and unused codes have been removed. If you're a binding mainainer you will need to update your result code constants. - API CHANGE: Change the order of the ma_backend enums to priority order. If you are a binding maintainer, you will need to update. - API CHANGE: Rename mal_dsp to ma_pcm_converter. All functions have been renamed from mal_dsp_*() to ma_pcm_converter_*(). All structures have been renamed from mal_dsp* to ma_pcm_converter*. - API CHANGE: Reorder parameters of ma_decoder_read_pcm_frames() to be consistent with the new parameter order scheme. - The resampling algorithm has been changed from sinc to linear. The rationale for this is that the sinc implementation is too inefficient right now. This will hopefully be improved at a later date. - Device initialization will no longer fall back to shared mode if exclusive mode is requested but is unusable. With this change, if you request an device in exclusive mode, but exclusive mode is not supported, it will not automatically fall back to shared mode. The client will need to reinitialize the device in shared mode if that's what they want. - Add ring buffer API. This is ma_rb and ma_pcm_rb, the difference being that ma_rb operates on bytes and ma_pcm_rb operates on PCM frames. - Add Web Audio backend. This is used when compiling with Emscripten. The SDL backend, which was previously used for web support, will be removed in a future version. - Add AAudio backend (Android Audio). This is the new priority backend for Android. Support for AAudio starts with Android 8. OpenSL|ES is used as a fallback for older versions of Android. - Remove OpenAL and SDL backends. - Fix a possible deadlock when rapidly stopping the device after it has started. - Update documentation. - Change licensing to a choice of public domain _or_ MIT-0 (No Attribution). v0.8.14 - 2018-12-16 - Core Audio: Fix a bug where the device state is not set correctly after stopping. - Add support for custom weights to the channel router. - Update decoders to use updated APIs in dr_flac, dr_mp3 and dr_wav. v0.8.13 - 2018-12-04 - Core Audio: Fix a bug with channel mapping. - Fix a bug with channel routing where the back/left and back/right channels have the wrong weight. v0.8.12 - 2018-11-27 - Drop support for SDL 1.2. The Emscripten build now requires "-s USE_SDL=2". - Fix a linking error with ALSA. - Fix a bug on iOS where the device name is not set correctly. v0.8.11 - 2018-11-21 - iOS bug fixes. - Minor tweaks to PulseAudio. v0.8.10 - 2018-10-21 - Core Audio: Fix a hang when uninitializing a device. - Fix a bug where an incorrect value is returned from ma_device_stop(). v0.8.9 - 2018-09-28 - Fix a bug with the SDL backend where device initialization fails. v0.8.8 - 2018-09-14 - Fix Linux build with the ALSA backend. - Minor documentation fix. v0.8.7 - 2018-09-12 - Fix a bug with UWP detection. v0.8.6 - 2018-08-26 - Automatically switch the internal device when the default device is unplugged. Note that this is still in the early stages and not all backends handle this the same way. As of this version, this will not detect a default device switch when changed from the operating system's audio preferences (unless the backend itself handles this automatically). This is not supported in exclusive mode. - WASAPI and Core Audio: Add support for stream routing. When the application is using a default device and the user switches the default device via the operating system's audio preferences, miniaudio will automatically switch the internal device to the new default. This is not supported in exclusive mode. - WASAPI: Add support for hardware offloading via IAudioClient2. Only supported on Windows 8 and newer. - WASAPI: Add support for low-latency shared mode via IAudioClient3. Only supported on Windows 10 and newer. - Add support for compiling the UWP build as C. - mal_device_set_recv_callback() and mal_device_set_send_callback() have been deprecated. You must now set this when the device is initialized with mal_device_init*(). These will be removed in version 0.9.0. v0.8.5 - 2018-08-12 - Add support for specifying the size of a device's buffer in milliseconds. You can still set the buffer size in frames if that suits you. When bufferSizeInFrames is 0, bufferSizeInMilliseconds will be used. If both are non-0 then bufferSizeInFrames will take priority. If both are set to 0 the default buffer size is used. - Add support for the audio(4) backend to OpenBSD. - Fix a bug with the ALSA backend that was causing problems on Raspberry Pi. This significantly improves the Raspberry Pi experience. - Fix a bug where an incorrect number of samples is returned from sinc resampling. - Add support for setting the value to be passed to internal calls to CoInitializeEx(). - WASAPI and WinMM: Stop the device when it is unplugged. v0.8.4 - 2018-08-06 - Add sndio backend for OpenBSD. - Add audio(4) backend for NetBSD. - Drop support for the OSS backend on everything except FreeBSD and DragonFly BSD. - Formats are now native-endian (were previously little-endian). - Mark some APIs as deprecated: - mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate(). - mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() are replaced with mal_dsp_set_sample_rate(). - Fix a bug when capturing using the WASAPI backend. - Fix some aliasing issues with resampling, specifically when increasing the sample rate. - Fix warnings. v0.8.3 - 2018-07-15 - Fix a crackling bug when resampling in capture mode. - Core Audio: Fix a bug where capture does not work. - ALSA: Fix a bug where the worker thread can get stuck in an infinite loop. - PulseAudio: Fix a bug where mal_context_init() succeeds when PulseAudio is unusable. - JACK: Fix a bug where mal_context_init() succeeds when JACK is unusable. v0.8.2 - 2018-07-07 - Fix a bug on macOS with Core Audio where the internal callback is not called. v0.8.1 - 2018-07-06 - Fix compilation errors and warnings. v0.8 - 2018-07-05 - Changed MA_IMPLEMENTATION to MINI_AL_IMPLEMENTATION for consistency with other libraries. The old way is still supported for now, but you should update as it may be removed in the future. - API CHANGE: Replace device enumeration APIs. mal_enumerate_devices() has been replaced with mal_context_get_devices(). An additional low-level device enumration API has been introduced called mal_context_enumerate_devices() which uses a callback to report devices. - API CHANGE: Rename mal_get_sample_size_in_bytes() to mal_get_bytes_per_sample() and add mal_get_bytes_per_frame(). - API CHANGE: Replace mal_device_config.preferExclusiveMode with ma_device_config.shareMode. - This new config can be set to mal_share_mode_shared (default) or ma_share_mode_exclusive. - API CHANGE: Remove excludeNullDevice from mal_context_config.alsa. - API CHANGE: Rename MA_MAX_SAMPLE_SIZE_IN_BYTES to MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES. - API CHANGE: Change the default channel mapping to the standard Microsoft mapping. - API CHANGE: Remove backend-specific result codes. - API CHANGE: Changes to the format conversion APIs (mal_pcm_f32_to_s16(), etc.) - Add support for Core Audio (Apple). - Add support for PulseAudio. - This is the highest priority backend on Linux (higher priority than ALSA) since it is commonly installed by default on many of the popular distros and offer's more seamless integration on platforms where PulseAudio is used. In addition, if PulseAudio is installed and running (which is extremely common), it's better to just use PulseAudio directly rather than going through the "pulse" ALSA plugin (which is what the "default" ALSA device is likely set to). - Add support for JACK. - Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no longer required to build miniaudio. - Remove dependency on dsound.h for the DirectSound backend. This fixes build issues with some distributions of MinGW. - Remove dependency on audioclient.h for the WASAPI backend. This fixes build issues with some distributions of MinGW. - Add support for dithering to format conversion. - Add support for configuring the priority of the worker thread. - Add a sine wave generator. - Improve efficiency of sample rate conversion. - Introduce the notion of standard channel maps. Use mal_get_standard_channel_map(). - Introduce the notion of default device configurations. A default config uses the same configuration as the backend's internal device, and as such results in a pass-through data transmission pipeline. - Add support for passing in NULL for the device config in mal_device_init(), which uses a default config. This requires manually calling mal_device_set_send/recv_callback(). - Add support for decoding from raw PCM data (mal_decoder_init_raw(), etc.) - Make mal_device_init_ex() more robust. - Make some APIs more const-correct. - Fix errors with SDL detection on Apple platforms. - Fix errors with OpenAL detection. - Fix some memory leaks. - Fix a bug with opening decoders from memory. - Early work on SSE2, AVX2 and NEON optimizations. - Miscellaneous bug fixes. - Documentation updates. v0.7 - 2018-02-25 - API CHANGE: Change mal_src_read_frames() and mal_dsp_read_frames() to use 64-bit sample counts. - Add decoder APIs for loading WAV, FLAC, Vorbis and MP3 files. - Allow opening of devices without a context. - In this case the context is created and managed internally by the device. - Change the default channel mapping to the same as that used by FLAC. - Fix build errors with macOS. v0.6c - 2018-02-12 - Fix build errors with BSD/OSS. v0.6b - 2018-02-03 - Fix some warnings when compiling with Visual C++. v0.6a - 2018-01-26 - Fix errors with channel mixing when increasing the channel count. - Improvements to the build system for the OpenAL backend. - Documentation fixes. v0.6 - 2017-12-08 - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll need to update. - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and ma_dsp object respectively. - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent. - Add support for SDL and Emscripten. - Simplify the build system further for when development packages for various backends are not installed. With this change, when the compiler supports __has_include, backends without the relevant development packages installed will be ignored. This fixes the build for old versions of MinGW. - Fixes to the Android build. - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of audio data to a different format. - Improvements to f32 -> u8/s16/s24/s32 conversion routines. - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend. - Fixes and improvements for Raspberry Pi. - Warning fixes. v0.5 - 2017-11-11 - API CHANGE: The mal_context_init() function now takes a pointer to a ma_context_config object for configuring the context. The works in the same kind of way as the device config. The rationale for this change is to give applications better control over context-level properties, add support for backend- specific configurations, and support extensibility without breaking the API. - API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for anything anymore. - ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config variable. - ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above) which is by design. - ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable. - ALSA: Fix a bug with channel mapping which causes an assertion to fail. - Fix errors with enumeration when pInfo is set to NULL. - OSS: Fix a bug when starting a device when the client sends 0 samples for the initial buffer fill. v0.4 - 2017-11-05 - API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic messages at the context level. Previously this was only available at the device level. - API CHANGE: The device config passed to mal_device_init() is now const. - Added support for OSS which enables support on BSD platforms. - Added support for WinMM (waveOut/waveIn). - Added support for UWP (Universal Windows Platform) applications. Currently C++ only. - Added support for exclusive mode for selected backends. Currently supported on WASAPI. - POSIX builds no longer require explicit linking to libpthread (-lpthread). - ALSA: Explicit linking to libasound (-lasound) is no longer required. - ALSA: Latency improvements. - ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config. - ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the alsa.preferPlugHW config. - WASAPI is now the highest priority backend on Windows platforms. - Fixed an error with sample rate conversion which was causing crackling when capturing. - Improved error handling. - Improved compiler support. - Miscellaneous bug fixes. v0.3 - 2017-06-19 - API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for enumerating and creating devices. Now, applications must first create a context, and then use that to enumerate and create devices. The reason for this change is to ensure device enumeration and creation is tied to the same backend. In addition, some backends are better suited to this design. - API CHANGE: Removed the rewinding APIs because they're too inconsistent across the different backends, hard to test and maintain, and just generally unreliable. - Added helper APIs for initializing mal_device_config objects. - Null Backend: Fixed a crash when recording. - Fixed build for UWP. - Added support for f32 formats to the OpenSL|ES backend. - Added initial implementation of the WASAPI backend. - Added initial implementation of the OpenAL backend. - Added support for low quality linear sample rate conversion. - Added early support for basic channel mapping. v0.2 - 2016-10-28 - API CHANGE: Add user data pointer as the last parameter to mal_device_init(). The rationale for this change is to ensure the logging callback has access to the user data during initialization. - API CHANGE: Have device configuration properties be passed to mal_device_init() via a structure. Rationale: 1) The number of parameters is just getting too much. 2) It makes it a bit easier to add new configuration properties in the future. In particular, there's a chance there will be support added for backend-specific properties. - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the added maintenance cost. - DirectSound: Increased the default buffer size for capture devices. - Added initial implementation of the OpenSL|ES backend. v0.1 - 2016-10-21 - Initial versioned release. */ /* This software is available as a choice of the following licenses. Choose whichever you prefer. =============================================================================== ALTERNATIVE 1 - Public Domain (www.unlicense.org) =============================================================================== This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to =============================================================================== ALTERNATIVE 2 - MIT No Attribution =============================================================================== Copyright 2019 David Reid Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ================================================ FILE: source-code/source/plugins/DivaSound/src/dllmain.cpp ================================================ #include "framework.h" #include "PluginConfigApi.h" #include #pragma comment(lib, "detours.lib") #include #include #include #include #include #include void InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } void NopBytes(void* address, unsigned int num) { std::vector newbytes = {}; for (unsigned int i = 0; i < num; ++i) newbytes.push_back(0x90); InjectCode(address, newbytes); } void resizeInternalBuffers(int frames) { float* oldMixbuffer = divaAudioMixCls->mixbuffer; divaBufSizeInFrames = frames; divaAudioMixCls->mixbuffer = (float*)malloc(divaBufSizeInFrames * 4 * 4); divaAudioMixCls->mixbuffer_size = divaBufSizeInFrames * 4 * 4; free(oldMixbuffer); for (int i = 0; i < divaAudioMixCls->streamingChannels_len; i++) { float* oldChannelBuffer = divaAudioMixCls->streamingChannels[i].buffer; if (oldChannelBuffer != nullptr) { if (divaAudioMixCls->streamingChannels[i].playing == 0) { divaAudioMixCls->streamingChannels[i].buffer = (float*)malloc(divaBufSizeInFrames * 4 * 4); divaAudioMixCls->streamingChannels[i].buffer_size = divaBufSizeInFrames * 4 * 4; free(oldChannelBuffer); } else if (divaAudioMixCls->streamingChannels[i].mutex != nullptr && mtx_lock_0(&divaAudioMixCls->streamingChannels[i].mutex) == 0) { divaAudioMixCls->streamingChannels[i].buffer = (float*)malloc(divaBufSizeInFrames * 4 * 4); divaAudioMixCls->streamingChannels[i].buffer_size = divaBufSizeInFrames * 4 * 4; free(oldChannelBuffer); mtx_unlock(&divaAudioMixCls->streamingChannels[i].mutex); //printf("[DivaSound] %d\n", i); } } } divaAudCls->buffer_size = divaBufSizeInFrames; printf("[DivaSound] Resized internal buffers to %d frames\n", frames); } void resizeTestLoop() { bool dir = true; while (true) { Sleep(3000); if (dir) resizeInternalBuffers(divaBufSizeInFrames + 10000); else resizeInternalBuffers(divaBufSizeInFrames - 10000); dir = !dir; } } void stopPlayback() { if (useAsio) { if (BASS_ASIO_IsStarted()) BASS_ASIO_Stop(); } else { if (ma_device_is_started(&device)) ma_device_stop(&device); } } void closeDevice() { stopPlayback(); if (useAsio) { BASS_ASIO_Free(); } else { ma_device_uninit(&device); ma_context_uninit(&context); } } void audioCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { (void)pDevice; (void)pOutput; (void)pInput; (void)frameCount; if (divaAudCls->breakDword != 0 || divaAudioMixCls->mixbuffer == nullptr) { stopPlayback(); return; } if (frameCount > divaBufSizeInFrames) { printf("[DivaSound] Warning: PDAFT buffer is too small\n"); // allocate a larger buffer if necessary. // add 128 frames of padding because this isn't normal and we want to avoid it happening again if possible. resizeInternalBuffers(frameCount + 128); } divaAudioFillbuffer(divaAudioMixCls, (int16_t*)pOutput, frameCount, 0, 0); if (bitDepth > 16) // we should generate the output buffer ourselves { float volumes[4]; for (int i = 0; i < 4; i++) { volumes[i] = divaAudioMixCls->volume_master * divaAudioMixCls->volume_channels[i]; } int startChannel = 4 - nChannels; for (unsigned int i = 0; i < frameCount; i++) { for (int currentChannel = startChannel; currentChannel < 4; currentChannel++) { // note: currentChannel is for the game's buffer, outputChannel is for our output buffer. // outputChannel should also be used for volumes. int outputChannel = currentChannel - startChannel; if (bitDepth == 24) // 24 bit int output { int32_t out_val = (int32_t)(divaAudioMixCls->mixbuffer[i*4 + currentChannel] * volumes[outputChannel] * 8388607.0f); if (out_val > 8388607) out_val = 8388607; else if (out_val < -8388608) out_val = -8388608; uint64_t out_pos = (i*nChannels + outputChannel) * 3; ((byte*)pOutput)[out_pos] = out_val; ((byte*)pOutput)[out_pos + 1] = out_val >> 8; ((byte*)pOutput)[out_pos + 2] = out_val >> 16; } else if (bitDepth == 32) // floating point output { ((float*)pOutput)[i*nChannels + outputChannel] = divaAudioMixCls->mixbuffer[i*4 + currentChannel] * volumes[outputChannel]; } } } } } DWORD asioCallback(bool input, DWORD channel, void* buffer, DWORD length, void* user) { ma_uint32 frames = length * 8 / bitDepth / nChannels; audioCallback(&device, buffer, NULL, frames); return length; } void asioNotifyProc(DWORD notify, void* user); bool asioInit(bool enablePanel) { if (BASS_ASIO_Init == NULL) { printf("[DivaSound] BASS ASIO not loaded...\n"); return false; } if (HIWORD(BASS_ASIO_GetVersion()) != BASSASIOVERSION) { printf("[DivaSound] Incorrect BASS ASIO version. Use 1.4.0.0.\n"); return false; } if (!BASS_ASIO_Init(asioDevice, BASS_ASIO_THREAD)) { printf("[DivaSound] Failed to initialize device\n"); return false; } if (enablePanel && showAsioPanel) BASS_ASIO_ControlPanel(); if (!BASS_ASIO_ChannelEnable(false, 0, (ASIOPROC*)asioCallback, NULL)) { printf("[DivaSound] Failed to enable channels\n"); BASS_ASIO_Free(); return false; } for (int i = 1; i < nChannels; i++) { if (!BASS_ASIO_ChannelJoin(false, i, 0)) { printf("[DivaSound] Failed to enable channels\n"); BASS_ASIO_Free(); return false; } } if (BASS_ASIO_CheckRate(44100)) BASS_ASIO_SetRate(44100); BASS_ASIO_ChannelSetRate(false, 0, 44100); if (bitDepth == 32) BASS_ASIO_ChannelSetFormat(false, 0, BASS_ASIO_FORMAT_FLOAT); else if (bitDepth == 24) BASS_ASIO_ChannelSetFormat(false, 0, BASS_ASIO_FORMAT_24BIT); else BASS_ASIO_ChannelSetFormat(false, 0, BASS_ASIO_FORMAT_16BIT); BASS_ASIO_SetNotify((ASIONOTIFYPROC*)asioNotifyProc, NULL); return true; } void asioReinit() { printf("[DivaSound] Reinitialising ASIO device...\n"); closeDevice(); if (!asioInit(false)) return; BASS_ASIO_INFO asioInfo; BASS_ASIO_GetInfo(&asioInfo); double actualRate = BASS_ASIO_GetRate(); printf("[DivaSound] Output buffer size: %d (%dms at %dHz)\n", asioInfo.bufpref, (int)(asioInfo.bufpref * 1000 / actualRate), (int)actualRate); divaBufSizeInFrames = (int)(asioInfo.bufpref * 44100 / actualRate); divaBufSizeInMilliseconds = divaBufSizeInFrames * 1000 / 44100; printf("[DivaSound] PDAFT buffer size: %d (%dms at %dHz)\n", divaBufSizeInFrames, divaBufSizeInMilliseconds, 44100); resizeInternalBuffers(divaBufSizeInFrames); if (!BASS_ASIO_Start(asioInfo.bufpref, 1)) { printf("[DivaSound] Failed to start playback device\n"); BASS_ASIO_Free(); return; } printf("[DivaSound] Started playback\n"); } void asioNotifyProc(DWORD notify, void* user) { if (notify == BASS_ASIO_NOTIFY_RESET) { std::thread asioReinitThread(asioReinit); asioReinitThread.join(); } } bool maInit() { ma_backend backends[] = { maBackend }; contextConfig = ma_context_config_init(); contextConfig.threadPriority = ma_thread_priority_highest; if (ma_context_init(backends, sizeof(backends) / sizeof(backends[0]), &contextConfig, &context) != MA_SUCCESS) { printf("[DivaSound] Failed to initialize context\n"); return false; } deviceConfig = ma_device_config_init(ma_device_type_playback); deviceConfig.playback.channels = nChannels; deviceConfig.sampleRate = 44100; deviceConfig.bufferSizeInMilliseconds = requestBuffer; // actual result may be larger deviceConfig.periods = nPeriods; deviceConfig.dataCallback = audioCallback; deviceConfig.pUserData = NULL; deviceConfig.playback.shareMode = maSharemode; if (bitDepth == 32) deviceConfig.playback.format = ma_format_f32; else if (bitDepth == 24) deviceConfig.playback.format = ma_format_s24; else deviceConfig.playback.format = ma_format_s16; if (nChannels == 4) { deviceConfig.playback.channelMap[0] = MA_CHANNEL_FRONT_LEFT; deviceConfig.playback.channelMap[1] = MA_CHANNEL_FRONT_RIGHT; deviceConfig.playback.channelMap[2] = MA_CHANNEL_BACK_LEFT; deviceConfig.playback.channelMap[3] = MA_CHANNEL_BACK_RIGHT; } if (ma_device_init(&context, &deviceConfig, &device) != MA_SUCCESS) { printf("[DivaSound] Failed to open playback device\n"); ma_context_uninit(&context); return false; } //printf("[DivaSound] Opened playback device\n"); return true; } void loadConfig() { nChannels = GetPrivateProfileIntW(L"general", L"channels", 2, CONFIG_FILE); if (nChannels != 4) nChannels = 2; bitDepth = GetPrivateProfileIntW(L"general", L"bit_depth", 16, CONFIG_FILE); if (bitDepth != 32 && bitDepth != 24) bitDepth = 16; requestBuffer = GetPrivateProfileIntW(L"buffer", L"buffer_size", 10, CONFIG_FILE); if (requestBuffer < 0) requestBuffer = 0; nPeriods = GetPrivateProfileIntW(L"buffer", L"periods", 2, CONFIG_FILE); if (nPeriods < 1) nPeriods = 1; useOldInit = GetPrivateProfileIntW(L"general", L"alternate_init", 1, CONFIG_FILE) > 0 ? false : true; GetPrivateProfileStringW(L"general", L"backend", L"wasapi", backendName, 32, CONFIG_FILE); for (wchar_t& chr : backendName) chr = towlower(chr); useAsio = false; maSharemode = ma_share_mode_shared; if (lstrcmpW(backendName, L"asio") == 0) { StringCchCopyW(backendName, 32, L"ASIO"); useAsio = true; } else if (lstrcmpW(backendName, L"directsound") == 0) { StringCchCopyW(backendName, 32, L"DirectSound"); maBackend = ma_backend_dsound; } else if (lstrcmpW(backendName, L"wasapi_exclusive") == 0) { StringCchCopyW(backendName, 32, L"WASAPI (Exclusive mode)"); maBackend = ma_backend_wasapi; maSharemode = ma_share_mode_exclusive; } else { StringCchCopyW(backendName, 32, L"WASAPI"); maBackend = ma_backend_wasapi; } if (GetPrivateProfileIntW(L"asio", L"auto_device", TRUE, CONFIG_FILE)) { asioDevice = -1; } else { asioDevice = GetPrivateProfileIntW(L"asio", L"device", -1, CONFIG_FILE); } showAsioPanel = GetPrivateProfileIntW(L"asio", L"show_config", 0, CONFIG_FILE) > 0 ? true : false; } void hookedAudioInit(initClass *cls, uint64_t unk, uint64_t unk2) { //printf("[DivaSound] Loaded\n"); printf("[DivaSound] Output config: %S %dch %dbit\n", backendName, nChannels, bitDepth); divaAudCls = cls; divaAudCls->breakDword = 0; if (useOldInit) { printf("[DivaSound] Using old initialisation method\n"); // let the game set some stuff up // might be necessary sometimes divaAudioInit(divaAudCls, unk, unk2); //printf("[DivaSound] Game audio initialised\n"); } else { // setup some variables instead of using the original init function divaAudCls->mixer = new audioMixer(); divaAudCls->mixer->volume_master = 1.0f; divaAudCls->mixer->volume_channels[0] = 1.0f; divaAudCls->mixer->volume_channels[1] = 1.0f; divaAudCls->mixer->volume_channels[2] = 1.0f; divaAudCls->mixer->volume_channels[3] = 1.0f; divaAudCls->mixer->audioClass = divaAudCls; mtx_init(&divaAudCls->mixer->volume_mutex, 2); } divaAudioMixCls = divaAudCls->mixer; divaAudCls->channels = nChannels; // this could replace stereo patch divaAudCls->rate = 44100; // really does nothing divaAudCls->depth = bitDepth; // setting this to something other than 16 just removes output if (useAsio) { if (!asioInit(true)) return; BASS_ASIO_INFO asioInfo; BASS_ASIO_GetInfo(&asioInfo); double actualRate = BASS_ASIO_GetRate(); printf("[DivaSound] Output buffer size: %d (%dms at %dHz)\n", asioInfo.bufpref, (int)(asioInfo.bufpref * 1000 / actualRate), (int)actualRate); divaBufSizeInFrames = (int)(asioInfo.bufpref * 44100 / actualRate); divaBufSizeInMilliseconds = divaBufSizeInFrames * 1000 / 44100; printf("[DivaSound] PDAFT buffer size: %d (%dms at %dHz)\n", divaBufSizeInFrames, divaBufSizeInMilliseconds, 44100); divaAudioAllocMixer(divaAudioMixCls, unk, unk2, divaBufSizeInFrames); printf("[DivaSound] Created internal audio mixer\n"); if (!BASS_ASIO_Start(asioInfo.bufpref, 1)) { printf("[DivaSound] Failed to start playback device\n"); BASS_ASIO_Free(); return; } printf("[DivaSound] Started playback\n"); } else { if (!maInit()) return; if (device.playback.internalSampleRate) { maInternalBufferSizeInMilliseconds = device.playback.internalBufferSizeInFrames * 1000 / device.playback.internalSampleRate; // because miniaudio doesn't seem to have this printf("[DivaSound] Output buffer size: %d (%dms at %dHz)\n", device.playback.internalBufferSizeInFrames, maInternalBufferSizeInMilliseconds, device.playback.internalSampleRate); printf("[DivaSound] Buffer periods: %d\n", device.playback.internalPeriods); divaBufSizeInFrames = device.playback.internalBufferSizeInFrames * device.sampleRate / device.playback.internalSampleRate; // +128; // 128 is just a bit extra in case resampling needs it or something. idk divaBufSizeInMilliseconds = divaBufSizeInFrames * 1000 / device.sampleRate; printf("[DivaSound] PDAFT buffer size: %d (%dms at %dHz)\n", divaBufSizeInFrames, divaBufSizeInMilliseconds, device.sampleRate); } else { printf("[DivaSound] Unable to determine output sample rate. Assuming 44100Hz.\n"); maInternalBufferSizeInMilliseconds = device.playback.internalBufferSizeInFrames * 1000 / 44100; // because miniaudio doesn't seem to have this printf("[DivaSound] Output buffer size: %d (%dms at %dHz)\n", device.playback.internalBufferSizeInFrames, maInternalBufferSizeInMilliseconds, 44100); printf("[DivaSound] Buffer periods: %d\n", device.playback.internalPeriods); divaBufSizeInFrames = device.playback.internalBufferSizeInFrames * device.sampleRate / 44100; divaBufSizeInMilliseconds = divaBufSizeInFrames * 1000 / device.sampleRate; printf("[DivaSound] PDAFT buffer size: %d (%dms at %dHz)\n", divaBufSizeInFrames, divaBufSizeInMilliseconds, device.sampleRate); } divaAudioAllocMixer(divaAudioMixCls, unk, unk2, divaBufSizeInFrames); printf("[DivaSound] Created internal audio mixer\n"); if (ma_device_start(&device) != MA_SUCCESS) { printf("[DivaSound] Failed to start playback device\n"); ma_device_uninit(&device); ma_context_uninit(&context); return; } printf("[DivaSound] Started playback\n"); } divaAudCls->hCallback = new HANDLE(); *divaAudCls->hCallback = (HANDLE)1; // this *should* be an actual thread handle, but I bypassed the destruction stuff anyway lol divaAudCls->buffer_size = divaBufSizeInFrames; //loopThread = std::thread(resizeTestLoop); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { loadConfig(); if (useOldInit) { // these patches are only needed if calling the game's own init function // they shouldn't be necessary anymore // force stereo mode InjectCode((void*)0x0000000140A860C0, { 0x02 }); // remove a call to get device info and skip the check for it NopBytes((void*)0x140626b56, 7); NopBytes((void*)0x140626b8a, 8); InjectCode((void*)0x140626b8a, { 0x48, 0x83, 0xEF, 0x18 }); // fix value of RDI because I changed the flow here NopBytes((void*)0x140626ba9, 11); // return from the original init early InjectCode((void*)0x0000000140626C29, { 0x48, 0xE9 }); } // skip some thread deinitialisation stuff I don't care about InjectCode((void*)0x0000000140625F42, { 0xEB, 0x29 }); DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaAudioInit, (PVOID)hookedAudioInit); DetourTransactionCommit(); } else if (ul_reason_for_call == DLL_PROCESS_DETACH) { closeDevice(); } return TRUE; } using namespace PluginConfig; void OpenWiki() { ShellExecuteW(NULL, L"open", L"https://github.com/somewhatlurker/DivaSound/wiki", NULL, NULL, SW_SHOW); } PluginConfigOption config[] = { { CONFIG_DROPDOWN_TEXT, new PluginConfigDropdownTextData{L"backend", L"general", CONFIG_FILE, L"Backend:", L"Sets the audio output protocol.", L"WASAPI", std::vector({ L"WASAPI", L"WASAPI_Exclusive" }), true, false } }, { CONFIG_DROPDOWN_NUMBER, new PluginConfigDropdownNumberData{ L"channels", L"general", CONFIG_FILE, L"Channels:", L"Sets the number of channels.", 2, std::vector({ 2, 4 }), false } }, { CONFIG_DROPDOWN_NUMBER, new PluginConfigDropdownNumberData{ L"bit_depth", L"general", CONFIG_FILE, L"Bit Depth:", L"Sets the audio sample format.\n(32 uses floating point samples)", 16, std::vector({ 16, 24, 32 }), false } }, { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"alternate_init", L"general", CONFIG_FILE, L"Use new init", L"Use the full initialisation replacement.\nTry unchecking this if DivaSound seems to cause crashes.", true, false } }, { CONFIG_SPACER, new PluginConfigSpacerData{ 8 } }, { CONFIG_GROUP_START, new PluginConfigGroupData{ L"WASAPI Buffer Settings", 75 } }, { CONFIG_NUMERIC, new PluginConfigNumericData{ L"buffer_size", L"buffer", CONFIG_FILE, L"Target Buffer Size:", L"Sets the target buffer size in ms.\nWASAPI will often ignore this and adapt to your hardware config automatically.", 10, 1, 100 } }, { CONFIG_NUMERIC, new PluginConfigNumericData{ L"periods", L"buffer", CONFIG_FILE, L"Buffer Periods:", L"Sets how often the buffer should be filled.\nFewer periods usually allows for lower latency, but lowering this may cause issues.", 2, 1, 8 } }, { CONFIG_GROUP_END, NULL }, { CONFIG_SPACER, new PluginConfigSpacerData{ 8 } }, { CONFIG_SPACER, new PluginConfigSpacerData{ 0 } }, // 0px spacers are placeholders for ASIO config { CONFIG_SPACER, new PluginConfigSpacerData{ 0 } }, { CONFIG_SPACER, new PluginConfigSpacerData{ 0 } }, { CONFIG_SPACER, new PluginConfigSpacerData{ 0 } }, { CONFIG_SPACER, new PluginConfigSpacerData{ 0 } }, { CONFIG_SPACER, new PluginConfigSpacerData{ 0 } }, { CONFIG_BUTTON, new PluginConfigButtonData{ L"Help", L"Get help on the DivaSound wiki.", OpenWiki } }, { CONFIG_SPACER, new PluginConfigSpacerData{ 8 } }, }; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"DivaSound"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"DivaSound Plugin by somewhatlurker\n\nDivaSound replaces the game's original audio output,\nimproving device support and adding configurable options."; } extern "C" __declspec(dllexport) PluginConfigArray GetPluginOptions(void) { if (BASS_ASIO_GetDeviceInfo != NULL && BASS_ASIO_SetUnicode != NULL) { if (BASS_ASIO_SetUnicode(true)) // ensure strings are UTF-16 { std::vector devices; BASS_ASIO_DEVICEINFO info; for (int i = 0; BASS_ASIO_GetDeviceInfo(i, &info); i++) { devices.push_back(_wcsdup((WCHAR*)info.name)); } // make sure user-set device isn't out of bounds int asioDevice = GetPrivateProfileIntW(L"asio", L"device", -1, CONFIG_FILE); while (asioDevice + 1 > devices.size()) { devices.push_back(L"---"); } if (devices.size() > 0) { ((PluginConfigDropdownTextData*)config[0].data)->valueStrings.push_back(L"ASIO"); const int cfgPos = 10; delete config[cfgPos].data; delete config[cfgPos + 1].data; delete config[cfgPos + 2].data; delete config[cfgPos + 3].data; delete config[cfgPos + 4].data; delete config[cfgPos + 5].data; config[cfgPos] = { CONFIG_GROUP_START, new PluginConfigGroupData{ L"ASIO Settings", 90 } }; config[cfgPos + 1] = { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"show_config", L"asio", CONFIG_FILE, L"Show ASIO config", L"Show the ASIO driver config window when the game opens.\nUse this to adjust output settings, then disable it.\n(ASIO devices are unaffected by the normal buffer settings)", false, false } }; config[cfgPos + 2] = { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"auto_device", L"asio", CONFIG_FILE, L"Automatic ASIO device", L"Automatically choose the first available device for ASIO backend.\nDisable this to use a manually choose a device.", true, false } }; config[cfgPos + 3] = { CONFIG_DROPDOWN_INDEX, new PluginConfigDropdownIndexData{ L"device", L"asio", CONFIG_FILE, L"ASIO Device:", L"Sets the ASIO device.\nMake sure automatic device selection is turned off to enable this.", 0, devices } }; config[cfgPos + 4] = { CONFIG_GROUP_END, NULL }; config[cfgPos + 5] = { CONFIG_SPACER, new PluginConfigSpacerData{ 8 } }; } } } return PluginConfigArray{ _countof(config), config }; } ================================================ FILE: source-code/source/plugins/DivaSound/src/framework.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include #include #include #include #define MINIAUDIO_IMPLEMENTATION #include #include #include #include void (*divaAudioInit)(void* cls, uint64_t unk, uint64_t unk2) = (void(*)(void* cls, uint64_t unk, uint64_t unk2))0x1406269F0; void (*divaAudioFillbuffer)(void* mixer, int16_t* buf, uint64_t nFrames, bool disableHpVol, bool invertPhase) = (void(*)(void* mixer, int16_t* buf, uint64_t nFrames, bool disableHpVol, bool invertPhase))0x140627370; // mixer is a pointer to an audioMixer (from audio init's cls + 0x70) // disableHpVol uses speaker volume for headphones (only works in 4ch mode) // invertPhase inverts the output signal (only works if disableHpVol == false) int (*divaAudioAllocMixer)(void* cls, uint64_t unk, uint64_t unk2, int64_t nFrames) = (int(*)(void* cls, uint64_t unk, uint64_t unk2, int64_t nFrames))0x140626710; // unks are the same as from the init call. they seem to set the internal mixing channel counts(?) // cls is the same as mixer in divaAudioFillbuffer // nFrames is number of audio frames to hold in the mixing buffers (only used when divaAudioFillbuffer is called). Internally this is multiplied by 16 (buffers are built using 32bit floats) int(*mtx_init)(void* mutex, int type) = (int(*)(void* mutex, int type))0x14081DEF4; int(*mtx_lock_0)(void* mutex) = (int(*)(void* mutex))0x14081DF50; int(*mtx_unlock)(void* mutex) = (int(*)(void* mutex))0x14081DFD4; typedef void streamingCallback(float* buffer, int64_t nFrames, void* userdata); #pragma pack(push, 1) struct initClass; // define these earlier so they can be used in other structs struct audioMixer; // known streaming channel variables // + 0x00 = pointer to mixer class // + 0x08 = buffer pointer (float) // + 0x10 = buffer size (frame count * 16) // + 0x18 = playing (32 bits, set to 0 for pause) // + 0x1c = reset (32 bits, set to 0 to kill channel) // + 0x20 = mutex pointer // + 0x28 = master volume float (multiply other volumes by this) // + 0x2c = ch1 volume // + 0x30 = ch2 volume // + 0x34 = ch3 volume // + 0x38 = ch4 volume // // + 0x40 = callback func // + 0x48 = callback userdata pointer struct streamingChannel { audioMixer* mixer; float* buffer; uint64_t buffer_size; // in bytes uint32_t playing; // set to 0 for pause (usually ==1) uint32_t reset; // set to 1 to kill (usually ==0) void* mutex; float volume_master; float volume_channels[4]; byte padding3c[0x4]; streamingCallback callback; void* userdata; }; // known SE channel variables // + 0x00 = pointer to mixer class // + 0x08 = some kind of toggle (is playing)? // + 0x10 = mutex pointer // + 0x18 = master volume float (multiply other volumes by this) // + 0x1c = ch1 volume // + 0x20 = ch2 volume // + 0x24 = ch3 volume // + 0x28 = ch4 volume // + 0x30 = buffer pointer (float) // + 0x38 = buffer size????? (frame count * 16)??? (buffers seem to hold whole sounds) // + 0x40 = num channels // + 0x48 = num frames // + 0x50 = sample rate??? // + 0x58 = loop start frame??? // + 0x60 = loop end frame??? // + 0x68 = current playback time struct seChannel { audioMixer* mixer; uint32_t unk1; // toggle on/off? byte padding0c[0x4]; void* mutex; float volume_master; float volume_channels[4]; byte padding2c[0x4]; float* buffer; byte padding38[0x8]; // probably buffer size int64_t nChannels; // seems to affect mapping uint64_t length; // in frames byte padding50[0x8]; // sample rate? uint64_t loop_start; // ? uint64_t loop_end; // ? uint64_t curTime; }; // known internal audio mixer variables (used by divaAudioFillbuffer and divaAudioAllocMixer) // cls + 0x00 = pointer to main audio/init class // cls + 0x08 = SE channels pointer // cls + 0x10 = SE channels count // cls + 0x18 = streaming channels pointer // cls + 0x20 = streaming channels count // cls + 0x28 = mixing buffer pointer (when a buffer is generated, this is filled with 32bit floats (four per frame) // cls + 0x30 = mixing buffer size (frame count * 16) // // cls + 0x38 = mutex lock for volume // cls + 0x40 = master volume float (multiply other volumes by this) // cls + 0x44 = ch1 volume // cls + 0x48 = ch2 volume // cls + 0x4c = ch3 volume // cls + 0x50 = ch4 volume struct audioMixer { initClass* audioClass; seChannel* seChannels; uint64_t seChannels_len; streamingChannel* streamingChannels; uint64_t streamingChannels_len; float* mixbuffer; uint64_t mixbuffer_size; void* volume_mutex; // not sure if this is pointer or not float volume_master; float volume_channels[4]; byte padding54[4]; }; // known main/init audio class variables (used by divaAudioInit) // cls + 0x0 = WAVEFORMATEXTENSIBLE wave_format (null with old method) (length 0x28) // cls + 0x28 = IMMDeviceEnumerator *pEnumerator // cls + 0x30 = IMMDevice *pDevice (default device) // cls + 0x38 = IAudioClient *pAudioClient // // cls + 0x40 = buffer size in frames // // cls + 0x48 = IAudioRenderClient *pRenderClient // // cls + 0x50 = HANDLE hEvent (for original WASAPI buffer timing) // // cls + 0x58 = number of output channels // cls + 0x60 = audio sample rate // cls + 0x68 = audio bit depth (only 16bit works) // // cls + 0x70 = pointer to mixer class // // cls + 0x78 = HANDLE* hCallback (handle to original callback thread) // // cls + 0x80 = break flag dword (becomes 1 on exit) struct initClass { WAVEFORMATEXTENSIBLE wave_format; IMMDeviceEnumerator *pEnumerator; IMMDevice *pDevice; IAudioClient *pAudioClient; uint64_t buffer_size; IAudioRenderClient *pRenderClient; HANDLE hEvent; uint64_t channels; uint64_t rate; // should always =44100 uint64_t depth; // should always =16 audioMixer* mixer; HANDLE* hCallback; int32_t breakDword; }; #pragma pack(pop) initClass *divaAudCls; audioMixer *divaAudioMixCls; std::thread loopThread; ma_context_config contextConfig; ma_context context; ma_device_config deviceConfig; ma_device device; int maInternalBufferSizeInMilliseconds; int divaBufSizeInFrames; int divaBufSizeInMilliseconds; int nChannels; // this can only be 2 or 4 int bitDepth; // signed 16/24 bit integer or 32 bit float int requestBuffer; int nPeriods; wchar_t backendName[32]; // wasapi or directsound ma_backend maBackend; ma_share_mode maSharemode; bool useAsio; int asioDevice; bool showAsioPanel; bool useOldInit; std::wstring ExePath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); return std::wstring(buffer); } std::wstring DirPath() { std::wstring exepath = ExePath(); std::wstring::size_type pos = exepath.find_last_of(L"\\/"); return exepath.substr(0, pos); } std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\DivaSound.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); ================================================ FILE: source-code/source/plugins/DivaWig/DivaWig.vcxproj ================================================  Debug x64 Release x64 16.0 {2394C586-F73B-4EF2-BA3E-2A0FC3034B1A} DivaWig 10.0 DynamicLibrary true v142 MultiByte DynamicLibrary false v142 true MultiByte .dva .dva Level3 Disabled true true ..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) -d2FH4- %(AdditionalOptions) Console ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) detours.lib;evr.lib;mfplat.lib;mfuuid.lib;strmiids.lib;syelog.lib;%(AdditionalDependencies) -d2:-FH4- %(AdditionalOptions) Level3 MaxSpeed true true true true ..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) MultiThreadedDLL -d2FH4- %(AdditionalOptions) Console true true detours.lib;evr.lib;mfplat.lib;mfuuid.lib;syelog.lib;%(AdditionalDependencies) ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/plugins/DivaWig/DivaWig.vcxproj.filters ================================================  ================================================ FILE: source-code/source/plugins/DivaWig/PluginConfigApi.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include // resolution class to store and sort the width and height easily class resolution { public: unsigned int width; unsigned int height; resolution() { width = 0; height = 0; } resolution(unsigned int width, unsigned int height) { resolution::width = width; resolution::height = height; } bool operator ==(const resolution &res2) { return width == res2.width && height == res2.height; } // in comparisons width takes priority because it's usually displayed first bool operator <(const resolution &res2) { if (width == res2.width) return height < res2.height; else return width < res2.width; } bool operator >(const resolution &res2) { if (width == res2.width) return height > res2.height; else return width > res2.width; } }; namespace PluginConfig { #pragma pack(push, 1) enum ConfigType { CONFIG_BOOLEAN, CONFIG_NUMERIC, CONFIG_STRING, CONFIG_DROPDOWN_INDEX, CONFIG_DROPDOWN_TEXT, CONFIG_DROPDOWN_NUMBER, CONFIG_RESOLUTION, CONFIG_GROUP_START, CONFIG_GROUP_END, CONFIG_BUTTON, CONFIG_SPACER }; struct PluginConfigBooleanData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; bool defaultVal; bool saveAsString; }; struct PluginConfigNumericData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; int minVal; int maxVal; }; struct PluginConfigStringData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; LPCWSTR defaultVal; bool useUtf8; }; struct PluginConfigDropdownIndexData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; std::vector valueStrings; }; struct PluginConfigDropdownTextData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; LPCWSTR defaultVal; std::vector valueStrings; bool editable; bool useUtf8; }; struct PluginConfigDropdownNumberData { LPCWSTR iniVarName; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; int defaultVal; std::vector valueInts; bool editable; }; struct PluginConfigResolutionData { LPCWSTR iniVarName; LPCWSTR iniVarName2; LPCWSTR iniSectionName; LPCWSTR iniFilePath; LPCWSTR friendlyName; LPCWSTR description; resolution defaultVal; std::vector valueResolutions; bool editable; }; struct PluginConfigGroupData { LPCWSTR name; int height; }; struct PluginConfigButtonData { LPCWSTR friendlyName; LPCWSTR description; void(*func)(); }; struct PluginConfigSpacerData { int height; }; struct PluginConfigOption { ConfigType cfgType; void* data; }; struct PluginConfigArray { int len; PluginConfigOption* options; }; #pragma pack(pop) } ================================================ FILE: source-code/source/plugins/DivaWig/dllmain.cpp ================================================ #include "framework.h" #include "PluginConfigApi.h" #include #include #include #include #include #include static const enum module_part { HEAD_ACCESSORY, HAIR, UNKNOWN_1, UNKNOWN_2, FACE_ACCESSORY, UNKNOWN_3, FACE_TEXTURES, UNKNOWN_4, CHEST_ACCESSORY, UNKNOWN_5, BODY, UNKNOWN_6, UNKNOWN_7, UNKNOWN_8, HANDS, UNKNOWN_9, BACK_ACCESSORY, UNKNOWN_10, UNKNOWN_11, UNKNOWN_12, UNKNOWN_13, UNKNOWN_14, UNKNOWN_15, UNKNOWN_16, HEAD, ALL = -1, NONE = -2 }; using namespace std; void(__cdecl* originalWig)(void* cls, uint64_t unk, uint64_t unk2) = (void(__cdecl*)(void* cls, uint64_t unk, uint64_t unk2))0x14052AD90; void(__cdecl* originalSec)(unsigned int* a1, unsigned int module_part) = (void(__cdecl*)(unsigned int* a1, unsigned int module_part))0x14052ADF0; void(__cdecl* originalThi)(unsigned int* a1, unsigned int module_part) = (void(__cdecl*)(unsigned int* a1, unsigned int module_part))0x140521FA0; void(__cdecl* pvTimerUpdate)(__int64 a1) = (void(__cdecl*)(__int64 a1))0x1405BDF90; void(__cdecl* unloadFunc)(uint64_t* classp, unsigned int unk, __int64 performer) = (void(__cdecl*)(uint64_t * classp, unsigned int unk, __int64 performer))0x14052F720; void(__cdecl* loadFunc)(uint64_t* classp, unsigned int unk, __int64 performer) = (void(__cdecl*)(uint64_t * classp, unsigned int unk, __int64 performer))0x14052FC00; const string Strings[25] = { "Head accessory", "Hair", "Unknown 1", "Unknown 2", "Face accessory", "Unknown 3", "Face textures", "Unknown 4", "Chest accessory", "Unknown 5", "Body", "Unknown 6", "Unknown 7", "Unknown 8", "Hands", "Unknown 9", "Back accessory", "Unknown 10", "Unknown 11", "Unknown 12", "Unknown 13", "Unknown 14", "Unknown 15", "Unknown 16", "Head" }; char part_to_update = -1; /*uint64_t *last_unload_a1 = 0, *last_reload_a1 = 0; unsigned int last_unload_a2 = 0, last_reload_a2 = 0; __int64 last_unload_a3 = 0, last_reload_a3 = 0;*/ bool dobeep = true, allowReloading = true, debug = false; void loadConfig() { dobeep = GetPrivateProfileIntW(L"general", L"beep", 1, CONFIG_FILE) > 0 ? true : false; allowReloading = GetPrivateProfileIntW(L"general", L"reloading", 0, CONFIG_FILE) > 0 ? true : false; debug = GetPrivateProfileIntW(L"general", L"debug", 0, CONFIG_FILE) > 0 ? true : false; return; } void setPartToUpdate(char part, string message, unsigned short beepfreq) { part_to_update = part; cout << "[DivaWig] " << message << endl; if (dobeep) Beep(beepfreq, 300); this_thread::sleep_for(chrono::seconds(1)); } void unloadAll() { unloadFunc((uint64_t*)0x1411B7060, 0, 5387286240); unloadFunc((uint64_t*)0x1411B7060, 0, 5387319280); unloadFunc((uint64_t*)0x1411B7060, 0, 5387352320); cout << "[DivaWig] All unloaded!" << endl; if (dobeep) Beep(500, 100); this_thread::sleep_for(chrono::seconds(1));; } void unload(__int64 performer_address) { unloadFunc((uint64_t*)0x1411B7060, 0, performer_address); cout << "[DivaWig] Performer " << performer_address/33040 + 1 << " unloaded!" << endl; if (dobeep) Beep(500, 100); this_thread::sleep_for(chrono::seconds(1));; } void loadAll() { loadFunc((uint64_t*)0x1411B7060, 0, 5387286240); loadFunc((uint64_t*)0x1411B7060, 0, 5387319280); loadFunc((uint64_t*)0x1411B7060, 0, 5387352320); cout << "[DivaWig] All loaded!" << endl; if (dobeep) Beep(600, 100); this_thread::sleep_for(chrono::seconds(1));; } void load(__int64 performer_address) { loadFunc((uint64_t*)0x1411B7060, 0, performer_address); cout << "[DivaWig] Performer " << performer_address / 33040 + 1 << " loaded!" << endl; if (dobeep) Beep(600, 100); this_thread::sleep_for(chrono::seconds(1)); } /*void hookedUnload(uint64_t* a1, unsigned int a2, __int64 a3) { cout << "[DivaWig] hookedUnload a1: " << a1 << "; a2: " << a2 << "; a3: " << a3 << endl; last_unload_a1 = a1; last_unload_a2 = a2; last_unload_a3 = a3; unloadFunc(a1, a2, a3); } void hookedLoad(uint64_t* a1, unsigned int a2, __int64 a3) { cout << "[DivaWig] hookedReload a1: " << a1 << "; a2: " << a2 << "; a3: " << a3 << endl; last_reload_a1 = a1; last_reload_a2 = a2; last_reload_a3 = a3; loadFunc(a1, a2, a3); }*/ void inputLoop(__int64 a1) { //if (GetKeyState(VK_CONTROL) < 0) { if (GetKeyState('0') < 0) setPartToUpdate(ALL, "Update all module parts!", 330); if (GetKeyState('1') < 0) setPartToUpdate(HAIR, "Only update the hair!", 440); if (GetKeyState('2') < 0) setPartToUpdate(HEAD_ACCESSORY, "Only update the head accessory!", 550); if (GetKeyState('3') < 0) setPartToUpdate(FACE_ACCESSORY, "Only update the face accessory!", 660); if (GetKeyState('4') < 0) setPartToUpdate(FACE_TEXTURES, "Only update the face textures!", 770); if (GetKeyState('5') < 0) setPartToUpdate(HEAD, "Only update the head!", 880); if (GetKeyState('6') < 0) setPartToUpdate(CHEST_ACCESSORY, "Only update the chest accessory!", 990); if (GetKeyState('7') < 0) setPartToUpdate(BODY, "Only update the body!", 1100); if (GetKeyState('8') < 0) setPartToUpdate(BACK_ACCESSORY, "Only update the back accessory!", 1210); if (GetKeyState('9') < 0) setPartToUpdate(NONE, "Update nothing!", 220); } if (allowReloading) { if (GetKeyState('U') < 0) { if (GetKeyState(VK_LCONTROL) < 0 || GetKeyState(VK_RCONTROL) < 0) unloadAll(); if (GetKeyState('1') < 0) unload(5387286240); if (GetKeyState('2') < 0) unload(5387319280); if (GetKeyState('3') < 0) unload(5387352320); } if (GetKeyState('L') < 0) { if (GetKeyState(VK_LCONTROL) < 0 || GetKeyState(VK_RCONTROL) < 0) loadAll(); if (GetKeyState('1') < 0) load(5387286240); if (GetKeyState('2') < 0) load(5387319280); if (GetKeyState('3') < 0) load(5387352320); } } pvTimerUpdate(a1); } __int64 hookedWig(__int64 classp, int module_part, int part_id) { if (debug) cout << "[DivaWig] Performer: " << (classp-5387286232)/33040+1 << "; Module part: " << module_part << " (" << Strings[module_part] << ")" << "; Default part: " << part_id << "." << endl; if (part_to_update == ALL || part_to_update == module_part) *(int*)(classp + 4i64 * module_part + 8) = part_id; return module_part; } void hookedSec(unsigned int* a1, unsigned int module_part) { if (part_to_update == ALL || part_to_update == module_part) originalSec(a1, module_part); } void hookedThi(unsigned int* a1, unsigned int module_part) { if (part_to_update == ALL || part_to_update == module_part) originalSec(a1, module_part); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { loadConfig(); DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); cout << "[DivaWig] Hooking functions..." << endl; DetourAttach(&(PVOID&)originalWig, (PVOID)hookedWig); DetourAttach(&(PVOID&)originalSec, (PVOID)hookedSec); DetourAttach(&(PVOID&)originalThi, (PVOID)hookedThi); DetourAttach(&(PVOID&)pvTimerUpdate, (PVOID)inputLoop); cout << "[DivaWig] Functions hooked." << endl; DetourTransactionCommit(); /*if (allowReloading) { DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)unloadFunc, (PVOID)hookedUnload); DetourTransactionCommit(); DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)loadFunc, (PVOID)hookedLoad); DetourTransactionCommit(); }*/ //thread* inputThread = new thread(inputLoop); } return TRUE; } PluginConfig::PluginConfigOption config[] = { { PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"beep", L"general", CONFIG_FILE, L"Beep", L"Beep when selecting the part that should be updated.", true } }, { PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"reloading", L"general", CONFIG_FILE, L"Unloading and loading (experimental)", L"Allow unloading (CTRL+U or U+number) and loading (CTRL+L or L+number).", false } }, { PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"debug", L"general", CONFIG_FILE, L"Debug", L"Print extra information.", false } }, }; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"DivaWig"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"DivaWig Plugin by nas\n\nDivaWig lets you mix some module parts by pressing CTRL+0~9."; } extern "C" __declspec(dllexport) PluginConfig::PluginConfigArray GetPluginOptions(void) { return PluginConfig::PluginConfigArray{ _countof(config), config }; } ================================================ FILE: source-code/source/plugins/DivaWig/framework.h ================================================ #include #include std::wstring ExePath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); return std::wstring(buffer); } std::wstring DirPath() { std::wstring exepath = ExePath(); std::wstring::size_type pos = exepath.find_last_of(L"\\/"); return exepath.substr(0, pos); } std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\DivaWig.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); ================================================ FILE: source-code/source/plugins/Launcher/ConfigOption.h ================================================ #pragma once #pragma warning(push) #pragma warning(disable: 4947) #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include #include #include #include #include #include "PluginConfigApi.h" #include "IniReader.h" using namespace System; using namespace System::Windows::Forms; float BaseScaleSize = 96; int Col1Width = 110; int Col2Left = 140; int Col2Width = 90; int ConfigBtnLeft = 120; int ControlSpacing = 6; // declare this early (actual definitions below) class ConfigOptionBase; Panel^ MakePanel(int width, int height, std::vector &cfg, ToolTip^ tooltip, bool* hasChanged); #define RESOPT_MATCH_WINDOW_TEXT "Match Window" #define RESOPT_MATCH_SCREEN_TEXT "Match Screen" #define RESOPT_DEFAULT_TEXT "Default" ref class ComboboxValidation { public: ComboBox^ cb; ComboboxValidation(ComboBox^ combobox) { cb = combobox; } System::Void CheckNumberLeave(System::Object^ sender, System::EventArgs^ e) { System::String^ text = cb->Text; cli::array^ digitsarray = gcnew cli::array{ L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9' }; System::Collections::Generic::List^ digitslist = gcnew System::Collections::Generic::List(digitsarray); if (text->Length <= 0) return; while (text->Length > 0 && text[0] != L'-' && !digitslist->Contains(text[0])) { text = text->Remove(0, 1); } if (text->Length <= 1) // can discard up to 1 now because first digit is known good { cb->Text = text; return; } for (int i = 1; i < text->Length; i++) { if (!digitslist->Contains(text[i])) { text = text->Remove(i, 1); i--; // negate the upcoming ++ } } cb->Text = text; } System::Void CheckResolutionLeave(System::Object^ sender, System::EventArgs^ e) { System::String^ text = cb->Text; if (text == RESOPT_MATCH_WINDOW_TEXT || text == RESOPT_MATCH_SCREEN_TEXT || text == RESOPT_DEFAULT_TEXT) return; cli::array^ digitsarray = gcnew cli::array{ L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9' }; System::Collections::Generic::List^ digitslist = gcnew System::Collections::Generic::List(digitsarray); int numX = 0; while (text->Length > 0 && text[0] != L'x' && !digitslist->Contains(text[0])) { text = text->Remove(0, 1); } if (text->Length <= 0) { cb->Text = "x"; return; } if (text[0] == L'x') { numX++; } if (text->Length <= 1) // can discard up to 1 now because first digit is known good { if (numX == 0) // if that digit wasn't an x though, add one { text += "x"; } cb->Text = text; return; } for (int i = 1; i < text->Length; i++) { if (!digitslist->Contains(text[i]) && !(numX == 0 && text[i] == L'x' && ++numX)) { text = text->Remove(i, 1); i--; // negate the upcoming ++ } } if (numX == 0) { text += "x"; } cb->Text = text; } }; ref class PluginConfigHandler { public: Form^ form; PluginConfigHandler(Panel^ optspanel, String^ title, float btnScaleSize) { form = gcnew Form(); form->Text = title; form->FormBorderStyle = FormBorderStyle::FixedDialog; form->StartPosition = FormStartPosition::CenterScreen; form->MaximizeBox = false; form->MinimizeBox = false; form->ShowInTaskbar = false; form->ShowIcon = false; //form->TopMost = true; form->BackColor = Drawing::Color::FromArgb(64, 64, 64); form->ForeColor = Drawing::Color::White; form->Font = optspanel->Font; optspanel->Left = 0; optspanel->Top = 0; Button^ OkBtn = gcnew Button(); OkBtn->Scale(btnScaleSize); OkBtn->Text = L"OK"; OkBtn->Left = 4; OkBtn->Top = optspanel->Bottom + 4; OkBtn->AutoSize = true; OkBtn->FlatStyle = System::Windows::Forms::FlatStyle::Flat; form->ClientSize = Drawing::Size(optspanel->Width, OkBtn->Bottom + 4); form->Controls->Add(optspanel); form->Controls->Add(OkBtn); form->AcceptButton = OkBtn; form->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &PluginConfigHandler::FormClosing); OkBtn->Click += gcnew EventHandler(this, &PluginConfigHandler::OkClick); } System::Void OpenForm(System::Object^ sender, System::EventArgs^ e) { // ShowDialog seems to prevent disposal by copying the panel... // which would be fine if I didn't rely on using the control handles // MessageBox::Show(form->Controls[0]->Handle.ToString()); //Application::OpenForms[0]->Enabled = false; form->Owner = Application::OpenForms[0]; if (form->Visible) form->Hide(); form->Show(); } System::Void FormClosing(System::Object^ sender, FormClosingEventArgs^ e) { if (e->CloseReason == CloseReason::UserClosing) { form->Hide(); //Application::OpenForms[0]->Enabled = true; e->Cancel = true; } } System::Void OkClick(System::Object^ sender, System::EventArgs^ e) { form->Close(); } }; ref class ChangeHandler { public: bool* changebool; ChangeHandler(bool* onchangebool) { changebool = onchangebool; } System::Void SetChanged(System::Object^ sender, System::EventArgs^ e) { *changebool = true; } }; ref class CustomFuncHandler { public: void(*_func)(); CustomFuncHandler(void(*func)()) { _func = func; } System::Void RunFunc(System::Object^ sender, System::EventArgs^ e) { _func(); } }; class ConfigOptionBase { public: LPCWSTR _iniVarName; LPCWSTR _iniSectionName; LPCWSTR _iniFilePath; LPCWSTR _friendlyName; LPCWSTR _description; System::IntPtr mainControlHandle; bool* hasChanged; virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { return 0; } virtual void SaveOption() { return; } }; class OptionMetaGroupStart : public ConfigOptionBase { public: int _height; OptionMetaGroupStart(LPCWSTR friendlyName, int height) { _friendlyName = friendlyName; _height = height; } }; class OptionMetaGroupEnd : public ConfigOptionBase { public: OptionMetaGroupEnd() { } }; class OptionMetaSectionLabel : public ConfigOptionBase { public: OptionMetaSectionLabel(LPCWSTR friendlyName) { _friendlyName = friendlyName; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Label^ lab = gcnew Label(); lab->Text = gcnew String(_friendlyName); lab->Left = left + 2; lab->Top = top; lab->Font = gcnew System::Drawing::Font(lab->Font->Name, 12.0f, System::Drawing::FontStyle::Bold); lab->AutoSize = true; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } lab->Scale(ScaleWidth, ScaleHeight); panel->Controls->Add(lab); mainControlHandle = lab->Handle; int ControlHeight = lab->Font->Height / ScaleHeight; return ControlHeight + ControlSpacing; } }; class OptionMetaSpacer : public ConfigOptionBase { public: int _height; OptionMetaSpacer(int height) { _height = height; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { return _height; } }; class OptionMetaSeparator : public ConfigOptionBase { public: OptionMetaSeparator() { } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Label^ lab = gcnew Label(); lab->Text = "_____________________________________"; lab->Left = left + 2; lab->Top = top; lab->AutoSize = true; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } lab->Scale(ScaleWidth, ScaleHeight); panel->Controls->Add(lab); mainControlHandle = lab->Handle; int ControlHeight = lab->Font->Height / ScaleHeight; return ControlHeight + ControlSpacing; } }; class BooleanOption : public ConfigOptionBase { public: bool _defaultVal; bool _saveAsString; BooleanOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, bool defaultVal, bool saveAsString) { _iniVarName = iniVarName; _iniSectionName = iniSectionName; _iniFilePath = iniFilePath; _friendlyName = friendlyName; _description = description; _defaultVal = defaultVal; _saveAsString = saveAsString; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { CheckBox^ cb = gcnew CheckBox(); cb->Text = gcnew String(_friendlyName); cb->Checked = GetIniBool(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); cb->Left = left + 2; cb->Top = top; cb->AutoSize = true; cb->FlatStyle = System::Windows::Forms::FlatStyle::Flat; // hack to ensure high contrast cb->BackColor = System::Drawing::Color::FromArgb(0, 127, 127, 127); Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } cb->Scale(ScaleWidth, ScaleHeight); tooltip->SetToolTip(cb, gcnew String(_description)); if (hasChanged == nullptr) hasChanged = new bool(false); ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); cb->CheckedChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); panel->Controls->Add(cb); mainControlHandle = cb->Handle; int ControlHeight = cb->Font->Height / ScaleHeight; return ControlHeight + ControlSpacing; } virtual void SaveOption() { SetIniBool(_iniSectionName, _iniVarName, ((CheckBox^)CheckBox::FromHandle(mainControlHandle))->Checked, _iniFilePath, _saveAsString); } }; class NumericOption : public ConfigOptionBase { public: int _defaultVal; int _minVal; int _maxVal; NumericOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, int minVal, int maxVal) { _iniVarName = iniVarName; _iniSectionName = iniSectionName; _iniFilePath = iniFilePath; _friendlyName = friendlyName; _description = description; _defaultVal = defaultVal; _minVal = minVal; _maxVal = maxVal; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Label^ label = gcnew Label(); NumericUpDown^ numberbox = gcnew NumericUpDown(); label->Text = gcnew String(_friendlyName); label->Left = left; label->Top = top + 3; label->Width = Col1Width; label->AutoSize = true; label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; numberbox->Minimum = _minVal; numberbox->Maximum = _maxVal; numberbox->Value = GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); numberbox->Left = left + Col2Left; numberbox->Top = top; numberbox->Width = Col2Width; numberbox->AutoSize = true; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } label->Scale(ScaleWidth, ScaleHeight); numberbox->Scale(ScaleWidth, ScaleHeight); tooltip->SetToolTip(label, gcnew String(_description)); tooltip->SetToolTip(numberbox, gcnew String(_description)); if (hasChanged == nullptr) hasChanged = new bool(false); ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); numberbox->ValueChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); panel->Controls->Add(label); panel->Controls->Add(numberbox); mainControlHandle = numberbox->Handle; int ControlHeight = numberbox->Height / ScaleHeight; return ControlHeight + ControlSpacing; } virtual void SaveOption() { SetIniInt(_iniSectionName, _iniVarName, Convert::ToInt32(((NumericUpDown^)NumericUpDown::FromHandle(mainControlHandle))->Value), _iniFilePath); } }; class StringOption : public ConfigOptionBase { public: LPCWSTR _defaultVal; bool _useUtf8; StringOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, LPCWSTR defaultVal, bool useUtf8) { _iniVarName = iniVarName; _iniSectionName = iniSectionName; _iniFilePath = iniFilePath; _friendlyName = friendlyName; _description = description; _defaultVal = defaultVal; _useUtf8 = useUtf8; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Label^ label = gcnew Label(); TextBox^ textbox = gcnew TextBox(); const wchar_t* stringBuf; label->Text = gcnew String(_friendlyName); label->Left = left; label->Top = top + 3; label->Width = Col1Width; label->AutoSize = true; label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; stringBuf = GetIniString(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath, _useUtf8); textbox->Text = gcnew String(stringBuf); textbox->Left = left + Col2Left; textbox->Top = top; textbox->Width = Col2Width; textbox->AutoSize = true; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } label->Scale(ScaleWidth, ScaleHeight); textbox->Scale(ScaleWidth, ScaleHeight); // disable editing for utf8 mode because the ANSI hack used may not work correctly //if (_useUtf8) { // textbox->Enabled = false; //} tooltip->SetToolTip(label, gcnew String(_description)); tooltip->SetToolTip(textbox, gcnew String(_description)); if (hasChanged == nullptr) hasChanged = new bool(false); ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); textbox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); panel->Controls->Add(label); panel->Controls->Add(textbox); mainControlHandle = textbox->Handle; int ControlHeight = textbox->Height / ScaleHeight; return ControlHeight + ControlSpacing; } virtual void SaveOption() { // disable saving for utf8 mode because the ANSI hack used may not work correctly //if (_useUtf8) // return; System::String^ tempSysStr; std::wstring tempWStr; tempSysStr = ((TextBox^)TextBox::FromHandle(mainControlHandle))->Text; tempWStr = msclr::interop::marshal_as(tempSysStr); SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, _useUtf8); } }; class DropdownOption : public ConfigOptionBase { public: int _defaultVal; int _indexOffset; std::vector _valueStrings; System::IntPtr labelHandle; DropdownOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, std::vector valueStrings, int indexOffset=0) { _iniVarName = iniVarName; _iniSectionName = iniSectionName; _iniFilePath = iniFilePath; _friendlyName = friendlyName; _description = description; _defaultVal = defaultVal; _valueStrings = valueStrings; _indexOffset = indexOffset; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Label^ label = gcnew Label(); ComboBox^ combobox = gcnew ComboBox(); label->Text = gcnew String(_friendlyName); labelHandle = label->Handle; label->Left = left; label->Top = top + 3; label->Width = Col1Width; label->AutoSize = true; label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; for (LPCWSTR& choice : _valueStrings) { combobox->Items->Add(msclr::interop::marshal_as(choice)); } combobox->SelectedIndex = GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath)-_indexOffset; combobox->Left = left + Col2Left; combobox->Top = top; combobox->Width = Col2Width; combobox->AutoSize = true; combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; combobox->DropDownStyle = ComboBoxStyle::DropDownList; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } label->Scale(ScaleWidth, ScaleHeight); combobox->Scale(ScaleWidth, ScaleHeight); tooltip->SetToolTip(label, gcnew String(_description)); tooltip->SetToolTip(combobox, gcnew String(_description)); if (hasChanged == nullptr) hasChanged = new bool(false); ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); panel->Controls->Add(label); panel->Controls->Add(combobox); mainControlHandle = combobox->Handle; int ControlHeight = combobox->Height / ScaleHeight; return ControlHeight + ControlSpacing; } virtual void SaveOption() { SetIniInt(_iniSectionName, _iniVarName, Convert::ToInt32(((ComboBox^)ComboBox::FromHandle(mainControlHandle))->SelectedIndex+_indexOffset), _iniFilePath); } }; class DropdownTextOption : public ConfigOptionBase { public: LPCWSTR _defaultVal; std::vector _valueStrings; bool _editable; bool _useUtf8; DropdownTextOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, LPCWSTR defaultVal, std::vector valueStrings, bool editable, bool useUtf8) { _iniVarName = iniVarName; _iniSectionName = iniSectionName; _iniFilePath = iniFilePath; _friendlyName = friendlyName; _description = description; _defaultVal = defaultVal; _valueStrings = valueStrings; _editable = editable; _useUtf8 = useUtf8; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Label^ label = gcnew Label(); ComboBox^ combobox = gcnew ComboBox(); const wchar_t* stringBuf; label->Text = gcnew String(_friendlyName); label->Left = left; label->Top = top + 3; label->Width = Col1Width; label->AutoSize = true; label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; for (LPCWSTR& choice : _valueStrings) { combobox->Items->Add(msclr::interop::marshal_as(choice)); } stringBuf = GetIniString(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath, _useUtf8); combobox->Text = gcnew String(stringBuf); combobox->Left = left + Col2Left; combobox->Top = top; combobox->Width = Col2Width; combobox->AutoSize = true; combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; if (_editable) combobox->DropDownStyle = ComboBoxStyle::DropDown; else combobox->DropDownStyle = ComboBoxStyle::DropDownList; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } label->Scale(ScaleWidth, ScaleHeight); combobox->Scale(ScaleWidth, ScaleHeight); // disable editing for utf8 mode because the ANSI hack used may not work correctly //if (_useUtf8) { // label->Enabled = false; // combobox->Enabled = false; //} tooltip->SetToolTip(label, gcnew String(_description)); tooltip->SetToolTip(combobox, gcnew String(_description)); if (hasChanged == nullptr) hasChanged = new bool(false); ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); if (_editable) combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); else combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); panel->Controls->Add(label); panel->Controls->Add(combobox); mainControlHandle = combobox->Handle; int ControlHeight = combobox->Height / ScaleHeight; return ControlHeight + ControlSpacing; } virtual void SaveOption() { // disable saving for utf8 mode because the ANSI hack used may not work correctly //if (_useUtf8) // return; System::String^ tempSysStr; std::wstring tempWStr; tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; tempWStr = msclr::interop::marshal_as(tempSysStr); SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, _useUtf8); } }; class DropdownNumberOption : public ConfigOptionBase { public: int _defaultVal; std::vector _valueInts; bool _editable; DropdownNumberOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, std::vector valueInts, bool editable) { _iniVarName = iniVarName; _iniSectionName = iniSectionName; _iniFilePath = iniFilePath; _friendlyName = friendlyName; _description = description; _defaultVal = defaultVal; _valueInts = valueInts; _editable = editable; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Label^ label = gcnew Label(); ComboBox^ combobox = gcnew ComboBox(); System::String^ tempSysStr; label->Text = gcnew String(_friendlyName); label->Left = left; label->Top = top + 3; label->Width = Col1Width; label->AutoSize = true; label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; for (int& choice : _valueInts) { combobox->Items->Add(Convert::ToInt32(choice).ToString()); } tempSysStr = Convert::ToInt32(GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath)).ToString(); combobox->Text = gcnew String(tempSysStr); combobox->Left = left + Col2Left; combobox->Top = top; combobox->Width = Col2Width; combobox->AutoSize = true; combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; if (_editable) combobox->DropDownStyle = ComboBoxStyle::DropDown; else combobox->DropDownStyle = ComboBoxStyle::DropDownList; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } label->Scale(ScaleWidth, ScaleHeight); combobox->Scale(ScaleWidth, ScaleHeight); tooltip->SetToolTip(label, gcnew String(_description)); tooltip->SetToolTip(combobox, gcnew String(_description)); ComboboxValidation^ validation = gcnew ComboboxValidation(combobox); combobox->Leave += gcnew System::EventHandler(validation, &ComboboxValidation::CheckNumberLeave); if (hasChanged == nullptr) hasChanged = new bool(false); ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); if (_editable) combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); else combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); panel->Controls->Add(label); panel->Controls->Add(combobox); mainControlHandle = combobox->Handle; int ControlHeight = combobox->Height / ScaleHeight; return ControlHeight + ControlSpacing; } virtual void SaveOption() { System::String^ tempSysStr; std::wstring tempWStr; tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; tempWStr = msclr::interop::marshal_as(tempSysStr); SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, false); } }; enum ResolutionOptionOpts { RESOPT_NONE, RESOPT_INCLUDE_MATCH_WINDOW, RESOPT_INCLUDE_MATCH_SCREEN, RESOPT_INCLUDE_DEFAULT = 4 }; class ResolutionOption : public ConfigOptionBase { public: LPCWSTR _iniVarName2; resolution _defaultVal; std::vector _valueResolutions; bool _editable; ResolutionOptionOpts _opts; ResolutionOption(LPCWSTR iniVarName, LPCWSTR iniVarName2, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, resolution defaultVal, std::vector valueResolutions, bool editable, ResolutionOptionOpts opts) { _iniVarName = iniVarName; _iniVarName2 = iniVarName2; _iniSectionName = iniSectionName; _iniFilePath = iniFilePath; _friendlyName = friendlyName; _description = description; _defaultVal = defaultVal; _valueResolutions = valueResolutions; _editable = editable; _opts = opts; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Label^ label = gcnew Label(); ComboBox^ combobox = gcnew ComboBox(); System::String^ tempSysStr; label->Text = gcnew String(_friendlyName); label->Left = left; label->Top = top + 3; label->Width = Col1Width; label->AutoSize = true; label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; if (_opts & RESOPT_INCLUDE_MATCH_WINDOW) combobox->Items->Add(RESOPT_MATCH_WINDOW_TEXT); else if (_opts & RESOPT_INCLUDE_MATCH_SCREEN) combobox->Items->Add(RESOPT_MATCH_SCREEN_TEXT); else if (_opts & RESOPT_INCLUDE_DEFAULT) combobox->Items->Add(RESOPT_DEFAULT_TEXT); for (resolution& choice : _valueResolutions) { tempSysStr = Convert::ToInt32(choice.width).ToString() + L"x" + Convert::ToInt32(choice.height).ToString(); combobox->Items->Add(tempSysStr); } int width = GetIniInt(_iniSectionName, _iniVarName, -39, _iniFilePath); int height = GetIniInt(_iniSectionName, _iniVarName2, -39, _iniFilePath); if (width == -39 || height == -39) { if (_defaultVal.width == -1 || _defaultVal.height == -1) width = -1; else { tempSysStr = Convert::ToInt32(_defaultVal.width).ToString() + L"x" + Convert::ToInt32(_defaultVal.height).ToString(); combobox->Text = tempSysStr; } } if (width == -1 || height == -1) { // -1 -> Match window/screen if (_opts & RESOPT_INCLUDE_MATCH_WINDOW) combobox->Text = RESOPT_MATCH_WINDOW_TEXT; else if (_opts & RESOPT_INCLUDE_MATCH_SCREEN) combobox->Text = RESOPT_MATCH_SCREEN_TEXT; else if (_opts & RESOPT_INCLUDE_DEFAULT) combobox->Text = RESOPT_DEFAULT_TEXT; } else { tempSysStr = Convert::ToInt32(width).ToString() + L"x" + Convert::ToInt32(height).ToString(); combobox->Text = tempSysStr; } combobox->Left = left + Col2Left; combobox->Top = top; combobox->Width = Col2Width; combobox->AutoSize = true; combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; if (_editable) combobox->DropDownStyle = ComboBoxStyle::DropDown; else combobox->DropDownStyle = ComboBoxStyle::DropDownList; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } label->Scale(ScaleWidth, ScaleHeight); combobox->Scale(ScaleWidth, ScaleHeight); tooltip->SetToolTip(label, gcnew String(_description)); tooltip->SetToolTip(combobox, gcnew String(_description)); if (hasChanged == nullptr) hasChanged = new bool(false); ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); if (_editable) combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); else combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); ComboboxValidation^ validation = gcnew ComboboxValidation(combobox); combobox->Leave += gcnew System::EventHandler(validation, &ComboboxValidation::CheckResolutionLeave); panel->Controls->Add(label); panel->Controls->Add(combobox); mainControlHandle = combobox->Handle; int ControlHeight = combobox->Height / ScaleHeight; return ControlHeight + ControlSpacing; } virtual void SaveOption() { System::String^ tempSysStr; std::wstring tempWStr; cli::array^ resolutionArray; tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; // Match window/screen -> -1x-1 if (tempSysStr == RESOPT_MATCH_WINDOW_TEXT || tempSysStr == RESOPT_MATCH_SCREEN_TEXT || tempSysStr == RESOPT_DEFAULT_TEXT) tempSysStr = "-1x-1"; resolutionArray = tempSysStr->Split('x'); tempSysStr = resolutionArray[0]; tempWStr = msclr::interop::marshal_as(tempSysStr); SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, false); tempSysStr = resolutionArray[1]; tempWStr = msclr::interop::marshal_as(tempSysStr); SetIniString(_iniSectionName, _iniVarName2, tempWStr.c_str(), _iniFilePath, false); } }; class ButtonOption : public ConfigOptionBase { public: void(*_func)(); ButtonOption(LPCWSTR friendlyName, LPCWSTR description, void(*func)()) { _friendlyName = friendlyName; _description = description; _func = func; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { Button^ button = gcnew Button(); button->Text = gcnew String(_friendlyName); button->Left = left; button->Top = top; button->AutoSize = true; button->FlatStyle = System::Windows::Forms::FlatStyle::Flat; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } button->Scale(ScaleWidth, ScaleHeight); tooltip->SetToolTip(button, gcnew String(_description)); CustomFuncHandler^ funchandler = gcnew CustomFuncHandler(_func); button->Click += gcnew System::EventHandler(funchandler, &CustomFuncHandler::RunFunc); panel->Controls->Add(button); int ControlHeight = button->Height / ScaleHeight; return ControlHeight + ControlSpacing; } }; class PluginOption : public ConfigOptionBase { public: bool _defaultVal; std::wstring _builddate; std::vector _configopts; PluginOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, bool defaultVal, std::vector configopts, std::wstring builddate = L"Unknown") { _iniVarName = iniVarName; _iniSectionName = iniSectionName; _iniFilePath = iniFilePath; _friendlyName = friendlyName; _description = description; _defaultVal = defaultVal; _configopts = configopts; _builddate = builddate; } virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) { CheckBox^ cb = gcnew CheckBox(); Button^ button = gcnew Button(); cb->Text = gcnew String(_friendlyName); cb->Checked = GetIniBool(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); cb->Left = left + 2; cb->Top = top + 3; cb->AutoSize = true; cb->FlatStyle = System::Windows::Forms::FlatStyle::Flat; // hack to ensure high contrast cb->BackColor = System::Drawing::Color::FromArgb(0, 127, 127, 127); button->Text = L"Config"; button->Left = left + ConfigBtnLeft; button->Top = top; button->AutoSize = true; button->FlatStyle = System::Windows::Forms::FlatStyle::Flat; Form^ RootForm = panel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } cb->Scale(ScaleWidth, ScaleHeight); button->Scale(ScaleWidth, ScaleHeight); tooltip->SetToolTip(cb, gcnew String(_description)); if (hasChanged == nullptr) hasChanged = new bool(false); ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); cb->CheckedChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); panel->Controls->Add(cb); mainControlHandle = cb->Handle; if (_configopts.size() > 0) { ToolTip^ paneltooltip = gcnew ToolTip(); Panel^ configPanel = MakePanel((Col2Left + Col2Width + 76), 250, _configopts, paneltooltip, hasChanged); configPanel->Scale(ScaleWidth, ScaleHeight); if (RootForm) configPanel->Font = RootForm->Font; PluginConfigHandler^ confighandler = gcnew PluginConfigHandler(configPanel, gcnew String(_friendlyName) + " Options", ScaleHeight); button->Click += gcnew System::EventHandler(confighandler, &PluginConfigHandler::OpenForm); panel->Controls->Add(button); } int ControlHeight = button->Height / ScaleHeight; return ControlHeight + ControlSpacing; } virtual void SaveOption() { SetIniBool(_iniSectionName, _iniVarName, ((CheckBox^)CheckBox::FromHandle(mainControlHandle))->Checked, _iniFilePath, false); for (ConfigOptionBase* opt : _configopts) { opt->SaveOption(); } } }; Panel^ MakePanel(int width, int height, std::vector &cfg, ToolTip^ tooltip, bool* hasChanged) { Panel^ outpanel = gcnew Panel(); outpanel->Width = width; outpanel->Height = height; outpanel->AutoScroll = true; Form^ RootForm = outpanel->FindForm(); float ScaleWidth = 1.0f; float ScaleHeight = 1.0f; if (RootForm) { Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; } int curX = 12; int curY = 3; for (int i = 0; i < cfg.size(); i++) { if (typeid(*cfg[i]).hash_code() == typeid(OptionMetaGroupEnd).hash_code()) continue; if (typeid(*cfg[i]).hash_code() == typeid(OptionMetaGroupStart).hash_code()) { OptionMetaGroupStart* groupData = (OptionMetaGroupStart*)(cfg[i]); GroupBox^ groupbox = gcnew GroupBox(); groupbox->Width = width - (ScaleWidth * 28); groupbox->Height = ScaleHeight * (groupData->_height); groupbox->Left = ScaleWidth * 4; groupbox->Top = ScaleHeight * curY; groupbox->Text = gcnew String(groupData->_friendlyName); groupbox->ForeColor = Drawing::Color::White; // find the end of this group by simple iteration keeping track of indent level int level = 1; int endidx; for (endidx = i + 1; endidx < cfg.size(); endidx++) { if (typeid(*cfg[endidx]).hash_code() == typeid(OptionMetaGroupStart).hash_code()) level++; if (typeid(*cfg[endidx]).hash_code() == typeid(OptionMetaGroupEnd).hash_code()) level--; if (level == 0) break; } Panel^ groupPanel = MakePanel(groupbox->Width - (ScaleWidth * 12), groupbox->Height - (ScaleHeight * 20), std::vector(&(cfg[i + 1]), &(cfg[endidx])), tooltip, hasChanged); groupPanel->Left = ScaleWidth * 2; groupPanel->Top = ScaleHeight * 14; groupbox->Controls->Add(groupPanel); outpanel->Controls->Add(groupbox); i = endidx; curY += groupData->_height; } else { cfg[i]->hasChanged = hasChanged; curY += cfg[i]->AddToPanel(outpanel, curX, curY, tooltip); } } return outpanel; } #pragma warning(pop) ================================================ FILE: source-code/source/plugins/Launcher/IniReader.h ================================================ #pragma once // kinda rushed and hacky wrapper around simpleini for use by ConfigOption // (has a similar API to windows GetPrivateProfile/SetPrivateProfile stuff) #include CSimpleIniW ini_reader; std::wstring loaded_ini_file; bool LoadIni(const wchar_t* filename, bool use_utf8=false) { if (ini_reader.IsUnicode() == use_utf8 && loaded_ini_file == filename) { return true; } ini_reader.Reset(); ini_reader.SetUnicode(use_utf8); if (ini_reader.LoadFile(filename) != 0) { // if the path doesn't exist, this isn't an error so we can still save filename and return true // (writing config will create the file) DWORD dwAttrib = GetFileAttributesW(filename); if (dwAttrib == INVALID_FILE_ATTRIBUTES) { loaded_ini_file = filename; return true; } loaded_ini_file = L""; return false; } else { loaded_ini_file = filename; return true; } } const wchar_t* GetIniString(const wchar_t* section, const wchar_t* key, const wchar_t* default, const wchar_t* filename, bool use_utf8) { if (!LoadIni(filename, use_utf8)) { return default; } return ini_reader.GetValue(section, key, default); } int GetIniInt(const wchar_t* section, const wchar_t* key, int default, const wchar_t* filename) { if (!LoadIni(filename)) { return default; } return ini_reader.GetLongValue(section, key, default); } bool GetIniBool(const wchar_t* section, const wchar_t* key, bool default, const wchar_t* filename) { if (!LoadIni(filename)) { return default; } return ini_reader.GetBoolValue(section, key, default); } void SetIniString(const wchar_t* section, const wchar_t* key, const wchar_t* value, const wchar_t* filename, bool use_utf8) { if (!LoadIni(filename, use_utf8)) { return; } ini_reader.SetValue(section, key, value); ini_reader.SaveFile(filename); } void SetIniInt(const wchar_t* section, const wchar_t* key, int value, const wchar_t* filename) { if (!LoadIni(filename)) { return; } ini_reader.SetLongValue(section, key, value); ini_reader.SaveFile(filename); } void SetIniBool(const wchar_t* section, const wchar_t* key, bool value, const wchar_t* filename, bool use_string) { if (!LoadIni(filename)) { return; } if (use_string) ini_reader.SetValue(section, key, value ? L"true" : L"false"); else ini_reader.SetValue(section, key, value ? L"1" : L"0"); ini_reader.SaveFile(filename); } ================================================ FILE: source-code/source/plugins/Launcher/Launcher.filters ================================================  {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx Source Files Header Files Header Files ================================================ FILE: source-code/source/plugins/Launcher/Launcher.vcxproj ================================================  Debug x64 Release x64 16.0 {60d5e9f4-335f-402b-9a07-d78674dffc9b} v4.5 ManagedCProj Launcher 10.0 Launcher DynamicLibrary true v142 true Unicode DynamicLibrary false v142 true Unicode true .dva false .dva $(ProjectName) NotUsing Level3 Disabled _DEBUG;%(PreprocessorDefinitions) ..\..\..\dependencies\simpleini;..\..\..\dependencies\WineVer;..\..\..\dependencies\GPUModel;..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\freeglut\include;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) stdcpp17 -d2FH4- %(AdditionalOptions) User32.lib Windows ..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) NotUsing Level3 NDEBUG;%(PreprocessorDefinitions) ..\..\..\dependencies\simpleini;..\..\..\dependencies\WineVer;..\..\..\dependencies\GPUModel;..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\freeglut\include;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) stdcpp17 MultiThreadedDLL -d2FH4- %(AdditionalOptions) User32.lib Windows ..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) CppForm ui.h ================================================ FILE: source-code/source/plugins/Launcher/PluginConfig.h ================================================ #pragma once #include "ConfigOption.h" #include "PluginConfigApi.h" namespace PluginConfig { ConfigOptionBase* GetConfigOption(PluginConfigOption cfg) { PluginConfigBooleanData* boolData = (PluginConfigBooleanData*)(cfg.data); PluginConfigNumericData* numericData = (PluginConfigNumericData*)(cfg.data); PluginConfigStringData* stringData = (PluginConfigStringData*)(cfg.data); PluginConfigDropdownIndexData* ddIdxData = (PluginConfigDropdownIndexData*)(cfg.data); PluginConfigDropdownTextData* ddTextData = (PluginConfigDropdownTextData*)(cfg.data); PluginConfigDropdownNumberData* ddNumberData = (PluginConfigDropdownNumberData*)(cfg.data); PluginConfigResolutionData* resData = (PluginConfigResolutionData*)(cfg.data); PluginConfigGroupData* groupData = (PluginConfigGroupData*)(cfg.data); PluginConfigButtonData* btnData = (PluginConfigButtonData*)(cfg.data); PluginConfigSpacerData* spacerData = (PluginConfigSpacerData*)(cfg.data); switch (cfg.cfgType) { case CONFIG_BOOLEAN: return new BooleanOption(boolData->iniVarName, boolData->iniSectionName, boolData->iniFilePath, boolData->friendlyName, boolData->description, boolData->defaultVal, boolData->saveAsString); case CONFIG_NUMERIC: return new NumericOption(numericData->iniVarName, numericData->iniSectionName, numericData->iniFilePath, numericData->friendlyName, numericData->description, numericData->defaultVal, numericData->minVal, numericData->maxVal); case CONFIG_STRING: return new StringOption(stringData->iniVarName, stringData->iniSectionName, stringData->iniFilePath, stringData->friendlyName, stringData->description, stringData->defaultVal, stringData->useUtf8); case CONFIG_DROPDOWN_INDEX: return new DropdownOption(ddIdxData->iniVarName, ddIdxData->iniSectionName, ddIdxData->iniFilePath, ddIdxData->friendlyName, ddIdxData->description, ddIdxData->defaultVal, ddIdxData->valueStrings); case CONFIG_DROPDOWN_TEXT: return new DropdownTextOption(ddTextData->iniVarName, ddTextData->iniSectionName, ddTextData->iniFilePath, ddTextData->friendlyName, ddTextData->description, ddTextData->defaultVal, ddTextData->valueStrings, ddTextData->editable, ddTextData->useUtf8); case CONFIG_DROPDOWN_NUMBER: return new DropdownNumberOption(ddNumberData->iniVarName, ddNumberData->iniSectionName, ddNumberData->iniFilePath, ddNumberData->friendlyName, ddNumberData->description, ddNumberData->defaultVal, ddNumberData->valueInts, ddNumberData->editable); case CONFIG_RESOLUTION: return new ResolutionOption(resData->iniVarName, resData->iniVarName2, resData->iniSectionName, resData->iniFilePath, resData->friendlyName, resData->description, resData->defaultVal, resData->valueResolutions, resData->editable, (ResolutionOptionOpts)0); case CONFIG_GROUP_START: return new OptionMetaGroupStart(groupData->name, groupData->height); case CONFIG_GROUP_END: return new OptionMetaGroupEnd(); case CONFIG_BUTTON: return new ButtonOption(btnData->friendlyName, btnData->description, btnData->func); case CONFIG_SPACER: return new OptionMetaSpacer(spacerData->height); default: return new ConfigOptionBase(); } } std::vector GetConfigOptionVec(PluginConfigArray &in) { std::vector outvec; for (int i = 0; i < in.len; i++) { // basic check for validity if (in.options[i].data == nullptr && in.options[i].cfgType != CONFIG_GROUP_END) break; outvec.push_back(GetConfigOption(in.options[i])); } return outvec; } /*std::vector testcfg = { PluginConfigOption{ CONFIG_GROUP_START, new PluginConfigGroupData{L"Screen Resolution", 400 } }, PluginConfigOption{ CONFIG_DROPDOWN_INDEX, new PluginConfigDropdownIndexData{ L"display", RESOLUTION_SECTION, CONFIG_FILE, L"Display:", L"Sets the window/screen mode.", 0, std::vector({ L"Windowed", L"Borderless", L"Fullscreen" }) } }, PluginConfigOption{ CONFIG_RESOLUTION, new PluginConfigResolutionData{ L"width", L"height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the display resolution.", resolution(1280, 720), getScreenResolutionsVec(screenModes) } } };*/ //std::vector testcfgconfigopts = GetConfigOptionVec(testcfg); }; ================================================ FILE: source-code/source/plugins/Launcher/SkinnedMessageBox.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include using namespace System; using namespace System::Windows::Forms; using namespace System::Drawing; // ported from https://stackoverflow.com/a/7785745 // original code by user LarsTech https://stackoverflow.com/users/719186/larstech static ref class SkinnedMessageBox { private: ref class SkinnedMessageBoxForm : Form { private: void SkinnedMessageBoxForm_Shown(Object^ sender, EventArgs^ e) { Activate(); } void SkinnedMessageBoxForm_FormClosed(Object^ sender, FormClosedEventArgs^ e) { if (CancelButton && (DialogResult == System::Windows::Forms::DialogResult::None || DialogResult == System::Windows::Forms::DialogResult::Cancel)) DialogResult = CancelButton->DialogResult; } void InitComponentNew() { this->SuspendLayout(); this->AutoSize = true; this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog; this->Width = 350; this->Height = 140; this->StartPosition = FormStartPosition::CenterScreen; this->MaximizeBox = false; this->MinimizeBox = false; this->ShowInTaskbar = false; this->ShowIcon = false; __try { this->Icon = Application::OpenForms[0]->Icon; } __except (1) { } this->Shown += gcnew EventHandler(this, &SkinnedMessageBoxForm::SkinnedMessageBoxForm_Shown); this->FormClosed += gcnew FormClosedEventHandler(this, &SkinnedMessageBoxForm::SkinnedMessageBoxForm_FormClosed); //this->Font = SystemFonts::MessageBoxFont; //this->Font = gcnew Font(SystemFonts::MessageBoxFont->FontFamily, SystemFonts::MessageBoxFont->SizeInPoints); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::None; this->ResumeLayout(false); this->PerformLayout(); } float ScaleWidth = 1.0; float ScaleHeight = 1.0; int btnWidth = 85; int btnHeight = 23; int btnPadding = 12; static cli::array^ buttonrefs = gcnew cli::array{ gcnew Button, gcnew Button, gcnew Button }; int numbuttons = 1; Button^ AddBtn(String^ text, System::Windows::Forms::DialogResult result, int btnNumber) { Button^ btn = buttonrefs[btnNumber]; btn->Text = text; btn->DialogResult = result; btn->Anchor = AnchorStyles::Bottom | AnchorStyles::Right; btn->Width = btnWidth; btn->Height = btnHeight; btn->Location = Point(ClientSize.Width - btnWidth * (numbuttons - btnNumber) - btnPadding * (numbuttons - btnNumber), ClientSize.Height - btnHeight - btnPadding); Controls->Add(btn); //buttonrefs[btnNumber] = btn; return btn; } void SetBackCol(Control^ elem, Color color) { Type^ elemType = elem->GetType(); if ((elem->HasChildren || elemType == Button::typeid || elemType == ComboBox::typeid) && elemType != NumericUpDown::typeid) { elem->BackColor = color; for (int i = 0; i < elem->Controls->Count; i++) { SetBackCol(elem->Controls[i], color); } } } void SetForeCol(Control^ elem, Color color) { Type^ elemType = elem->GetType(); if (elemType != NumericUpDown::typeid && elemType != TextBox::typeid) { elem->ForeColor = color; } if (elem->HasChildren && elemType != NumericUpDown::typeid) { for (int i = 0; i < elem->Controls->Count; i++) { SetForeCol(elem->Controls[i], color); } } } void SetUIStyle(Control^ elem, FlatStyle style) { Type^ elemType = elem->GetType(); if (elemType == Button::typeid) { ((Button^)elem)->FlatStyle = style; } else if (elemType == ComboBox::typeid) { ((ComboBox^)elem)->FlatStyle = style; } else if (elemType == CheckBox::typeid) { ((CheckBox^)elem)->FlatStyle = style; } if (elem->HasChildren && elemType != NumericUpDown::typeid) { for (int i = 0; i < elem->Controls->Count; i++) { SetUIStyle(elem->Controls[i], style); } } } public: SkinnedMessageBoxForm(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultbutton, MessageBoxOptions options) { InitComponentNew(); Graphics^ grfx = Graphics::FromHwnd(Handle); ScaleWidth = Font->SizeInPoints / 72 * grfx->DpiX / 10.67f; ScaleHeight = ScaleWidth; btnWidth *= ScaleWidth; btnHeight *= ScaleHeight; btnPadding *= ScaleWidth; Width *= ScaleWidth; Height *= ScaleHeight; if (owner->Handle != IntPtr::Zero) { Owner = Control::FromHandle(owner->Handle)->FindForm(); } else { Owner = ActiveForm; } Text = caption; System::Windows::Forms::Padding lblMargin = System::Windows::Forms::Padding(14 * ScaleWidth, 0 * ScaleHeight, 14 * ScaleWidth, 45 * ScaleHeight); Point lblLocation = Point(14 * ScaleWidth, 14 * ScaleHeight); Drawing::Size lblMinSize = Drawing::Size(ClientSize.Width - lblLocation.X - lblMargin.Right, 0); Drawing::Size lblMaxSize = Drawing::Size(600 * ScaleWidth, 0 * ScaleHeight); Label^ MessageLbl = gcnew Label(); MessageLbl->Text = message; MessageLbl->AutoSize = true; MessageLbl->Margin = lblMargin; MessageLbl->Location = lblLocation; MessageLbl->MinimumSize = lblMinSize; MessageLbl->MaximumSize = lblMaxSize; Controls->Add(MessageLbl); if (buttons == MessageBoxButtons::OK) { numbuttons = 1; Button^ OkBtn = AddBtn("&OK", System::Windows::Forms::DialogResult::OK, 0); CancelButton = OkBtn; //(not sure why, but this matches official .NET behaviour) } else if (buttons == MessageBoxButtons::OKCancel) { numbuttons = 2; AddBtn("&OK", System::Windows::Forms::DialogResult::OK, 0); Button^ CancelBtn = AddBtn("&Cancel", System::Windows::Forms::DialogResult::Cancel, 1); CancelButton = CancelBtn; } else if (buttons == MessageBoxButtons::YesNo) { numbuttons = 2; AddBtn("&Yes", System::Windows::Forms::DialogResult::Yes, 0); Button^ NoBtn = AddBtn("&No", System::Windows::Forms::DialogResult::No, 1); CancelButton = NoBtn; //(official .NET doesn't set cancel button, but this seems pretty clear to me...) } else if (buttons == MessageBoxButtons::RetryCancel) { numbuttons = 2; AddBtn("&Retry", System::Windows::Forms::DialogResult::Retry, 0); Button^ CancelBtn = AddBtn("&Cancel", System::Windows::Forms::DialogResult::Cancel, 1); CancelButton = CancelBtn; } else if (buttons == MessageBoxButtons::YesNoCancel) { numbuttons = 3; AddBtn("&Yes", System::Windows::Forms::DialogResult::Yes, 0); AddBtn("&No", System::Windows::Forms::DialogResult::No, 1); Button^ CancelBtn = AddBtn("&Cancel", System::Windows::Forms::DialogResult::Cancel, 2); CancelButton = CancelBtn; } else if (buttons == MessageBoxButtons::AbortRetryIgnore) { numbuttons = 3; AddBtn("&Abort", System::Windows::Forms::DialogResult::Abort, 0); AddBtn("&Retry", System::Windows::Forms::DialogResult::Retry, 1); AddBtn("&Ignore", System::Windows::Forms::DialogResult::Ignore, 2); //this.CancelButton = IgnoreBtn; //(official .NET doesn't set cancel button) } else { throw gcnew System::ComponentModel::InvalidEnumArgumentException("buttons", (int)buttons, MessageBoxButtons::typeid); } if (!CancelButton) ControlBox = false; if (icon != MessageBoxIcon::None) { int iconsize = 32 * ScaleWidth; int iconpadding = 12 * ScaleWidth; int textpadding = -8 * ScaleWidth; PictureBox^ iconPB = gcnew PictureBox(); iconPB->Width = iconsize; iconPB->Height = iconsize; iconPB->Top = 10 * ScaleHeight; iconPB->Left = 10 * ScaleWidth; iconPB->AccessibleName = "Icon"; iconPB->SizeMode = PictureBoxSizeMode::Zoom; System::Resources::ResourceManager^ ResMgr = gcnew System::Resources::ResourceManager("Launcher.SkinnedMessageBox", SkinnedMessageBox::typeid->Assembly); // there are many duplicated values: // https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.messageboxicon?view=netframework-4.7.2 if (icon == MessageBoxIcon::Error) // also Hand and Stop { iconPB->Image = (Image^)(ResMgr->GetObject("FeelsThinkMan")); iconPB->AccessibleDescription = "Error"; //this.Icon = SystemIcons.Error; System::Media::SystemSounds::Hand->Play(); } else if (icon == MessageBoxIcon::Question) { iconPB->Image = (Image^)(ResMgr->GetObject("PokeWhat4xvc2")); iconPB->AccessibleDescription = "Question"; //this.Icon = SystemIcons.Question; System::Media::SystemSounds::Question->Play(); } else if (icon == MessageBoxIcon::Warning) // also Exclamation { iconPB->Image = (Image^)(ResMgr->GetObject("PokeSnarf4xd")); iconPB->AccessibleDescription = "Warning"; //this.Icon = SystemIcons.Warning; //textpadding -= 2 * ScaleWidth; // triangle shape looks worse without this System::Media::SystemSounds::Exclamation->Play(); } else if (icon == MessageBoxIcon::Information) // also Asterisk { /*Drawing::Icon^ infoicon = gcnew Drawing::Icon(SystemIcons::Information, iconsize, iconsize); iconPB->Image = infoicon->ToBitmap(); iconPB->AccessibleDescription = "Information"; //this.Icon = SystemIcons.Question; System::Media::SystemSounds::Asterisk->Play();*/ iconPB->Image = (Image^)(ResMgr->GetObject("Help")); iconPB->AccessibleDescription = "Question"; //this.Icon = SystemIcons.Question; System::Media::SystemSounds::Question->Play(); } else { throw gcnew System::ComponentModel::InvalidEnumArgumentException("icon", (int)icon, MessageBoxIcon::typeid); } MessageLbl->MinimumSize = Drawing::Size(MessageLbl->MinimumSize.Width - (iconsize + iconpadding + textpadding), MessageLbl->MinimumSize.Height); MessageLbl->Left += (iconsize + iconpadding + textpadding); Controls->Add(iconPB); } if (defaultbutton == MessageBoxDefaultButton::Button1) { AcceptButton = buttonrefs[0]; ActiveControl = buttonrefs[0]; } else if (defaultbutton == MessageBoxDefaultButton::Button2) { if (!Controls->Contains(buttonrefs[1])) throw gcnew ArgumentOutOfRangeException("defaultbutton", "defaultbutton cannot be set to a button number that does not exist"); AcceptButton = buttonrefs[1]; ActiveControl = buttonrefs[1]; } else if (defaultbutton == MessageBoxDefaultButton::Button3) { if (!Controls->Contains(buttonrefs[2])) throw gcnew ArgumentOutOfRangeException("defaultbutton", "defaultbutton cannot be set to a button number that does not exist"); AcceptButton = buttonrefs[2]; ActiveControl = buttonrefs[2]; } else { throw gcnew System::ComponentModel::InvalidEnumArgumentException("defaultbutton", (int)defaultbutton, MessageBoxDefaultButton::typeid); } // TODO: TEXT ALIGNMENT AND RTL MODE /* // MessageBoxOptions are more like flags than concrete settings. // For ease of use, we assume default value is whatever winforms gives us in current locale -- but we override if any value is set if ((options & MessageBoxOptions.RightAlign) == MessageBoxOptions.RightAlign) MessageLbl.TextAlign = ContentAlignment.TopRight; else if (options != 0) MessageLbl.TextAlign = ContentAlignment.TopLeft; // RtlReading should be what actually affects layout, and RightAlign only affects the text label if ((options & MessageBoxOptions.RtlReading) == MessageBoxOptions.RtlReading) { foreach (Control control in this.Controls) { control.Left = this.ClientSize.Width - control.Right; control.RightToLeft = RightToLeft.Yes; } this.RightToLeft = RightToLeft.Yes; this.RightToLeftLayout = true; } else if (options != 0) { foreach (Control control in this.Controls) { control.RightToLeft = RightToLeft.No; } this.RightToLeft = RightToLeft.No; this.RightToLeftLayout = false; } */ SetBackCol(this, Color::FromArgb(64, 64, 64)); SetForeCol(this, Color::White); SetUIStyle(this, FlatStyle::Flat); } SkinnedMessageBoxForm(String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultbutton, MessageBoxOptions options) { SkinnedMessageBoxForm(NativeWindow::FromHandle((IntPtr::Zero)), message, caption, buttons, icon, defaultbutton, options); } }; public: static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultbutton, MessageBoxOptions options) { // I probably shouldn't do this, but from what I can tell this should be safe enough -- out of thread owner is allowed // and it only seems to appear when debugging (???) Control::CheckForIllegalCrossThreadCalls = false; SkinnedMessageBoxForm^ mb = gcnew SkinnedMessageBoxForm(owner, message, caption, buttons, icon, defaultbutton, options); DialogResult res = mb->ShowDialog(); Control::CheckForIllegalCrossThreadCalls = true; return res; } static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultbutton) { return Show(owner, message, caption, buttons, icon, defaultbutton, (MessageBoxOptions)0); } static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons, MessageBoxIcon icon) { return Show(owner, message, caption, buttons, icon, MessageBoxDefaultButton::Button1, (MessageBoxOptions)0); } static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption, MessageBoxButtons buttons) { return Show(owner, message, caption, buttons, MessageBoxIcon::None, MessageBoxDefaultButton::Button1, (MessageBoxOptions)0); } static DialogResult Show(IWin32Window^ owner, String^ message, String^ caption) { return Show(owner, message, caption, MessageBoxButtons::OK, MessageBoxIcon::None, MessageBoxDefaultButton::Button1, (MessageBoxOptions)0); } static DialogResult Show(IWin32Window^ owner, String^ message) { return Show(owner, message, "", MessageBoxButtons::OK, MessageBoxIcon::None, MessageBoxDefaultButton::Button1, (MessageBoxOptions)0); } }; ================================================ FILE: source-code/source/plugins/Launcher/SkinnedMessageBox.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 FeelsThinkMan.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a Help.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a PokeSnarf4xd.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a PokeWhat4xvc2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ================================================ FILE: source-code/source/plugins/Launcher/TabPadding.cpp ================================================ #include "TabPadding.h" //#include // ported from https://stackoverflow.com/a/7785745 // original code by user LarsTech https://stackoverflow.com/users/719186/larstech TabPadding::TabPadding(TabControl^ tc) { tabControl = tc; tabControl->Selected += gcnew TabControlEventHandler(this, &TabPadding::tabControl_Selected); AssignHandle(tc->Handle); } void TabPadding::tabControl_Selected(Object^ sender, TabControlEventArgs^ e) { tabControl->Invalidate(); } void TabPadding::WndProc(Message %m) { NativeWindow::WndProc(m); if (m.Msg == 15) { //WM_PAINT Graphics^ g = Graphics::FromHwnd(m.HWnd); //Replace the outside white borders: if (tabControl->Parent) { g->SetClip(System::Drawing::Rectangle(0, 0, tabControl->Width - 2, tabControl->Height - 1), Drawing2D::CombineMode::Exclude); g->FillRectangle(gcnew SolidBrush(tabControl->Parent->BackColor), System::Drawing::Rectangle(0, tabControl->ItemSize.Height + 2, tabControl->Width, tabControl->Height - (tabControl->ItemSize.Height + 2))); } //Replace the inside white borders: if (tabControl->SelectedTab) { g->ResetClip(); System::Drawing::Rectangle r = tabControl->SelectedTab->Bounds; g->SetClip(r, Drawing2D::CombineMode::Exclude); g->FillRectangle(gcnew SolidBrush(tabControl->SelectedTab->BackColor), System::Drawing::Rectangle(r.Left - 3, r.Top - 1, r.Width + 4, r.Height + 3)); } delete g; } } ================================================ FILE: source-code/source/plugins/Launcher/TabPadding.h ================================================ #pragma once using namespace System::Windows::Forms; using namespace System::Drawing; // ported from https://stackoverflow.com/a/7785745 // original code by user LarsTech https://stackoverflow.com/users/719186/larstech ref class TabPadding : public NativeWindow { public: TabPadding(TabControl^ tc); private: TabControl^ tabControl; void tabControl_Selected(Object^ sender, TabControlEventArgs^ e); protected: virtual void WndProc(Message %m) override; }; ================================================ FILE: source-code/source/plugins/Launcher/composition.h ================================================ #pragma once #include enum AccentState { ACCENT_DISABLED = 0, ACCENT_ENABLE_GRADIENT = 1, ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, ACCENT_ENABLE_BLURBEHIND = 3, ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, ACCENT_ENABLE_HOSTBACKDROP = 5, ACCENT_INVALID_STATE = 6 }; enum WindowCompositionAttribute { WCA_ACCENT_POLICY = 19, WCA_USEDARKMODECOLORS = 26 }; struct AccentPolicy { AccentState accentState; int accentFlags; int gradientColor; int animationId; }; struct WindowCompositionAttributeData { WindowCompositionAttribute attribute; PVOID pData; ULONG dataSize; }; bool setBlur(HWND hWnd, AccentState accentState) { HKEY CurrentVersion; auto result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &CurrentVersion); if (result == ERROR_SUCCESS) { DWORD DataSize = 32; WCHAR* DataPtr = (WCHAR*)malloc(DataSize); memset(DataPtr, 0, DataSize); bool queryBuild = RegQueryValueEx(CurrentVersion, L"CurrentBuild", NULL, NULL, (LPBYTE)DataPtr, &DataSize) == ERROR_SUCCESS; RegCloseKey(CurrentVersion); if (queryBuild) { int BuildNum = _wtoi(DataPtr); //MessageBox::Show(BuildNum.ToString()); if (BuildNum < 19042) return 0; } else return 0; } else return 0; const HINSTANCE hModule_user32 = LoadLibrary(TEXT("user32.dll")); if (hModule_user32) { typedef BOOL(WINAPI* p_SetWindowCompositionAttribute)(HWND, WindowCompositionAttributeData*); const p_SetWindowCompositionAttribute SetWindowCompositionAttribute = (p_SetWindowCompositionAttribute)GetProcAddress(hModule_user32, "SetWindowCompositionAttribute"); bool result = false; if (SetWindowCompositionAttribute) { AccentPolicy policy; policy.accentState = accentState; policy.accentFlags = 2; policy.gradientColor = 0x01000000; policy.animationId = 0; WindowCompositionAttributeData data; data.attribute = WCA_ACCENT_POLICY; data.pData = &policy; data.dataSize = sizeof(AccentPolicy); result = SetWindowCompositionAttribute(hWnd, &data); } FreeLibrary(hModule_user32); return result; } return 0; } void setDarkTheme(HWND hWnd, bool dark=true) { const HINSTANCE hModule_dwmapi = LoadLibrary(TEXT("dwmapi.dll")); if (hModule_dwmapi) { typedef BOOL(WINAPI* p_DwmSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD); const p_DwmSetWindowAttribute DwmSetWindowAttribute = (p_DwmSetWindowAttribute)GetProcAddress(hModule_dwmapi, "DwmSetWindowAttribute"); if (DwmSetWindowAttribute) { LONG useDarkModeColors = dark; if(DwmSetWindowAttribute(hWnd, 20, &useDarkModeColors, sizeof(useDarkModeColors))) DwmSetWindowAttribute(hWnd, 19, &useDarkModeColors, sizeof(useDarkModeColors)); } FreeLibrary(hModule_dwmapi); } } ================================================ FILE: source-code/source/plugins/Launcher/dllmain.cpp ================================================ #include "ui.h" #include "framework.h" #include #pragma comment(lib, "detours.lib") using namespace System; using namespace System::Windows::Forms; [STAThread] int showUI() { SetProcessDPIAware(); Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); Application::Run(gcnew Launcher::ui()); return 0; } int hookedMain(int argc, const char** argv, const char** envp) { for (int i = 0; i < argc; ++i) { arg = argv[i]; if (arg == "--launch" || nSkipLauncher) return divaMain(argc, argv, envp); } return showUI(); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaMain, hookedMain); DetourTransactionCommit(); } return TRUE; } ================================================ FILE: source-code/source/plugins/Launcher/framework.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include #include #include #include #include #include "ConfigOption.h" #include "PluginConfig.h" #include int (__cdecl* divaMain)(int argc, const char** argv, const char** envp) = (int(__cdecl*)(int argc, const char** argv, const char** envp))0x140194D90; using namespace std; string arg; wstring ExePath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); return wstring(buffer); } wstring DirPath() { wstring exepath = ExePath(); wstring::size_type pos = exepath.find_last_of(L"\\/"); return exepath.substr(0, pos); } wstring DIVA_EXECUTABLE_STRING = ExePath(); LPCWSTR DIVA_EXECUTABLE = DIVA_EXECUTABLE_STRING.c_str(); wstring DIVA_DIRPATH_STRING = DirPath(); LPCWSTR DIVA_DIRPATH = DIVA_DIRPATH_STRING.c_str(); wstring DIVA_EXECUTABLE_LAUNCH_STRING = DIVA_EXECUTABLE_STRING + L" --launch"; LPWSTR DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING.c_str()); wstring PLUGINS_DIR = DirPath() + L"\\plugins"; wstring PATCHES_DIR = DirPath() + L"\\patches"; wstring CONFIG_FILE_STRING = PLUGINS_DIR + L"\\config.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); wstring COMPONENTS_FILE_STRING = PLUGINS_DIR + L"\\components.ini"; LPCWSTR COMPONENTS_FILE = COMPONENTS_FILE_STRING.c_str(); wstring PLAYERDATA_FILE_STRING = PLUGINS_DIR + L"\\playerdata.ini"; LPCWSTR PLAYERDATA_FILE = PLAYERDATA_FILE_STRING.c_str(); wstring KEYCONFIG_FILE_STRING = PLUGINS_DIR + L"\\keyconfig.ini"; LPCWSTR KEYCONFIG_FILE = KEYCONFIG_FILE_STRING.c_str(); LPCWSTR PATCHES_SECTION = L"patches"; LPCWSTR GRAPHICS_SECTION = L"graphics"; LPCWSTR RESOLUTION_SECTION = L"resolution"; LPCWSTR LAUNCHER_SECTION = L"launcher"; LPCWSTR COMPONENTS_SECTION = L"components"; LPCWSTR PLAYERDATA_SECTION = L"playerdata"; LPCWSTR KEYCONFIG_SECTION = L"keyconfig"; int nSkipLauncher = GetPrivateProfileIntW(LAUNCHER_SECTION, L"skip", FALSE, CONFIG_FILE); int nNoGPUDialog = GetPrivateProfileIntW(LAUNCHER_SECTION, L"no_gpu_dialog", FALSE, CONFIG_FILE); resolution getCurrentScreenResolution() { return resolution(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); } std::vector getScreenModes() { static std::vector outVec = std::vector(); DEVMODEW dm = { 0 }; dm.dmSize = sizeof(dm); for (int iModeNum = 0; EnumDisplaySettingsW(NULL, iModeNum, &dm) != 0; iModeNum++) { outVec.push_back(dm); } return outVec; } std::vector getScreenResolutionsVec(std::vector &screenModes) { static std::vector outVec = std::vector(); for (DEVMODEW &dm : screenModes) { resolution res = resolution(dm.dmPelsWidth, dm.dmPelsHeight); if (std::find(outVec.begin(), outVec.end(), res) == outVec.end()) { outVec.push_back(res); } } const resolution defaultres(1280, 720); if (std::find(outVec.begin(), outVec.end(), defaultres) == outVec.end()) { outVec.push_back(defaultres); } std::sort(outVec.begin(), outVec.end()); return outVec; } static std::vector getScreenDepthsVec(std::vector &screenModes) { static std::vector outVec = std::vector(); for (DEVMODEW &dm : screenModes) { int depth = dm.dmBitsPerPel; if (depth < 24) continue; if (std::find(outVec.begin(), outVec.end(), depth) == outVec.end()) { outVec.push_back(depth); } } std::sort(outVec.begin(), outVec.end()); return outVec; } static std::vector getScreenRatesVec(std::vector &screenModes) { static std::vector outVec = std::vector(); for (DEVMODEW &dm : screenModes) { int rate = dm.dmDisplayFrequency; if (std::find(outVec.begin(), outVec.end(), rate) == outVec.end()) { outVec.push_back(rate); } } std::sort(outVec.begin(), outVec.end()); return outVec; } std::vector screenModes = getScreenModes(); const std::vector internalResOptions = { resolution(320,240), resolution(426,240), resolution(640,480), resolution(854,480), resolution(960,540), resolution(1280,720), resolution(1366,768), resolution(1600,900), resolution(1920,1080), resolution(2560,1440), resolution(3200,1800), resolution(3840,2160), resolution(5120,2880), resolution(7680,4320) }; DropdownOption* DisplayModeDropdown = new DropdownOption(L"display", RESOLUTION_SECTION, CONFIG_FILE, L"Display:", L"Sets the window/screen mode.", 1, std::vector({ L"Windowed", L"Fast", L"Exclusive", L"Safe" })); ResolutionOption* DisplayResolutionOption = new ResolutionOption(L"width", L"height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the display resolution.", resolution(-1, -1), getScreenResolutionsVec(screenModes), true, RESOPT_INCLUDE_MATCH_SCREEN); DropdownNumberOption* RefreshRateOption = new DropdownNumberOption(L"refreshrate", RESOLUTION_SECTION, CONFIG_FILE, L"Refresh Rate:", L"Sets the display refresh rate.", 60, getScreenRatesVec(screenModes), true); ConfigOptionBase* screenResolutionArray[] = { DisplayModeDropdown, DisplayResolutionOption, //new DropdownNumberOption(L"bitdepth", RESOLUTION_SECTION, CONFIG_FILE, L"Bit Depth:", L"Sets the display bit depth.", 32, getScreenDepthsVec(screenModes), true), RefreshRateOption, }; BooleanOption* InternalResolutionCheckbox = new BooleanOption(L"r.enable", RESOLUTION_SECTION, CONFIG_FILE, L"Enable", L"Enable or disable custom internal resolution.", false, false); ResolutionOption* InternalResolutionOption = new ResolutionOption(L"r.width", L"r.height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the internal resolution (instead of 1280x720).", resolution(1920, 1080), internalResOptions, true, RESOPT_INCLUDE_MATCH_WINDOW); ConfigOptionBase* internalResolutionArray[] = { InternalResolutionCheckbox, InternalResolutionOption }; ConfigOptionBase* graphicsArray[] = { new DropdownOption(L"model", L"GPU", CONFIG_FILE, L"Nvidia GPU:", L"Select your Nvidia GPU's architecture to apply the necessary workarounds.\n\nNOTE: Automatic detection does not currently work on GNU/Linux.", -1, std::vector({ L"Automatic", L"Kepler", L"Maxwell/Pascal", L"Turing", L"Ampere", L"Ada Lovelace", L"Blackwell or newer"}), -1), new BooleanOption(L"TAA", GRAPHICS_SECTION, CONFIG_FILE, L"TAA", L"Temporal Anti-Aliasing", true, false), new BooleanOption(L"MLAA", GRAPHICS_SECTION, CONFIG_FILE, L"MLAA", L"Morphological Anti-Aliasing", true, false), new DropdownOption(L"MAG", GRAPHICS_SECTION, CONFIG_FILE, L"Filter:", L"Image filter.\n\nBilinear: default filter\nNearest-neighbour: sharpest, but blocky\nSharpen: sharp filter\nCone: smooth filter", 0, std::vector({ L"Bilinear", L"Nearest-neighbour", L"Sharpen", L"Cone" })), new BooleanOption(L"DOF", GRAPHICS_SECTION, CONFIG_FILE, L"Depth of Field", L"Blurs the background. Disable for better performance.", true, false), new BooleanOption(L"reflections", GRAPHICS_SECTION, CONFIG_FILE, L"Reflections", L"Enable or disable reflections.", true, false), new ResolutionOption(L"reflect_res_width", L"reflect_res_height", GRAPHICS_SECTION, CONFIG_FILE, L"Reflection Res:", L"Sets the reflection buffer resolution (instead of 512x256).", resolution(512, 256), std::vector({resolution(256,256), resolution(512,256), resolution(512,512), resolution(640,480), resolution(854,480), resolution(960,540), resolution(1280,720), resolution(1366,768), resolution(1600,900), resolution(1920,1080), resolution(2560,1440), resolution(3200,1800), resolution(3840,2160), resolution(5120,2880), resolution(7680,4320)}), true, RESOPT_NONE), new ResolutionOption(L"refract_res_width", L"refract_res_height", GRAPHICS_SECTION, CONFIG_FILE, L"Refraction Res:", L"Sets the refraction buffer resolution (instead of 512x256).", resolution(512, 256), std::vector({resolution(256,256), resolution(512,256), resolution(512,512), resolution(1024,1024), resolution(2048,2048), resolution(4096,4096)}), true, RESOPT_NONE), new BooleanOption(L"shadows", GRAPHICS_SECTION, CONFIG_FILE, L"Shadows", L"Enable or disable shadows.", true, false), new ResolutionOption(L"shadow_res_width", L"shadow_res_height", GRAPHICS_SECTION, CONFIG_FILE, L"Shadow Res:", L"Sets the shadow buffer resolution (instead of 2048x2048).", resolution(2048, 2048), std::vector({resolution(256,256), resolution(512,512), resolution(1024,1024), resolution(2048,2048), resolution(4096,4096), resolution(8192,8192)}), true, RESOPT_NONE), new NumericOption(L"gamma", GRAPHICS_SECTION, CONFIG_FILE, L"Gamma:", L"Increase to darken shadows.\nSet to 125 for a console-like experience.\n\nDefault: 0 or 100", 100, 0, 200), new BooleanOption(L"punchthrough", GRAPHICS_SECTION, CONFIG_FILE, L"Transparent Meshes", L"Show transparent meshes.", true, false), new BooleanOption(L"glare", GRAPHICS_SECTION, CONFIG_FILE, L"Glare", L"Enable or disable glare.", true, false), new BooleanOption(L"shader", GRAPHICS_SECTION, CONFIG_FILE, L"Shader", L"Enable or disable high-quality shaders.", true, false), new DropdownOption(L"NPR1", GRAPHICS_SECTION, CONFIG_FILE, L"Toon (F9):", L"NPR1 shader\n\nPress F9 to toggle.", 0, std::vector({ L"Default", L"Force on", L"Force off" })), new BooleanOption(L"2D", GRAPHICS_SECTION, CONFIG_FILE, L"Disable 3D rendering", L"Disable all 3D passes.\n\nWARNING: The extended data will be deleted unless Prevent Data Deletion is enabled.", false, false), }; ConfigOptionBase* optionsArray[] = { new OptionMetaSectionLabel(L"Compatibility"), new BooleanOption(L"no_movies", PATCHES_SECTION, CONFIG_FILE, L"Disable Movies", L"Disable movies (enable this if the game hangs when loading certain PVs).", false, false), new BooleanOption(L"mp4_movies", PATCHES_SECTION, CONFIG_FILE, L"Custom MP4 Adv Movies", L"Enable MP4 (instead of WMV) advertise/attract movies.", false, false), new BooleanOption(L"cursor", PATCHES_SECTION, CONFIG_FILE, L"Cursor", L"Enable or disable the mouse cursor.", true, false), new BooleanOption(L"stereo", PATCHES_SECTION, CONFIG_FILE, L"Stereo", L"Use 2 channels instead of 4 (when not using DivaSound).", true, false), new OptionMetaSeparator(), new OptionMetaSpacer(8), new OptionMetaSectionLabel(L"Controller Options"), new BooleanOption(L"rumble", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Rumble", L"Enables rumble during chainslides.", true, true), new NumericOption(L"xinput_rumble_intensity_left", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Left motor:", L"Left rumble motor intensity (XInput).\n\nDefault: 8000", 8000, 0, USHRT_MAX), new NumericOption(L"xinput_rumble_intensity_right", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Right motor:", L"Right rumble motor intensity (XInput).\n\nDefault: 4000", 4000, 0, USHRT_MAX), new NumericOption(L"xinput_preferred", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Controller Num:", L"Sets the preferred XInput controller.\nIf unavailable, the next connected controller is used.", 0, 0, 3), new BooleanOption(L"hardware_slider", PATCHES_SECTION, CONFIG_FILE, L"Use Hardware Slider", L"Enable this if using a real arcade slider.\n(set the slider to port COM11)", false, false), new OptionMetaSeparator(), new OptionMetaSpacer(8), new OptionMetaSectionLabel(L"PV Selector"), new DropdownOption(L"quick_start", PATCHES_SECTION, CONFIG_FILE, L"Quick Start:", L"Skip one or more menus.", 1, std::vector({ L"Disabled", L"Guest", L"Guest + Normal" })), new BooleanOption(L"no_scrolling_sfx", PATCHES_SECTION, CONFIG_FILE, L"Disable Scrolling SFX", L"Disable the scrolling sound effect.", false, false), new BooleanOption(L"unlock_pseudo", PATCHES_SECTION, CONFIG_FILE, L"Unlock PSEUDO modules (incomplete)", L"Lets you play any PV with any performer.\n(incomplete, recommended modules will default to Miku)", false, false), new BooleanOption(L"card", PATCHES_SECTION, CONFIG_FILE, L"Unlock card menu (incomplete)", L"Enables the card menu.\n(incomplete, it doesn't bypass the card prompt)", false, false), new OptionMetaSeparator(), new OptionMetaSpacer(8), new OptionMetaSectionLabel(L"Stages/Songs"), new BooleanOption(L"Auto_Databank", PATCHES_SECTION, CONFIG_FILE, L"Auto Databank", L"Automatically generate databank for missing entries and allow multiple PvList files to be used.", true, false), new NumericOption(L"Enhanced_Stage_Manager", PATCHES_SECTION, CONFIG_FILE, L"Number of Stages:", L"Set the number of stages (0 = default).", 0, 0, INT_MAX), new BooleanOption(L"Enhanced_Stage_Manager_Encore", PATCHES_SECTION, CONFIG_FILE, L"Encore", L"Enable encore stages.", true, false), new BooleanOption(L"sing_missed", PATCHES_SECTION, CONFIG_FILE, L"Sing Missed", L"Sing missed notes.", false, false), new BooleanOption(L"autopause", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Pause Automatically", L"Pause when focus is lost.", true, true), new OptionMetaSeparator(), new OptionMetaSpacer(8), new OptionMetaSectionLabel(L"PV Customization"), new BooleanOption(L"enable_pv_customization", PATCHES_SECTION, CONFIG_FILE, L"Enable PV Customization", L"Enable the options below.", false, false), new DropdownOption(L"force_mouth", PATCHES_SECTION, CONFIG_FILE, L"Mouth Type:", L"Change the mouth animations.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), new DropdownOption(L"force_expressions", PATCHES_SECTION, CONFIG_FILE, L"Expression Type:", L"Change the expressions.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), new DropdownOption(L"force_look", PATCHES_SECTION, CONFIG_FILE, L"Look Type:", L"Change the look animations.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), new BooleanOption(L"no_hand_scaling", PATCHES_SECTION, CONFIG_FILE, L"No Hand Scaling", L"Disable hand scaling.", false, false), new NumericOption(L"default_hand_size_uint", PATCHES_SECTION, CONFIG_FILE, L"Default Hand Size:", L"0-10000: default\n12200: PDA\n1000000: maximum", 0, 0, 1000000), new OptionMetaSeparator(), new OptionMetaSpacer(8), new OptionMetaSectionLabel(L"UI Elements"), new BooleanOption(L"hide_volume", PATCHES_SECTION, CONFIG_FILE, L"Hide Volume Buttons", L"Hide the volume and SE control buttons.", false, false), new BooleanOption(L"no_pv_ui", PATCHES_SECTION, CONFIG_FILE, L"Disable PV UI", L"Remove the photo controls during PV playback.", false, false), new BooleanOption(L"hide_pv_watermark", PATCHES_SECTION, CONFIG_FILE, L"Hide PV Watermark", L"Hide the watermark that's usually shown in PV viewing mode.", false, false), new BooleanOption(L"hide_status_icons", PATCHES_SECTION, CONFIG_FILE, L"Hide Network Icons", L"Hide the top-right corner status icons.", false, false), // technically reduntant, but somehow a lot of users miss the dropdown new DropdownOption(L"status_icons", PATCHES_SECTION, CONFIG_FILE, L"Network Icons Status:", L"Set the state of card reader and network status icons.", 3, std::vector({ L"Default", L"Hidden", L"Error", L"OK", L"Partial OK" })), new BooleanOption(L"no_lyrics", PATCHES_SECTION, CONFIG_FILE, L"Disable Lyrics", L"Disable showing lyrics.", false, false), new BooleanOption(L"no_error", PATCHES_SECTION, CONFIG_FILE, L"Disable Error Banner", L"Disable the error banner on the attract screen.", true, false), new BooleanOption(L"hide_freeplay", PATCHES_SECTION, CONFIG_FILE, L"Hide \"FREE PLAY\"/\"CREDIT(S)\"", L"Hide the \"FREE PLAY\"/\"CREDIT(S)\" text.", false, false), new BooleanOption(L"freeplay", PATCHES_SECTION, CONFIG_FILE, L"FREE PLAY", L"Show \"FREE PLAY\" instead of \"CREDIT(S)\" and don't require credits.", true, false), new BooleanOption(L"pdloadertext", PATCHES_SECTION, CONFIG_FILE, L"PD Loader FREE PLAY", L"Show \"PD Loader\" instead of \"FREE PLAY\".", true, false), new BooleanOption(L"no_timer", PATCHES_SECTION, CONFIG_FILE, L"Freeze Timer", L"Disable the timer.", true, false), new BooleanOption(L"no_timer_sprite", PATCHES_SECTION, CONFIG_FILE, L"Disable Timer Sprite", L"Disable the timer sprite.", true, false), new OptionMetaSeparator(), new OptionMetaSpacer(8), new OptionMetaSectionLabel(L"Framerate"), new BooleanOption(L"FPS.Limit.LightMode", GRAPHICS_SECTION, CONFIG_FILE, L"Use Lightweight Limiter", L"Makes the FPS limiter use less CPU.\nMay have less consistent performance.", true, false), new NumericOption(L"FPS.Limit", GRAPHICS_SECTION, CONFIG_FILE, L"FPS Limit:", L"Allows you to set a frame rate cap. Set to -1 to unlock the frame rate.", 60, -1, INT_MAX), new NumericOption(L"frm.motion.rate", GRAPHICS_SECTION, CONFIG_FILE, L"FRM Motion Rate:", L"Sets the motion rate (fps) for the Frame Rate Manager component.\nLarger values should be smoother, but more CPU intensive and possibly buggier.", 300, 1, INT_MAX), new OptionMetaSeparator(), new OptionMetaSpacer(8), //new OptionMetaSectionLabel(L"Advanced Compatibility"), //new BooleanOption(L"opengl_patch_a", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch A", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false), //new BooleanOption(L"opengl_patch_b", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch B", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false), //new OptionMetaSeparator(), //new OptionMetaSpacer(8), new OptionMetaSectionLabel(L"Loader"), new BooleanOption(L"custom_patches", PATCHES_SECTION, CONFIG_FILE, L"Enable Custom Patches", L"Enables all custom patches.", true, false), //new BooleanOption(L"prevent_data_deletion", PATCHES_SECTION, CONFIG_FILE, L"Prevent Data Deletion", L"Prevents the game from deleting files.", false, false), new OptionMetaSeparator(), new OptionMetaSpacer(8), new OptionMetaSectionLabel(L"Launcher"), new BooleanOption(L"dark_launcher", LAUNCHER_SECTION, CONFIG_FILE, L"Dark Launcher", L"Sets the dark colour scheme in the launcher.", false, false), //new BooleanOption(L"acrylic_blur", LAUNCHER_SECTION, CONFIG_FILE, L"Acrylic Blur", L"Enables acrylic blur in the launcher on Windows 10 20H2 or later.", false, false), new BooleanOption(L"no_gpu_dialog", LAUNCHER_SECTION, CONFIG_FILE, L"Disable GPU Warning", L"Disables the warning dialog for unsupported GPUs.", false, false), //new BooleanOption(L"ignore_exe_checksum", PATCHES_SECTION, CONFIG_FILE, L"Ignore exe checksum", L"Use at your own risk.", false, false), new StringOption(L"command_line", LAUNCHER_SECTION, CONFIG_FILE, L"Command Line:", L"Allows setting command line parameters for the game when using the launcher.\nDisabling the launcher will bypass this.", L"", false), new BooleanOption(L"use_divahook_bat", LAUNCHER_SECTION, CONFIG_FILE, L"Use divahook.bat/start.bat", L"Launches divahook.bat/start.bat intead of diva.exe.", false, false), }; ConfigOptionBase* playerdataArray[] = { new StringOption(L"player_name", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Player Name:", L"Player name shown in game.", L"NO-NAME", true), new StringOption(L"level_name", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Name:", L"Level (plate) name shown in game.", L"忘れないでね私の声を", true), new NumericOption(L"level_plate_id", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Plate:", L"Sets the level background image (plate).", 0, 0, INT_MAX), new NumericOption(L"level_plate_effect", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Plate Effect:", L"Sets the effect on the level background image (plate).", -1, -1, 2), new NumericOption(L"skin_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Skin:", L"Sets the gameplay UI skin.", 0, 0, INT_MAX), new NumericOption(L"btn_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Button Sound:", L"Sets the sound effect for buttons.\n-1 = song default", -1, -1, INT_MAX), new NumericOption(L"slide_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Slide Sound:", L"Sets the sound effect for slides.\n-1 = song default", -1, -1, INT_MAX), new NumericOption(L"chainslide_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Chainslide Sound:", L"Sets the sound effect for chain slides.\n-1 = song default", -1, -1, INT_MAX), new NumericOption(L"slidertouch_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Slider Touch Sound:", L"Sets the sound effect for touching the slider with no note.\n-1 = song default", -1, -1, INT_MAX), new BooleanOption(L"act_toggle", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Button SE", L"Enables button/slider sounds.", true, true), new BooleanOption(L"border_great", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Great)", L"Shows the clear border for a great rating on the progress bar.", true, true), new BooleanOption(L"border_excellent", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Excellent)", L"Shows the clear border for an excellent rating on the progress bar.", true, true), new BooleanOption(L"border_rival", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Rival)", L"Shows the clear border for beating your rival on the progress bar.", false, true), new BooleanOption(L"use_card", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Use Card", L"Enables IC card. This allows module selection.", true, true), new BooleanOption(L"module_card_workaround", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Fast Module Selection (buggy)", L"Allows module selection without card and tries to improve menu performance.\nKnown to cause issues, especially with song-specific modules.", false, true), new BooleanOption(L"use_pv_module_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Modules", L"Allows song-specific module selection.", true, true), new BooleanOption(L"use_pv_skin_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Skins", L"Allows song-specific skin settings.\nValues stored in skins.ini", true, true), new BooleanOption(L"use_pv_sfx_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Sound Effects", L"Allows song-specific sound effect settings.\nValues stored in sfx.ini", true, true), new BooleanOption(L"gamemode_options", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Game Modifiers", L"Allows use of game mode modifiers (hi-speed, hidden, and sudden).", true, true), }; ConfigOptionBase* componentsArray[] = { new BooleanOption(L"input_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Input Emulator", L"Emulates input through keyboard and/or mouse.", false, true), new BooleanOption(L"touch_slider_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Slider Emulator", L"Emulates slider through keyboard and/or mouse.", false, true), new BooleanOption(L"touch_panel_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Touch Panel Emulator", L"Emulates touch panel through mouse.", false, true), new BooleanOption(L"player_data_manager", COMPONENTS_SECTION, COMPONENTS_FILE, L"Player Data Manager", L"Loads user-defined values into the PlayerData struct.\nRequired for modules and game mode modifiers.", false, true), new BooleanOption(L"frame_rate_manager", COMPONENTS_SECTION, COMPONENTS_FILE, L"Frame Rate Manager", L"Adjusts animations to the correct speed at different frame rates.\nOnly needed when FPS isn't locked at 60.", false, true), new BooleanOption(L"fast_loader", COMPONENTS_SECTION, COMPONENTS_FILE, L"Fast Loader", L"Skip or speed up unnecessary loading steps.", false, true), new NumericOption(L"fast_loader_speed", COMPONENTS_SECTION, COMPONENTS_FILE, L"Fast Loader Speed", L"Set this to 4 or less when playing online.\nDefault: 39", 39, 2, 1024), new BooleanOption(L"camera_controller", COMPONENTS_SECTION, COMPONENTS_FILE, L"Camera Controller", L"Enables freecam (toggled using F3).\nWASD to move, SPACE/CTRL for up/down, Q/R to rotate, R/F for zoom.\nHolding SHIFT/ALT changes control speed.", false, true), new BooleanOption(L"scale_component", COMPONENTS_SECTION, COMPONENTS_FILE, L"Scale Component", L"Scales the graphics output framebuffer to fill the screen/window.", false, true), new BooleanOption(L"debug_component", COMPONENTS_SECTION, COMPONENTS_FILE, L"Debug Component", L"Allows for changing game state (F4-F8 keys), using dev GUI and tests, and speeding up 2d animations/menus (hold SHIFT+TAB).", false, true), new BooleanOption(L"target_inspector", COMPONENTS_SECTION, COMPONENTS_FILE, L"Target Inspector", L"Enables hold transfers.", false, true), new BooleanOption(L"score_saver", COMPONENTS_SECTION, COMPONENTS_FILE, L"Score Saver", L"Saves high scores to plugins/scores.ini.", false, true), new BooleanOption(L"pause", COMPONENTS_SECTION, COMPONENTS_FILE, L"Pause", L"Adds a pause menu.", false, true), }; bool IsLineInFile(LPCSTR searchLine, LPCWSTR fileName) { bool result = false; std::ifstream fileStream(fileName); if (!fileStream.is_open()) return false; std::string line; // check for BOM std::getline(fileStream, line); if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0) fileStream.seekg(3); else fileStream.seekg(0); while (std::getline(fileStream, line)) { if (line.compare(searchLine) == 0) { result = true; break; } } fileStream.close(); return result; } void PrependFile(LPCSTR newStr, LPCWSTR fileName) { std::fstream fileStream(fileName); if (!fileStream.is_open()) return; std::string origStr; // this is apparently more efficient than just going straight into the string fileStream.seekg(0, std::ios::end); origStr.reserve(fileStream.tellg()); fileStream.seekg(0, std::ios::beg); // check for BOM std::string BOMcheckLine; std::getline(fileStream, BOMcheckLine); if (BOMcheckLine.size() >= 3 && BOMcheckLine.rfind("\xEF\xBB\xBF", 0) == 0) fileStream.seekg(3); else fileStream.seekg(0); origStr.assign((std::istreambuf_iterator(fileStream)), std::istreambuf_iterator()); std::string outStr = newStr; outStr += origStr; fileStream.seekg(0, std::ios::beg); fileStream << outStr; fileStream.close(); } struct PluginInfo { HMODULE handle; std::wstring filename; std::wstring name; std::wstring description; std::wstring builddate; std::vector configopts; }; std::vector LoadPlugins() { std::vector outvec; HANDLE hFind; WIN32_FIND_DATAW ffd; hFind = FindFirstFileW((PLUGINS_DIR + L"\\*.dva").c_str(), &ffd); if (hFind != INVALID_HANDLE_VALUE) { do { if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (ffd.cFileName[0] == '.' && ffd.cFileName[1] == '_') continue; // exclude macOS metadata auto pos = wcslen(ffd.cFileName); if (ffd.cFileName[pos - 4] == '.' && (ffd.cFileName[pos - 3] == 'd' || ffd.cFileName[pos - 3] == 'D') && (ffd.cFileName[pos - 2] == 'v' || ffd.cFileName[pos - 2] == 'V') && (ffd.cFileName[pos - 1] == 'a' || ffd.cFileName[pos - 1] == 'A')) { PluginInfo thisplugin; thisplugin.handle = LoadLibraryW((PLUGINS_DIR + L"\\" + ffd.cFileName).c_str()); thisplugin.filename = ffd.cFileName; if (thisplugin.handle == NULL) continue; auto nameFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetPluginName"); auto descFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetPluginDescription"); auto dateFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetBuildDate"); auto optsFunc = (PluginConfig::PluginConfigArray(*)())GetProcAddress(thisplugin.handle, "GetPluginOptions"); if (nameFunc != NULL) thisplugin.name = nameFunc(); else thisplugin.name = thisplugin.filename; if (descFunc != NULL) thisplugin.description = descFunc(); else thisplugin.description = (thisplugin.filename + L" Plugin").c_str(); if (dateFunc != NULL) thisplugin.builddate = dateFunc(); else thisplugin.builddate = L"Unknown"; thisplugin.description += L"\n\nVersion: " + thisplugin.builddate; if (optsFunc != NULL) thisplugin.configopts = PluginConfig::GetConfigOptionVec(optsFunc()); // sometimes this might screw with custom button config, so let's just not free stuff // FreeLibrary(thisplugin.handle); outvec.push_back(thisplugin); } } } while (FindNextFileW(hFind, &ffd)); FindClose(hFind); } return outvec; } // don't load until actually needed to avoid loading disabled plugins std::vector AllPlugins; // = LoadPlugins(); std::vector GetPluginOptions(std::vector* plugins) { std::vector outvec; for (PluginInfo &pi : *plugins) { PluginOption* opt = new PluginOption(pi.filename.c_str(), L"plugins", CONFIG_FILE, pi.name.c_str(), pi.description.c_str(), true, pi.configopts, pi.builddate); outvec.push_back(opt); } return outvec; } // don't load until actually needed to avoid loading disabled plugins std::vector AllPluginOpts; // = GetPluginOptions(&AllPlugins); std::vector LoadCustom() { std::vector outvec; HANDLE hFind; WIN32_FIND_DATAW ffd; hFind = FindFirstFileW((PATCHES_DIR + L"\\*.p*").c_str(), &ffd); if (hFind != INVALID_HANDLE_VALUE) { do { if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (ffd.cFileName[0] == '.' && ffd.cFileName[1] == '_') continue; // exclude macOS metadata auto pos = wcslen(ffd.cFileName); if ((ffd.cFileName[pos - 2] == '.' && (ffd.cFileName[pos - 1] == 'p' || ffd.cFileName[pos - 1] == 'P')) || (ffd.cFileName[pos - 3] == '.' && (ffd.cFileName[pos - 2] == 'p' || ffd.cFileName[pos - 2] == 'P') && (ffd.cFileName[pos - 1] == '2'))) { PluginInfo thisplugin; thisplugin.filename = ffd.cFileName; thisplugin.name = thisplugin.filename; if (thisplugin.filename[pos - 1] == '2') thisplugin.name.resize(thisplugin.name.size() - 3); else thisplugin.name.resize(thisplugin.name.size() - 2); thisplugin.description = L"Custom patch"; outvec.push_back(thisplugin); } } } while (FindNextFileW(hFind, &ffd)); FindClose(hFind); } return outvec; } std::vector AllCustomPatches; // = LoadCustom(); std::vector GetCustomOptions(std::vector* patches) { std::vector outvec; for (PluginInfo& pi : *patches) { PluginOption* opt = new PluginOption(pi.filename.c_str(), L"plugins", CONFIG_FILE, pi.name.c_str(), pi.description.c_str(), true, pi.configopts); outvec.push_back(opt); } return outvec; } // don't load until actually needed to avoid loading disabled plugins std::vector AllCustomOpts; // = GetCustomOptions(&AllCustomPatches); // used to trick Optimus into switching to the NVIDIA GPU HMODULE nvcudaModule = LoadLibraryW(L"nvcuda.dll"); // cuInit actually returns a CUresult, but we don't really care about it void(WINAPI * cuInit)(unsigned int flags) = (void(WINAPI*)(unsigned int flags))GetProcAddress(nvcudaModule, "cuInit"); // needed to close the OpenGL window (freeglut only) HMODULE glutModule = LoadLibraryW(L"glut32.dll"); void(__stdcall * glutMainLoopEventDynamic)() = (void(__stdcall*)())GetProcAddress(glutModule, "glutMainLoopEvent"); using namespace PluginConfig; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"Launcher"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"PD Launcher is the window you currently have open.\nYou can disable it if you want, but you'll need to edit config.ini if you ever want to re-enable it."; } ================================================ FILE: source-code/source/plugins/Launcher/ui.h ================================================ #pragma once #include "framework.h" #include #include #include "TabPadding.h" #include #include #include "SkinnedMessageBox.h" #include "PluginConfig.h" #include "GPUModel.h" #include "WineVer.h" #include "composition.h" #include namespace Launcher { using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; using namespace msclr::interop; HWND hWnd; ///

/// Summary for ui /// public ref class ui : public System::Windows::Forms::Form { public: ui(void) { InitializeComponent(); hWnd = (HWND)Control::Handle.ToPointer(); this->ClientSize = Drawing::Size(444, 323); TabPadding^ tabpad = gcnew TabPadding(tabControl); // if components.ini has no section name, add one if (!IsLineInFile("[components]", COMPONENTS_FILE)) { PrependFile("[components]\n", COMPONENTS_FILE); } // if playerdata.ini has no section name, add one if (!IsLineInFile("[playerdata]", PLAYERDATA_FILE)) { PrependFile("[playerdata]\n", PLAYERDATA_FILE); } // if keyconfig.ini has no section name, add one if (!IsLineInFile("[keyconfig]", KEYCONFIG_FILE)) { PrependFile("[keyconfig]\n", KEYCONFIG_FILE); } this->panel_ScreenRes->SuspendLayout(); // populate options (patches) from array in framework // (easier than manually setting everything up) int screenresY = 3; for (ConfigOptionBase* option : screenResolutionArray) { option->hasChanged = ResolutionConfigChanged; screenresY += option->AddToPanel(panel_ScreenRes, 12, screenresY, toolTip1); } ((ComboBox^)ComboBox::FromHandle(DisplayModeDropdown->mainControlHandle))->SelectedIndexChanged += gcnew System::EventHandler(this, &ui::DisplayTypeChangedHandler); DisplayTypeChangedHandler(this, gcnew EventArgs); // run handler now this->panel_ScreenRes->ResumeLayout(false); this->panel_ScreenRes->PerformLayout(); this->panel_IntRes->SuspendLayout(); // populate options (patches) from array in framework // (easier than manually setting everything up) int intresY = 3; for (ConfigOptionBase* option : internalResolutionArray) { option->hasChanged = ResolutionConfigChanged; intresY += option->AddToPanel(panel_IntRes, 12, intresY, toolTip1); } ((CheckBox^)CheckBox::FromHandle(InternalResolutionCheckbox->mainControlHandle))->CheckedChanged += gcnew System::EventHandler(this, &ui::InternalResEnabledChangedHandler); InternalResEnabledChangedHandler(this, gcnew EventArgs); // run handler now this->panel_IntRes->ResumeLayout(false); this->panel_IntRes->PerformLayout(); this->panel_Details->SuspendLayout(); // populate details (patches) from array in framework // (easier than manually setting everything up) int detailsY = 3; for (ConfigOptionBase* option : graphicsArray) { option->hasChanged = OptionsConfigChanged; detailsY += option->AddToPanel(panel_Details, 12, detailsY, toolTip1); } trackBar_LagCompensation->Value = GetIniInt(GRAPHICS_SECTION, L"lag_compensation", 0, CONFIG_FILE); this->panel_Details->ResumeLayout(false); this->panel_Details->PerformLayout(); this->panel_Patches->SuspendLayout(); // populate options (patches) from array in framework // (easier than manually setting everything up) int optionsY = 3; for (ConfigOptionBase* option : optionsArray) { option->hasChanged = OptionsConfigChanged; optionsY += option->AddToPanel(panel_Patches, 12, optionsY, toolTip1); } this->panel_Patches->ResumeLayout(false); this->panel_Patches->PerformLayout(); this->panel_Playerdata->SuspendLayout(); // populate playerdata options from array in framework // (easier than manually setting everything up) int playerdataY = 3; for (ConfigOptionBase* option : playerdataArray) { option->hasChanged = PlayerdataConfigChanged; playerdataY += option->AddToPanel(panel_Playerdata, 12, playerdataY, toolTip1); } this->panel_Playerdata->ResumeLayout(false); this->panel_Playerdata->PerformLayout(); this->panel_Components->SuspendLayout(); // populate components from array in framework // (easier than manually setting everything up) int componentsY = 3; for (ConfigOptionBase* component : componentsArray) { component->hasChanged = ComponentsConfigChanged; componentsY += component->AddToPanel(panel_Components, 12, componentsY, toolTip1); } this->panel_Components->ResumeLayout(false); this->panel_Components->PerformLayout(); AllPlugins = LoadPlugins(); AllPluginOpts = GetPluginOptions(&AllPlugins); this->panel_Plugins->SuspendLayout(); int pluginsY = 3; for (ConfigOptionBase* option : AllPluginOpts) { option->hasChanged = new bool(false); pluginsY += option->AddToPanel(panel_Plugins, 12, pluginsY, toolTip1); } this->panel_Plugins->ResumeLayout(false); this->panel_Plugins->PerformLayout(); AllCustomPatches = LoadCustom(); AllCustomOpts = GetPluginOptions(&AllCustomPatches); this->panel_Custom->SuspendLayout(); int customY = 3; for (ConfigOptionBase* custom : AllCustomOpts) { custom->hasChanged = new bool(false); customY += custom->AddToPanel(panel_Custom, 12, customY, toolTip1); } this->panel_Custom->ResumeLayout(false); this->panel_Custom->PerformLayout(); // trick Optimus into switching to the NVIDIA GPU if (cuInit != NULL) cuInit(0); int argc = 1; char* argv[1] = { (char*)"" }; updateLagCompMsec(); updateStyle(); checkHasInvalidGLUT(); glutInit(&argc, argv); int window = glutCreateWindow("glut"); // a context must be created to use glGetString glutHideWindow(); String^ vendor = gcnew String((char*)glGetString(GL_VENDOR)); vendor = vendor->Replace(" Corporation", ""); // this is useless.. remove it to help ensure the GPU type line fits String^ renderer = gcnew String((char*)glGetString(GL_RENDERER)); renderer = renderer->Replace("Apple ", ""); // "Apple Apple M1" -> "Apple M1" String^ version = gcnew String((char*)glGetString(GL_VERSION)); version = version->Replace(" Profile Context", "") // we don't need this, either // misleading - the Metal layer always provides 2.1 as well as 4.1 Core (with the forwards compatiblity bit) // even though the GLUT context is technically 2.1, inform the user that 4.1 fwcompat is supported (in case they want to use mods) ->Replace("2.1 Metal", "2.1/4.1 (forward-compatible) Metal"); String^ gpuModel = gcnew String(GPUModel::getGpuName().c_str()); String^ wineVersion = gcnew String(WineVer::getWineVer().c_str()); int driver_version_major = 1; int driver_version_minor = 0; auto version_split = version->Split(' '); if (version_split->Length > 1) // make sure we don't use the OpenGL version instead of the driver version { String^ driver_version = gcnew String(version_split[version_split->Length - 1]); auto driver_version_split_major_minor = driver_version->Split('.'); if (driver_version_split_major_minor->Length >= 2) { driver_version_major = int::Parse(driver_version_split_major_minor[0]); driver_version_minor = int::Parse(driver_version_split_major_minor[1]); } } glutDestroyWindow(window); // destroy the window so it doesn't remain on screen if (glutMainLoopEventDynamic != NULL) glutMainLoopEventDynamic(); // freeglut needs this if (wineVersion != "") { this->labelGPU->Text = "Wine " + wineVersion + " (remember to disable movies!)\n"; } else this->labelGPU->Text = "GPU Info:\n"; this->labelGPU->Text += vendor + " " + renderer + "\n"; this->labelGPU->Text += "OpenGL: " + version + "\n"; int linkStart = this->labelGPU->Text->Length; bool showGpuDialog = false; bool showGpuTypeWarning = false; bool hasNovidia = false; bool novidiaEnabled = false; bool hasDivaGL = false; bool divaGLEnabled = false; for (PluginInfo i : AllPlugins) { if (i.name == L"Novidia") { hasNovidia = true; novidiaEnabled = GetIniBool(L"plugins", i.filename.c_str(), 1, CONFIG_FILE); } else if (i.name == L"DivaGL") { hasDivaGL = true; divaGLEnabled = GetIniBool(L"plugins", i.filename.c_str(), 1, CONFIG_FILE); } if (hasNovidia && hasDivaGL) break; } if (divaGLEnabled) { this->labelGPU->Text += L"Rendering provided by DivaGL."; GPUIssueText = L"Please check DivaGL's requirements to ensure compatibility with your graphics driver."; this->labelGPU->LinkColor = System::Drawing::Color::HotPink; } else { if (vendor->Contains("AMD") || vendor->Contains("ATI")) // check OpenGL to get actual GPU being used for vendor check (to get accurate results for iGPU) { if (hasNovidia) { if (novidiaEnabled) { if (wineVersion == "" && (driver_version_major < 21 || (driver_version_major == 21 && driver_version_minor < 6))) { if (driver_version_major == 21 && driver_version_minor == 5) { this->labelGPU->Text += L"Driver may have issues."; GPUIssueText = L"The graphics driver you're using should be able to play movies without issues, but may crash while loading a song after playing multiple stages in one session.\nIf possible, please install the latest driver from your GPU vendor's website.\nHowever, note that if your GPU is old, you may not be able to install a more recent driver."; } else { this->labelGPU->Text += L"Driver has known issues."; GPUIssueText = L"The graphics driver you're using has known issues. Movies may not play back correctly.\nPlease install the latest driver from your GPU vendor's website."; showGpuDialog = true; } this->labelGPU->LinkColor = System::Drawing::Color::Orange; } else if (wineVersion == "" && (driver_version_major > 22 || (driver_version_major == 22 && driver_version_minor > 6))) { this->labelGPU->Text += "Issues: Unsupported GPU driver."; GPUIssueText = "The graphics driver you're using is too new for Novidia.\nThe game will not run unless you install driver version 22.6.1 or earlier from AMD's website.\n\nAlternatively, you can try mods such as DivaGL."; this->labelGPU->LinkColor = System::Drawing::Color::Red; showGpuDialog = true; } else { this->labelGPU->Text += "Issues: AMD GPU support is unofficial."; GPUIssueText = "AMD GPUs are not supported without mods.\nThe PD Loader AMDPack seems to be installed, but please keep in mind that it may have issues."; this->labelGPU->LinkColor = System::Drawing::Color::Yellow; } } else { this->labelGPU->Text += "Issues: Mods needed for AMD compatibility!"; GPUIssueText = "AMD GPUs are not supported without mods.\n" + (hasDivaGL ? "DivaGL/" : "") + "Novidia is installed, but disabled; please enable it to use your AMD GPU.\n\nIf you have a laptop with an NVIDIA GPU and wish to use it instead of the detected GPU, you may need to set diva.exe to use it in Windows settings or NVIDIA Control Panel."; this->labelGPU->LinkColor = System::Drawing::Color::Red; showGpuDialog = true; } } else if (hasDivaGL) { this->labelGPU->Text += "Issues: Mods needed for AMD compatibility!"; GPUIssueText = "AMD GPUs are not supported without mods.\nDivaGL is installed, but disabled; please enable it to use your AMD GPU.\n\nIf you have a laptop with an NVIDIA GPU and wish to use it instead of the detected GPU, you may need to set diva.exe to use it in Windows settings or NVIDIA Control Panel."; this->labelGPU->LinkColor = System::Drawing::Color::Red; showGpuDialog = true; } else { this->labelGPU->Text += "Issues: Mods needed for AMD compatibility!"; GPUIssueText = "AMD GPUs are not supported without mods.\nEither DivaGL or Novidia is required. Please download either plugin and check its requirements to ensure compatibility with your graphics driver.\n\nIf you have a laptop with an NVIDIA GPU and wish to use it instead of the detected GPU, you may need to set diva.exe to use it in Windows settings or NVIDIA Control Panel."; this->labelGPU->LinkColor = System::Drawing::Color::Red; showGpuDialog = true; } } else if (vendor->Contains("NVIDIA")) { if (wineVersion == "" && (driver_version_major < 391 || (driver_version_major > 446 && driver_version_major < 460))) { this->labelGPU->Text += L"Driver has known issues."; GPUIssueText = L"The graphics driver you're using has known issues. Please install the latest driver from your GPU vendor's website."; this->labelGPU->LinkColor = System::Drawing::Color::Orange; showGpuDialog = true; } else if (gpuModel->StartsWith("GB")) // unconfirmed?? { this->labelGPU->Text += L"Issues: Blackwell GPU detected! Possible noise.\n(Click for more information)"; GPUIssueText = L"On Blackwell GPUs (RTX 50xx), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; this->labelGPU->LinkColor = System::Drawing::Color::Yellow; } else if (gpuModel->StartsWith("AD")) { this->labelGPU->Text += L"Issues: Ada Lovelace GPU detected! Possible noise.\n(Click for more information)"; GPUIssueText = L"On Ada Lovelace GPUs (RTX 40xx), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; this->labelGPU->LinkColor = System::Drawing::Color::Yellow; } else if (gpuModel->StartsWith("GA")) { this->labelGPU->Text += L"Issues: Ampere GPU detected! Possible noise.\n(Click for more information)"; GPUIssueText = L"On Ampere GPUs (RTX 30xx), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; this->labelGPU->LinkColor = System::Drawing::Color::Yellow; } else if (gpuModel->StartsWith("TU")) { this->labelGPU->Text += L"Issues: Turing GPU detected! Possible noise.\n(Click for more information)"; GPUIssueText = L"On Turing GPUs (GTX 16xx/RTX 20xx), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; this->labelGPU->LinkColor = System::Drawing::Color::Yellow; } else if (gpuModel->StartsWith("GV")) { this->labelGPU->Text += L"Issues: Volta GPU detected! Possible noise.\n(Click for more information)"; GPUIssueText = L"On Volta GPUs (TITAN V), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; this->labelGPU->LinkColor = System::Drawing::Color::Yellow; } else if (gpuModel->StartsWith("GM") || gpuModel->StartsWith("GP")) { this->labelGPU->Text += L"Issues: May have minor noise on some stages.\n(Click for more information)"; GPUIssueText = L"On Maxwell GPUs (~GTX 900) and newer, some minor stage shaders create noise.\nPlease make sure the ShaderPatch plugin is enabled."; this->labelGPU->LinkColor = System::Drawing::Color::Teal; } else if (gpuModel->StartsWith("GK")) { this->labelGPU->Text += L"Issues: None."; GPUIssueText = L"Your GPU should have no issues running the game."; this->labelGPU->LinkColor = System::Drawing::Color::LightBlue; } else if (gpuModel->StartsWith("GF")) { if (version[0] < '4') { this->labelGPU->Text += L"Issues: Driver too old."; GPUIssueText = L"Your GPU should be able to run the game, but it looks like your OpenGL version is too old.\nA driver update should fix this."; this->labelGPU->LinkColor = System::Drawing::Color::Orange; showGpuDialog = true; } else { this->labelGPU->Text += L"Issues: No known issues."; GPUIssueText = L"Your GPU should have no issues running the game, but it is older than the GPU the game was originally designed for (GTX 650 Ti).\nThere may be some issues with graphics.\nPlease report any issues so that they can be analysed and potentially fixed."; this->labelGPU->LinkColor = System::Drawing::Color::Teal; } } else if (gpuModel->StartsWith("G") || gpuModel->StartsWith("NV") || gpuModel->StartsWith("NB") || gpuModel->StartsWith("N10") || gpuModel->StartsWith("MCP")) { this->labelGPU->Text += L"Issues: GPU too old! 3D rendering might be broken.\n(Click for more information)"; GPUIssueText = L"Your GPU is very old and does not support rendering techniques used by the game.\nYou may be able to play, but graphics will likely have major issues.\nPlease upgrade to a GTX 600 series or later GPU."; this->labelGPU->LinkColor = System::Drawing::Color::Orange; showGpuDialog = true; } else if (version[0] >= '4' && gpuModel->Length > 0 && !gpuModel->StartsWith("Unk") && !gpuModel->StartsWith("Oth")) { this->labelGPU->Text += L"Issues: GPU may be too new.\n(Click for more information)"; GPUIssueText = L"It looks like your GPU may be too new. Only up to Ada Lovelace (RTX 40xx) is currently supported.\nYou will likely see lines/noise on important character shaders and some minor stage shaders.\nPlease report any issues so that ShaderPatch can be updated.\n\nTo try to get rid of any artifacts, try selecting a specific GPU architecture in Graphics -> Nvidia GPU (e.g. \"Ada or newer\"), or use DivaGL."; this->labelGPU->LinkColor = System::Drawing::Color::Orange; showGpuDialog = true; showGpuTypeWarning = true; } else { this->labelGPU->Text += L"Issues: Unable to detect GPU architecture.\n(Click for more information)"; GPUIssueText = L"It looks like you have an NVIDIA GPU, but something went wrong while trying to determine your GPU's architecture (type).\nThis may be a caused by a bug, but it probably indicates potential issues.\nPlease make sure you have a GTX 600 series or later GPU. (GTX 400 series or later should also work)\n\nIf the game runs but has artifacts, try selecting a specific GPU architecture in Graphics -> Nvidia GPU (e.g. \"Ada or newer\"), or use DivaGL."; this->labelGPU->LinkColor = System::Drawing::Color::Orange; showGpuDialog = true; showGpuTypeWarning = true; } } else //if (gpuModel->Length == 0 || gpuModel->StartsWith("Unk") || gpuModel->StartsWith("Oth")) { this->labelGPU->Text += L"Issues: UNSUPPORTED GPU!"; GPUIssueText = L"Your graphics card is not supported. Only NVIDIA GPUs are recommended (though others can be used with mods).\nPlease use a GTX 600 series or later NVIDIA GPU.\n\nIf you have a laptop with an NVIDIA GPU and wish to use it instead of the detected GPU, you may need to set diva.exe to use it in Windows settings or NVIDIA Control Panel.\n\nOwners of other GPUs may be able to run the game using plugins or mods, such as DivaGL, Novidia, or DivaImGui."; this->labelGPU->LinkColor = System::Drawing::Color::Red; showGpuDialog = true; } } int linkEnd = this->labelGPU->Text->Length - linkStart; this->labelGPU->LinkClicked += gcnew System::Windows::Forms::LinkLabelLinkClickedEventHandler(this, &ui::LinkLabelLinkClickedGPUIssueHandler); this->labelGPU->LinkArea = System::Windows::Forms::LinkArea(linkStart, linkEnd); if (!nNoGPUDialog) { if (showGpuDialog) SkinnedMessageBox::Show(this, GPUIssueText + "\n\nYou can disable this message from the Options tab.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Warning); if (showGpuTypeWarning) { Label^ gpuTypeLabel = ((Label^)Control::FromHandle(((DropdownOption*)(graphicsArray[0]))->labelHandle)); ComboBox^ gpuTypeCtrl = ((ComboBox^)Control::FromHandle(((DropdownOption*)(graphicsArray[0]))->mainControlHandle)); gpuTypeLabel->Text = "/!\\ " + gpuTypeLabel->Text; gpuTypeLabel->BackColor = System::Drawing::Color::Gold; gpuTypeLabel->ForeColor = System::Drawing::Color::Crimson; gpuTypeCtrl->Items[0] = "SELECT ONE"; gpuTypeCtrl->BackColor = System::Drawing::Color::Gold; gpuTypeCtrl->ForeColor = System::Drawing::Color::Crimson; gpuTypeCtrl->FlatStyle = System::Windows::Forms::FlatStyle::Flat; } } } protected: /// /// Clean up any resources being used. /// ~ui() { if (components) { delete components; } } void OnPaintBackground(PaintEventArgs e) override { } /*property System::Windows::Forms::CreateParams^ CreateParams { virtual System::Windows::Forms::CreateParams^ get() override { System::Windows::Forms::CreateParams^ params = Form::CreateParams; params->ExStyle |= 0x00200000L; return params; } }*/ void updateLagCompMsec() { this->groupBox_Lag->Text = "Lag Compensation (" + this->trackBar_LagCompensation->Value + " msec)"; } void updateStyle() { int nDarkLauncher = GetPrivateProfileIntW(LAUNCHER_SECTION, L"dark_launcher", FALSE, CONFIG_FILE); Color colourBg, colourBg2, colourFg; if (nDarkLauncher) { setDarkTheme(hWnd); colourFg = Color::White; colourBg = Color::FromArgb(32, 32, 32); // tabControl colourBg2 = Color::FromArgb(25, 25, 25); } else { setDarkTheme(hWnd, false); colourFg = Color::FromArgb(64, 64, 64); colourBg = Color::White; // tabControl colourBg2 = Color::FromArgb(242, 242, 242); } this->button_Discord->BackColor = Color::Transparent; this->button_github->BackColor = Color::Transparent; this->button_Wiki->BackColor = Color::Transparent; this->tabPage_Resolution->BackColor = colourBg; this->tabPage_Resolution->ForeColor = colourFg; this->tabPage_Patches->BackColor = colourBg; this->tabPage_Patches->ForeColor = colourFg; this->tabPage_Playerdata->BackColor = colourBg; this->tabPage_Playerdata->ForeColor = colourFg; this->tabPage_Plugins->BackColor = colourBg; this->tabPage_Plugins->ForeColor = colourFg; this->tabPage_Components->BackColor = colourBg; this->tabPage_Components->ForeColor = colourFg; this->creditsTextBox->BackColor = colourBg; this->creditsTextBox->ForeColor = colourFg; this->tabControl->BackColor = colourBg; this->tabControl->ForeColor = colourFg; this->BackColor = colourBg2; this->button_Launch->BackColor = colourBg; this->button_Launch->ForeColor = colourFg; this->button_Apply->BackColor = colourBg; this->button_Apply->ForeColor = colourFg; this->labelGPU->ForeColor = colourFg; this->groupBox_Details->ForeColor = colourFg; this->groupBox_InternalRes->ForeColor = colourFg; this->groupBox_Lag->ForeColor = colourFg; this->groupBox_ScreenRes->ForeColor = colourFg; } private: private: System::Windows::Forms::Button^ button_Launch; private: System::Windows::Forms::GroupBox^ groupBox_ScreenRes; private: System::Windows::Forms::TabControl^ tabControl; private: System::Windows::Forms::TabPage^ tabPage_Resolution; private: System::Windows::Forms::GroupBox^ groupBox_InternalRes; private: System::Windows::Forms::TabPage^ tabPage_Components; private: System::Windows::Forms::Panel^ panel_Components; private: System::Windows::Forms::TabPage^ tabPage_Patches; private: System::Windows::Forms::Panel^ panel_Patches; private: System::Windows::Forms::TabPage^ tabPage_Plugins; private: System::Windows::Forms::Panel^ panel_Plugins; private: System::Windows::Forms::Button^ button_Discord; private: System::Windows::Forms::Button^ button_github; private: System::Windows::Forms::TabPage^ tabPage_Playerdata; private: System::Windows::Forms::Panel^ panel_Playerdata; private: System::Windows::Forms::ToolTip^ toolTip1; private: System::Windows::Forms::Panel^ panel_ScreenRes; private: System::Windows::Forms::Panel^ panel_IntRes; private: System::Windows::Forms::LinkLabel^ labelGPU; private: System::Windows::Forms::TabPage^ tabPage_Credits; private: System::Windows::Forms::TextBox^ creditsTextBox; private: System::Windows::Forms::GroupBox^ groupBox_Details; private: System::Windows::Forms::Panel^ panel_Details; private: System::Windows::Forms::Panel^ panel_Custom; private: System::Windows::Forms::Button^ button_Apply; private: System::Windows::Forms::GroupBox^ groupBox_Lag; private: System::Windows::Forms::TrackBar^ trackBar_LagCompensation; private: System::Windows::Forms::Button^ button_Wiki; private: System::ComponentModel::IContainer^ components; private: /// /// Required designer variable. /// #pragma region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// void InitializeComponent(void) { this->components = (gcnew System::ComponentModel::Container()); System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(ui::typeid)); this->button_Launch = (gcnew System::Windows::Forms::Button()); this->groupBox_ScreenRes = (gcnew System::Windows::Forms::GroupBox()); this->panel_ScreenRes = (gcnew System::Windows::Forms::Panel()); this->tabControl = (gcnew System::Windows::Forms::TabControl()); this->tabPage_Resolution = (gcnew System::Windows::Forms::TabPage()); this->groupBox_Lag = (gcnew System::Windows::Forms::GroupBox()); this->trackBar_LagCompensation = (gcnew System::Windows::Forms::TrackBar()); this->groupBox_Details = (gcnew System::Windows::Forms::GroupBox()); this->panel_Details = (gcnew System::Windows::Forms::Panel()); this->labelGPU = (gcnew System::Windows::Forms::LinkLabel()); this->groupBox_InternalRes = (gcnew System::Windows::Forms::GroupBox()); this->panel_IntRes = (gcnew System::Windows::Forms::Panel()); this->tabPage_Patches = (gcnew System::Windows::Forms::TabPage()); this->panel_Patches = (gcnew System::Windows::Forms::Panel()); this->tabPage_Playerdata = (gcnew System::Windows::Forms::TabPage()); this->panel_Playerdata = (gcnew System::Windows::Forms::Panel()); this->tabPage_Components = (gcnew System::Windows::Forms::TabPage()); this->panel_Components = (gcnew System::Windows::Forms::Panel()); this->tabPage_Plugins = (gcnew System::Windows::Forms::TabPage()); this->panel_Custom = (gcnew System::Windows::Forms::Panel()); this->panel_Plugins = (gcnew System::Windows::Forms::Panel()); this->tabPage_Credits = (gcnew System::Windows::Forms::TabPage()); this->creditsTextBox = (gcnew System::Windows::Forms::TextBox()); this->button_Discord = (gcnew System::Windows::Forms::Button()); this->button_github = (gcnew System::Windows::Forms::Button()); this->toolTip1 = (gcnew System::Windows::Forms::ToolTip(this->components)); this->button_Apply = (gcnew System::Windows::Forms::Button()); this->button_Wiki = (gcnew System::Windows::Forms::Button()); this->groupBox_ScreenRes->SuspendLayout(); this->tabControl->SuspendLayout(); this->tabPage_Resolution->SuspendLayout(); this->groupBox_Lag->SuspendLayout(); (cli::safe_cast(this->trackBar_LagCompensation))->BeginInit(); this->groupBox_Details->SuspendLayout(); this->groupBox_InternalRes->SuspendLayout(); this->tabPage_Patches->SuspendLayout(); this->tabPage_Playerdata->SuspendLayout(); this->tabPage_Components->SuspendLayout(); this->tabPage_Plugins->SuspendLayout(); this->tabPage_Credits->SuspendLayout(); this->SuspendLayout(); // // button_Launch // this->button_Launch->BackColor = System::Drawing::Color::White; this->button_Launch->FlatAppearance->BorderColor = System::Drawing::SystemColors::Control; this->button_Launch->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->button_Launch->Location = System::Drawing::Point(344, 778); this->button_Launch->Margin = System::Windows::Forms::Padding(6); this->button_Launch->Name = L"button_Launch"; this->button_Launch->Size = System::Drawing::Size(434, 46); this->button_Launch->TabIndex = 20; this->button_Launch->Text = L"Launch"; this->button_Launch->UseVisualStyleBackColor = false; this->button_Launch->Click += gcnew System::EventHandler(this, &ui::Button_Launch_Click); // // groupBox_ScreenRes // this->groupBox_ScreenRes->Controls->Add(this->panel_ScreenRes); this->groupBox_ScreenRes->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->groupBox_ScreenRes->Location = System::Drawing::Point(10, 12); this->groupBox_ScreenRes->Margin = System::Windows::Forms::Padding(6); this->groupBox_ScreenRes->Name = L"groupBox_ScreenRes"; this->groupBox_ScreenRes->Padding = System::Windows::Forms::Padding(6); this->groupBox_ScreenRes->Size = System::Drawing::Size(526, 226); this->groupBox_ScreenRes->TabIndex = 10; this->groupBox_ScreenRes->TabStop = false; this->groupBox_ScreenRes->Text = L"Screen Resolution"; // // panel_ScreenRes // this->panel_ScreenRes->AutoScroll = true; this->panel_ScreenRes->Location = System::Drawing::Point(10, 38); this->panel_ScreenRes->Margin = System::Windows::Forms::Padding(6); this->panel_ScreenRes->Name = L"panel_ScreenRes"; this->panel_ScreenRes->Size = System::Drawing::Size(506, 178); this->panel_ScreenRes->TabIndex = 0; // // tabControl // this->tabControl->Controls->Add(this->tabPage_Resolution); this->tabControl->Controls->Add(this->tabPage_Patches); this->tabControl->Controls->Add(this->tabPage_Playerdata); this->tabControl->Controls->Add(this->tabPage_Components); this->tabControl->Controls->Add(this->tabPage_Plugins); this->tabControl->Controls->Add(this->tabPage_Credits); this->tabControl->Location = System::Drawing::Point(0, 0); this->tabControl->Margin = System::Windows::Forms::Padding(6); this->tabControl->Name = L"tabControl"; this->tabControl->SelectedIndex = 0; this->tabControl->Size = System::Drawing::Size(1120, 768); this->tabControl->TabIndex = 10; // // tabPage_Resolution // this->tabPage_Resolution->BackColor = System::Drawing::Color::White; this->tabPage_Resolution->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; this->tabPage_Resolution->Controls->Add(this->groupBox_Lag); this->tabPage_Resolution->Controls->Add(this->groupBox_Details); this->tabPage_Resolution->Controls->Add(this->labelGPU); this->tabPage_Resolution->Controls->Add(this->groupBox_InternalRes); this->tabPage_Resolution->Controls->Add(this->groupBox_ScreenRes); this->tabPage_Resolution->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), static_cast(static_cast(64))); this->tabPage_Resolution->Location = System::Drawing::Point(8, 39); this->tabPage_Resolution->Margin = System::Windows::Forms::Padding(6); this->tabPage_Resolution->Name = L"tabPage_Resolution"; this->tabPage_Resolution->Padding = System::Windows::Forms::Padding(6); this->tabPage_Resolution->Size = System::Drawing::Size(1104, 721); this->tabPage_Resolution->TabIndex = 0; this->tabPage_Resolution->Text = L"Graphics"; // // groupBox_Lag // this->groupBox_Lag->Controls->Add(this->trackBar_LagCompensation); this->groupBox_Lag->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->groupBox_Lag->Location = System::Drawing::Point(10, 564); this->groupBox_Lag->Margin = System::Windows::Forms::Padding(6); this->groupBox_Lag->Name = L"groupBox_Lag"; this->groupBox_Lag->Padding = System::Windows::Forms::Padding(6); this->groupBox_Lag->Size = System::Drawing::Size(526, 146); this->groupBox_Lag->TabIndex = 21; this->groupBox_Lag->TabStop = false; this->groupBox_Lag->Text = L"Lag Compensation"; // // trackBar_LagCompensation // this->trackBar_LagCompensation->LargeChange = 1; this->trackBar_LagCompensation->Location = System::Drawing::Point(14, 40); this->trackBar_LagCompensation->Margin = System::Windows::Forms::Padding(6); this->trackBar_LagCompensation->Maximum = 500; this->trackBar_LagCompensation->Name = L"trackBar_LagCompensation"; this->trackBar_LagCompensation->Size = System::Drawing::Size(500, 90); this->trackBar_LagCompensation->TabIndex = 0; this->trackBar_LagCompensation->TickStyle = System::Windows::Forms::TickStyle::None; this->trackBar_LagCompensation->Scroll += gcnew System::EventHandler(this, &ui::trackBar_LagCompensation_Scroll); // // groupBox_Details // this->groupBox_Details->Controls->Add(this->panel_Details); this->groupBox_Details->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->groupBox_Details->Location = System::Drawing::Point(548, 12); this->groupBox_Details->Margin = System::Windows::Forms::Padding(6); this->groupBox_Details->Name = L"groupBox_Details"; this->groupBox_Details->Padding = System::Windows::Forms::Padding(6); this->groupBox_Details->Size = System::Drawing::Size(544, 698); this->groupBox_Details->TabIndex = 11; this->groupBox_Details->TabStop = false; this->groupBox_Details->Text = L"Details"; // // panel_Details // this->panel_Details->AutoScroll = true; this->panel_Details->Location = System::Drawing::Point(10, 23); this->panel_Details->Margin = System::Windows::Forms::Padding(6); this->panel_Details->Name = L"panel_Details"; this->panel_Details->Size = System::Drawing::Size(522, 667); this->panel_Details->TabIndex = 0; // // labelGPU // this->labelGPU->AutoSize = true; this->labelGPU->BackColor = System::Drawing::Color::Transparent; this->labelGPU->ForeColor = System::Drawing::Color::Black; this->labelGPU->Location = System::Drawing::Point(10, 418); this->labelGPU->Margin = System::Windows::Forms::Padding(4, 0, 4, 0); this->labelGPU->MinimumSize = System::Drawing::Size(526, 26); this->labelGPU->Name = L"labelGPU"; this->labelGPU->Size = System::Drawing::Size(526, 26); this->labelGPU->TabIndex = 21; this->labelGPU->TextAlign = System::Drawing::ContentAlignment::MiddleLeft; // // groupBox_InternalRes // this->groupBox_InternalRes->Controls->Add(this->panel_IntRes); this->groupBox_InternalRes->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->groupBox_InternalRes->Location = System::Drawing::Point(10, 248); this->groupBox_InternalRes->Margin = System::Windows::Forms::Padding(6); this->groupBox_InternalRes->Name = L"groupBox_InternalRes"; this->groupBox_InternalRes->Padding = System::Windows::Forms::Padding(6); this->groupBox_InternalRes->Size = System::Drawing::Size(526, 166); this->groupBox_InternalRes->TabIndex = 20; this->groupBox_InternalRes->TabStop = false; this->groupBox_InternalRes->Text = L"Internal Resolution (Quality)"; // // panel_IntRes // this->panel_IntRes->AutoScroll = true; this->panel_IntRes->Location = System::Drawing::Point(10, 38); this->panel_IntRes->Margin = System::Windows::Forms::Padding(6); this->panel_IntRes->Name = L"panel_IntRes"; this->panel_IntRes->Size = System::Drawing::Size(506, 118); this->panel_IntRes->TabIndex = 1; // // tabPage_Patches // this->tabPage_Patches->BackColor = System::Drawing::Color::White; this->tabPage_Patches->Controls->Add(this->panel_Patches); this->tabPage_Patches->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), static_cast(static_cast(64))); this->tabPage_Patches->Location = System::Drawing::Point(8, 39); this->tabPage_Patches->Margin = System::Windows::Forms::Padding(6); this->tabPage_Patches->Name = L"tabPage_Patches"; this->tabPage_Patches->Size = System::Drawing::Size(1104, 721); this->tabPage_Patches->TabIndex = 1; this->tabPage_Patches->Text = L"Options"; // // panel_Patches // this->panel_Patches->AutoScroll = true; this->panel_Patches->Location = System::Drawing::Point(0, 0); this->panel_Patches->Margin = System::Windows::Forms::Padding(6); this->panel_Patches->Name = L"panel_Patches"; this->panel_Patches->Size = System::Drawing::Size(1104, 716); this->panel_Patches->TabIndex = 9; // // tabPage_Playerdata // this->tabPage_Playerdata->BackColor = System::Drawing::Color::White; this->tabPage_Playerdata->Controls->Add(this->panel_Playerdata); this->tabPage_Playerdata->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), static_cast(static_cast(64))); this->tabPage_Playerdata->Location = System::Drawing::Point(8, 39); this->tabPage_Playerdata->Margin = System::Windows::Forms::Padding(6); this->tabPage_Playerdata->Name = L"tabPage_Playerdata"; this->tabPage_Playerdata->Size = System::Drawing::Size(1104, 721); this->tabPage_Playerdata->TabIndex = 3; this->tabPage_Playerdata->Text = L"Player"; // // panel_Playerdata // this->panel_Playerdata->AutoScroll = true; this->panel_Playerdata->Location = System::Drawing::Point(0, 0); this->panel_Playerdata->Margin = System::Windows::Forms::Padding(6); this->panel_Playerdata->Name = L"panel_Playerdata"; this->panel_Playerdata->Size = System::Drawing::Size(1104, 716); this->panel_Playerdata->TabIndex = 1; // // tabPage_Components // this->tabPage_Components->BackColor = System::Drawing::Color::White; this->tabPage_Components->Controls->Add(this->panel_Components); this->tabPage_Components->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), static_cast(static_cast(64))); this->tabPage_Components->Location = System::Drawing::Point(8, 39); this->tabPage_Components->Margin = System::Windows::Forms::Padding(6); this->tabPage_Components->Name = L"tabPage_Components"; this->tabPage_Components->Padding = System::Windows::Forms::Padding(6); this->tabPage_Components->Size = System::Drawing::Size(1104, 721); this->tabPage_Components->TabIndex = 2; this->tabPage_Components->Text = L"Components"; // // panel_Components // this->panel_Components->AutoScroll = true; this->panel_Components->Location = System::Drawing::Point(0, 0); this->panel_Components->Margin = System::Windows::Forms::Padding(6); this->panel_Components->Name = L"panel_Components"; this->panel_Components->Size = System::Drawing::Size(1104, 716); this->panel_Components->TabIndex = 0; // // tabPage_Plugins // this->tabPage_Plugins->BackColor = System::Drawing::Color::White; this->tabPage_Plugins->Controls->Add(this->panel_Custom); this->tabPage_Plugins->Controls->Add(this->panel_Plugins); this->tabPage_Plugins->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), static_cast(static_cast(64))); this->tabPage_Plugins->Location = System::Drawing::Point(8, 39); this->tabPage_Plugins->Margin = System::Windows::Forms::Padding(6); this->tabPage_Plugins->Name = L"tabPage_Plugins"; this->tabPage_Plugins->Padding = System::Windows::Forms::Padding(6); this->tabPage_Plugins->Size = System::Drawing::Size(1104, 721); this->tabPage_Plugins->TabIndex = 3; this->tabPage_Plugins->Text = L"Plugins and Patches"; // // panel_Custom // this->panel_Custom->AutoScroll = true; this->panel_Custom->Location = System::Drawing::Point(552, 0); this->panel_Custom->Margin = System::Windows::Forms::Padding(6); this->panel_Custom->Name = L"panel_Custom"; this->panel_Custom->Size = System::Drawing::Size(552, 716); this->panel_Custom->TabIndex = 3; // // panel_Plugins // this->panel_Plugins->AutoScroll = true; this->panel_Plugins->Location = System::Drawing::Point(0, 0); this->panel_Plugins->Margin = System::Windows::Forms::Padding(6); this->panel_Plugins->Name = L"panel_Plugins"; this->panel_Plugins->Size = System::Drawing::Size(552, 716); this->panel_Plugins->TabIndex = 0; // // tabPage_Credits // this->tabPage_Credits->Controls->Add(this->creditsTextBox); this->tabPage_Credits->Location = System::Drawing::Point(8, 39); this->tabPage_Credits->Margin = System::Windows::Forms::Padding(4); this->tabPage_Credits->Name = L"tabPage_Credits"; this->tabPage_Credits->Padding = System::Windows::Forms::Padding(4); this->tabPage_Credits->Size = System::Drawing::Size(1104, 721); this->tabPage_Credits->TabIndex = 5; this->tabPage_Credits->Text = L"Credits"; this->tabPage_Credits->UseVisualStyleBackColor = true; // // creditsTextBox // this->creditsTextBox->BackColor = System::Drawing::Color::White; this->creditsTextBox->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), static_cast(static_cast(64))); this->creditsTextBox->Location = System::Drawing::Point(0, 0); this->creditsTextBox->Margin = System::Windows::Forms::Padding(4); this->creditsTextBox->Multiline = true; this->creditsTextBox->Name = L"creditsTextBox"; this->creditsTextBox->ReadOnly = true; this->creditsTextBox->ScrollBars = System::Windows::Forms::ScrollBars::Both; this->creditsTextBox->Size = System::Drawing::Size(1100, 712); this->creditsTextBox->TabIndex = 0; this->creditsTextBox->Text = resources->GetString(L"creditsTextBox.Text"); // // button_Discord // this->button_Discord->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), static_cast(static_cast(242))); this->button_Discord->Cursor = System::Windows::Forms::Cursors::Hand; this->button_Discord->FlatAppearance->BorderSize = 0; this->button_Discord->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->button_Discord->Image = (cli::safe_cast(resources->GetObject(L"button_Discord.Image"))); this->button_Discord->Location = System::Drawing::Point(992, 768); this->button_Discord->Margin = System::Windows::Forms::Padding(6); this->button_Discord->Name = L"button_Discord"; this->button_Discord->Size = System::Drawing::Size(64, 64); this->button_Discord->TabIndex = 31; this->button_Discord->UseVisualStyleBackColor = false; this->button_Discord->Click += gcnew System::EventHandler(this, &ui::button_Discord_Click); // // button_github // this->button_github->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), static_cast(static_cast(242))); this->button_github->Cursor = System::Windows::Forms::Cursors::Hand; this->button_github->FlatAppearance->BorderSize = 0; this->button_github->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->button_github->Image = (cli::safe_cast(resources->GetObject(L"button_github.Image"))); this->button_github->Location = System::Drawing::Point(1056, 768); this->button_github->Margin = System::Windows::Forms::Padding(6); this->button_github->Name = L"button_github"; this->button_github->Size = System::Drawing::Size(64, 64); this->button_github->TabIndex = 32; this->button_github->UseVisualStyleBackColor = false; this->button_github->Click += gcnew System::EventHandler(this, &ui::button_github_Click); // // button_Apply // this->button_Apply->BackColor = System::Drawing::Color::White; this->button_Apply->FlatAppearance->BorderColor = System::Drawing::SystemColors::Control; this->button_Apply->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->button_Apply->Location = System::Drawing::Point(8, 778); this->button_Apply->Margin = System::Windows::Forms::Padding(6); this->button_Apply->Name = L"button_Apply"; this->button_Apply->Size = System::Drawing::Size(138, 46); this->button_Apply->TabIndex = 33; this->button_Apply->Text = L"Apply"; this->button_Apply->UseVisualStyleBackColor = false; this->button_Apply->Click += gcnew System::EventHandler(this, &ui::button_Apply_Click); // // button_Wiki // this->button_Wiki->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), static_cast(static_cast(242))); this->button_Wiki->BackgroundImage = (cli::safe_cast(resources->GetObject(L"button_Wiki.BackgroundImage"))); this->button_Wiki->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; this->button_Wiki->Cursor = System::Windows::Forms::Cursors::Hand; this->button_Wiki->FlatAppearance->BorderSize = 0; this->button_Wiki->FlatStyle = System::Windows::Forms::FlatStyle::Flat; this->button_Wiki->Location = System::Drawing::Point(928, 768); this->button_Wiki->Margin = System::Windows::Forms::Padding(6); this->button_Wiki->Name = L"button_Wiki"; this->button_Wiki->Size = System::Drawing::Size(64, 64); this->button_Wiki->TabIndex = 34; this->button_Wiki->UseVisualStyleBackColor = false; this->button_Wiki->Click += gcnew System::EventHandler(this, &ui::button_Wiki_Click); // // ui // this->AcceptButton = this->button_Launch; this->AutoScaleDimensions = System::Drawing::SizeF(192, 192); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Dpi; this->AutoSize = true; this->AutoSizeMode = System::Windows::Forms::AutoSizeMode::GrowAndShrink; this->BackColor = System::Drawing::Color::Magenta; this->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; this->ClientSize = System::Drawing::Size(1120, 834); this->Controls->Add(this->button_Wiki); this->Controls->Add(this->button_Apply); this->Controls->Add(this->tabControl); this->Controls->Add(this->button_Launch); this->Controls->Add(this->button_github); this->Controls->Add(this->button_Discord); this->DoubleBuffered = true; this->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), static_cast(static_cast(64))); this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::Fixed3D; this->HelpButton = true; this->Icon = (cli::safe_cast(resources->GetObject(L"$this.Icon"))); this->KeyPreview = true; this->Margin = System::Windows::Forms::Padding(6); this->MaximizeBox = false; this->Name = L"ui"; this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; this->Text = L"PD Launcher -- TEST VERSION --"; this->TransparencyKey = System::Drawing::Color::Magenta; this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &ui::Ui_FormClosing); this->FormClosed += gcnew System::Windows::Forms::FormClosedEventHandler(this, &ui::Ui_FormClosed); this->groupBox_ScreenRes->ResumeLayout(false); this->tabControl->ResumeLayout(false); this->tabPage_Resolution->ResumeLayout(false); this->tabPage_Resolution->PerformLayout(); this->groupBox_Lag->ResumeLayout(false); this->groupBox_Lag->PerformLayout(); (cli::safe_cast(this->trackBar_LagCompensation))->EndInit(); this->groupBox_Details->ResumeLayout(false); this->groupBox_InternalRes->ResumeLayout(false); this->tabPage_Patches->ResumeLayout(false); this->tabPage_Playerdata->ResumeLayout(false); this->tabPage_Components->ResumeLayout(false); this->tabPage_Plugins->ResumeLayout(false); this->tabPage_Credits->ResumeLayout(false); this->tabPage_Credits->PerformLayout(); this->ResumeLayout(false); } #pragma endregion private: System::Void SaveSettings() { if (*ResolutionConfigChanged) { for (ConfigOptionBase* option : screenResolutionArray) { option->SaveOption(); } for (ConfigOptionBase* option : internalResolutionArray) { option->SaveOption(); } *ResolutionConfigChanged = false; } if (*OptionsConfigChanged) { for (ConfigOptionBase* option : optionsArray) { option->SaveOption(); } for (ConfigOptionBase* option : graphicsArray) { option->SaveOption(); } *OptionsConfigChanged = false; } if (*PlayerdataConfigChanged) { for (ConfigOptionBase* option : playerdataArray) { option->SaveOption(); } *PlayerdataConfigChanged = false; } if (*ComponentsConfigChanged) { for (ConfigOptionBase* component : componentsArray) { component->SaveOption(); } *ComponentsConfigChanged = false; } if (*LagCompensationConfigChanged) { SetIniInt(GRAPHICS_SECTION, L"lag_compensation", trackBar_LagCompensation->Value, CONFIG_FILE); *LagCompensationConfigChanged = false; } for (ConfigOptionBase* option : AllPluginOpts) { if (*(option->hasChanged)) { option->SaveOption(); } *(option->hasChanged) = false; } for (ConfigOptionBase* option : AllCustomOpts) { if (*(option->hasChanged)) { option->SaveOption(); } *(option->hasChanged) = false; } } private: System::Void Button_Help_Click(System::Object^ sender, System::EventArgs^ e) { System::Diagnostics::Process::Start("https://github.com/PDModdingCommunity/PD-Loader/wiki"); } private: System::Boolean hasInvalidGLUT = false; private: System::Void checkHasInvalidGLUT() { HMODULE glutHm = GetModuleHandleW(L"glut32.dll"); hasInvalidGLUT = glutHm != NULL && GetProcAddress(glutHm, "__glutGetFCB") == NULL; if (hasInvalidGLUT) { SkinnedMessageBox::Show(this, "Support for custom versions of \"glut32.dll\" is deprecated and will be removed in future versions of PD Loader.\nPlease restore a valid copy of the original file, then validate your files and make sure \"glut32.dll\" passes.\n\nPlease DO NOT ASK for a copy of the file in our support channels!\nWe cannot provide it to you.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Warning); } } private: System::Boolean launchanyway_divagl_novidia() { return (SkinnedMessageBox::Show( this, "Plugins: Novidia and ShaderPatch should be disabled if DivaGL is enabled.\n\nLaunch anyway?", "PD Launcher", MessageBoxButtons::YesNo, MessageBoxIcon::Error ) == System::Windows::Forms::DialogResult::Yes); } private: System::Boolean invalid_divagl_freeglut() { SkinnedMessageBox::Show( this, "Plugins: DivaGL does not support custom versions of \"glut32.dll\".\nPlease restore a valid copy of the original file, then validate your files and make sure \"glut32.dll\" passes.\n\nPlease DO NOT ASK for a copy of the file in our support channels!\nWe cannot provide it to you.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error ); return true; } private: System::Boolean invalid_divagl_divaimguiold() { SkinnedMessageBox::Show( this, "Plugins: Your version of DivaImGui is too old for DivaGL; please either update or disable it.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error ); return true; } private: System::Boolean hasInvalidSettings() { bool divaGLEnabled = false; bool novidiaEnabled = false; bool shaderPatchEnabled = false; bool divaImGuiOldEnabled = false; for (PluginOption* option : AllPluginOpts) { auto handle = option->mainControlHandle; if (handle == IntPtr::Zero) continue; auto checkbox = dynamic_cast(CheckBox::FromHandle(handle)); if (checkbox == nullptr) continue; if (lstrcmpW(option->_friendlyName, L"DivaGL") == 0) divaGLEnabled = checkbox->Checked; else if (lstrcmpW(option->_friendlyName, L"Novidia") == 0) novidiaEnabled = checkbox->Checked; else if (lstrcmpW(option->_friendlyName, L"ShaderPatch") == 0) shaderPatchEnabled = checkbox->Checked; else if (lstrcmpW(option->_friendlyName, L"DivaImGui") == 0 && option->_builddate == L"Unknown") divaImGuiOldEnabled = checkbox->Checked; } if (divaGLEnabled) { if (hasInvalidGLUT) return invalid_divagl_freeglut(); if (divaImGuiOldEnabled) return invalid_divagl_divaimguiold(); if ((novidiaEnabled || shaderPatchEnabled) && !launchanyway_divagl_novidia()) return true; } return false; } private: System::Boolean warnCheck() { if (((ComboBox^)Control::FromHandle(((DropdownOption*)(graphicsArray[0]))->mainControlHandle))->Text == "SELECT ONE" && SkinnedMessageBox::Show(this, L"GPU detection has failed and no Nvidia GPU architecture has been selected.\nAs such, characters and stages may exhibit artifacts, such as noisy shadows and stages.\nIf unsure, try all of the options starting from Kepler.\n\nLaunch anyway?", "PD Launcher", MessageBoxButtons::YesNo, MessageBoxIcon::Error) != System::Windows::Forms::DialogResult::OK) return false; return true; } private: System::Void Button_Launch_Click(System::Object^ sender, System::EventArgs^ e) { //SkinnedMessageBox::Show(this, "It looks like the executable has been tampered with, or the version of the game is not 7.10.\n\nPlease use the \"patches\" folder instead of modifying the executable directly (or disable verification).", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error); if (!warnCheck()) return; if (hasInvalidSettings()) return; SaveSettings(); if (GetPrivateProfileIntW(LAUNCHER_SECTION, L"use_divahook_bat", FALSE, CONFIG_FILE)) { if (GetPrivateProfileIntW(L"patches", L"quick_start", 1, CONFIG_FILE) > 0) { SkinnedMessageBox::Show(this, L"\"Quick Start\" and \"Use divahook.bat / start.bat\" cannot be enabled at the same time.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error); return; } DIVA_EXECUTABLE = NULL; wstring DIVA_EXECUTABLE_LAUNCH_STRING_cmd = L"cmd.exe /C \""; const wstring DIVA_EXECUTABLE_LAUNCH_STRING_path = DIVA_DIRPATH; wstring DIVAHOOK_BAT_PATH = DIVA_EXECUTABLE_LAUNCH_STRING_path; DIVAHOOK_BAT_PATH.append(L"\\divahook.bat"); if (std::filesystem::exists(DIVAHOOK_BAT_PATH)) { DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(DIVAHOOK_BAT_PATH); DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(L"\""); DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING_cmd.c_str()); } else { wstring START_BAT_PATH = DIVA_EXECUTABLE_LAUNCH_STRING_path; START_BAT_PATH.append(L"\\start.bat"); if (std::filesystem::exists(START_BAT_PATH)) { DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(START_BAT_PATH); DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(L"\""); DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING_cmd.c_str()); } else if (SkinnedMessageBox::Show(this, L"divahook.bat/start.bat not found.\nThe game will start normally/offline.\n\nNOTE: Disable \"Use divahook.bat / start.bat\" to avoid this warning.", "PD Launcher", MessageBoxButtons::OKCancel, MessageBoxIcon::Warning) != System::Windows::Forms::DialogResult::OK) return; } } else { // read the command line here so it'll be up to date even if the user changed it WCHAR stringBuf[256]; GetPrivateProfileStringW(LAUNCHER_SECTION, L"command_line", L"", stringBuf, 256, CONFIG_FILE); DIVA_EXECUTABLE_LAUNCH_STRING += L" " + wstring(stringBuf); DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING.c_str()); } STARTUPINFOW si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); CreateProcessW(DIVA_EXECUTABLE, DIVA_EXECUTABLE_LAUNCH, NULL, NULL, false, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); // this->Close won't work in here since it will prompt the user to save the settings TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); } private: System::Void InternalResEnabledChangedHandler(System::Object^ sender, System::EventArgs^ e) { if (((CheckBox^)CheckBox::FromHandle(InternalResolutionCheckbox->mainControlHandle))->Checked) { ((Control^)Control::FromHandle(InternalResolutionOption->mainControlHandle))->Enabled = true; } else { ((Control^)Control::FromHandle(InternalResolutionOption->mainControlHandle))->Enabled = false; } } private: System::Void DisplayTypeChangedHandler(System::Object^ sender, System::EventArgs^ e) { int idx = ((ComboBox^)ComboBox::FromHandle(DisplayModeDropdown->mainControlHandle))->SelectedIndex; if (idx == 2) // fullscreen { for (ConfigOptionBase* option : screenResolutionArray) { if (option == RefreshRateOption) { ((Control^)Control::FromHandle(option->mainControlHandle))->Enabled = true; } } } else { for (ConfigOptionBase* option : screenResolutionArray) { if (option == RefreshRateOption) { ((Control^)Control::FromHandle(option->mainControlHandle))->Enabled = false; } } } } private: System::Void Ui_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) { if (!AnyConfigChanged()) return; switch (SkinnedMessageBox::Show(this, "Do you want to save your settings?", "PD Launcher", MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question)) { case System::Windows::Forms::DialogResult::Yes: SaveSettings(); break; case System::Windows::Forms::DialogResult::No: break; case System::Windows::Forms::DialogResult::Cancel: e->Cancel = true; break; } } private: System::Void Ui_FormClosed(System::Object^ sender, System::Windows::Forms::FormClosedEventArgs^ e) { // Prevents abnormal termination messages, remember that the game is still technically running and must be killed! TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); } private: System::Void button_Discord_Click(System::Object^ sender, System::EventArgs^ e) { switch (SkinnedMessageBox::Show(this, "Would you like to read the user guide for troubleshooting?", "PD Launcher", MessageBoxButtons::YesNoCancel, MessageBoxIcon::Information)) { case System::Windows::Forms::DialogResult::Yes: System::Diagnostics::Process::Start("https://github.com/PDModdingCommunity/PD-Loader/wiki"); break; case System::Windows::Forms::DialogResult::No: System::Diagnostics::Process::Start("https://discord.gg/cvBVGDZ"); break; } } private: System::Void button_github_Click(System::Object^ sender, System::EventArgs^ e) { System::Diagnostics::Process::Start("https://github.com/PDModdingCommunity/PD-Loader"); } private: System::Void button_Apply_Click(System::Object^ sender, System::EventArgs^ e) { SaveSettings(); updateStyle(); ShowWindow(hWnd, SW_HIDE); ShowWindow(hWnd, SW_SHOW); } private: System::Void Ui_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) { if (e->KeyCode == Keys::Escape) this->Close(); } private: bool* ResolutionConfigChanged = new bool(false); bool* OptionsConfigChanged = new bool(false); bool* PlayerdataConfigChanged = new bool(false); bool* ComponentsConfigChanged = new bool(false); bool* LagCompensationConfigChanged = new bool(false); private: bool AnyConfigChanged() { if (*ResolutionConfigChanged || *OptionsConfigChanged || *PlayerdataConfigChanged || *ComponentsConfigChanged || *LagCompensationConfigChanged) return true; // fast case for (ConfigOptionBase* option : AllPluginOpts) { if (*(option->hasChanged)) return true; // slow case for iterating over individual plugins } return false; } private: String^ GPUIssueText; private: System::Void LinkLabelLinkClickedGPUIssueHandler(System::Object^ sender, System::Windows::Forms::LinkLabelLinkClickedEventArgs^ e) { SkinnedMessageBox::Show(this, GPUIssueText, "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Information); } private: System::Void trackBar_LagCompensation_Scroll(System::Object^ sender, System::EventArgs^ e) { *LagCompensationConfigChanged = true; updateLagCompMsec(); } private: System::Void tabPage_Resolution_Click(System::Object^ sender, System::EventArgs^ e) { } private: System::Void button_Wiki_Click(System::Object^ sender, System::EventArgs^ e) { System::Diagnostics::Process::Start("https://github.com/PDModdingCommunity/PD-Loader/wiki"); } }; } ================================================ FILE: source-code/source/plugins/Launcher/ui.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 PD Loader is intended for educational purposes only; not for piracy. Users should possess a legally-obtained dump of the game to use this software. Please check your local laws/regulations to verify the legality of tampering with and dumping data from protected arcade machine hardware. Project Contributors: ano, Brolijah, crash5b, ona, korenkonder, Kyberal, lybxlpsv, nastys, Nezarn, samyuu, Skyth, somewhatlurker, Stewie1.0, SwigS-27, zsccat PD Loader and the included plugins are distributed under MIT License: Copyright (c) Project DIVA Modding 2nd Community Copyright (c) samyuu (nop) (original TLAC code) Copyright (c) ThirteenAG (original Ultimate ASI Loader code) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Microsoft Detours, utilized by many plugins, is licensed under MIT License: # Copyright (c) Microsoft Corporation All rights reserved. # MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Launcher, Patches, Render and TLAC plugins utilize files from FreeGLUT: Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies or substantial portions of the Software. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of Pawel W. Olszta shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Pawel W. Olszta. Launcher uses SimpleIni, licensed under MIT License: The MIT License (MIT) Copyright (c) 2006-2013 Brodie Thiesfield Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. DivaSound uses miniaudio (public domain or MIT-0) and BASSASIO (free for non-commercial use only) AMD compatibilty pack dependencies have additional licenses, detailed in the AMD iVBORw0KGgoAAAANSUhEUgAAACoAAAApCAYAAABDV7v1AAAABGdBTUEAALGPC/xhBQAAA7hJREFUWEft mEtME0EYgIshUY/GqwcPevbsjYMXb95MPHnTKAUWEVADNQLdFnlUUHkEA4IKmMhD8BEf1IiCUQERIt3t g7ZIodBCS+mDbbu/MyUtLaVAYbYa7CSTbbrT///+50xHJEqOpAeiPXBeMnkgvZg5S0nZIopmS4WYmVKG zqA1YrFEfWRHMaCoqYOUjOnIlrOQiEnJWO1FyeTRuGEzSibECNCfCMigjiwZMywWq/fHBYvC7EgkZEiX jDmxbdC0NGXqX4FEaZYlVZ9MgpL0/v/t0bxyNZQ36qGiSQ/5Fatt7EopCzm3Vz/nlrGgaNZDTasRbt7T bKvNEfdo9SMDDI3boLlrGrrem+HT0AL80i6DweQG44w78Bz+ZYd3AxZo6zXBGLsEfV+scL1SvSkwUdCW bhPMWz0wxtiB4/yw1fD5eFDpsBEuZIwjcaAagxM8K1sDrjfA7+eB53moQtGIVYDEPFpcq93KgVu+ty1x gVzeCJYY6CgK924H5/WDvGFSONBrqBDWhxyH0uH0wtKyF3Bow4fT7QW7wwsYDK8LDvy558OccKCKZgN4 kdJwhaMqOxTX6qCwWgMfvy+E3lltHJQ1TsINhRraXs1G/A4v6kddQrDQ9yrnozwjrVsLYf3T3yHQps7p EIjkrhYW7FyEt3EXEAz0zWdLhDIcQtyqggofPFsDHRxZDH1/674OnC5vxG9XOJ9woP1hocVaMSjOv+6+ OXjyYgZWVnwRaTEwssg3dU3zZos7IhLBRXnl0ZVPpOoHR20hEA+CMpndUQUUqyO4PL5Aw8fNPzgKqqK3 VSKgr/vXctSPvPmTtUPLcxNoDMsxgXGXGPyxCK1oG11a5kKetSxycBWdBdbnKRHQXBQq5dcFsDlWFeJp tnhA8VAPhahgatunoP3lDHS8nYXHPSa402KEfHRwwbntcq+mhdfnB+2UE6paNt6diIAGrS+p00E3OohM oH37GzqY4FPUZmfSyiYDaI1OwAVW02YMtCzBt1CSh2TB2pPQkFg+0dALCbw3QUUiyT50c+Em7TlKzvJI rgM/iRQT/l9NSZkK0qCBHKRV9ehGpDMWbFyhx6Dn8g2H0N3T+GbW78QQSqZqTZMoU7Notm0j2XGDYtgL RZrjSGBBtoxtREKbiUwZ04BlX5ZOHM6kVTVIJhdu8I5Aw65WUkQiIDhDklOyaEYWfhm3W9BtXwfFu/A0 ur1DOZuDiswadx+NVxmJ9elS5gwlZ1z/rEfDjRTTzKlL9PgxEoYnZewZD/wB4r+Nvne+oTwAAAAASUVO RK5CYII= iVBORw0KGgoAAAANSUhEUgAAACoAAAAnCAYAAAB5XdqFAAABgWlDQ1BJQ0MgcHJvZmlsZQAAKM+VkUso RFEcxn9zEXlkYZJkcRfDihKSpYZIUZoZZbBw7x0z1Nw7070jG0tlqyw8Nl4LG2u2FrZKKY+Sja0VsZGu /5mZmkmNcup0fn3nfF/nfAe0w7Rle9W9YDs5NzIe1mfjc3rtC3VotNIAhuVlp6JjMSqOzzsCar3tUVn8 bzQlljwLArrwsJV1c8KLwoNruaziXeGgtWwkhM+Eu125oPCD0s0CvypO5VlTmUE3FhkRDgrrqTI2y9ha dm3hAeFQwnYkX5stcELxumI7vWoV76le2LjkzESVLrODcSaYYhodk1VWSJOjR1ZHFI+I7Icr+Nvz/mlx meJawRLHKBlsjLwf9Qe/u/WS/X2FpMYw1Dz7/nsn1G7D95bvfx35/vcxVD3BpVPyZw5h6EP0rZIWOoDm DTi/KmnmDlxsQttj1nCNvFQlU0sm4e1UvikOLTdQP1/orbjPyT3EpKvJa9jbh66UZC9UeHddeW9/nin2 9wPzU3J08NKhyQAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAAd0SU1FB+MIAhYLMBv7dmMAAAYJSURBVFhH xZh5bGVTHIDb6qpU7dWxDEVQprWLNWhRuxgSKmPoWFOEMCS2igmmsUVim4jaNamREcZWa6h9iTQSLSYm mfGHIDomaahxfF9z3+R6W+/rtOlJvtzXe88953d++21R0fSNHVh6r+lbPvfKxTySJKOKSbfCHVCS5IWp nFPBYtvCRhMs6mF2gzfhESifSiGSrKWATXDcBJuX8fxceBbug+oki0/1nK1Z8Ba4Mo+wW/HsSbgAFsIm Uy1EkvXU1oHwGrRCus/qj8dAH8yBNtg4ycLTMWdLFr0a3gB/x4d+fDfMBzXbmEfz6bJ5aINwH9g7ixIK Pkspb+wLH8I8iEf1FpE21apBVJv2PNtmvu97+v5dcG902MPShS0k7aQ22pwfnfAu1Md235nfb0UHyZfK fOZBdoEOeAEegFNBjSr09bBf/GSarwFOhGPhUDgA9oDNsqmAe2pVsz4DZ0cnd3MXfh9MT9mGrjEbTofH YAAMvLNgVzDwjIOdIlku5Orhx4cv7whHwClwDlwKRrenPAGyBYTmcqEnoBJMX5r8PZiVWjy6al5T2zL4 Br6Eh+FM2B02hbgLudb2cDjoZuufpUxRy83tQJOoMTfuAgVuBjWZGprOw6lBtaEm1MzbEA8y13bTF+Fx MMcqwGwwx+aqXN6vAw/i2lmHi/tQ0+sCF8HrcD8cFC3uQprY6D8PjNjLYTnUxFbVnLdBPxwMWsJDJinH znEtNT7hUIs2GGfAp7AKdHYFtQCYjl6Jft/JVZ9TaIcCtYOmPgkmW6XilswpsCe6DB6CG0BTD4FuoWmu gZ8i4Z+PBNfvUz77dfR+rsDMuXHSB6rdNq0XPoGn4Tt4NRL2R66fwy+wDn6GEXgObF7MAJ+B/q2PJjF1 UtnWz/P08+ELsAMyG+ib+upX8GskXOCazlgk7Edc9VdLqaYTs4fa3uCh4+tLOr5+pVkPATVkCjK69UE1 mE3I1D2fD0YHbOZqg2LO/QCWwclgUBWkZScbLObPd0AT2lSYajS9ATC+YFlZ2dH19fW/lZeX5xPSZ3+B LqJgP4AuYGk0+nUN/fxl6ALztCnIapc3aMx51u0/QVNfC0eCpXH8xerq6qKOjo7avr6+5YODg6Gnpyc0 NDSEkpKS0NTUFBobG0NxcXFc+L8jAXu4XgIGnom7Gax8Zg0rmkF6O6gYrag/q+msw3LlCW8Czf4/LfoG QhQtXbp07tq1a8fWrFkTFi1aFNra2sLixYvDihUrwsDAwPjfTE0xzO+nwL7VEqhLmapEF6oFrWiXpOC2 jObibrgKsn5F7MmDR8H6bl7MmFRTU1OENueNjo6uY4TVq1eH7u7usHLlyjA2NhaWLFkSFixYEKqqqhT0 d7AIWKG+B0tntqE7aTEPYTW0GbHX0KIGYMbYnzv3gPU5q3Or0fb29jkIu2poaCig3dDa2hqGh4eDY2Rk JPT29oaKiorRSCu2a/qenyIWgSTfWWYDg7UFzDIZ76h6GxAb3XxjFsH0cV1dXSgtLR33yc7OztDf3x84 QGhpafmHl18Cg7AL7Bfs8E1RaivJ0C3UplbIEPQobpqG0rv19IXNrZZLBVrvj5WVlQaVgbg00obV6wpw U3uBm0F/TVo+DSbjJCMDGJFG5kQlziZFHzIzKOy/8AeY2K8DO3IFM8UZlGrE8muE2yNY85PkTXsIfTbj M7uZmzbNqUaCnzmHif80uBG64GI4HtSAQeFBvgXNp1Buao50vpmlNt/isWcKmdHaWYdNExM5vOs4R2EV xLyo87u59zWVKU6NbhPb1AMcDTY11v9JD9UcXzjJQgomcVMq0INgEo9bxznmarv585MsnmuOzpuzgy5g 4QbmGjTNkN61G1hq06Ymw/eS7jHpF2MbKNhcWAjZSqBa9btMf04a/UnlL2iem5vkTXW5rGNWsVWcsf+c eCKDy6KRs7rxzMpj0M6YoJrdftPcqS/mGprfT5d8cwoyY6GTLb3+V8PIniihmynSA63Q/SY9367Ljn3G TJpEcpO8JdjSOWOaSiKotdz8mOgfBEkWnK45tSzst85EvrnB+/8H9IFAujdzCzQAAAAASUVORK5CYII= 17, 17 iVBORw0KGgoAAAANSUhEUgAAAikAAAIrCAYAAAAqWwkVAAABgWlDQ1BJQ0MgcHJvZmlsZQAAKM+VkUso RFEcxn8uIo0sjDyyuAusTAnJUkOkqGmMMli4944Zau413TuysVS2ysJj47WwsWZrYauU8ijZ2VkRG+n6 n5mpmdQop07n13fO93XOd0A7TFu2V9UDtpN1o2NhfSY+q9e8oNFKE800G5aXmZwajVF2fN5RodbbkMri f6M+sehZUKELD1kZNyu8IDywls0o3hUOWktGQvhMuNuVCwo/KN3M86viVI41lRl0Y9Fh4aCwniphs4St JdcW7hfuSNiO5GszeU4oXldsp1etwj3VCwOLzvSU0mW2M8Y4k0TQMVllmTRZQrI6onhEZT9cxt+W80fE ZYprGUscI6xgY+T8qD/43a2X7OvNJwXCUP3s+++dULMN31u+/3Xk+9/HUPkEl07Rv3IIgx+ibxW1jgNo 2IDzq6Jm7sDFJrQ8ZgzXyEmVMrVkEt5O5Zvi0HgDdXP53gr7nNxDTLqauIa9fehKSfZ8mXfXlvb255lC fz93xXKpDPMGbQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+UCGRUXHaHk4jAAAEcySURBVHhe 7Z3vz2XXddct8Q/MC14ghOEFvAAJCfGCViABL1CFLKqiItWVkJAAVQipiFd2RYWgAygSwq6nbUjj0E4z LmoDFlarUbFo62baOh7/mPGPmdhOHDlKMk3Gjh0nntjzw3bsy7Nmeh7fuc+99+xzzlp7r7XXZ6QrN33O 3Weftb5rrc9de59z7litVnfwwQZoAA1YaeDGlWvH5PMnT371729+5P9vdV7GRdNoIL4GABQgDQ2gAVUN CHicOX76hHx+/s57V6UfOV4gBnCJX1iAA3yopQHV5KQ1KcZB4GgglgYGMCkFkrHjBmBBB7F0gL/wl7YG gBR+RaMBNDBbA9pwsg1epLuinfgYj2KKBmJoYHZywsExHIyf8JOFBmrAySawACto2ULLjOlbV0AKv6LR ABqYpAGBhbHlGqu/s2fFd0Gh4OMfbQ1MSk7aJ2c8BI0GYmmgJaCsgw9dlVi6Ic7x11wNACn8ikYDaKBI A1Pv1rHqpgArFLy5BY/vxdNOUXLCsfEci8/wmaYGPALKACvcCYTWNbXOWL70BKTwKxoNoIG9GvAMKHRV fBUUCjz+0NYABYoChQbQwE4NRAEUYIXiqF0cGc+HpihQFCg0gAa2asDLJtk5e1tYAvJRYCj0+GGpBihQ FCg0gAaOaCAyoNBVoTAuLYx834+GKFAUKDSABm7TQC+AAqz4KTQUfXwxVwMUKAoUGkADhxroEVCAFQrk 3ALJ99prhwJFgUIDaOCmBnoHlAFWeBBc+8JD8ccHpRqgQFGg0AAaSAModFUojqXFkeN8aIUCRYFCA8k1 kKWDsusuITorPooRUIAftmmAApW8QJEYcieG7IDCElBu/ZP//PsfSAFS0EBSDQAo9642uyt0VfwXLcAi l48oUEkLFIGeK9A3/Q2gHAUU9qvkjglyok//AylAChpIpgEAZT+gsATks1gBETn9QoFKVqAI9JyBPvgd QCkDFLoqueOEPOnH/0AKkIIGkmjgxpVrx+a8B4fv3AIb9qv4KVxARB5fUKCSFCiCOk9Qb/M1gDK9g7IN zgCV3HFEHq3vfyAFSEEDnWsAQNEBFJaA6hcooACbU6A6L1AEee4gB1D0AQVYyR1T5NS6/gdSgBQ00KkG ABRbQFm/C0hsTfGqW7ywdw57U6A6LVAEcI4A3udnNrzWgRRuWSbWyLd2GgBSgBQ00KEGzhw/fQJIqQsp wIpdoQIC8tqWAtVhgSKg8wa0+B5AaQMnm3tVWALKHYfkYR3/AylAChroSAMASntAYWOtTnGiyGNH0QAF qqMCRVDnDmoAxRegACu545F8rON/IAVIQQMdaABA8QsoA6yIj3gYnE7hAgDy2JEC1UGBImDzBOw2XwMo /gGFrkruGCVHz/c/kAKkoIHAGuCFgbEABViZX6wo9DltR4EKXKAI2pxByxuN44LJ5m3hLAHljmFy+Lj/ gRQgBQ0E1AAdlH5AhTcsjxcqinleG1GgAhYoAjZvwIrvAZS+AIUloNzxTD7f738gBUhBA4E0AKD0CyjA CrACsBzVAAUqUIFCwLmTGICSA1B4vH7uOCfP3+5/IAVIQQMBNACg5AIUuiqACrBySwMUqAAFCrHmTlgA Sl5AAVZyxz65H0gB0oA01xoAUAAUQAVQyQwrrhN0Zsdw7SQmAAVA2XyuCvtVyAvZagOQQicBDTjUAIAC oOwCFDorgEomUKFAOSxQmQTItR5NuAAKgFICKHRVgJUM+RNIAVLQgCMN3Lhy7diUAsWxAA2wAqz0DCsU KEcFqmehcW3jiRRAATg0oFM6ccTbeLxhoxg2AlKAFDTgQAMACoCiASh0VWIUXgCp3E8UKAcFCsGWC7ZH WwEoAIomoLCxNnc+6S1HAilAChpoqAEABUCxAhRgBVjpAVgoUA0LVA8C4hqWJcIaBYpzAEKiAdmrIlBM zC6LWexX135ACpCCBhpp4Mzx0ycACACitgbYWFu3yAI1y+xNgWpUoBDuMuFGtx+AApzUhpPN8wEruXNQ lBwKpAApaKCyBgAUAKU1oKzfBcQSELDiGVgoUJULlGcxMDf7ZAWgACheAIWNtfbxTk5dbmMgBUhBA5U0 AKAAKB4BBVhZXkiBETsbUqAqFShEbCfiCLblfTwAindAGeYnMM1+ldz5ylNOBVKAFDRgrAEABUCJAih0 VYATT4Aic6FAGRcobw5nPnWTEIACoEQEFGClbp4gL++2N5ACpKABIw0AKABKdEBhCQhYaQ1QFCijAtXa sZy/bXIBUACUXgCFrkrbXJI9lwMpQAoaUNYAgAKg9AgowAqw0gKYKFDKBaqFEzmnn+QBoAAovQMKsOIn 32TI/UAKkIIGlDQAoAAomQBl/am1GYol19gGzihQSgUKAbcRsBe7AygASkZAoauSO+/VyL9ACpCCBhZq AEABULIDCrACrFgBCwVqYYGycgzjxgh6AAVAAVCOaoAn1sbIXxHqDJACpKCBmRoAUAAUAGW/BoAVYGUp CFGgZhaopYbn+7GDV15vT4ECUtBAmQaAldj5rmW9AlKAFDQwUQMASllhooBjJ/aqACdLAYcCNbFALTU4 348dtAAKhRf4WqYBuiqxc2DtGgakAClooFADAMqy4kRxx350VgCUqZBDgSosUFMNy/F9BSOAQoEFsvQ1 QFelrzxpUfeAFCAFDRRogAKlX6CwKTblqbVAyhjYUKAKCtSYEfl734F25vjpExRUCioasNcAnZW+c+mc WgmkACloYI8GABT7wkTxx8abe1VkeXVOQeM7/UEOBQpIQQM7NACgUDwBqHYaoKvSH3DMgUgKFJCCBrZo AEBpV5wAA2zPXUAAygA0FCggBQ1saABAoUgCSr40IF0VloByggsFCkhBA2sa4H08vooTsIA/6KrkhBM6 KcAJcLKhAQCFgggUxdAA+1XygAuFClhBAwcaAFBiFCcgAj8NGpBlWWClf1ihQAEp6TUAoFD4gJ+4GgBU +gaV9AVqzi1RfKefoABQ4hYnwALfsV+ln1y8q64CKXRS0moAQPFd5B6++8FV6Qdg8e3LWv5hCag/aElb oOiG9CfmKT4FUNoWtQE+zj7we6tLZ189/Bz4cPG/YTwZWz5yrlpFkvO01RXvAuovrwMpdFLSaQBAqVtI BBIGGFlMIAsHEIAZ4AWgqKuDFvZmv0p8aElXoKb82ubY+ALf9CGAYl+YBEqGbsZCpqjydaDFXhMtAIX9 Kn3kbyCFTkoaDQAoNsVoWLoRMIn+b+i0tC6qnF9fq3RVYkJLmgJFVySmQLX8BqDoJ/2hYxIdTHbNH2DR 14wH+AJWYtUCIIVOSvcaAFD0ik3vYAKw6GnFA5DsmwOwEgNWui9QWr/EGSeGoDf9JC8l854sI8wvK5xs gxb2sPQDMoCK/7wOpNBJ6VYDAMryYgKc7F7MYjloub68ADqw4hdWui1QdD78iq6GbwCUZQUEOJm200a6 K14KLvOYr31gxV/dAFLopHSnAQBlfpIGTqbByebRwMp87XmBK0DFF6h0V6Bq/ErnHL5EvO4PAGVekQBO lsEJsDJPd17AZNs8gBUfeR5IoZPSjQYAlHmFQn7988/GAnRW5mnSE7wAK21hpZsCRXejrZA82F9eLuYp uXmfC90TGzDZdUeQdz0wv91ABai0qy9ACp2ULjQAoEz7xUr3pB6grJ+Jzso0nXoDJ2ClPqx0UaA8/Ipn DvXFO9gcQClP/HRP2sAJoFKuUW9gwn6VdrldcjyQQicltAYAlPLkT/ekPaAAK+V69Q4r0lWRfXD8QLWF mNAFCnHYisO7fQGU8oTfw8v/fCGG3mxYAirXsUdwYQnItg4BKXRSQmoAQClL7LK8wz//FgBUyvTsEVKG OQErNrASskB5/4XP/GzEOtiVFwaWJXSWd/zDCc9XKdOyZzhZnxtLQPq5H0ihkxJKAwBKWVIHUOIByjBj uiplGvcMLnRV9GAlVIGiQ6Hn+Ii2BFDKkjeAEhdQ2FhbpnHPgLLZWYmYaz3NGUihkxJCAwBKWfJmg2wf gEJXpUzvEWBF9s/RWZn/AztEgfJEdcxlvtjm2g5AKUvYAEpfgDJcjfg1QjFmjvvjFFCZVzuAFDoprjUA oAAofaLH9Ktir0pZLHiHJWBlGqy4LlBzf3nzvWki8GovAKUsKdNBmV7wo34DUCmLCe+gwhJQeY0CUuik uNQAgFKWjAGUqLgxf96ASllseAcVmR9dlXFYcVmgvP6yZ17jgtKwEYBSloQBlPmFPvo32adSFiMRQAVY 2V9XgBQ6Ka40AKCUJV9uM46OGTrzlycKRynEzHM8tumsHAUWVwVK41c4Y9TpdljYGUAZT2KS6AEUnQLf yygs/5TFTRRIAlRur2FACp0UFxoAUMoSLYDSC1roXgegUhY/UUCFJaCPQcVFgbL4Vc6YcToq8rrzSMmj 1VwBFN3C3ttogEp/oAKsrO4AUuikNNUAgFKeWHsrqlyPvgUAlfJ4avVjY855My8BNS1QdDvidDssfAWg lCdU7uTRL+i9jgiolMfVHGBo+Z2MsAKk0ElpogEApTyRsszTK07YXRegUh5fLaFj7rkzwUqTAmXxq5wx 43RlAJTyBAqg2BXy3kcGVMrjbC4stPxeFlABUuikVNdAy8COdu7eCynXZ2sBQKVvUMmwsbZ6gaLjEafj YeEreWdFNFBoNd/MXRTZgyMfsYE8sGz47PLF8Hc5fviwj+cWAAEq/YNKz7ACpNBJqaYBAKU8WWYDFAGK MRCZC4sy7gAutn0Lv6PzZNry2JurMw/f63EJqFqBsvhVzphxujIAyrQkmaELMIBJ7eQ+QItfpLCZGaAy LQZr61LzfD3BCpBCJ8VcAwDK9ORoU6baj9oKTPYtE2XpWvFSwulxqAkOLcbqAVbMCxTdjjjdDgtfASjT E6P84u3tnzc42VYwMiwJASrT47EFXGieU0BF7qi0yO81xgRS6KSYaYD38cxLiD1BSgQ42SwIvS8HsZF2 XlxqgkOLsaJ2VcwKVA3C4hx+uzQAyvxE2AOkRISTXd2V3rpacj3sT5kfny0AQ/Oc0WAFSKGToq4BAGV5 AoxcGHv8pd7jvhVAZXmcasJDzbEiLQGpFyi6G367GzV8A6DoJL6Id/f00j3ZVSx627PC/hSdWK0JF9rn itBVAVLopKhpAEDRS3rRlnx67J7sg5XIna71uWfym3aB72k8z7CiVqBq/ErnHH67NACKHqAMyS9CN6X3 7sm+QtTLEhDLPvqxGxFg5E5Mj7ACpNBJWawBAMUuyXn+xc6v8HtvPsk2+j+WfeziNyKseAOVxQWK7obf 7kYN3wAotglOfuV67KgAKLf7PTqs4E/bOAZW5tdJIIVOymwNACj1EpunIsjywHa/e/LRnO4Ofq0Xz1Gg xcMS0OwCVeNXOueYT5/WtgNQ2iS01oWQQjbud4+drxJoYdln3LdR4EJ7ni2XgIAUOimTNQCgtE1mLUAl 8wbZOQm/hY9KQGTsGJZ92sb2HK3V/E4LWJlcoKx/oTO+3+6J+AZA8ZPEahVCfmHP83kt/4yBx9S/0y2b 5++asND6XDVhBUihk1KsAXlJVevg4PxHE6hlMQRQlhWsaM+7EaDB58t8niVH1QKV4gJFh8N3h8PaPwCK 78RlASoUKx2fRwQVuik6vs8ALNawAqTQSRnVAIASJ2FpwkqGBFvzGiNtqAVQ48R8TQ3vO5cVrIwWKOtf 6Izvu0MDoMRMVkthhV/SNn6PBCpowEYDXqDCYh4WoAKk0EnZqQEAJXaSmgMq3MVj7/MooEI3xV4LFqDg YUxNWAFSgJSdGvAgduawPFGWwgq3ny63daleo4AK3ZR6mijVTqTjNGAFSAFStmpAnjQYKRiY63gyFQiR jxTI4SP/m0I0bjttfUXZTEs3pb42tLXWeryloAKkAClHNACgkJhaJ7YM548CKkAs+UAjHufCCpACpNym AQCFhKSRkBijTEelS3FTH8imeTzdlDJfovkyO02FFSAFSDnUAIBSFmQkI+ykqYEIoEI3Bc1ran4KqAAp QMpNDQAoJCHNJMRY0/TkfSMt3ZRp/kT/4/YqBRUgBUjhfTx3jgcUSQcbWWtAc4nGYizr62f8fDEmP47H npUGpCSHFF4YmC8xUAx8+tz7RlqWfHzqJno8j4EKkJIYUgAUkk70BNfb/D0v+7DkQ76wird9Sz9ASlJI AVBIOFYJh3GXactiqUZrTLopy3xLbOy23y5QAVISQgqAQqIhWfrVgOdlHyDFr256iGl5FcvmHhUgJRmk ACgkmR6SWe/X4HXZhyUf8odl7G3bnwKkJIIUAIUEY5lgGFtPX3RT9GyJLmPZcnPZB0hJAikASqxAJbHi L6/dFJZ80KZ1flpf8gFSEkAKgEJSsU4qjK+vMa/dFJZ89H1N/Nxu0/VuCpDSOaQAKCQUEmBcDXjtpqCp uJqK4Lv1vSlASseQAqCQSCIkJOa4W6deuyks+ZBbrON2uNMHSOkUUgAUkoh1EmH8Ohrz2E1hyaeO7zPH 2NBNAVI6hBQh0Mzi5tpJoD1pwGM3BUghxmrEmGygBVI6gxQAheRRI3lwjro689hNQQN1NZDR3lLPgJSO IAVAIWlkTGQZrtljN4V9KeQb69gDUgCUlbXIGJ9EhgaWawBIWW5DdBjPhrIvhU5KB6BCByVe8JEw8dlU DXhb8mFfChqequGpxwMpAAqdlDtJNFMTB8e30Yy3bgqQ0kYHmeIPSOkAUsSJmUTLtZIYs2rAG6Qc3HnB jxx+5JhrgOWewKACoFCwsxbsrNctYODpX1Y/cN31ci+QEhRSAJR6QUJCwtZeNOBtXwp3+BAb1rEBpASE FACFxGCdGBjfp8bOPvB7nhopKyDFp056iV/2pAAo5uuJvQQL10Ey9qABb/tSBJo82IU59BmfQEowSKGD 0mcgkmDxa6kGgBS0UqqVHo6Td9Cx3BMEVHhhIMmph6TDNSzTMZCyzH7oL5b9gBQAhVYttxCigWAa8LQp hWelxCr60SCNx+IHgBQ6KCSBaImF+dpqFkixtS/69WNf3oLsHFIAFD/BQuLCF140AKSgRS9atJyH7MEE UhxDCoBCIrJMAIwdV19ASlzfEXflvpMaCKQ4hRQApVzIBD22yqYBIAXNZ9C8AAqQ4hBSABQSUIYExDXO 1zmQMt926C6G7YYuCpDiDFIAlBgBRKLDTy01AKSgv5b6q3HuoYsCpDiCFACFxFMj+DlHbJ15e04KtyDH 1pPHfLDeRQFSnEAKgEKge0wWzMmfLr29uwdI8aeR6HG73kUBUhxACoBCkEdPKsy/noaBlHq2Rtf1bb3Z RQFSGkMKgFI/CEg82DyyBqRz4ekfLxgknrTiaRugACkNIUUe96vlXMYhUaCBHBrwBCgyFyAlh+5q5JfN ZR5uQQZQeGdLsHe21EgUnMNv0fG2aRZI8auVaHEsP9qBlIZQsm58OigEdrQEwnx9aNbbfhQgxYcuosfn PkBhuacyuAAoBHX0hML822nY21KPzEe6O2iinSai237XPhSek1IZTsTgAAqBHD2hMP92Gva41COQgiba aSK67f/g/tOP71riAVIaQEp0QTF/khEaaKcBj0s9QEo7PUSPxf9zz6nVpUuXTgApDWBkm9HlldPRRcX8 SUhooJ0GPC718CC3dnqIHIsCKOfPnwdSSgitxjEACoEcOaEw9/b69dpF4fbj9tqIFp8DoAApdFBYK+b2 YjTQiQY8dlG4swdAmQpI64ACpDiAFDooBPHUIOZ4NLOpAa9dFO7sQatT8tUmoAApjSEFQCGApwQwx6KX XRrw2kVh0yyaLc1b2wAFSGkIKbyPh+AtDV6OQyv7NOC5i8KmWbRbkr92AQqQ0ghSABQCtyRwOQadlGjA cxeFTbNoeEzD+wAFSGkAKQAKQTsWtPwdjZRqwHMXhf0o6HhMx2OAAqRUhhQAhaAdC1r+jkZKNeAdUNiP gpb3abkEUICUipACoBCwpcWH49BKiQY8L/Nw6zEa3qfhk3fdd/NBbSUfnjhbAVQAFAK2pOhwDDop1YBs SPX+j/0o6HmbnqcACp0UAIUHeXXyIK/S4sZx8QtHhGUelnri68wiV0wFFCDFGFLooBCoFoHOmHl1FQVQ 6KLk1eiu/DQHUIAUQ0gBUAhSYAINaGrg4bsf9L7Cczg/IAXtr2t/LqAAKUaQAqAQoJrFibHQUyRAYakH vWoBCpBiACkACgEKVKABTQ1EAxS6KOh/Xf8ld/DsO4a7exRBBUAhODWLE2Ohp2iAQhcFza7nrcdOPVp0 mzGQoggiB0F4x7bPjSvXjlFUCFA0gAa0NBARUOiioP9B/xqAwnKPErwAKASmVmFiHLQkGohyF8/mTl70 i35FA1qAAqQoQAqAQlCSmNGApgaiAgpdFOJAG1CAlIWQAqAQlJrFibFy60mWdyI8SXbXfdDoN7d+LQAF SFkAKQAKAUlSRgNaGojaPRmAhS4KsVD6wsCpd/twd89MUNFKToxDcKOBvBqIuDl2WycFDefVsPjeClDo pMwElDPHT58gKHMHJf7H/0s0EH1pZx1U6KLkjgVLQAFSZkAKgJI7IJcUJr6bWzsCJtGXdeii5NbwZg6z BhQgZSKkACgEKKCBBqZqoKeuySak0EXJGw81AAVImQApAEreYJxalDgerQxgEvlunbG3Gcq1ofWcWq8F KEBKIaQAKDkDkQSM36doIAOYsBeFmKgJKEBKAaTwPh6Cckqh4thceskGJtxynEvfLfagbN6izC3Ie0AF QMkdkAAH/t/UgEBJz3tMxpZ4hr8TG/lio3YHZYAVIGUHpAAo+YKQxIvPt2kga7dkF7CwWTZfnLQCFJZ7 ABQ2vh08iAg4wQaDBtY7JT1vei3tmHA3D7HRElCAlC2QQgeFoARa8mgAKCnHFe7myRMXQw5sDShAygak ACj5ghAgyeNzgKQcSLYdKfYjXvLEy8m77ltNfc+OxfHsSflTUAFQ8gQfiTaHr9lLsgxKuN04R5xsy4de AIVOCoDCLyP2pHShAbokekDCPpS8cCLA4glQgJQDSKGDkjsg6arE9D+3AttBCR2UmDGhkcu8AUp6SAFQ 8gajRkAzRj39ACV1oGT9LGyUradvD7nEI6CkhhQAJVcAekgCzGGa5thTUh9MhjMCKNO02kNsW2x61Rgz 5cZZACVfAPaQRHq/BoESeVAYzydpByfDmbmTJ1eOfOzUoy7u5NkGNekg5caVa8d6T/ZcX64EE9nfPGK+ PZBszgBAyZU/PANKuuUeACVX8EUu3j3PHTDxByZ0UHLmRu+AkgpSAJScQdhzsY90bYCJXzCRmckSGx2U XDkyAqCkgRQAJVfwRSrevc8VOPENJwOg9K5Dru/2GhAFUFJACoACoJCg6mtANsDyz78FeKNx/dhonY8i AUr3kAKg5AvA1gkg+/mBE/9gMswQQMmXHz28MHDqbclP/c7jX5dafqDbO/Z99v5x7Mut/p69YHD9+ZJQ K58DJ3HgRGbK/pN8uSEioAjQSOdH8toYqISDlDPHT59olbA5b74EkNXn7DmJBSc8pC1nbooKKOuQIjm2 m04KgJIzELOCQovrBk5iwYnMluWdnHkxMqBsQorU9l2gEqaTAqDkDMQWhTrrOVnaiQUo3F6cNydGB5RN SJGcK0+M3wYqISAFQMkbjFmBoeZ10z2JBSfsPcmdD3sAlG2Qsmt/intIAVByB2TNYp3xXHRPYgEKSzu5 82EvgLILUrbtT3ENKbwwMHdAZoSGWtdM9yQWnLC0Qy7sCVD2Qcrmso9bSAFQCMpaBTvbeeiexAEU4IQ8 KPmpN0DZBymbyz4uIQVAITCzgUOt6wVQYgAKcEIOHHJCj4AyBinrd/u4gxQAheCsVbCznUcKH/98WwA4 If+t56VeAWUMUtb3priCFACFAM0GDrWuF0ABTmppjfPo5PGeAaUEUoYn0bqBFABFR9gkCOy4qQEAxSeg 0DUhVnfl65N33bea+i6caMcPj8XfZYNhyccFpAAoBCtwpa8B7uDxByeAib7Oe8sdGQBFgOqRex+6+e6e fR95uFtzSAFQCNoxofL3eRqhg9IeUsQHgMk8/WaM+yyAIpAi1zrmY1nyaQopAArBOyZS/j5PIwBKG0BZ hxLeSDxPu1ljPhOglHRRRAfCCM0gBUAhgLMmI+vrBlDqAQpQQh7TiGcAZbuOZF9KE0gBUAhsjcBmjKM6 4jkotoAClJC7LPJOtE2vc+db2kEZbNwEUgAUgtwiyBnz3hWAogsoAAm5qkZekbtc5hb9SN+bCihi++qQ Iptgajidc5BcsmkAQFkGKAAJOaNFzgBQxnVXbbkHQBl3Rosg4Zx9+GVZic71bYCkD81Hz10ASpkOq0AK gFLmjOhBx/zb+JmNsvshS+wjnSbutmmjT/LCUbsDKOVaNIcUAKXcGQQztpqqAZZ5jgLK8FwSoIR4mhpP NY4HUMp1ab4nBUApd0aN4OAcffkDQLkFKEBJX7ruOU/1/j6eYSPvnE2y2/xuDik9i41rIzG21kCunSQf Xy1PcSX2WsfenPNnAZSxd/JMsZ3pw9yEgKZMhmNJPGigXAPZuiiASbk2iCN/tgJQ5vnEDFIAlHkOIblg txINZAEUwIR4KIkH78cAKPN1bPLuHgBlvkO8Bxvz8+Hb3u/m4YV8PnRGvC/3A4CyzIbqb0EGUJY5hKSA /cY00GsXBTBB+2Paj/Z3AGWZpmWpRxVSAJRlDokWgMy3jb972ywLnLTREfFra/csgCJ388jLES30pAop vI/HVvAWAmDMeD7rqYsCnMTTHzmjzGcASpmdxvQkXRSVTgqAouOQMYfxd+zcQxcFOEHHPecyAEVH30MX ZTGkACg6Duk5aLk2HY1E76IAJzo6IJ782hFA0fPN0EVZBCkAip5DSDzYcp8GogOKzB+No/GeNQCg6Ol7 vYsyG1IAFD2H9By4XJuOTiJDCu/P0dEAseTXjpkARetx9/v0vN5FmQUpAIrfYCGR9eebqIAiyzvosT89 4tPbfSp3tgzvq+n9vzUAZbOLMhlSABSSDkmqrgYibpZleaeuRojJNvYGUHTtvg1QJkEKgKLrEBIL9hzT QMQuCoCCrsd03cPfARRdnctz1jaXeSbdggyg6DqkhyDlGuw1Ea2LAqDYa4K4a29jAEXXB/sApaiTAqDo OoQkgz1LNBCtiwKgoOsSXUc/BkDR1fkYoIxCCoCi65DoAcr86+kh0ksEAZR6uiAG29kaQNG3vbzleNcy z+hyj3yZgNB3CjbFpiUaiLLUA6Cg5xI993DMY6ceTXEnT427eEQPJYCyt5PSg6i4BhJoVA1EgZSo9mXe 5IYpGgBQdPVSCig7IYVlHl2HTAkGjsX2ooEI/3hQG1rNkK+yAIpcZw1/TgGUrZACoJB4agiVc+zXmXdI YZmHPJEhhgEUXZ1PBZStkJJBeFyjrvCwp749PW+cBVD0/U0M+bMpgKLrkzmAcgRS6KLoOoXEgz3nasAz pMy9Jr5HPETRAICiq9VdT5Mdu7PnCKREERDz1BUQ9vRnT9nv4fEfXRR/WiF+dX2S6YWBNbSzBFBugxS6 KLpCr+F8ztG3z7x1UwCUvvVGPrl3lQlQ5Lkv1j5fCii3QYo8+c16woxPkkMD5Rrw1k3Bd+W+w1bxbAWg 6PpMA1Bug5T1oLr/4BbIn7/znh2Udc/q1t/5YAM0YK0BL4/Hp4uC1q213nJ8AEVX31qAcggpLPXoOqhl sHHu/nzpAVTQVX+6wqe3fAqg6GpbE1CAFLpBdMSCaKAlqNBF0U3iwIEfe2YClBqPu9cGlENIIWj8BA2+ wBf7NFAbVgAU9NhrTgJQdLVtAShASpBf0b0mCa5rXpIQcKh15w+Pvp/nI7Tt224Aiq5/rADlJqTwtmNd Z5GcsGctDVh3VeiioOVaWq55HgBFV9eWgPIxpPyFhZNe+n06GuwNQQOzNWAFKzULB+damIOJn6L4AVB0 dWYNKHRSCOyiwKaA6Aa2hT21l4Doovj3uYWOeh4TQNHVdA1AAVKAFCClMw1odFUAFN1k3nPhj3JtAIqu puXhryXv3dE4hj0pnRWpKEmDeeomjU17zoUVAMXWL+i+vn3l8e/nz59P8alxm3FNQKGTAqDQSelYAwIc pbAidwtxJ0/9Agq02NocQNG1b21AAVI6LlAkP93gjGzPfbACnKCTyNreN3cARVfbLQCF56QAKXRS0AAa QAPdaSAToDx26lFz/7UCFCCF5GQu7l5/pXFdur/SsCf21NIAgKKvJY0NsHPHuEO++Jkf+sQlLYEwjr5A sCk2RQNoAA2UaSDLJtkaHRTRnDzwdS5gaHzvJqT89k899FsEQFkAYCfshAbQABrwqQEp3BkgJQugHC73 ACk+A45EiF/QABpAA2UayAIoAmE1NNG6gzJ0YW52Un7/Zx/5dI2L5hxlwYadsBMaQANooFwDmQBF9txY a8MLoBx2UoCU8mCwFgfj4ws0gAbQQLkGAJRyW5XoyhOgACnc3WNO5CVBwTG6SQZ7Ys8sGgBQdLVe6308 UzbUstwDqAAqaAANoIFwGsj0Pp4aSzweAYVOCokpXGLy+gtRHikvT2+Vz+a/4YmvXufOvHR/jWJPe3tm ApQa7+PxCihACpACpCzUwAAnR8hky/9DYIX349gXMCChbxsDKLr+9QwoQMrCAkUy1A2WaPYsfXnfts5K tGtlvrm17sX/AIquDr0DCpACpNBJmamBuYCyDiwyhpfkzzx0kz/21LcngKJr0wiAAqTMLFAkIN1giWZP DUAZYEX2sAArufUUTf8t5gug6MZIFEABUoAUfsnP0EDJ/pOpxwAqukm4RSHlnDY+BFB07RoJUICUGQWK RKQbMNHsqdlF2QYywEpufUWLB+v5Aii68RANUIAUIIVOykQNTO2QzDmeJSDdxGxdSBnfxl8Aiq5dIwIK kDKxQJGMdIMmmj2tuyjcBZRbX9HiwXK+AIpuLEQFFCAFSKGTUqiB2oDCXUC6SdqyoDK2rq8AFF17RgYU IKWwQJGEdIMmoj1bQsoALOxXQYcRY2fKnDMBirx3aIpt5hx75vjpE1Pek+PxWN7dA6iYB8qc4PL0HQ+A AqgAKJ5iwmIu8n6a8+fPp/gAKKub7FHyAVKAFCBlRANzNr9af4euCtBiAQqtxgRQdPXcQwdlABgVSPnc j3+KB1IBO13CjqcuCrcs6ybyVgWZ897uRwBFV9c9AYranhSBFNrRukIjkfmwp3VHRGN8uio+tELMTvdD JkCRpSxrjfQGKCaQIkmXpDk9WK3Fy/jTfeK9i8IdQNN9Shz4sVk2QJHrtdRfj4BiBil0VfwkAsug6H1s jS5HzTEevvtB0yTYu7+5vnp5C0DRt3XJJtSIx6jtSdmXjOms6AuShGpr00hdlCH25Em16MJWF9hXx75Z 7uKR67TuoIgmb1y5diwigJTMuQqksASkE9gkyDp2jAgoA6jQTamjEWJxvp3l9tsskAKglN1mvA9WqkEK S0Dzg5qEWNd2kSGFbkpdrRCb0+ydCVAeufch885mzx0U9VuQp669swQ0LbhJhnXsFRlQJAaBlDo6IR6n 2xlAmW6zfTrLACjmG2fHwAVQ0RUtiXO5Pcc0G+Hv6GC5DrChrg0BFF17ZgGU5pDCEpCucEmsy+wZvYsy xBM6WKYD7KdrPwBF157RXxhYsll2/Zjqe1K4C0hXsCRUPXtG6JKUzBFN6GkCWy6zZaYXBtbYg5INUNx0 UjYfSsUdCssSA4l1uv166aJILOH/6f7HZvo2A1B0bZoRUFxCCktAusIm+ZbZs6RDEeEYNs6W+Zu4sLUT gKJr36yA4hpSgBVdkZOUd9uzpy4Km9GJm9axDqDoajAzoISAlOFBcCwB6Qq/dSLzdP4IHZLSOXqyK3PJ F7MAiq7PswNKGEihq6IrfIrHx/aki4K2iAcdDWQCFLljyVo3AMqtp9W6urun9NciLW2dpGIdZBHG7wlS ItibOfYZuwCKrl8BlI8fpx8SUoYnawIruoGRsYDIRtMe/hELxEKr+AVQdLUHoNz+vp+wkMISkG5gtEpw rc/bC6S0tiPnzxmPAIqu3wGUoy8kDA8pwIpukGQrNj1ACl0UYqBF3AIouroDULa/MbkbSGEJSDdgWiS9 FueMDik8FwXdt4ibTIBy/vz51cm77jPdKAugbAeUsBtnx/YQ8MuSxF2auOXW9sj/0DpaL9W61nEAiq7m zhw/fUKKMZ8EnZTNYkMC1w0mrSTnaZzIkIK+0XftWJKOgnQWsnysOygAyjicdbXcs+sXMcmcZL4vmUdd 8qldoDhf7jgCUHT9D6CMA0q3yz3bYAVQ0Q2wngpWxG4KekbPNWMQQNHVG4BSBiipIIW7gHSDrGaCrHGu aA91q2ETzkHMiAayAcoj9z5kukkWQCkHlJSQAqyQeHcV3yigQhcFDdcCSABFX2tskAVSim/WINnrB2Ct 5Gl1ngigYnXtjEs8bGogywZZuU7rDorY9saVa8eAFCClGFLoqpCUtxVm2aPiFVYAazRbCyblJXpZIAVA mQYONUErxd09pdRCAaAArBcAb6CCPtEngKJ/+zOA4hdQUu9J4XZlEn5pwvcCK0AKmi3V7JLj6KDo6owl nmUQRCdlB61QEHQDdUnS9PDd1ktA6BE91ogDAEVXZwDKMkChk1KwDkRx0A3aGonW8hytuiqW18TYaFw0 AKDo6gBAWQ4oQEoBpMghgIpu8PZQFGvCCvpDf9YxA6DoaowXBuoACpBSCCncBaQbwNYJt+b4NWCl5vVw rnxaz/TCQIExa40DKHqAAqRMhBRgJV8CL0lolqBCFwXNlWhw7jEAiq6+ABRdQAFSZkLKsAQkmynnJge+ p5scPNhTG1bkxYceros59KdV8SmAoutXAEUfUICUBZBCV0U3wHsqhFqwAgSjMau4AFB0tQWg2AAKkKIA KcCKbrBbJeXa4y4FFQAFXVlpNhOgyBNzrew4jAug2AEKkKIIKSwBUVS2JcOpsCJLPAAKWrIqrNkARV6Q aGVLGRdAsQUUIEUZUuiqUFx2JcQxWAFO0I5lMc22B0U6KACKPUDUeIcPT5w1AhWer0LR2VZ0hifXCrTI R/43nRO0AqDovpMHQOkDUOikGALKMLT8QuY2UoqQdRFifDS2SwMs8ehqgyWeugBEJ6UCqNBV0U0SFGTs iQbKNJANUKzfaAyg1AUUOimVAGX9NHRVypIrRQg7oYFlGgBQltlvU38ASn1AAVIaQIqckiUg3eRBMcOe aOB2DQAoujFx5vjpEzU2iXKOoyDEck8jUGEJSDeJUKSwJxq4pQHZNCp3t2T5WC/xAChtOigDsAEpDSGF W5YprBRWNKCpAQBFV08ASltAYbnHAaBwF5BuUtFM+IyFbyJpAEDR1SuA0h5QgBRHkEJXRTfBRCouzBXf L9UAgKKrIQDFB6AAKQ4hBVjRTTZLkz/fxx/eNQCg6GuUDaxAimM88DU1blnWT0Deiw7zw+dTNJBlg6xc p/UmWbH7jSvXjgEpQIovEnA+G0CFojWlaHFsHr08dupR7uI5AAstzQMofuCEu3ucg8m26QEreslIK6kx Dj5ppYFMgCLXam1nAMUfoBzuSfntn3rot5YI4HM//qmAJT/ulIEVCuOSeOW78fUDoOj6EEDxCSiHkPKb P/bJJ5ckLiClPvAAKrpJaon++S6+qKkBAEVXbwCKX0A5hJTP/NAnLi0JMiClPqRwF5Buolqif76LL2pp AEDR1Rrv4/ENKIeQsjTAgJR2kAKs6CatpbHA9/GHlQayvY/Hyo7DuACKf0AJCymXLl1avfHGG+3JwNkM WAKiQFondsZvo7FsgCLPfrHUGoASA1BuQoqsxy0VQ81Oyte+9rXVCy+8cPO2u+eff3715ptvOkOF9tMB VtoUkqVxxPfx2zYNACi6ugBQ4gBKOEj5xje+cQgowwOMBFguXLiw+s53vtOeDpzNAFjRTW5ABPasrQEA RVdzAEosQAkFKbLEI52TbU9XfPbZZ1df/OIXb8LKd7/7XWeo0HY6gIpukqtdpDhfXv8BKLq+B1DiAUoY SPnmN7+5E1A2oeXixYsr+Xzve99rSwfOzg6s6CY84AF7WmogG6BYP+4eQIkJKCEg5Vvf+taRJZ6Sd1UI qEh35e2333aGC22nA6xQXC2LK2Mv1xeAstyG6zoEUOICintIuXz5cnEHZRe4yBLQV77yldX3v//9tnTg 6OwCKg/f/aDp7nmKlW6ixZ457Amg6PoZQIkNKGqQIglUCp/mv9dee20xoAzgcu7cuZvdmFdffXX1zjvv aE4z9Fh0VXQTIiCBPZdoAEDR1Q+AEh9Q1J6TMgSmFqh8+9vfXj333HMmb/eUzbdf/epXV1evXg0NGJqT B1Z0k+OSQsV3c/oCQNH1O4DSB6AcQsrSx+JvJtYlsCIPaRueg1Ky92TOMdJZEQiSZ65cu3ZNs96HHYsl IN0kCWxgz1INACi6WgFQ+gGUQ0j5Hz+87N09u4JxKqzIg9kEHuSW4jnwMec7cj55/sr169fDAobmxOmq 6CbM0kLFcTntDqDo+v3M8dMnpLDx6ccGN535h//59ANWSbIUVORhbLuegzIHPuZ8R57F8t5772nW/LBj ASu6ydMqvhg3rp/k0e9z8lTU71jfZgyg9AMm65B5E1Je+Z0LP2Gd7PbByltvvWW2B2VKQMsykBwvz2V5 //33wwKG1sQvnX315oZoa20wftxCi+/m+Q5AmWe3XXoDUPoElMPlno8+/OjP1Eg220BFHrpWc3lnDFoG UJHj5BktH3zwgVbNDzsOoKKbUGvEGufw6zMARdc3AEq/gHIIKfJ/PPfZJ/7NrMT2F39m8i/tAVbkQWtj 0ND677JnRZ7X8tFHH4WFDK2JAyu6yXVWvB3c7s/34togG6A8dupRU70CKH0Dym2QIv/j/okJcOrx68n1 1/7R/TcBZb1z0RpI9p1fYOX111/Xqvdhx2EJKG6BBG7a+g5A0bU/gNI/oByBlK//0Ss/UiOR/eo//G+r c0/f2v8R7SN3IPFvxV6ViUBfI644h24R1LQngKLvmxtXrh3jLp7+QeXIrVoSmPffec/eFt3Y3/cF96/8 g/+6eubs0672oZSC0ssvvwyfbFiAJSD95KtZHBnLh39k2aM0z0Q/znqJRzQNoPQPJwOAHoEUcb5VYnvw 731i9fQXngoXrLIkBaDs5zNgxUcxtIpdxp3v30yAIoBlrRUAJQ+gHFnuGchF1vq0hfbpv/1fVk/98ZPh AEWCTgDlww8/pIsyYgFAZX4h0443xvPhi2yAIstaltoDUHIByk5IkT9oCu2X/9Z/Wj35h2dDAspLL720 +sEPfgCgTLAAsOKjQGrGMGNN9ymAMt1m+3QGoOQDlL2QorXs89//5s+tnvz8EyEB5cUXXwRQJsDJ5qHA im6SBhTi2BNA0fUVgJITUPZCivxRXtS0JDF+8q//h9XZ3/9CSEC5ePEiD3JbACjDVwEV3WS9JB75bh1f ACi6duaFgXkBZRRSloDKL/7Vf7964nf/OCSgXLhwgcfiKwDK+hDAim7iBjh82pMXBur6BUDJDShFkDIH VH7hr/zs6guP/lFYQOElg8qEsjYcsKKbxIEVP/YEUHR9AaAAKMWQIgcW71H5Sz+z+sL/jQco8v4g6aAA KHaAwhKQbhIHUPzYE0DR9QWAAqDsfE7K8Idd/x3bp/L53/jdkB2U559/fnXjxg37Cs0ZDi1AV0U3sQMt bewJoOjaHUABUNb548jD3MYgZd/yzx/8+v8LCyjXr18HHxpZAFjRTfLASj17Aii6tgZQAJRNBpkFKcMg 612Vxz4b87HP8uLAa9euNSrPnJYlIN0kD6DUsyeAomtrAAVA2dYkWQQpw4AvPP7c56O9b0IedS9LPACK L1Ciq6Kb+IEWG3sCKLp2BVAAlF2rOIsh5fLly/8xGqDIfKWDcvXqVV8VmtmwX4W3K5s+Vl0D2gAUAKVk WwTH6IDXIkh57bXX/l1EQJE7ed555x2QwLkFpKvy8N0Pui9aGoWPMXQLn5U9ARRdP9FB0SnkPQPRIkg5 6EZcjQYpAIpzMtkyPZaAdAuDVQHvfdxsgCJPzrX0KYACoJTA1SJIiQYo58+dX7361JfjVWlmfNMCwAqw Ylk0940NoOhqD0ABUEoARY7JAykHgPJrP3r/zV8GUuz4F9MCLAHpFotWRT/SeQEUXc2dOX76RGmB4jhg Jg2kfPYfP3CkdQmsxAQVuiq6RSMSMNSe68m77gv57Ke5XW7rJR4ABeiYCp5dQ4rsPzn3zLnVqX/yCzvX VgGVuKACrAArltACoOjqC0ABUKYCSvfLPeeePrd66Cd+sWjzF7ASF1YunX2V/SrculwU56VQkw1QpPMi 11xqn6nHASgAyhxA6RpSzj31zOrXf/KXJgWdgIoUPP7FtAAba3V/+U4tRL0cD6Do6ghAAVDmAkq/kHKw xPM//+knJwHKeoKlqxITUoZZAyu6RaYX+Ci5DgBFXztLChTfBXC62pMij7p/5qCD8hv/7FOzAQVYiQ0o w+xZAtIvNiVFPvoxczecRv2e5RKPaOHGlWvHAA1AY4kGuoKUm4Dyz39ZBVCGZEtXJTa00FUBVkrBSe5s iQobc+YNoAAPS+Ch1ne7gZRnnnxm9Zv/8tOqgEJXJTagrM8eWAFW9sFKNkB55N6HzHIlHRTgRxNguoCU p88+vfrcv/qMadAND4FjY21ccGEJCFDZBioAiq4uWOIBUoCUg9vlhvbm0088tfpf//pXzAGFrkpcONmc OV0V3aJUupzi8TgARVcLAAqAogko4e/uEUD53z/9q1UBBVgBVjwWW+Y0vdgCKNNttk9nvI8HQNEGlNCQ 8vQXnlo9/G9PNgMUNtYCK4CBbpGrac9s7+Ox3oMCoAAoFoASFlLkVuN3333370hg1Exs+87FXUCxoYUl oLjAMTUHACi6vgZQABQrQAkLKbIfZd0oXmCFJ9bGBhWZPbCiW8CmAoT18QCKrn8BFADFElC6gRS5EC+g MtwFFL9c574CYEW3mFnDR8n4AIquTwEUAMUaULqClMFYwEpuuNC8ekBFt6iVgITVMQCKri8BFAClBqB0 CSneYIW9KprY0GYsYEW3wFmByK5xswGK3LVkaWMABUCpBShdQwpLQG0Kes9nBVbiwQqAouszAAVAqQko 3UOKx64KT6yNjTGAim7Rs/zFD6Do+gpAAVBqA0oaSPEIK7FLNbMHVnQLoDasACi6/gFQAJQWgJIOUlgC Ai60LQCs6BZDDVjJBijySAYNu+0aA0ABUFoBSkpIoauiXaYZD1DxAyoZAeXkXfeZQQqAAqC0BJTUkAKs ABfaFgBW2sIKgKJr/zPHT59oXaA4P5B0xxIRDG8ibvHfJfPe/K6XZ6vwxFptbGgzHrCiWyxLljKkm9Ai D7U8p2UHBUABDjRr7JKxgJSDp9XSVWlTzHs+q4DKw3c/aNaGLyncWY4BUHShEEABUJZAhfZ3gZQ1SAFW esaGNtdGV0W3gG6CV0ZAsXyjMYACoGhDxtLxgJQtkCJGlSUgCdjWv0Z5Ym0buNA+K7CiDysAiq5NARQA ZSlQWHwfSNkBKXRVtMs047EEpFdUARQ9W8oPMQAFQLEADI0xF0HKl7/85cfnbhw7+O4Tzz777OzNbhoX P2UMD5tr2VjbB+jQVVlWYAGUZfbb1h2ekgs5FqCpqYFFkLJkoh988MGfPQCcD8+dOzcLVJace+53WQLq AxK8XAWwMq/Yzv1hFPV7lntQBFhuXLl2bG5O5HsAi7UGmkGKXNj777//5w66KdfnJA9rw+wb30NXRZIL +1W84Mb8eci7nICVcliRN/zOyRdRvwOgAAEta52HczeFFDHAe++9d+cLL7zwvalJxIPxPMAKoDIfEDx9 E1AZBxUAZdxGUzb600EBgDzU0bE5NIcUmeCNGzf+8oULF16fAipjF1br7xLowIqnch97LsDK9kIMoAAo tXI65/EFby4gRURx/fr1v3bx4sWvl4KKNyF5ARVZPuBfbAuwBHR7QQZQABRv+Z751AMZN5AiTr969erf ePHFF18pARWvIvECK7HLNLMXC9BVuXcFoOgCCi8MrFdcvdaoaPNyBSlivHffffeHX3rppQtjoOLZ0CwB ARmaFsgKK9leGChANmVPydRjARQAxXPd3DU3d5AiE33nnXf+7ssvv3zAKed37uSPYGy6KpqlmrEywQqA QgclQo5njvbg5xJSxPFXrlz5kS996UtP7AKVSOIAVgAMLQtkABUABUCJlN+Zqy2ouIUUcfzbb7/9Y6+8 8srntz3wLaIwWsMKT6zVQoX24/QKKwAKgBIxtzNnO1BxDSni+Lfeeusnt22mjSqK1qDCQ+DaA4bmDHqC lWyAIl3iqftKphzPHhS7whm1/kSct3tIEaO++eab/+IAVF5aX/qJaOz1OQMrmqU691g9gEpGQJF3EE2B jinHAigASvQaOcw/BKTIZN94442fXr/rpxcHtIYVnljbD+BEhRUAhSWeXvI516EPh2EgRZz/+uuv33Ow mfY56aj0JIbWoMISUD+gIlcSCVYAFAClp1zOtSSHFBHA5cuXf643SBmE3RpW2FjbD6xEABUABUChqOsX 9d5sGqqTMhj/4O3Jf743R3jar8ISELAyZf/DnGMzAorlG43Zg0Kx77UmhoSUXp3hCVRYAuoHVLwtAQEo dFAy5HCuUQccgZSDJSTPYvKwBNRXuc57NR6WgLK9i0eWpi07KGeOnz7hOX8xN9/1JYJ/XBfoCAasNUdg JS9caF95C1iR223H3sfV498BFIp0rRrR63mAFOedFE9LQA/f/eDq0tlXtWsm4zWyQA1YETjJ2D2hgwKc 9AoNta8LSAkEKYM46Ko0quqdntYCVjLDCYACoNQu5D2fD0gJCCnASqe00PiyBFaWAMsAJlk7J8NyFUs8 QErP0FD72oCUwJAiYpGuimyem3MbqMZ3uF25MVkYnV6W9QZoOfWjD6wEQLZ95E6d7FCyvpfGElAkXmsX CM4HcLXWAJASHFLoqhhVaYY9tMDBm8hTbnqdupHXGlBuXLl2rHXB4PxAS20NACmdQIoHWGFjbZ9kA6Sc H4U0AIXiXbt4ZzkfkNIZpLAE1CcotLwqIGU/pMhyl8bS6a4x6KAAQFmAZNt1AikdQoqHrgpPrG2JFbrn BlJ2QwqAAkBkBoga1w6kdAwpHmCFjbW6wNBiNCBlO6QAKABKjSKd/RxASgJIYQmoRWnv55xAylFIAVAA lOzwUOv6gZQkkOKhq8LG2pjgAqQchRTLPSi80RgAqgUAEc4DpCSDFA+wwhJQLFgBUm6HFHlejBWkACgA SgRwqDlHICUppIjI5K6Blo/YB1ZiwAqQ8jGkAChARM0CzblWdwApiSGFrkoMSGg9SyDlFqQAKAAK0FBf A0AKkHKoAboqrXHA5/mBFACF4ly/OGPzWzYHUoCU2zTQcgmIjbVAytRH0dc43vJpsuxBofgDI/s1AKQA KVs1QFfFJzC0mFXmTgqAAkQAEW01AKQAKXs1AKy0wAJf58wKKQBK2+IEHGB/lnsAlGJIbQUr3AHUHlgy QgqAQoEEknxooLhI4TAfDmvph1agwnuA2oJKNkgBUMh1LfMs575df0AK3ZTJGmgFK2ysbQMrmSAFQAFQ gARfGphcoHCgLwe29EcrWGEJqC6sZIEUAIXc1jKfcu7t+gNS6KQs0kArUGEJqB6oZIAUS0A5c/z0CQoQ AIQG5mlgUYHC6POM3qPdWsEKXRV7WOkdUgAU8liPObmXawJS6KSoagBYsYeG2mfoGVIAFACll2Le63Wo FqhejcR1TUtkrUCFjbU2+NIrpDx26lGztxmzxDMtZ5BjsdcuDQApdFLMNNAKVlgC0oWVHiEFQKEoAkYx NGBWoBBADAHU8BOwogsNtUfrDVIsAUU2dNeIKc5Bfs2iASCFTkoVDQAqtdFC73w9QYo1oMgLOrMUD64T UKqhgSoFqsaFcI4YAQOs6MFDrZF6gpSTd91ntg8FQImRg6gVsfwEpNBJaaKBFrDCxtp5WNMLpAAosYoT MIG/RANNChTiQ3yiAQEVuQtC1vFrfthYOw1WeoAUAIWcQ92JqQEghU5Kcw206KrwxNpyUIkOKQBKzOIE VOA3OikASnNAWU9ELWCFrso4rESGFEtAEb1SSCmkaMBWA66KFM62dXYE+7IENA4NtY+ICimWT5MFUMhV EfJpD3MEUuimuNRAi64KG2u3409ESAFQgIgeCjTXwMZZlwUaYX6cYFvACktAt8NKNEgBUAAUcmg/GqBI 00lxrwF5/gSwUnuR5+PzRYIUAKWf4gRo4Es2zgIo7gGFjbXt4GQ4cxRIAVAoaoBNfxoIVaQQYH8CnONT uip1wSUCpAAo5IY5uYTv+NcNkEI3JaQGWiwBZd1Y6x1SABT/hQYYwEdzNRCyQM29WL7XX6DQVbHvqniG FAClv5gmT+PTdQ0AKXRSutAAsGIHK14hBUChmAE0/WugiwKFUPsXaqmPa8NKhtuVPULKY6ceNXvfEw9q I5+U5huOs9cKkEInpTsN1AaV3t8D5A1SABT7wkDxxcZeNNBdgfJiWObRPshrw0qvG2s9QYoloMgbuYnb 9nGLD/ABe1LonqSC09qw0tsSkBdIAVAoXgBMPg2kKlYIPJ/AB5/XBpWeloA8QAqAkjd2ydu5fQ+k0FVJ pYHasNJDV8UDpJy86z6TjbIs8eQugACQf/+nKlAI0r8ga/kIWCm/Zbk1pAAoxG2tvMB5/GkNSKGTklYD tUEl6sbalpACoPgrGhRyfFJTA2kLVE0jcy7fQV0bVqItAbWCFCtAkf1C8loF4tJ3XOIf/CMaAFLopKCB P9UAsLJ9CagFpFg+TRZAofgBQHE0QIECUtDAmgYAlaOgUhtSAJQ4BYRij6+sNUCBAlLQwBYNACsfw0pN SAFQKHrWRY/xY2mMAgWkoIE9GqgJK1431taCFAAlVvGg2OOvGhqgQAEpaGBEAwIq8jwN2XBZ4+NtY20N SAFQKHg1Ch7niKczChSQggYKNVCzq+LpibXWkGIJKLzROF5RAiTwGe/uKSxKBAvBsk0DNWHFQ1fFElIA FGKMPIsG9mmAX9EACxqYoYFMS0BWkAKgUJwAFDQwpgEK1IwCNWZU/p4n8Gp2VWRjbYvOigWkACh5YoR8 iK+XaABIAVLQgIIGasJKbVDRhhQAhaK1pGjx3Vz6oUApFCiCJlfQ7PJ3r0tAmpDy2KlHze6QYpMscUgu 7k8DQAqQggaUNdBbV0ULUgCU/goIUIBPrTVAgVIuUNYOY/w4SaEXWNGAFAAljm7JMfjKkwaAFCAFDRhq QF5mVwtWrDbWLoUUAIWi56noMZdYeqRAGRYogiFWMFj6qxaoWDwEbimkWD2llz0oxJdlzDK2D30BKUAK GqiogYiwsgRSTt51n8lGWQDFRwGhkOMHaw1QoCoWKGtnMn6MhFFzCUjjduW5kAKgxNAjeQM/edYAkAKk oIFGGojSVZkDKVaAIi969JxQmRsFHw3oaoAC1ahAIWRdIUe2Zy1YmbuxdiqkAChoO3I8Mndf+gVSgBQ0 4EQDtWBl6hLQFEixeposHRRfhYNCjj9qaYAC5aRA1XI45/GdXGqBypS7gEohBUDxrS1iH/9E1ACQAqSg AYcaqAUrJV2VEkgBUCiAEQsgc/avWwqUwwJF4PgPnFo+8gArY5BiBSjS7allZ85DzKEBnxoAUoAUNOBc A7VAZdfG2n2QYgkocqs2hcNn4cAv+KWWBihQzgtULSFwHv9JpxasbC4B7YIUAMW/ZohrfBRdA0AKkIIG gmmgNqxsgxQAheIXvfgx/xgapkAFK1AEVozAsvZTTVC5fPny6vz584efpx953ORR97IHhSUe9G0dO4wf S2NACpCCBgJroBasCJhcPPfCCkCJleApyPgrugYoUIELVHTxMX+9BFoLVnijsZ7P0D+2RAPjGgBSgBQ0 0IkGooIKbzQeT9QUM2yUVQMUqE4KVFYBc91Hk3ckWAFQKL7EMBrYpwEgBUhBA51qwDusACgUJwAFDYxp gALVaYEaczx/z5EcBATk5XxWe0nmjgug5NAfeQY/L9UAkAKkoIEEGvDUVeE2YwrX0sLF9/NoiAKVoEAR 0HkCeszXLWFFOjoACloc0yh/RyPrGgBSgBQ0kEwDLZaAWN6h8AAfaGCOBihQyQrUHJHwnT6TS42uinRP 0E+f+sGv+LWGBoAUIAUNJNeAwIomsAiYyHgs7VDEahQxztG3zihQyQsUAd53gE/179ylIAET9pygpal6 43g0M6YBIAVIQQNoYKsGpBMin6HTsvnf4e9jSYa/U4jQABqYq4H/Dx9K5BQhRG+7AAAAAElFTkSuQmCC AAABAAEAgIAAAAEAIAAoCAEAFgAAACgAAACAAAAAAAEAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AADt7e0m6+zrw+rq6vXq6ur86unp9+rp6e/q6Ojj6uDk/enX3/7p0tz/6cnY/em/1f/pss396KzK/ui3 zubowNKq6MXVVejI1hQAAAAAn4qSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADl6+0B5OrtDeTr 7Szi6uxR4ertbuHq7ZDg6uyt3+rt197q7eze6ezs3ens993p7Pjd6ez73Ojr+d3o7Prd6Ov03ejr597o 69rf6eu53+nrneDp7Hji6es84+nrFOTn6gIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOe2zSTnrcjt56HC/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO3t7q7s7Oz/6+vr/+rq6v/q6en/6ejp/+no 6f/p6Oj/6ejo/+no6f/q4eX/6tDd/+m60v/oocX/55i+/+aVvf/mpMT/5a3I9Oe80JToydcYAAAAAAAA AAAAAAAAAAAAAOTq7RTi6uw94ersiN/q7L7e6ezv3Ons/9vp7f/a6e3/2unt/9np7P/Y6ez/2Ons/9bp 7f/X6e3/1ejs/9bo7P/W6Oz/1ufr/9fo7P/X6Oz/1+js/9jo7P/Y6Oz/2Ojr/9ro7P/b6Ovz3ejrxt7n 6oHh5+k14+nqCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmVngDowtIR57DJyeem xP/nnr//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAD38vAB7e3u5uzs7P/s6+v/6+nq/+ro6f/p5+j/6efo/+nn6P/p5ef/6OHl/+jf5P/o4OT/6LTO/+eT vf/mgbH/5YGw/+SMtv/lk7r/5aHB/+awyOznwNJy5ObqI+Hq7Gff6ey73ens79vp7P/Y6e3/1ujt/9Tp 7f/U6e7/1ent/9Tp7f/U6O3/0uju/9Lo7f/R6O3/z+jt/8/o7v/P6O7/z+jt/9Lo7f/Q5+3/0Ojt/9Po 7f/T6O3/1Ojt/9Pp7f/S6O3/1unt/9bo7P/X5+v/1+fr/9nn6//b5+vj3ufqmeDo6jPr6ekBAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAADRrr8A57rPEOe0y8Pno8L/55u9/+aWu/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu7u7L7Ozs/+zq6//r6uv/6ujp/+rn 6P/p5uj/6ebn/+nj5f/o2OD/6MjY/+jT3f/nosb/6IW0/+dxpv/lbqX/5XGm/+V+r//mlLr/5b7Q/+Le 5P/d6ez52Ons/9fp7P/V6O3/0enu/9Dp7v/O6O7/zOju/83o7v/L6O7/zeju/8/o7f/H5+7/yuft/8jn 7v/G6O//xefv/8Xo7//M6O7/zuft/8nn7v/K5+7/yefu/9Do7f/Q6O3/z+ju/83o7v/U6O3/0ejt/9Ho 7f/T6Oz/1efr/9bn6//Y5+v/2ufq+d3n6svf5+lh4+bqCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASj5EAOW+0Qnmtsy+5qTC/+Wa vf/mkLj/5o23/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAO/v73bt7Oz/7Orr/+vp6v/r6On/6ujp/+rm5//p5ef/6eHl/+nZ4f/ovdT/57HN/+ma v//qeab/5Wad/+N1qP/ldaT/5bXJ/+Di6P/c6u3/2Onu/9Tp7v/Q6O3/zejt/83o7v/N6O7/y+ju/8rn 7v/G5+7/x+fu/8zm7f/F5u7/yebt/8Lm7v/E5u3/v+bu/8Tn7//E5+7/wefu/8Hn7v/B5+//x+fv/8vo 7v/C5u7/xObu/8rn7f/N5+3/yOfu/8/o7f/M6O3/zujt/8zo7f/Q6O3/0Ofs/9Pn6//U5uv/1ubr/9nn 6v/c5urc3+fqW+Lo6gcAAAAAKy0tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAABMPEQDksc8B5q/ImeWfwP/lmbz/5Y21/+aFsf/lirT/AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7+/vEu7t7u3s6+v/7Orq/+vo 6f/r5+n/6ubo/+nk5//q4uX/6t7k/+vF2P/pk7//6m2i/+htof/jdKf/4ajB/9/h5v/Z6u3/1+ru/9Tp 7v/Q6O3/zOju/8bn7v/H5+7/xufu/8fn7v/F5+7/xebu/8jm7f/G5u3/w+bu/8Lm7v+/5u7/u+bu/8Ll 7f+55e7/uObv/73m7v/A5e3/uuXu/7/m7v+85+//w+fu/77m7v++5u7/w+bt/8Pm7f+55u//xefu/8Pn 7v/I5+7/xufu/8rn7f/N5+z/zufs/8/m7P/S5uv/0ubq/9Xm6v/Y5+r/3Obq19/m6Vfi6OsIAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOa0ylHlosD+5ZW6/+ST uv/ljLb/5oWw/+WBrv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA7+ztlu3r7P/s6er/6+jp/+vo6f/r5Of/6uXn/+rg5f/r2eH/7sbW/+uE sv/paJz/53ml/+HO2f/b6e3/1unu/9Hp7v/Q6O7/yufu/8jn7v/F5+7/x+fu/8Xn7v/E5u7/x+bu/8Hm 7//D5+//zObt/8bm7v/G5u7/xOXt/7zk7f+55O7/vOPt/7fk7v+65O7/tuTu/73k7f+65O3/uuXu/7nm 7/+45e//vOXt/7rl7v+05O7/vuXu/7bl7//C5u7/webu/7zm7v/B5u7/x+bt/8bm7f/M5+3/xebt/83n 7P/O5+z/zufs/9Hm6//V5uv/2ebq/tzm6szf5+lZ4uXrApmdnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAADnus1A5qjD8+WNtf/kibP/5JC3/+V2qP/mfav/5Yey/wAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAuLwDu3+Yh7uXp+O3o 6v/s5un/7Obp/+zk5//s4eb/7c7b/+2tyf/tiq//6n2r/+aeuv/f4OX/2ent/9Tp7v/Q6O7/0ejt/8rn 7v/C5+//vOfw/8Hm7v+/5u//v+bu/8Dl7v/B5e7/vOXu/7fk7v+x4u3/rOHt/63h7f+s4O3/r+Ht/7Dh 7v+w4u7/sePu/7Lj7f+y4u3/seLt/6/i7v+24u3/suPt/7bk7f+w4+7/tOTu/7Xj7v+34+7/s+Tu/7vl 7v+85e3/veXt/7bl7v+95u7/wubu/8fm7P/G5u3/yebt/83n7P/N5+z/zufs/9Hm6//T5ur/1ubq/9jm 6v7c5um43+XpHgAAAAAqKioAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5a3GQeajwfXkl7v/44mz/+WE sf/liLP/5nqp/+eCrv/lbaH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO3D1APtwtXV7dfh/+7g5v/u2OL/7svb/++zzP/ujrj/6nWn/+ho m//norr/3ujr/9bp7v/R6e7/z+ju/83o7v/J5+7/yObu/77m7v/A5u7/wOTt/7Tk7/+34+3/suHt/6Le 6/+c3Ov/jNjp/4DT5v+B0uf/idbp/4HT5/+O2On/rt7s/6bd7f+j3ez/ptzt/6Td7f+k3u3/qd7t/6Pe 7v+o3+7/q+Dt/6ng7f+s4e3/sOLt/7bh7P+14+3/t+Pt/7Xk7v+85e3/v+Tt/73k7f/B5e3/wObt/73m 7v/J5u3/y+bs/8fm7f/J5u3/z+fs/9Hm6//R5uv/0+br/9bl6v/a5unw3eXpgeDl5wkAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAOawyCvloL/t5JK4/+OPtv/kgK//5Xur/+WDsP/mfq3/5Yez/+Znmf8AAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOmr xqzqmr3/6pq//+yQuP/shbL/6n2r/+pyo//pap3/5qW9/9/n6//V6e7/zuju/8zn7v/K5+7/yefu/8Lm 7//B5e7/uOXv/7fj7f+14u3/suHt/7Pi7v+u4O3/g9Po/3HB4f9eo9b/QHrL/zJfx/82Ycj/NmDH/zBc yv9CYsr/P2HK/z5fyf8/ZMn/Q2vK/0x4zf9dkNL/cqTZ/4K94v+Tzun/oNns/6He7f+l3u3/pt/t/6rg 7f+t4u7/tePt/7Xj7f++5Oz/seTu/8Ll7f++5e3/t+Xu/7/l7f/E5u3/wubu/8Tm7v/F5u3/zefs/8vn 7P/R5uv/0ebr/9Tl6v/W5er/2uTo0d3j5zkAAAAArK6xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ0iADlrsYO5aLB1OSUuf/kj7b/5Iay/+V8 q//meKj/5oSx/+dclP/lga//5XGi/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA56vDf+acvf/mh7H/6YCu/+hvof/nb6L/6Xan/+mM rf/f5+v/1urv/8/o7v/K5+7/xufu/8Lm7v+/5u7/t+Xv/7Pj7v+y4u7/rODt/6Te7f+Tzuj/eq/c/2KJ 0P8rSsT/CwC//wwAv/8IBL7/BAG4/wIBrP8BAa//AAC3/wYEwP8MBsT/EgfF/xMIxf8SBsb/DwTG/w8F x/8NAcX/BADE/w0axf8yUsr/UobT/3Kl2/+Jx+b/ndnr/6Xc7P+k3u3/p9/t/7Dh7f+04u3/vOPt/7nk 7P+25O3/u+Tt/7nk7v++5e3/wuXt/8Xm7v/E5u3/x+bt/8/m7P/P5uz/0ebs/9Hm6v/U5er/2OTp+Nzj 54/f4uQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AABmVVwA477NBeWiwKnjlLn/44iy/+OLtP/kirT/5H+t/+V7qv/kg7D/5mSZ/+SArf/kdqf/AAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AADoqcNk557A/+WFr//ngq7/54q1/+d3p//peKT/4dzi/9Xp7v/K6O//yOfv/8Xm7v+75e//tuTv/7bk 7v+t4e7/rODt/5jV6v9up9j/PWbH/xMev/8HAL//BAG9/wEAtv8AAKX/AACg/wwEsf8zIcb/UDvb/2NN 5P9yW+f/fGPo/4Fo6f+Daun/hWno/4Bk5/94XOf/cVTn/2VL5v9cQuX/Ujvj/0Uw4f82It7/IxDZ/xYY 0/86Ydf/aZ3d/5DO6P+g3Oz/p97t/6vg7f+w4e3/suPt/7Tj7f+54+z/u+Ps/7rl7f+95e3/wOXt/77m 7v/A5u7/yObt/83m7P/O5uz/zebs/9Dm6//T5er/1+To/9vj59Dd4+Y3AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXFBUAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOS0yRLkqcSw45e6/+OKs//khrD/4oey/+KF sf/jeKn/43+t/+OCsP/lYpn/5Hmo/+Vwo/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOipxE3ooMD/55K3/+Z8qv/mibL/6IWy/+XF 0f/W6e7/0eju/8Ln7/+75u//uePu/7bi7f+v4u7/rN/t/5jU6v9mnNT/GzW8/woEvf8DAb3/AQC2/wAA p/8DAZj/Ixaz/0851P92XOb/kXfp/6GJ6/+okuz/rpnr/7Kd6/+0n+v/tJ/r/7Oe6/+znev/sp3s/7Ca 6/+sluv/po/r/56G6v+Xfen/knbo/4tw5/9+Y+b/Zkzk/0sz4f81IN7/Kifa/1uK3/+Nyej/oNzs/6be 7P+p3+3/rOHt/7ri6/+34+z/t+Tt/7Xk7v+55e3/vuXt/7fl7v/B5u3/x+bs/8vm7P/H5uz/zebs/8/m 6//Q5er/1OXp/9jj6PTg2+G75sbUvebD0sHmxdTE58XTxObE08PmxNO+5sXTuebG1LLmxdOu5sbUrObG 1Kvmx9Wp5sfVp+bH1J/mx9SW5snVjObI1YDmyNV05snVZ+bK1lbmy9ZH58vXNebN2CPmzdgU583YCubN 2AXjsMdE46PA3uSZu//ij7b/44aw/+KCrv/hhLD/4oCu/+KDr//jcaT/5Hen/+Vyof/keKf/42ab/wAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAwKCoA6KnEQ+mdv//ojLX/5oi0/+d8qv/mo7//3Ont/87p7//J5+7/t+Xu/63j7/+t4e7/p97t/5zZ 7P9wqtn/IEC+/wgBu/8DAbz/AACz/wAAn/8MBJr/RjPE/3Vd5P+UfOr/qZLr/7Oe7P+5pez/vqzs/8Gw 7P/Dsu3/xLTt/8W17f/Gt+3/x7ju/8i47v/Iue3/x7ft/8W17f/Csuz/v67s/7uo6/+0oOv/r5nq/6uU 6f+ljuj/ln7n/4Np5f9oTeX/UDbi/zss3v9ah+D/jMnp/6Lc7P+n3+z/seDr/6zi7f+y5O7/tuTt/7bk 7f+95O3/tuTt/73l7f/A5e3/x+bt/8nm7P/M5uz/yObs/87l6//R5er/0+Xq/9fk6P/e2OD/5L7P/+S4 zP/ktsv/5bbL/+W1y//lt8z/5bbL/+S1yv/ltsv/5LfM/+S3zP/kuMz/5LrN/+W6zf/lu83/5bvN/+W9 z//lvs//5b/P/+XA0P/lwtH/5cPR/+XF0vzlwtHw5LLI3+Ogv/3jlbn/4ouz/+GIsv/if6z/4X+s/+F9 q//ifaz/4n2r/+N+rP/lZ5r/5WOY/+Rzo//jdaT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADoqMI1556+/+eOtv/mfq3/5Yax/+HY 4P/V6e7/yOjv/73m7/+t4+//o9/t/57d7f+Iy+j/QHHG/wUAuP8DAbr/AAC1/wAApv8DAJb/Uj7C/4lw 5f+pkuv/uabs/8Gw7f/Gtu3/yLnu/8m77v/LvO7/zL3u/82+7v/OwO7/zsHu/8/C7v/Pwu7/zsHu/83A 7v/Mvu7/y73u/8q77f/Iue3/x7ft/8S07P/BsOz/vavr/7uo6v+2oun/rJfp/6CI5/+Ocub/eVzl/2NH 4v9EOd//YI/h/5PQ6v+k3Oz/pt/t/67i7f+x4+3/tOPt/7nj7P+25O3/uuTt/7Pk7v/D5e3/xeXs/8vl 6//K5uz/yebs/8nl6//R5er/0uXr/9bk6f/b3eP/48TS/+W7zf/luc3/5LbL/+Syyf/ksMj/5LDI/+Sv x//krMb/5KzG/+Sux//kq8X/5KnE/+Ssxv/krcb/463H/+Stxv/jrcb/5K7H/+Oqxf/kq8X/5KfE/+Oi wP/jmLv/45G3/+KLs//hhrD/4YKu/+F3p//hfqz/4Xin/+Jzpf/icqP/43mq/+Ztn//mZZf/5HWl/+N5 qP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAOmrxSvnocD/5pK4/+aRuP/kuMz/2Ont/87o7v/D5u//s+Lu/6Pf7v+b2+z/esLj/yA+ u/8GAbj/AgC2/wAAr/8AAJv/PCyt/4hx4f+slev/vavs/8W17f/KvO7/zb/u/87B7v/Qw+//0cXv/9HG 7//Sxu//0sfv/9PI7//TyO//08jv/9LH7//QxO//z8Lu/83A7v/Mvu7/y73u/8q87f/Ju+3/ybrt/8e4 7f/Ftez/w7Ps/8Cv6/+9q+v/uabq/7Gd6P+ji+j/lHnn/4Fm5f9gRuL/QEff/32s5P+a2ev/o93s/6jg 7P+s4e3/tOLs/7Pj7P+34+z/tuTt/7rk7f/D5e3/xeXt/8bm7P/F5ez/yubs/87l6//O5ev/0eXr/9Xk 6f/Z3+X/4cHS/+SxyP/ktMr/5LbL/+S3y//ktcr/5LDI/+Stxv/kq8X/5KjE/+Omw//jpsP/46PB/+Sg wP/kocD/45y+/+Ofv//jnb7/45m9/+OXu//jlLn/45O5/+KOtv/iibL/4YSu/+GFsP/hgKz/4Xqo/+B6 qP/hd6f/4m+h/+N2pv/jc6P/5WCT/+Rmmv/kaJz/5Gmd/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6KrGH+egwPvokbj/55W6/93j 6P/R6O7/xOfv/7vk7v+o4O7/oN3t/4XF5f8bO7f/BgK0/wEAtf8AAKv/BgOZ/2dUyf+nkOr/uqbs/8S0 7f/Juu7/zL7u/87A7v/Pwu//0sXv/9PJ7//Vyu//1czv/9bM7//Wze//1s3v/9bM7//Vy+//08fv/9HE 7//Pwu7/zsDu/82/7v/Mvu3/y73t/8q87f/Ju+3/ybrt/8e47P/Gt+z/xbbs/8Oz7P/Bsev/vq3q/7im 6v+vm+n/ppDn/5mA5f98YeT/UDfh/1yF4f+S0ur/n9zs/6He7P+s4Ov/s+Hr/7Ti7P+v4+3/t+Pt/7nk 7f+85e3/weXt/8Hl7f/H5ez/yubs/83l6//O5ev/0OXr/9Pk6v/X4eb/38nW/+Slwv/kp8P/5KrE/+St xv/kr8f/5K3G/+Sux//krcb/46rF/+Skwv/koMD/5Jy+/+Sdvv/knL7/5Ja7/+SXvP/jlbv/45G4/+OP t//ijLX/4ou0/+GGsP/ghbD/4H2s/+CCrv/gfav/33im/+Brnv/ib5//4myd/+Nvov/kZJf/42+e/+Vn mv/lZ5n/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAADpqsMV6aHA9emSuf/lxNT/1unt/8vm7f+95e7/tuLt/6nf7f+O0On/KFC7/wUC tf8BALX/AACq/w4Hmf98Z9j/tJ7r/7+u7P/Ht+3/yrzu/8y+7v/NwO7/z8Hu/9HD7//Tx+//1cvv/9fN 7//Yz+//2M/v/9jQ7//Yz+//187v/9XL7//Tx+//0cTu/8/B7v/Nv+7/zL7t/8u97f/LvO3/yrzt/8q7 7f/Ju+3/ybrs/8i57P/HuOz/xrfs/8W17P/Ds+v/wLDr/72s6v+3pen/sJzo/6SN5/+MceX/ZUnj/1Ri 3/+Kx+j/mtrs/6Hc6/+s3uv/r+Hs/7Ti7P+54uz/tOPt/7vk7f+85e3/veXt/7/l7f/G5ez/xuXs/8vm 7P/M5ez/0OXr/9Hk6f/V4uf/3srX/+Oiwf/jnL//45+//+Ojwf/jn7//46bD/+Olwv/jp8P/46TB/+Oi wf/jnr//45i7/+SUuv/jlLr/45C4/+OTuf/jj7f/44y2/+KHs//ijLX/4YSw/+B9q//gean/4H6s/998 q//fd6b/4Gqb/+BnmP/gcaD/4GaY/+Fyov/ic6L/42KW/+Rjl/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOiuxhHppMPy6Jq8/97l 6v/Q5+3/w+Ts/7rj7v+r4O3/mtns/0R4xf8EALP/AQC0/wAAqv8MBZv/g23a/7ei6//Csez/yLnt/8u8 7v/Mvu7/zb/u/87A7v/Pwe7/0cTv/9PH7//Vy+//187v/9nQ7//Y0O//2NDv/9jQ7//Xzu//1cvv/9PG 7//Qwu7/zcDu/8u97f/LvO3/yrzt/8q77f/Ku+z/yrvs/8m67P/Juuz/yLns/8i57P/HuOz/xrfs/8W1 7P/Ds+v/wrLr/7+v6/+8qur/taPp/6uV6P+VfOb/b1Tk/1JT4f9/uOb/mtnr/57b6/+k3uz/quHs/7Hi 7P+14+z/uePs/7rk7f+15O3/v+Xt/8bl7P/H5uz/yuXs/8nl7P/L5ez/0OXr/9Lk6f/V4uj/3NDb/+Kc vv/jmLv/4pW7/+Obvf/jm73/45y+/+Ocvv/jmrz/45+//+Obvf/jmr3/45e7/+OSuf/jjrf/45C4/+KM tv/ijrf/4omz/+KEsf/hfqz/4Xuq/+Bil//feaj/3nGh/99voP/geKb/33Kh/99mmP/fdKP/33in/+Fh lf/jYpT/422d/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA6K3FDemjwu3lwNH/1+nt/8vn7v++5O3/r+Ht/6Dc7f9pqNj/AQCw/wEA s/8AAKv/AACc/3xm0/+4pOv/w7Ps/8e47f/LvO7/zL7u/8y+7v/Mvu7/zb/u/87A7v/Pwu7/0sbv/9XL 7//Xzu//2M/v/9jP7//Xzu//187v/9bM7//UyO//0cTu/83A7f/Lve3/yrvt/8m77P/Juuz/ybvs/8q7 7P/Ku+z/ybrs/8m67P/Iuez/yLjs/8e37P/Gt+z/xrbs/8W17P/EtOv/wrPr/8Cw6/++rer/uKfq/6+b 6P+Zgef/e2Lk/1pI4f9tquP/kNXq/53b6v+h3uz/qeHt/7Hi7f+24+z/tuPt/7Xk7v+/5Oz/veTt/8Pl 7P/H5ez/x+Xs/8jl7P/L5ev/0eTq/9Lk6f/V4uj/3NLc/+KZvP/ilLr/4pS6/+KVu//jl7v/45W6/+OV uv/jmbz/45a7/+OTuf/jlrv/45O5/+OPt//jibT/4oq0/+KGsv/ifq3/4n+u/+KBr//hean/4GaX/99w oP/fbJz/3VWH/952pP/eapr/3mqa/952pf/eaJr/4GaY/+Jkl//iZ5r/AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADjucoF6aHA4+Hd 5P/Q6O3/w+bu/7jj7v+q3uz/iM/o/xo9tP8CALL/AACu/wAAof9iUcH/taHq/8Sz7P/Juu3/yrzt/8y9 7f/Mvu3/zL7t/8y97f/Mve3/zL7t/87A7v/Qw+7/08fv/9TJ7//Vyu//1Mrv/9TJ7//TyO//0sbu/9DE 7v/OwO3/y73t/8q77P/Juuz/yLns/8i57P/Juuz/ybrs/8m67P/Iuez/yLjs/8e37P/Gt+z/xrfs/8a3 7P/Gt+z/xbbs/8W16//Etev/w7Pr/8Gx6/+/r+r/u6rq/7Gf6P+Yg+X/e2Hg/0w42v9knN7/kdTp/5na 6/+l3uv/reDs/7Di7P+y4+3/tuPt/7nk7f/A5e3/veXt/8Tl7P/F5ez/yOXs/8rl7P/M5ev/0OTr/9Hk 6f/U4uf/29Db/+Gbvf/ikbj/4pC4/+OUuv/ikrn/4pS5/+OTuf/jlLn/45O5/+OTuf/jjrb/44+3/+OH s//jiLP/44Cv/+OCsP/jgrD/4nmr/+J9rP/gaZz/33Cg/99unf/ebZv/3WOV/95ik//ea5r/3m2e/95u nf/gZ5j/4GmY/99Qhf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADotszE2ujs/87n7f++5O7/seHt/6Db7P9bmdH/AgCv/wAA sf8AAKj/LySn/6qW6P/Csez/x7nt/8q87f/LvO3/y73t/8u97f/LvO3/yrzt/8q87f/LvO3/zL7t/87A 7v/Pwu7/0MPu/9DD7v/Pwu7/z8Hu/87A7v/NwO3/zL7t/8q77P/Juuz/yLns/8e47P/HuOz/x7js/8i5 7P/Iuev/yLnr/8e47P/Gt+z/xrfs/8a37P/Gt+z/xrfs/8a36//Gt+v/xbbr/8S16//DtOv/w7Pr/8Ky 6/+/sOr/uKjo/6iU5f+LdN//bFPZ/0Mx0/9cmNz/ktXp/5ra6v+j3er/reDr/7Th6/+64uz/tePt/7rk 7f+55O3/vOTt/8Pl7P/A5ez/x+Xs/8jl7P/K5ez/zeXr/8/k6//V4ej/2tHc/+GXu//ijLb/4om0/+KQ uP/ikrn/45C4/+ONtv/jj7f/4462/+OMtf/jjLX/44m0/+OHs//jgq//4nys/+OBr//hX5P/4n2r/+Bz pf/fbaD/3mWY/95sm//dRnn/3VmM/91dkP/dW47/3miX/99De//gapv/31iK/wAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOTY 4KLU6O7/x+bt/7fj7v+o3u3/kdXr/x5Etf8BALH/AACt/wAAnP+GdNT/vqzs/8a37f/Ju+3/yrzt/8u9 7f/Lve3/y73t/8q87f/Ku+3/ybvt/8q77P/Ku+z/yrzs/8u97f/Lve3/y7zt/8q87f/Ku+z/ybvs/8m6 7P/Iuez/xrjs/8a36//Ftev/xbXr/8W26//Gt+v/xrfr/8a26//Gtuv/xbXr/8W16//Ftev/xbbr/8W2 6//Ftuv/xrbr/8a26//Ftuv/xLXr/8S06//Ds+v/wLDq/7ur6f+zoef/qZTk/5mD4P+EbNz/aU/Y/0Is 0v9hnN3/jtTp/5ja6v+l3Or/rN/r/7Th6/+t4u3/tePt/7Xk7f+65O3/weXs/8Hl7P/C5Oz/yeXs/8fl 7P/M5ev/zOXr/9Dk6v/U4uj/2tPd/+CXu//ijLb/4ou1/+KGsv/ijrf/4oez/+OIs//jirT/44q0/+OF sv/jibP/4oey/+KFsf/ifqz/4n2s/+Jxo//icKP/4nin/+BtoP/gcqP/3muc/95Pgv/dUYL/3F2O/95w oP/cWYv/3WOS/95nmP/eXY//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3urtp83n7f/A5O3/reDt/6Ld7P9zt9//AACp/wAA rv8AAKf/Niqn/7Wi6v/Etez/ybrt/8q87f/KvO3/yrzt/8u87f/KvOz/yrvs/8m67P/Iuez/yLns/8i5 7P/Iuev/x7ns/8e47P/Ht+z/xrfs/8a36//Gtuv/xbXr/8S16//Ds+r/w7Pq/8Oz6v/Ds+r/w7Pq/8S0 6v/EtOr/w7Pr/8Oy6//Csuv/wrLr/8Oz6//DtOv/xLXr/8S16//Etev/xLXr/8W16//Ftev/xLXr/8Gy 6v+7q+n/s6Hm/6yX5P+mkeL/oYzh/5eC3/+Gbt3/Z07Y/0Au0f9qpN3/lNbo/5vY6P+g3Or/pd/s/6zi 7P+v4u3/rePt/7Xj7f+55O3/vuTs/7/l7f++5Oz/vuTs/8vl7P/N5ev/zOTr/9Dj6v/U4ej/2tPe/+CP t//hhrP/4oez/+KMtv/ih7P/44Wy/+ONtv/ji7X/44Wx/+OKtP/ih7L/4oGv/+F/rf/hfKv/4Xmp/+F8 q//gcKL/4W2g/+Btof/fZpr/3maW/9xcj//ccqH/3Guc/9tglP/ecKH/3WaX/95jlP8AAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHx4eAODq 7g7Y6e7pyebt/7jj7f+s3+3/l9ns/1CNyv8AAKb/AACo/wAAmP+BcMv/wbDs/8e57f/KvO3/yr3t/8q8 7f/KvOz/yrvs/8m67P/Iuez/yLns/8e47P/Gtuv/xbXr/8W16//EtOv/xLTr/8S06//Ds+v/w7Pq/8Oy 6v/Csur/wbHq/8Cw6v/AsOr/wbDq/8Gx6v/Bser/wbHq/8Gx6v/AsOr/wK/q/7+v6v/AsOr/wbHq/8Gx 6v/Bsur/wbLq/8Gx6v/Bser/wLDq/7+v6f+9rOn/uafo/7Sh5v+tmeT/qZTj/6eS4v+lkOL/oYzg/5iD 3/+FbNv/ZErX/z8z0f9wseD/j9bp/5nZ6f+e3On/pt/s/6rh7P+t4uz/tOLr/7rj7P+55O3/uuTt/7vk 7f+/5ez/yeXs/8nl7P/E5ez/zuTr/9Hj6v/U4ej/2dDc/+B/sv/hdKz/4oi0/+KGs//ihLD/44m0/+OJ s//ihLD/4oiy/+KJs//ihrH/4Xur/+F/rf/hdaf/4Xao/+Fvov/hc6X/4Gug/+Bmm//dU4n/3mud/9tt nf/aXZD/3FyN/9xunv/bVob/3FKF/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3ursQ9Lo7v/D5u7/tOLt/6Ld7P+P0+r/Klu0/wAA n/8AAJn/AACN/66c5f/Ftu3/ybvt/8q87P/KvOz/yrvs/8m67P/Iuez/x7js/8a37P/Gtuv/xbXr/8S0 6//Ds+r/wrLq/8Gx6v/BsOr/wbDq/8Cw6v/AsOr/wK/p/7+u6f++ren/va3p/72t6f++ren/v67p/76u 6f++run/vq7p/72s6f+9rOn/vKzp/76t6f++run/vq7q/76u6v+/r+r/va3p/7uq6P+5puf/taPm/7Gd 5f+smOT/qpbj/6mV4/+plOP/p5Pj/6aS4v+jj+H/n4vg/5eB3v+Badr/XkbV/0JC0f94uuH/jdTo/5TZ 6f+e3er/ouDs/6nh7P+s4ez/t+Lr/7bi7P+65Oz/ueTt/77k7P/H5ev/xeXs/8Tl7P/N5ev/zuTr/9Lj 6f/V4uf/2s3a/+CGs//hgLH/4oi0/+KIs//ji7X/43+u/+KEsP/ihrL/4oWx/+GCr//hdKX/4Xmq/+Fw pP/hdaf/4XKl/+Fwpf/gX5j/4Wee/95Xjf/eZZn/21+T/9xpmf/dYpT/20l8/9xgjf/cXYz/AAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AADc6e2byuft/7zk7f+p4O3/ltnr/3rK6P8SK6H/AACb/wAAj/9SRKj/va3r/8e57P/Ju+3/yrzs/8m7 7P/Iuuz/x7js/8a36//Ftuv/xLTr/8Oz6//Csuv/wrHq/8Gx6v+/r+r/vq3p/76t6f++ren/va3p/72t 6f+9rOj/vKzo/7uq6f+7qen/u6rp/7yr6P+8q+j/u6vo/7ur6P+6quj/uajo/7qp6P+7quj/vKvo/7ur 6P+6quj/uqno/7in5/+0o+b/sZ7l/62Z5P+qlOP/ppDi/6WP4f+lkOH/ppHi/6aR4v+lkOL/pJDi/6OP 4f+ijuH/n4rg/5V/3f96Ytr/XETU/0NO0P97xOT/i9bp/5XZ6f+e3uz/pODs/7Hg6v+t4ez/seLs/7Pj 7P+24+z/u+Ts/73k7P/A5ez/xuXs/8jl6//K5ev/zuTq/87j6v/T4ef/28jX/+CDs//hh7P/4Xet/+KH s//jhrL/44ey/+N/rf/if67/4oiz/+J7qv/hf63/4Xeo/+F2qP/hc6b/4Wqg/+Flnf/gZJr/4Gmf/99k mv/eZ5z/3V2T/9xTh//eZZb/21WG/91tnP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4OnrCdno7OjC5e3/sOLt/6He7P+K1ur/bb3j/wIW m/8AAJj/AACI/3Zkxf+6qur/xrns/8m87f/Ju+z/yLrs/8e46//Ftuv/xLXq/8Kz6v/Bser/wLDq/7+v 6v+/r+n/v67p/76u6f+8rOn/u6ro/7uq6P+7quj/uqro/7qp6P+5qOf/uKfo/7im6P+5p+j/uajo/7mo 6P+5p+j/uKfn/7al5/+1o+f/taPo/7Wj5/+0ouf/sqDm/7Cd5f+tmeP/qJTj/6SP4v+hjOH/oYvg/6GL 4P+hi+D/oYvg/6KM4P+ijOD/oY3g/6GN4P+ijuH/oY7h/6GN4P+gjOD/nIjf/4553f91Xdn/W0TV/0Je 0v9/y+X/i9bp/5fZ6f+e3ev/o+Ds/6fg7P+z4ev/ruLt/6ri7f+34+z/uuPs/7vk7f/B5ez/xeXs/8fk 6//K5Ov/zeTr/9Lj6f/V4Of/3MHT/+B6rv/hg7L/4Xqt/+KIs//jirT/436t/+N/rv/jhLD/4n6t/+J/ rf/hbKH/4Xip/+Fypv/haJ//4XCj/+Fnn//gXZX/4Guf/+Bck//gYJT/3UV5/91hk//cVIX/3F+R/wAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AADg6ewx1unt/8Dk7f+p4Oz/ndzr/4XT6v9UodD/AACX/wAAk/8AAIj/j3nY/7Oi5//Bs+r/xbjr/8W3 6//Ftuv/xLXr/8O06v/Csur/wLHq/76u6f+9rOn/vKvp/7yr6f+8q+n/u6vo/7qq6P+5qOj/uKfo/7im 5/+4puf/t6bn/7el5/+2pOf/tqTn/7el5/+4puf/t6bn/7al5/+1o+b/tKHn/7Gf5v+wneb/rprl/6qW 4/+mkuH/oovh/52F4P+YgN7/lX7d/5Z+3v+Ygd7/mYLe/5qE3/+bhd//nIXf/52G3/+dh9//nojg/56K 4P+eiuD/n4vf/5+L4P+eit//mITe/4p12/92X9n/VD7S/0Vz0/+Azeb/jNbp/5ba6v+e3+z/pt7r/6zg 6v+v4ev/rOLs/7Hj7P+44+z/uuTt/7zl7f/E5ez/weTs/8Pl7P/J5Ov/zuTq/9Hj6f/W3+b/3rPM/+F6 r//hWqP/4Xuv/+KBr//jhrL/44Sx/+OCsP/jf67/43Wo/+Bhlv/heKj/4Xeo/+Fuov/ha6H/4F6X/+Bi mP/gcaT/4WGX/948c//eUof/3nCg/95pmv/eMGb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASEpLAN3p7GvQ5+3/vuPs/6ff6/+Z2+v/hNLp/zt7 vP8AAJf/AACP/ycdkf+eiOL/sJ/m/7en5/+7quj/va3p/7+w6f/Asen/v7Dp/72u6f+8rej/u6vo/7mp 6P+4p+j/uKfo/7mo6P+5qOf/uajn/7mo5/+4p+f/t6Xn/7al5v+2peb/taTm/7Wj5v+1o+b/taPm/7Si 5v+yoOb/sJ3l/66Z5P+qleP/ppLi/6SP4f+hi+D/nYfe/5mC3v+Wft3/lHvd/5N52/+Tetz/lHzd/5V9 3f+Vfd3/lX3d/5R93v+Vfd3/ln/d/5iB3v+Zg97/mYTf/5qF3/+aht7/m4bf/5uH3/+bh9//lIDd/4Rw 2f9rVNP/OibG/1SP0P+H0+f/j9jo/5Xb6v+c3Or/pd7r/6zh6/+o4uz/r+Ls/7Di7P+25O3/t+Xt/77l 7P/A5ez/vuTt/8fk6//M5Ov/zuTq/9Ph6P/W3eT/3qfG/+Juq//hdq3/4YKx/+KFsv/jfq7/5ISy/+SF sf/jZ57/4nKj/+J+rP/geKj/4Han/+Fypv/hcqX/4Xao/99soP/gY5r/30J4/+Bqnf/dW5H/3m6f/940 Z/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAA3Ortpcvn7f+64+z/o97r/5na6v96zef/HUqm/wAAlv8AAI3/STqm/6aS5P+wnuX/sJ7k/7Cd 5P+yoOX/s6Ll/7Oi5f+zoeb/s6Lm/7Sj5v+0o+b/taPm/7Wj5v+1o+X/taPm/7Wj5/+1pOb/taTl/7Oh 5f+xnuX/rpvl/6yZ5P+qluP/qZbj/6iU4/+nk+L/ppHh/6KM4f+eh+D/moLf/5iA3v+Xf93/ln3c/5N6 2/+Qdtz/jnTb/4102/+OdNr/kHba/5B32/+QeNv/kHfb/5B32/+Pdtz/jnbc/4933P+ReNz/knvc/5R9 3f+Uft3/lH/d/5WA3f+Xgt7/l4Tf/5eF3/+Ugd3/iXXY/3Zi0f9OOcj/Ixy5/2Wv2P+F0+b/ktjo/5Pb 6v+d3er/oOHs/6bi7f+n4ez/ruLs/7Hj7f+x5O7/vOXt/7/k7P/B5Oz/w+Ts/8nl6//L5ev/0OPp/9Li 6P/X2uL/3qHD/+B5r//ghrP/4YSy/+N6r//khLD/43ur/+R/rP/jdKX/44Ow/+F/rP/hd6j/4Guh/+Fx pf/gcaP/4HKk/+Bqnf/gVYv/4GOZ/95hk//eZJj/3VSG/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOfy+QDZ6e3Yw+bu/7Hi7f+k3ev/mtrq/3bE 4/8BHpj/AACR/wAAiv9oVrn/p5Tk/66d5f+uneT/rJnj/6mW4/+mk+H/oo/g/6KO4P+jkOH/pZLh/6eT 4f+oleL/qJTi/6eS4v+mkeL/ppHi/6aR4v+lj+H/oo3g/6CL3/+dh9//m4Pf/5iB3v+Wf93/lX7d/5N7 3P+Qd9z/jXPb/4xy2v+Kcdr/inDZ/4tx2P+Lcdj/inDZ/4hv2f+Ib9n/iW/Z/4pw2f+Kcdn/inHa/4px 2f+Jcdn/iG/Z/4hv2f+Hb9r/iXDa/4px2v+Lc9r/jHTa/4x12v+Nd9v/j3nb/5B73P+Oetz/jHfb/4dz 2P9/a9X/dmLR/2VRyP86KsH/KD63/3LB4P+G0+b/i9nq/5Xc6v+g3uv/ouHs/6Xh7P+n4ez/quLt/7Dk 7f+25O3/uuPs/7/k7P/B5Oz/xuXs/8nl6//L5ev/zuTq/9Th6P/X1uD/3pe9/+B5rf/hh7P/43Ks/+SG sv/kgK7/5Iax/+SCr//jg7D/4n2r/+J8q//heKj/4Xeo/+Bpnf/gb6L/4W+i/+Bdkv/fY5f/3lmO/91l mP/eZ5n/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAA4OrtEtbp7vnD5O3/suHr/57c6v+P1+n/bbba/wAAkP8AAJH/AACF/3tpyf+mleP/q5rk/6ya 4/+oleL/pJHh/6GN4P+eid//m4Xe/5mF3v+ZhN7/mYTd/5mD3P+YgN3/ln3d/5J83f+Qetz/kXnb/5B4 2v+Qdtr/j3Xb/4502v+Mctr/i3Ha/4tx2v+Kcdn/inDZ/4lv2f+Jbtj/iG3Z/4ht2f+Ibdj/h27Y/4Zt 2P+FbNf/hGvX/4Rq2P+Eatj/hGrY/4Rr2P+Ea9f/g2vX/4Jq1/+BaNf/gWjX/4Fo1/+Cadj/hGrX/4Rq 2P+Fa9j/hW3Z/4Rt2f+Ebdj/g23X/39o1/94YtT/cFzR/21b0f9tWc//aVfK/1E/w/8sHrn/OWy9/3zO 5P+I1ef/j9np/5nc6v+a3uv/n9/r/6Lg7P+l4e3/quPt/7Hj7f+34+z/v+Tr/77k7P++5Oz/xOXs/8rl 6//I5ev/0ePp/9Ph6P/X097/3oi1/+CCsv/iZ6n/43us/+R3qf/kfaz/44ez/+N+rf/jf6z/44Kv/+Fy pP/ieKn/4Xao/+FlnP/gbqL/4GSa/99vov/eZ5n/32yf/9xWjP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKeqrQDe6u1F0+jt/8Hk7P+u4Oz/mtvq/4zW 6f9eocv/AACI/wAAjP8AAH3/iXbT/6aV4v+pmOL/qJbh/6OR4P+fjOD/nYrf/5uH3v+Yg93/lH/c/5J8 2/+Qedr/j3jZ/4922f+Mc9r/i3La/4px2v+JcNn/iXDZ/4lw2f+Ib9n/h27Z/4du2P+Gbdj/hm3Y/4Zt 1/+FbNf/hWvX/4Vq1/+Eadf/g2jX/4Jn1/+BZ9b/gGbW/4Bm1f9/ZdX/fmPW/35j1v9/ZNX/f2XV/35k 1f98Y9T/e2LU/3ph1P97YdX/fGLV/3xj1f99Y9X/fWTV/31k1f99ZNX/emHU/3Ve0v9xWdH/bVXP/2dQ zP9kTc3/Y03N/2NOyv9iT8n/WknG/zwuvf8kGbL/SY7J/3fN5P+J1uf/jNrq/5Tc6v+b3ev/nN/r/57g 7P+m4ez/quLs/7fi6/+34+z/tuTt/7Xk7v/A5O3/x+Xs/8fl7P/L5Ov/zeTq/9Ph5//aydn/4IKz/+F0 rf/iea//44Sy/+ODsP/jg7D/436t/+OBr//jgK7/43ao/+J4qf/ib6P/4nSm/+FzpP/hcKP/32me/95z pP/eaJv/3VqN/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAANrp7YjQ6O3/vOPs/6be6/+U2uv/g9To/0uOuv8AAID/AACB/w0Hd/+Sftz/pZTi/6aW 4f+kkuD/nozf/5mG3v+Wgt3/lH/c/5J92/+Qetr/jXfa/4t02v+Kctn/iXDZ/4hv2f+Ib9j/h27Y/4Zs 2P+Fa9j/hGrY/4Np2P+Cadf/gGjW/4Bn1v9/Ztb/f2XW/35k1f9+ZNX/fmTV/35k1P98Y9X/fGPU/3xi 0/97YtP/emHT/3le0/93XNT/d13U/3hf0/93XdP/dlzT/3Vb0v90WtH/dFrS/3Ra0v91W9P/dFrS/3JZ 0v9wV9H/bVTP/2pRzv9mTM7/YkjM/2BGyv9eRMr/XEPJ/1tDyf9aRMj/WkTI/1lFyP9VRcX/RDi9/zEl tP8bGqn/V6bQ/33Q5f+F1+n/i9nq/5ba6f+Y3Or/n93q/6Lf6/+i4e3/qeHt/7ni6/+x4+3/uOXt/73l 7P/E5ev/yOXs/8jk6//P5Or/0OPq/9Xf5f/buM//4Hux/+F9sP/hea3/4oWy/+OFsv/jgq//44Kv/+OE sP/kf63/432t/+N1p//idaf/4myi/+Fuof/gaZ7/33Sk/91ilf/fcqH/AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2ejtzsnm7v+z4+3/pN7r/5ba 6v+A0uf/OXSp/wAAef8AAHj/GRJ7/5eD3/+klOH/o5Pg/5+O3/+Yht3/k4Dc/5B82/+Nd9r/i3TZ/4ly 2f+IcNj/hm3Y/4Rq1/+CaNf/gmjW/4Jp1f+BZtb/gGbW/39l1v9/Zdb/fmTW/3xj1P97YtT/emDV/3pg 1f96X9T/eV7T/3he0/94XtP/eF3T/3dc0/92XNL/dlzR/3Zb0f90WtD/c1jQ/3JY0f9yWdL/clnR/3JY 0P9xV8//h3fT/56U1v94ZM//cVfR/25V0f9pUc//ZEzN/2FHyv9dQ8b/Vz7D/1U7w/9UOsT/VTvF/1Q5 xv9SOsb/UTrF/1E8w/9TPMX/Uz3E/088v/9GN7r/Ny22/yEaqv8WNKf/Ybfc/3/Q5v+C1ej/jtfp/5ba 6f+X2+r/oNzq/6He6/+l4Oz/rOHs/7Ti7P+z4+3/tOTt/7/l7P/F5ez/yOTr/83k6v/P4+j/0uLo/9bc 5P/cscz/4IOz/+Fuq//ifa//43Or/+SDsv/keqr/436t/+SEsf/kfq3/5Hmq/+R5qf/jbqP/43io/+N2 p//hdKb/322g/950pf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAOHp7BvV6O32x+bt/7Di7f+b3Ov/jtjp/3/P5/8pX5j/AAB3/wAAdP8bEnv/jnnc/56N 3/+cjd//l4bc/5GA2/+Oetr/iXTZ/4Vw1/+CbdX/gmvV/4Fp1f+AZtX/fmXV/3xh1f97YdT/e2LT/3xg 0/97YNT/el/U/3hf1P94XtP/d13R/3Zb0v91WtP/dVrT/3Ra0v9zWdH/cljS/3BX0v9wVtL/cFbQ/3BW 0P9wVc//b1TP/21Tzv9sU83/bFPO/21Vzv9uVc3/bVPN/4R10f/m5en/6+vr/9zb5v9/b83/YEbI/1lA x/9UO8X/UDfD/0w1wP9LM77/TTW//042wP9ONsH/TDXA/0s0wP9IMr//SDK//0kzwP9HMsD/RTG8/0Av t/85LbP/LSmt/xgZnv8sXaf/a8Ph/3XS6P+F1un/h9jr/5Ha6v+g2+n/n93r/6Pf7P+i4O3/p+Hs/7Di 7f+w4+3/vuTs/7/k7P/F5ev/yOXr/8zk6v/N4+n/0+Lp/9fX4f/dnsP/34Cx/+JwrP/kUqD/5H+w/+Vs p//kdaj/5H+t/+V1qP/laqD/5Xip/+RwpP/kd6j/42Sc/+FroP/hcqT/4G6h/wAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3OnsSdLo7f/F5Oz/ruHs/5/c 6v+O1+j/d8vk/xlGjP8AAHP/AABv/xgQev96Ztb/jHvZ/5GB2f+Pftr/infa/4Vx2P+CbNb/f2jV/3pi 1P95YtP/emLT/3pg0/95X9L/eF7S/3Zc0f91XND/dVvQ/3RZ0f90WdH/cljR/3BX0P9xV87/cVbP/3BV 0P9wVNH/b1TQ/25Uz/9tU8//alHP/2lPzv9qUM3/a1HM/2pRzf9rUcz/aVDL/2hPzP9oUMz/aE/L/2VL y/9hRsr/w7/d/+vr7P/r6+v/6urq/9XU4/9XRcD/SDC8/0Qtvf9ELbv/RC25/0QtuP9EK7r/RzC8/0w8 vf9aWMH/ZmzE/3WAxf+Hms7/iZrO/5+z1/+ku9r/qsDc/67H3/+0zN3/sMrd/7LO3/+32OT/ttro/7Lc 6f+w3On/qtzq/6jc6v+r3Or/oN7s/5zf7f+o4Oz/quDs/7Hi7P/B4+v/uuTt/8Pl7P/F5ez/xeXs/8fk 6//O4+n/1OHn/9nN2//elb7/4XKt/+NvrP/lda7/5nSs/+V+rv/lhbH/5Hyr/+V7q//ke6v/43ip/+R4 qf/keKr/43Wm/+Jxov/hYJT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAADc6OxtzOft/8Lj6/+v4Ov/m93q/4nV5/9zx+L/Aih+/wAAcP8AAGv/EQps/2xX z/94ZtT/fGvU/3po1P93ZNP/eGPR/3hh0f94YNL/dl/S/3Rd0f9xWtD/clnQ/3JZ0P9yWdD/cVjP/3BW zv9vVc3/bVPO/21Tzv9rUc7/alHO/2xSzP9rUc3/a1DO/2tQzv9pT83/aFDN/2lQzf9oT83/Z07M/2ZN y/9mTcn/ZkzJ/2ZMyf9kScn/YkfI/2BHx/9dRMX/Vj3E/19Nxf/l5un/6+vr/+vr6//q6ur/6urq/66t 0v87ILX/RTW2/1xcvf9+h8f/iJjN/5ir1P+xyOD/utHj/7/Y5v/E3ej/xuDp/8jh6v/I4er/y+Pq/8zj 6v/M5Ov/yuTr/83k6//M5ev/zuXr/8vk6//O5ev/zOTr/83k6v/P5On/zePp/8ri6f/C4er/uuHr/67f 6/+y3+v/teHr/7zj7P++4+z/vOPs/8Tk6//E5Oz/xuTr/8vk6v/Q4+n/1N7m/9q70v/firr/4nOv/+Rv rf/laqr/5Xet/+Ryp//jirT/5IOw/+R6qv/jean/43eo/+Rjmf/jeKn/43Wm/+JmmP8AAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANjo7Z/I5u7/vuHq/6zf 6v+b2+n/h9Tn/23D3/8AAGv/AABq/wAAZ/8CAV7/XErE/2tbzv9oV83/ZVPL/2BLy/9gSMv/ZEzK/2dQ y/9qUs3/alHN/2dOzf9mTc3/Z07M/2hOzP9oTs3/alDN/2pQzf9oT8z/Zk3M/2VMzP9lS8z/ZUzL/2VM zP9lTMz/ZEvK/2JJyf9gSMj/YEfI/19HyP9eRcj/W0LG/1lAxf9WPcT/VDrC/1A3v/9LNL7/STG9/0Yv u/9ELLj/kIvH/+vs7P/r6+v/6+vr/+rq6v/q6ur/5OXo/7PF3P+0zuH/wNnm/8fg6f/I4Or/y+Lq/8vj 6v/M5Or/zOTr/8vl6//M5ev/y+Xr/8zl6//N5uz/zebs/8zm7P/M5u3/zObs/8zm7P/J5u3/yuft/8zn 7f/N5+z/zubs/87m6//O5ev/0OXq/87l6//Q5er/zuTq/8rj6v/M4+r/zOTq/8Pj7P/B4+v/v+Ps/8Hj 7P/C5Oz/xOTr/8nk6//R4un/1dfi/9ysy//ggLP/5Eyi/+Vip//la6j/5YGx/+R+rf/kgK7/43+t/+J/ rf/jean/5Wub/+R6qf/jcaP/43en/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA1ufszsDk7f+64uv/qd7r/5Ha6v9+0+j/ZLzc/wAAZP8AAGf/AABj/wAA V/9GNq7/YFHK/1tKyf9aRMb/WEDE/1Q8w/9ROsL/UjrA/1M7wP9VPMH/VjzD/1c9wv9XPsL/Vz/D/1lB xP9bQ8X/XUTG/1xDxP9aQsP/WUDE/1c/xP9YPsT/Wj/F/1lBxv9YP8X/Vz/E/1U9xP9SO8L/UDnA/043 v/9LNL7/RzG8/0Ywuf9DLbb/Pym1/zwmtP85I7P/Oiiy/1BLtP++v9f/6uvs/+vr6//q6+v/6urq/+jp 6v/m6er/1uXq/8jj7P/J5ez/y+Xs/8rl7P/K5ev/y+Xr/8vm6//N5uz/xubt/8Tm7f/K5uz/yubs/8jm 7f/F5u3/xubt/8jm7P/C5u3/yObt/8jm7f/F5u3/yubt/8bm7f/A5u3/yebs/8nm7f/F5ez/yuXr/87m 6//N5ev/z+Xr/8/l6v/Q5Or/z+Tq/8zk6v/F4+v/w+Pr/7/j6//B5Ov/yOPq/9Hk6f/R4ej/2cfY/96e w//hfLD/5HGu/+RxrP/kfq//5Xys/+V4qP/jfKv/4oGu/+N9rP/ke6r/5HKl/+V4qf/kbaH/AAAAAAAA AAAAAAAAAAAAAAAAAADAwMAA7+/vF+vr66TX2985AAAAAAAAAAAAAAAAAAAAAODq7BPU5+3yvuLr/7Dh 7P+i3ev/jdnq/33R6P9cs9b/AABc/wAAZP8AAF3/AABS/ysgjP9UQ8T/Tz7D/047wv9NOMD/Tja+/0ky vf9EL7z/Qi66/0Mtuf9GLrj/Ry+5/0Uuu/9ELbz/RS26/0Ytuv9GLbv/RS26/0Msuf9DLLn/RC25/0Uu uf9HLrn/Ri67/0Qsu/9DK7r/QSu5/0Apuf8/Kbn/PSi2/zwmtP87JLX/OSKz/zorsv9KRbT/bXTC/5el 0P+xxN3/ydzn/9rm6//j6ez/5+rr/+bq6//k6er/4Ojq/9nn6//R5uz/x+bt/8fm7f/K5+3/wObt/8Tm 7f/E5uz/w+Xt/8nm7P/D5ez/wuXt/8Xl7P/B5e3/wOXt/8Xl7P/A5ez/w+Xt/8Xl7P/E5ez/xuXs/8Hl 7P/H5ez/w+bt/77l7f/I5ez/x+bt/8bl7P/H5ez/zObs/8jl7P/L5uz/zeXr/87l6v/O5Or/zeTq/8/k 6v/O5Or/y+Tq/8Dk7P/C5Ov/yuTq/9Di6f/U1uL/3LfR/9+Ouv/igLL/5G+r/+N5rf/keKv/5X6s/+SA rv/ifKv/436t/+OArv/jeKj/43yr/+Vypf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu7u6n6urr/9PY 26wAAAAAAAAAAAAAAAAAAAAA3unsPtPn7f++4en/sN7p/5zb6/+H1+r/eM7m/0+o0f8AAFv/AABg/wAA WP8AAE7/Dglf/0Mxtf9GM7r/RDC6/0QvuP9CLbj/QSu5/z8puP89KLb/Pii0/z4ntP87JrX/OiW2/zkj tf86I7T/OSOz/zgjs/83IrP/NyKz/zgjs/85I7L/OSSx/zgksf83I7H/NyKw/zcgr/82IK//NCCw/zIe r/8zH67/V1e2/3uEw/+Uoc7/ucvf/77U4//M4ur/zeTr/87l7P/O5u3/0Ofu/9Ho7v/U6O3/0+jt/9Pn 7P/Q6O3/xObu/8Lm7f/D5u3/yebs/8Lm7f++5e7/v+Xt/77l7f+/5ez/x+Xr/8Pk6//C5Oz/wuTs/73k 7P+95Oz/weXs/73k7P/C5ez/v+Ts/7/k7P/A5Oz/wOTs/8Ll7P/B5e3/u+Xt/8Xl7P/I5ez/yOXs/8Pm 7f/F5u3/x+bs/8nm7P/I5ez/y+bs/8zm6//L5ev/zeXr/9Dk6v/R5On/z+Tq/8jk6//F5Oz/zOPq/9Lh 6P/Xz97/3ajK/+GFtf/kbav/5HGs/+R/sP/kiLP/5Iax/+R/rf/jfq3/4n6s/+N8q//jgK3/43Kk/wAA AAAAAAAAAAAAAAAAAAAAAAAA7+/vLO3t7frq6+v/1trd7srV3Rfa5ekb2eTpIdjk6Bra6Ox+yuXs/7nh 6/+m3+z/mdrr/33W7P92zuj/TaDO/wAAWv8AAF7/AABU/wAATP8AAET/KxyV/zgmsf84JbL/NyWw/zck sP82I7D/NiOw/zYir/81Ia7/NCCt/zQgq/8zIKz/MiCu/zMgrv8yH63/MR6t/zEdrf8xHa3/MR6t/zIe rP8xHav/MB2r/zAcrP8uG6z/Lhyo/zguqv9xe73/k6PP/63C2//H2+f/zeLq/87k6//P5ez/zubs/87n 7f/M5+3/xubt/8nn7v/L5+3/wefu/8Tn7v+/5u//xubu/8Pm7f/G5u3/v+Xt/8Hl7P/A5ez/uuTs/7/k 7P/F5ez/vuXs/7nl7f/A5Oz/xOTr/8Hk6/+/5Ov/wOTr/8Lk6/+75Oz/vePs/8Hl6/+55Oz/vuTs/8Tl 7P+95Oz/vOTs/8Hk7P/C5Ov/xuXr/8bl7P/B5e3/xebt/7/l7f/F5u3/xubt/8jl7P/I5uz/yeXs/8nl 7P/K5ev/y+Xr/87l6//Q5Or/0uTp/9Lj6f/P4+r/0ePo/9Ld5f/Zwtb/3pe+/+Jyr//jfrP/5G+q/+R6 rf/kfq3/5H2s/+R6qf/jfqz/43Cj/+N8q//kc6T/AAAAAAAAAAAAAAAAAAAAAAAAAADu7u6V7Ozt/+rr 6//c3+L/ztzi+tDg5/7M3+f+yd7m/Mre5vzG3uf/wN7o/7De6/+c2+v/f9fs/3HO6f9NoM7/AABY/wAA W/8AAFH/AABK/wAAQ/8GA1T/JBed/yobpf8rG6f/Kxum/yoapf8qGqX/Khql/ysapf8rGqT/Khqk/yoZ pf8qGaf/Khmn/ykZpv8qGaX/Khmk/yoYo/8rGKX/KRWn/yscp/82L6j/YWm1/4ybyP+nudf/vdLh/8vh 6v/P5Ov/zOXt/8/m7P/O5uz/zeft/83n7f/N5+3/yeft/8Tm7f/F5u3/x+bs/8Tm7f/B5u3/wOXt/8Xm 7P+95e7/wOXt/77l7f+/5Oz/weTs/7vk7f+65O3/wuTs/77k6//A5Oz/uuTt/7Xk7f/B5Ov/uOPs/7/k 6/+74+v/weTr/8Lk6//B5Ov/w+Xr/7rl7f+95ez/v+Ts/7nk7P/C5Ov/v+Ts/8Lk6//H5ev/weXs/8Tl 7P/E5ez/xeXs/8fm7P++5e3/wuXt/8Tl7P/I5ez/yuXs/8fl7P/H5ez/y+Xr/87l6//R5ev/0uXq/9Pj 6f/U4uj/0uHo/9XX4v/dsc7/4Hey/+J9sf/jfrH/5H2v/+WBsP/lh7L/5IKu/+OGsf/jgKz/5Hen/+Vx o/8AAAAAAAAAAAAAAAAAAAAA5OrsLO3t7u3s7e3/6evs/+Pm6f/J1t//v9bh/77Y5P+/2eT/udfk/7fZ 5v+x2Ob/sdnn/7Da6P+Q2ez/e9Lq/1Cdyv8AAF//AABX/wAAT/8AAEr/AABD/wAAQf8GA1n/GxCU/yAS mv8hE5v/IhSZ/yETmv8iFJz/IxSf/yQVoP8kFZ//IxSg/yITof8jE6H/IAyd/yQTnf85OaL/VVuu/3KA vf+brtD/qb3X/7zR4f/N4en/z+Tr/8/l7P/O5uz/z+ft/83n7P/J5u3/zebs/8zm7P/L5uz/yebs/8bm 7P/H5uz/x+Xs/8Hl7f/F5uz/vuXt/8Dl7f+55O3/wuXs/7zl7f+95e3/wuXs/7rj7P/A5Oz/veTs/7vk 7P+95Ov/uuPr/73j6//A5Ov/vOTs/8Hk6//C5Ov/vOPr/8Lk6/+64+z/v+Pr/8Dk6//B5Ov/vOTs/7Xk 7f/B5Oz/weTr/8Lk6//B5ez/teTt/8Ll7P/A5ez/v+Xs/8Dl7P/F5ez/xOXs/8Dl7f++5e3/xeXs/77l 7f/J5ev/xuXr/8fl7P/K5ev/zOXr/8jl7P/O5ev/0eXq/9Xj6f/T4uj/1N3l/9y/1v/dl7//4X6w/+J0 rP/igrH/5Xau/+WBr//kfqz/5Iax/+R8qv/keqn/5YGu/wAAAAAAAAAAwMjLAOLq7SDi6u3o6uzt/+Pq 7P/c5+z/1eTr/83g6f/E2eX/vNbj/7XU4/+t0eL/kcnj/2ehzv9Igb7/SHm3/1iax/9gsNb/RYGz/wAA aP8AAFn/AABS/wAATf8AAEf/AABC/wAAN/8FAlT/EwqF/xcNjf8YDo7/GQ+Q/xsQkv8cEJL/Gw2V/xgA lv8tKJz/YGmt/3+Ovf+arc7/rsTZ/77T4v/I3uj/zOLq/8/l7P/P5ez/z+bs/8/n7f/P5+3/zOft/8bo 7//N6O7/yOft/8bm7f/H5u3/xubs/8fm7f/C5u3/weXt/77l7f/D5ez/veXt/8Pm7f+95e3/weXs/7zl 7f+75e3/vOXt/7nk7f/D5Oz/uuTs/8Hk7P+35O3/vuTs/7zk7P/A4+v/uuLr/8Hj6v+/4+v/v+Tr/7fk 7P+64+z/wOTr/7/k7P++5Oz/wuTr/8Dk7P+45Oz/vuTs/77k7P/A5Oz/vePr/7/k7P/A5Oz/u+Ts/8Pl 7P+95e3/weXs/8Hl7P/C5ez/weXt/8Tl7P/F5ez/xOXs/8Xl6//E5ez/yOXr/8fl6//F5ez/xOXs/8nm 7P/O5uz/0eXq/9Pj6f/V4ef/2NLf/92syv/gf7L/4nit/+KJtf/lea3/5n6v/+aDsP/leKn/5IKv/+R9 q//lga7/AAAAAAAAAAAAAAAA4ertseDq7f/d6u3/2Ojt/9Xn7P/T5uz/0uXr/87j6v/I3uj/xtzm/7vW 5P+Hp87/SFyt/yU4oP8AAI3/AACC/wAAef8AAG7/AABr/wAAXP8AAFT/AABQ/wAATP8AAEf/AAA+/wAA Nf8AAEn/CwZ//yw0jf9XZaP/bnyw/4mZwP+YqMj/tsnb/7/U4f/N4en/zePr/87k6//P5ez/zebt/8/m 7P/P5+z/zefs/83n7f/K5+3/xefu/8zo7f/I6O7/wufu/8Tn7v/H5+3/w+bt/8bm7f/D5e3/vuXu/73l 7v/A5u3/vOXt/8Hl7f+95e3/uuTt/77l7P+95Oz/weTr/7/l7P+25e3/t+Tt/7rk7f+85ez/tuTt/7/l 7P+45Oz/u+Ts/73j7P++4+r/v+Pq/77k6/+25Oz/u+Ts/7rj7P+74+v/u+Ts/7rk7P+45O3/vOTs/77k 7P/A5Oz/tOTt/8Dk6/+74+z/weTr/7/k6/+95Oz/xOXr/7/l7f+95e3/t+Xt/8Hl7P/D5ez/w+Xs/8Ll 7P/G5ez/weXs/7/l7P/E5ez/vOXt/8fl7P/G5ez/yuXs/9Dm6//R5uv/0+Xr/9Tj6f/V3+b/273V/9+R vP/heK3/4oa0/+VopP/ncaf/53mp/+d5pv/lf6z/5YGt/+R8q/8AAAAAAAAAAOHq7UPf6u793Oru/9np 7f/W6O3/1ujs/9Xn7P/T5uz/0ubs/9Hk6//P5Ov/zuLq/87h6f/J3uf/wdnl/7bO3v+uxNj/m7HN/5ux yP+YrcT/k6a9/5Kmvf+Oo7r/lqq//4qft/+QpLb/nbLD/6nA0f+70+D/wtnl/8nf6P/N4ur/zuTq/9Dl 6//Q5uz/0Obt/87n7v/O5+3/zuft/87n7f/K5+7/zuft/8vn7f/G5+7/xufu/8fn7v/D5+//wufu/73n 7//F5+7/xebt/8Ll7P/F5ez/uuXt/77m7f+55e7/u+Xt/7nk7f+95e3/wOXt/7nk7f+95Oz/u+Ts/7bj 7P/C5Ov/vuTs/7bk7f+z5O3/wOXs/7fk7f+25O3/vOXs/7nk7f+z4+3/veTs/8Dk6/+75Oz/ueTs/77k 6/+75Oz/vuTs/8Pk6/+55Oz/vuTs/7jk7P+75Oz/vuTs/73k7P+24+3/veTs/7/k6//B5Ov/xeTr/8Xk 6//B5ez/wOXs/73l7f+/5e3/vOXt/8Hl7P/H5Ov/vuTs/8bl7P/B5ez/xOXs/8bl7P/C5e3/yObs/8Tm 7f/J5ez/y+bt/8/n7f/T5uz/1eXq/9Tj6P/Z1+L/3aHE/+FrrP/hgrD/5Het/+Z2rf/lgq7/54Ct/+Vy o//lgq7/5Xqp/wAAAAAAAAAA3+rttNzq7f/b6u7/2enu/9bp7f/X6O3/1ejt/9Tn7P/T5+z/0ubs/9Hm 7P/S5uz/0ebs/9Dm7P/O5Ov/zeTr/83k6//N5Oz/zuTr/9Dk6//P5Ov/zuTr/83k6//P5Ov/zuTr/87k 6//O5ez/z+bs/83m7f/Q5+3/0Oft/8/n7f/Q5+3/zOft/8fn7v/O6O3/zOfu/8vn7v/J5+3/y+fu/8nn 7v/K5+3/yeft/8jn7f/C5u3/x+ft/7nm7/+95u7/wObu/8Lm7f/D5u3/u+Xt/8Hl7f+65e3/ueXt/7fl 7f+75e3/uuTt/73l7f+35O3/tOTt/7nk7f+/5ez/wOTr/8Dl7P+25O3/s+Tt/73l7P++5Oz/tuTt/8Dj 6//B5Ov/tOTt/7nj7P+95Oz/veTr/7Xk7f+34+z/wuTs/73k7f+15O3/vOTs/7zk7P+45Oz/ueTs/8Dk 6/+64+z/uOPs/8Dk7P++5ez/u+Ts/7/k6/+94+v/weXs/7Tl7v+95e3/wObt/7zm7f/B5u3/wOXs/7rl 7P/A5Oz/vuXt/7vl7f/C5ez/xeXs/8Lm7f/G5uz/x+ft/8rn7f/O5+3/z+ju/9Po7f/V5uz/1OXp/9jf 5v/cutL/4Xqz/+F1rf/ih7T/5YKx/+aGsv/ng67/5n6r/+WIsv/lfav/LDAwAODq7Rne6u302+ru/9nq 7v/W6e7/1+nu/9Xp7f/U6e3/0+nu/9Po7f/S6O3/0ujt/9Lo7f/R5+z/0ufs/9Dn7P/P5+z/z+ft/9Dn 7f/R5+z/0ebs/8/m7P/P5+z/z+fs/8/n7f/O5+3/z+ft/8/n7f/O5+3/zuju/8zo7v/M6O7/yOfu/83o 7f/I5+7/w+jv/8vo7v/M5+3/y+ft/8nn7f/F5+7/yeju/8Ln7v/D5+7/yOft/8Hm7f/H5u3/weXu/73l 7v/C5u3/u+Xt/77l7f+/5ez/veXs/7vl7P+75ez/vOTs/73k7P+55Oz/vOTs/7zk7f+15O3/uOTt/7zl 7P+75Oz/uuXt/7Lk7f+95O3/uuTt/7Xk7f+24+z/vuTs/7jk7P+75Oz/uOTs/7Xk7f+25O3/s+Tt/7vk 7P++5Oz/tuXt/7bl7v+45O3/v+Ts/7fk7f+45O3/vuPr/77j6/+65Oz/vuTs/7jl7f+65O3/vuTs/7fk 7f/C5Oz/uOXt/7zl7f/B5u3/veXu/7fl7v/A5e3/uOTt/73k7P/B5e3/uuXu/8Hm7v/C5u3/webu/8Dm 7v/K5+7/zOju/8Xn7v/O6O//yefu/9Ln7P/V5+z/1+Lp/97C1//fi7v/4X2v/+KCs//kgLL/5oCu/+eA rP/mf6z/5omz/+Zzo/8AAAAA4evuVd3q7v/b6u7/1+ru/9Xp7v/V6e7/0+nu/9Pp7v/T6e7/zunv/9Pp 7f/S6O3/zOju/8/o7v/O6O7/zujt/9Do7f/O5+3/0Ofs/9Hn7P/P5+z/zufs/9Dn7P/M5+3/zuft/83o 7v/M6O7/zuju/8ro7v/N6O7/yuju/8vo7v/E6O//xujv/8fo7v/E5+7/yefu/8Pm7v/F5u7/yeft/8Dm 7v/I6O7/v+fu/8Hm7v/F5uz/vuXt/7vl7f/D5u3/wOXt/7zl7f/A5e3/uOXt/8Dl7f+05O3/uuTt/7nk 7f++5Oz/u+Ps/73k7P+95Oz/veTs/7jk7f+/5Oz/uuXt/7jk7f+45e7/ueXt/77l7f+45O3/tuTt/7fj 7P+85Oz/tuTt/7nk7P+44+z/uuTs/7nk7P+55Oz/ueTt/77l7f+05e3/ueXu/7rk7f/B5Oz/v+Xt/7Pj 7f+94+z/vOTs/7zk7f+55e3/vOXt/7nl7f/A5e3/veXt/8Hl7f+65O3/wubt/8Hm7v/C5u7/ueXu/8Dk 7f/D5ez/yebs/8Xm7f/B5u7/wufu/8Ln7v++5u7/xufu/8Xn7v/E5+//y+nv/8ro7//P6O7/1Ojt/9Tn 7P/V5er/2s3d/96ix//jcq7/43yx/+J+sP/khLH/5nyq/+aBrf/mdaX/5nal/wAAAADg6+6n3ert/9nq 7v/V6u7/1enu/9Pp7v/S6e7/0+nv/9Lp7v/R6e7/0enu/8zo7v/N6e7/zeju/8ro7v/O6O7/zejt/8vo 7v/O5+3/zufs/83n7f/N5+3/zOft/83o7v/L6O7/zeju/8vo7v/O6O7/xujv/8To7//G6O7/y+ft/8Lm 7f/H6O7/x+fu/8Tn7v/C5+//wufu/8Tn7v/D5+3/wefu/7jm7/+95u7/xObt/8Lm7f+85e3/vebu/7zl 7v++5e3/veXt/7Tl7v+45e3/vOTs/7nk7f+75O3/vuTs/7/j6/+94+v/uuTs/7Tk7P+45Oz/u+Pr/77k 7P+15O3/uOXu/7bl7v+15O3/t+Tt/7Xk7P+34+z/v+Xs/7jk7P+05O3/t+Tt/7vk7P+95Oz/t+Ps/7vk 7f+55e3/uuXt/7nl7f+05O7/vuXt/8Hl7f+55e3/uOXt/7zk7P+14+3/uuTs/7zl7f+35O3/u+Xt/7vm 7v/C5u7/ueXt/8nn7f/H5+3/xOfu/8Dn7/+95u7/xefu/8nn7f/K6O7/xuju/8zp7//C5+//xOfu/8nn 7v/N5+7/v+fu/8ro7//P6e//zejv/9Pp7v/T6O3/1Ofs/9Xj6//b0d//36XI/+N0r//jda7/5Iq2/+SN t//mirT/5oix/+WBrf/kibL/4OvtCd/r7ujc6u7/2Oru/9Xq7v/W6e7/0+rv/9Lq7//S6u//0enu/83p 7v/O6e7/y+ju/87o7v/O6O7/y+ju/8zo7v/L6O7/zOjt/8ro7v/L5+3/yefu/8Tn7v/L6O7/xOfv/8Xo 7//J6O7/x+jv/8jo7v/J6O7/x+jv/8Pn7v/J5+3/yOft/8bn7f/G5+7/wObu/8Pn7//B5+7/wOfu/8Dm 7v/B5u3/weXt/7/l7f/A5ez/u+Xt/7nl7v+45e7/vuXt/7vl7f+25e7/s+Xu/7rl7f+85O3/uOTs/8Dl 7P+24+z/v+Tr/7/k6/+y4+3/uOPs/7jj7P+74+v/t+Ps/7Hk7f+15e3/suTu/7Xj7f+54+z/uePs/7nk 7P+z5O3/tuTt/7Tk7f+55e3/ueTt/7jk7f+/5Oz/vuXs/7jl7f+05O7/uOXt/7/l7f/A5u7/t+Xt/7fl 7v+45e3/ueXt/7fk7f/C5Oz/v+bt/7zl7f/C5u7/w+fv/77m7v/I6O//xOjv/8fn7v/H6O//vOfv/8jn 7v/B5+//v+fv/8Lo7//E6O//vOfv/8jo7//G6O//yujv/8zo7f/M6O7/0unu/9Dq7//R6e//0Oju/9Ho 7v/W5+z/1uPq/93F2P/fosb/44K0/+Vtrf/ka6v/5Iq1/+aBrv/mdqX/5IKv/+SMtP/h6+4r3uvu/9vq 7v/Y6u//1+ru/9Lp7//S6u//zerw/9Dp7//O6e7/zeju/83o7v/K6O7/yuju/8no7v/N6O7/y+ju/83o 7v/G5+7/yeju/8rn7v/L5+3/xOfu/8no7v/G6O7/x+ju/8bo7v/G5+7/xufu/8Po7//F5+7/w+fu/8Hn 7v/E5u3/xObu/77m7v/F5+7/wObu/8Tn7v/A5u7/wubt/8Lm7f/C5ez/veTs/8Hl7f+65e3/u+bu/73m 7v/A5u3/veXt/7rl7v+z5e7/v+Xs/7rk7f+05O7/teTt/7bk7f+35Oz/vuTs/7Xj7P+54+v/vOPq/7ri 6/+44+z/teTt/7Pk7f+25O3/uuPs/7rj6/+54+z/sePt/7Xk7f+55O3/tOTt/7fk7f+65e3/uOXt/7zl 7f+35e3/tuXt/77m7f+85e3/weXt/7vm7v+z5e7/v+bu/7nl7v/A5u7/wObu/8Lm7v+85u7/xefu/8bn 7v/C5+//x+nv/8Xo7//C6PD/yOnv/8To8P/J6O//yunv/8bp8P/D6PD/xujw/8vp7//B6O//yOjv/8rp 8P/N6fD/zOju/87p7v/Q6e7/z+nv/9Pq7//R6e//0uju/9Tn7f/V4Oj/3r3U/96Zwv/lg7T/5YO1/+Ry rP/khbP/53ur/+eErv/kga3/5Iqz/9/r7lbd6+7/2uvu/9nq7//W6u//1Orv/9Lq7//L6fD/z+nv/87o 7v/M6O7/zOjt/8vo7v/G6O//yejv/83n7f/E5+//yuju/8ro7v/K5+3/x+ft/8vn7f/K5+3/w+fu/8jn 7v/D5+//xufu/8fn7f/C5+7/xOfu/8Pn7v/B5+7/wufu/8Tn7v/D5u3/wObu/8Pn7f/B5u7/vubu/73m 7f/A5u7/vebu/8Pl7P/E5ez/wOXs/77m7f+35e7/v+bt/7bk7v+85e3/uOXt/7bl7f+55O3/u+Xt/7rl 7f+25e3/suTt/7Xk7f+y5O3/t+Ps/7rj6/+44+v/u+Pr/7rj7P+05O3/uuTt/7nk7P+44+z/u+Lr/7rj 6/+54+z/uOTt/7nk7f+/5ez/vuXt/8Hm7f+45e3/v+bt/7/l7f/A5e3/webu/7jl7v++5e3/uObu/7Tl 7v+/5u7/vubv/7vm7//E5+7/webv/8Ln7//D6O//z+nv/8Lo7//H6fD/yunw/8np8P/K6fD/xunw/73n 7//E6PD/xOjw/8fp8P/L6vD/x+nx/8Xp8P/N6vD/yenw/8rp7//Q6e//0Oju/9Lo7v/T6e//z+nv/9Do 7v/R6O7/1OXr/9rX4v/dwNX/34S6/+N5r//le7H/436z/+WPuv/ng7H/5oGs/+WBrf/kjLT/4Ovucdzr 7//b6u7/2Orv/9Xq7//T6u//0env/8np8P/Q6e//zuju/8vo7v/O6O3/y+ju/8vo7v/H6O//zeju/8Xo 7//H6O//yuju/8jn7f/G5+3/yuft/8fn7v/G5+7/x+ju/8Tn7//J5+3/xeft/8Ln7v/D5+7/v+fv/8Hn 7v/G5+7/wObu/8Xm7f+75u7/xObt/8Hm7f++5u7/vebu/7rm7v/B5u3/wObt/7zl7f/D5u3/uuXu/7zm 7v+55e7/vubu/7nl7f+95e3/u+Tt/7zk7f+x5O7/t+Xu/7bk7f+85Oz/tuTt/7Xk7f+04+z/tuPs/7jj 7P+35Oz/t+Tt/7Xk7f+z5e3/tOTt/8Hk7P+34+v/vePr/7zk6/+95Oz/uuTt/73l7f++5e3/teXt/7/l 7f/B5u3/t+Xu/8Lm7f/C5+7/uubv/8Tm7f/B5u7/t+bu/8Pn7/+95u//wOfu/8fo7//L6O7/yejv/8jp 8P/D6O//z+nv/8fp7//T6/D/yOnv/83p8P/D6PD/zOnv/83q8P/Q6/H/yenw/8np8P/D6fD/zurw/83q 8P/N6vD/z+nv/8/p7//S6O3/0eju/8/p7//S6e7/0unu/8/o7v/T4ej/283c/9vE1f/ib7L/5G6v/+Rt qv/ld6//5YCz/+eCsP/mcaL/5Y62/+WTuf/e6++D3Ovv/9vq7v/Y6u7/1erv/9Tq7//R6u//0unv/9Dp 7v/M6O//y+ju/8zo7v/N6O3/y+ju/8Xo7//L6O7/xOjv/8jo7//K6O7/x+fu/8Ho7//I5+7/xOfu/8Xo 7//C6O//xOjv/8Tn7v/I5+3/vefv/8Pn7v/E5+7/webu/7/n7v+/5u7/w+bt/8Dm7f/A5u3/w+bt/7rm 7v+65u7/vubu/7rm7v+75u7/vubt/73l7f+45e7/v+bt/73m7f++5u3/uOXt/7fl7f+25O3/v+Ts/7fk 7f+05e7/uuXt/7jk7f+35O3/sOTt/7zl7f+45O3/u+Ts/7Xk7f+35e3/teXu/7nl7f+y5O3/u+Xt/7jk 7P+/5ev/w+Xs/7Hj7f/C5u7/v+bu/7zm7v+55u7/xebt/8Tn7v+65u//xuju/7vm7v+65u//wefv/8Dn 7//B6O//zOrw/8To7//Q6u//yejv/8vo7//S6vD/z+rw/8zp8P/Q6u//y+nv/8zq8P/K6vD/0Ovx/8zq 8P/Q6vD/0Ovx/8np8P/N6vD/zerw/8rp8P/N6/D/x+rx/8jq8f/Q6u//zuju/9Ho7f/P6O//z+ju/8/o 7v/O6O7/z+bt/9Xc5P/bzNr/3bDO/+Nmsv/kaqn/5W6w/+Z4r//miLT/6Imz/+iKtP/njrf/5oWx/9/r 7ojb6+//2uru/9jq7v/W6u//0unv/87q8P/Q6e//zunv/87o7v/I6O//yuju/87o7f/I6O7/v+jw/8jp 7//I6e//yOjv/8ro7v/H6O7/w+fv/8nn7f/G5+7/xOjv/8Lo7//C5+//wejv/8Xn7v/B5+7/xuft/77m 7v/E5+7/webu/8Tm7f++5e3/vebu/8Xm7f/B5u3/uObu/77m7v+65u7/uubu/7zm7v+65e3/v+Xt/7nk 7f+15e7/seXu/7Hl7/+z5e7/uOTt/7rk7P+65Oz/teXt/7Xl7f+y5O3/tuTt/7Tk7f+25e3/u+bt/7jk 7f+35e3/teXu/7Pl7v+55e7/s+Xu/7Xl7v+25e3/t+Xu/7bl7f+95e3/wObt/7/m7v+35u7/uObv/7rm 7/++5e7/xOfv/8np7/+55u7/zOnv/8Ho8P/B6O//yujv/8rp7//C6PD/vejv/8Ho8P/T6/D/0evw/8jq 8f/J6fD/xenw/8zp7//R6vD/0urw/8vq8f/J6vH/xunw/8/q8P/J6vH/yOrx/87p8P/P6vD/zOrx/8jq 8P/N6fD/zenw/8vp7//M5+3/yufu/8zn7v/O5+3/zebs/9Dj6f/R3uf/2drh/9nK2f/gi77/5Fuv/+Vf qv/kdK//522p/+h2qv/ohbH/6Iix/+eGsf/ogKz/3uvue9vr7//a6+//2Oru/9Xq7//S6u//z+rv/8/q 7//Q6e7/z+nu/83o7//K6e//yejv/8fp7//H6fD/x+jv/8jo7//H6O//yeju/8ro7v/I5+7/xefu/8Dn 7//C5+//xeju/8Hn7v/F5+7/wufv/77n7//C5+7/xOfu/7vm7//E5+7/xuXs/8Hl7f/A5u7/u+bu/7rm 7v+/5+7/vebu/7zm7v+85e7/vOXt/7Xl7v/C5Oz/v+Ts/7nk7f+05O7/uuXt/7vk7f+25O3/uuTt/7nk 7P+z5O3/s+Tt/7Pk7v+35O3/tOTt/7bk7f+25e7/seTu/7rl7v+z5e7/tOXu/7fl7v+35e7/seXu/7Xl 7v+y5O3/veXu/7rl7f/A5+7/v+bu/8Po7/+65u//wOfu/83o7f/G6O//w+jv/8Do7//B5+//x+nw/7/n 7//K6e//yOjv/8fp8P/J6PD/zenv/8Xp8P/K6vD/yOnw/8Xo8P/P6vD/zurw/8rq8f/H6fD/zOvx/8Xp 8P/O6vD/y+nw/83p8P/J6fD/zenv/83p8P/M6O//zOjv/8bo8P/B5+//yebt/8vl7f/J5e3/y+Pr/8rf 6f/N3ub/0tvk/9XT3v/Zz9v/36rN/+Rgrv/kRKv/5UKj/+WCs//mea//53mq/+eOtv/pfan/6H+r/+mA rP/d6+5p3Ovv/9rr7//Z6+//1+vv/9Pq7//R6e//z+rv/8zp7//Q6e7/zuju/87p7//L6O//yOnv/8np 7//N6O7/yuju/8fo7v/E6O7/xOjv/8fn7v/G5+7/wefv/8Pn7//A5+//vOfv/8Pn7//F5+7/wOfu/8bm 7f+75u7/wOfv/8Hn7//G5uz/w+Xs/8Dm7v+75u7/u+bu/7vm7v+65u7/tubu/7rl7v+75e3/uuXt/7jk 7f+85e3/vOXt/7jk7f+35O3/ueTt/7rk7P+35O3/tOTt/7Hk7v+55O3/vOTt/7vk7f+65e3/ueTt/7Pk 7f+y5O7/uOXu/7bl7v+45u//uOXu/7zm7v+25e7/wObu/8Tm7f/C5e3/wObt/7jl7v/E6O7/uubv/8Dn 7v/F6O//xeju/8fp7/+95u7/seXv/8Po7//C6fD/yOnw/8jp7//M6e//wejw/8rp8P/G6fD/yenw/8bp 8P/K6vD/zOnv/9Hp8P/H6fD/yurw/9Pq8P/J6fD/zuju/83o7//N6e7/yejv/8zo7//K6O//y+bt/83n 7f/F5+//xuXt/8fl7f/K5ez/yuPq/83d5v/R1eH/ztjj/9LY4P/Xzdv/2bjS/9+Iwv/kLKb/5C+o/+RL rf/lX6z/5HGt/+aCtP/mhLP/54+2/+l9qf/pkLj/6YWv/97r70bc6+//2+vv/9fr8P/V6/D/1evv/9Lq 7//N6e//zenv/8/p7v/P6O7/yeju/8vp7//K6e//y+nv/8/o7v/L6e7/zeju/8Xo7v/K6O7/yOfu/8bn 7v/F5+7/xefu/8bn7v+85+//vufv/8bn7v/A5u7/x+ft/7/m7v++5+//wOfu/7/m7f/D5u3/w+bu/8Hm 7v+35u//u+bu/7zm7v/B5u7/uOXt/7zl7P+35e3/ueXt/7Ll7v+65e3/r+Tt/7Pk7v+15O3/uOTs/7Hj 7f+85O3/ueXt/7Pk7v+75e3/s+Xu/7jl7v+55e7/teTu/7vl7f+55e7/v+bu/7nm7v+45e7/xefu/7vm 7v++5u7/uuXu/8jn7v/A5u7/yOju/8bp7//C5+7/z+ju/8Po7//C6O//v+bu/8fn7v/M5+7/y+ju/8Po 7//D6PD/zenv/8Hn7//C5+7/yejv/8fo7//O6e//yujv/8To8P/I5+//zeft/8To7//E6O//zefu/8fn 7v/Q5ez/zuft/87n7v/N5+7/xufu/8rl7f/M5Oz/yubt/8fk7P/J4+v/xuLq/8jc6P/J2uT/ztPg/9TI 2f/Tz9v/1sjW/9yZx//fSqz/4k+w/+Q2of/kMKj/5Ge0/+RwsP/lhbf/5nyz/+iGs//nibH/6Iqz/+iP t//pi7P/3+zvHNvr7/7b7PD/1+zx/9fr8P/W6/D/0erv/8/q7//P6e//0Orv/8/p7//N6e//yenv/83p 7//L6e//zOrw/8np8P/O6e//x+jv/8jo7v/J5+3/xOfu/8fn7v/J5+7/y+bs/8Hn7v/D5+7/w+fv/8Ln 7//I5+7/wOfu/8Po7v/B5+7/w+bt/77m7v+45u//vebu/7rm7v+95u7/vebu/73l7f/A5e3/vuXt/7rl 7f+25e7/tuXu/7nk7f+45O3/t+Tt/7fk7f+w5O3/sOPt/7Tk7f+05O3/tOTu/6/k7v++5u7/uOXu/7vm 7/++5u7/uuXt/73l7f+45e3/uebv/8Ho7v+/5+//xunv/8Po7//E5+7/xuju/8Tn7v/E6O//wufv/8no 7//S6u//yejv/8Dn7//L6O7/x+fu/8ro7v/D5+7/y+jv/8Dn7v/G5u3/zujt/8nm7f/C5+7/y+fu/8Tm 7v/I5u3/xebt/73k7f/H5ev/x+Xs/7zl7v/I5e3/xOTs/8bj6//I5Oz/xOXt/8Xk7P/G5Oz/xOPr/8fi 6//G4er/xuDp/8fa5P/L1eL/zNDd/8/J2f/Wv9T/177R/9Ctzv/daLX/4CWg/+NIpP/jR6r/5kuh/+U4 ov/lb7X/5GKy/+aKt//nbqz/6H+w/+eIsv/pg67/6HOj/+qPt//d6/AG3ezv4dvs8P/Z7PD/1+vw/9Xr 8P/T6u//0erv/9Dp7//P6vD/0Orw/9Dq7//L6e//y+nv/8bp7//H6fD/y+rw/8zq8P/H6e//yeju/8zo 7v/G6O7/xujv/8To7//F5u3/v+fu/8Xn7v+/5+//xefv/8Dn7//M6O7/0Oju/8Tn7f/C5u3/wOfu/7/m 7v++5u7/vebu/7zm7v+65u7/webu/7/m7f+75e7/v+bu/7bl7v+25e3/tuTt/73k7P+55Oz/tePt/7rk 7P+64+z/uOTs/7Tj7f+55O3/t+Tu/7zm7v+z5u//u+bu/7vm7//A5+//vObu/73l7f/N6e//wunw/7rn 7//B5+//x+jv/8no7v/J6O7/z+nv/8vp7//R6u//xejv/8jo7v/C5+//x+fv/8jn7v+65u//xubt/8Tm 7f/L5u3/wOXt/8bl7f/B5O3/weTs/8Pj6/+94+z/w+Lq/7/h6f+/4Or/vd/p/8Lf6f+84Or/v9/p/8Lg 6P/B3+n/xd/o/8Lh6v/C4er/xeDp/8Hg6f/C3+j/xdzl/8nV4v/MzNv/0MHX/9S80//SutH/zpXH/9WH uf/ecrL/3kil/+E+nv/hJ6D/4leo/+Rbrf/mQKT/5zSl/+Zosv/kcLX/52un/+diqv/mY6T/6JO5/+mC rv/qhrD/6omz/wAAAADd7PCo2uzw/9ns8f/X7PD/1evw/9Xr8P/V6+//0+rv/9Lq8P/P6vD/z+rw/9Dq 7//Q6u//yunv/83p7//S6vD/0Orv/8vp7//H6O//yOnv/8jp7//D6O//xejw/83p7v/A6O//vejv/73o 8P/F6O//vufv/8Hm7f+65e3/w+bt/8bn7v/H5+7/xebu/8Lm7v/D5+7/t+Xu/73m7v+65u7/uObu/7zm 7v+95u7/vOXu/73l7f+95Oz/ruPt/7bk7f+z4+3/t+Tt/73k7P+25O3/u+Tt/7fk7v+95u7/u+bu/7bm 7/+65u//vufu/7vn8P/O6e//yefu/8Hn7/+25u//wujw/8np8P/K6fD/yunv/8vq7//D6e//x+nw/8jo 7//K6O//x+fv/8Hn7//L5+7/wubt/8fn7v/F5u3/weTt/8Ll7P/A5Oz/vuLr/7ri6//D4On/wN7n/7ve 6P+73ef/u9zn/7fc5/+32+f/udrl/7Ha5v+32eT/udjj/7rY5P+62eX/vNrl/7zb5P/B2uP/wdTf/8fN 3P+/0N//z8LX/8nE1//Oqcn/0pfA/9Vxtv/bT6H/33Ws/+J3sv/hQZn/4TGi/+NKp//jXqv/5GOm/+ZS rv/nTaf/6DOf/+Zfsf/oW6L/53ax/+d9rf/ojbX/6n+r/+p4pv/rfa3/AAAAANzs717b7PD/2ezx/9fr 8f/X6/D/z+vx/9Xr8P/U6/D/0uvw/9Dr8P/Q6vD/0Orv/9Dp7//T6u//z+nu/8To7v/H6O//yOjv/8fn 7//D6e//xunv/8Tp8P/F6fD/xenw/8To7//B6O//x+jv/8Ho7/+35e7/kd/q/4bc6P+v4uv/yebt/8jm 7f/F5u3/vebu/77n7v+75u7/vuXt/7vl7v+25e7/vObu/7zn7v++5u7/v+bt/8Tm7f+15O3/wOXs/7jl 7f+95u7/vObu/7fm7v+75u7/ueXu/8Xo7/+65u//uebv/8Hn7v/B5+//wOfv/7zn7//J6e//yOjv/8rp 7//O6vD/wefw/8vq8P/F6O//v+jv/7/n7//K6O7/x+jv/8/o7v/N6O7/wObu/8Tl7f/J5uz/webt/8Pl 7P+94uz/teHr/77g6P+74On/td7q/7bd5/+42+b/r9rm/7PY4/+41uH/sdPi/7rP3v+0ytv/ssPY/7S8 1f+7vtX/uL7V/7i61P+7vdP/usXW/7280f/OocL/zp3D/8yexv/TjMH/0Ya9/9h1rv/bUJn/31id/+NM m//hR5f/4V2m/+BVo//iVKH/5Eig/+RPqP/kXav/5kOm/+dcof/naa3/53+u/+d5qf/nirT/54av/+eR t//qhK3/6mea/+uTuf9CR0cA2+zxEdzs8Ova7PD/2Ovw/9bs8f/S7PH/0ezx/9Lr8f/T6/D/0+vw/9Lq 8P/R6vD/0uvw/9br8P+75u3/h97p/63i6//J6e//z+nv/8rp8P/M6vD/xenw/8Lp8f/E6fH/yOrx/8fp 8P/E6O//v+fv/63j7f9By+D/Ksrf/0XM4P+P3un/uuXt/9Ho7f/H5u3/wOfu/8nn7v/I5+7/w+fu/8Hm 7v++5+7/vOfv/8Po7//F6O//xefu/7/l7f/F5u3/v+fu/8Dn7v+85u7/wufv/7vn7v+75u//vefv/7rm 7//J6O//zurv/83q8P/W6+//yOrw/8jp8P/L6e//yenw/8nq8P/L6fD/vejw/8fp7//I5+7/yefu/8ro 7//G5+7/x+fu/77m7v/G5u3/y+Xr/8Lj6/+34+z/wOHp/7jd6P+83Ob/s93o/7Tc5v+x2eb/s9Lh/7jI 2v+zxtn/wLjR/8Cnzv+/mcn/zY69/9WTuv/Ng7D/0oey/9eNtv/ShrH/03up/9CBsP/Ph7X/zGqj/8tw pv/Obqn/1FGa/9k8jf/dX5f/202S/99poP/jSZX/5SB8/+Q1jf/iPpH/4kOg/+VAmv/oM5L/5mCm/+Vg rP/mXqv/51Cl/+ZjrP/mi7T/5YS0/+eLsf/oiLD/6Iy1/+l5pP/ph7H/6oew/wAAAAAAAAAA2+3wh9rs 8P/Z7PD/1uzx/9bs8f/T7PH/0+vx/9Ps8P/P7PL/0+vw/9Pr8P/U6/H/v+jw/2/c5/8tz+H/hNjl/7rm 7v/P6/D/zurw/73p8P/G6fH/yOnw/8Tp8P/J6vH/wunw/8zp7//K6e//tuTt/0jL3/8Zv9j/GL3W/ybB 2P9k1eT/nODr/7nk7f+95u7/w+bu/7rm7//C5+//wObu/73n7//B6O//uubv/7/o7//E6O//xufu/8Pm 7f+35e7/t+Xu/8jo7v/H6fD/vujw/87q8P/A6O//xefv/87p7//M6/D/wenw/87r8P+96PD/yunw/8rq 8P/K6vD/xunv/8Xo7//C5/D/zOnv/8bn7v/J5+3/xefu/8Pn7v+85e7/vOXt/8Ll7P+84uv/wODq/7bd 6P+43Ob/uNrl/7fY4/+20+D/scfc/7utz/+8kcD/yoS2/9OMt//Ve63/3YCv/9x2p//cXpf/3XCi/9t0 pf/be6r/3ISv/9x0pP/chbH/3Hmo/9xpn//aZZz/2GGW/9NQjf/YM4P/2lCR/9xUj//caqD/3mif/+Nh nv/mM4X/5UGR/+Jop//jc6z/5j+Z/+dsov/nXaT/51Cg/+d7q//mX6T/53Op/+WMtP/ljbP/54Ss/+eE rv/oha//6X+q/+mIsf/qgq7/AAAAACgqKwDa7fEY2u3x8dns8P/Y7PH/1+3y/9bs8f/V7PH/0ezy/9Ps 8f/S6/D/1evw/8zq7/+I4Or/ONDh/zLN3/9y1OP/uOXu/8zq8P/N6vD/yOnw/8Xp8P/I6vD/x+rw/8Xp 8P/G6fD/zenv/8jp8P/J6O7/c9Pj/zLG2/8kwdn/FbbT/y7H2/87zuD/idnm/7nj7P/S5+3/uObv/7zn 7/+75u//vebu/7bm7/+/6O//vOfv/7rn7//G6O//zejt/8Xm7v/L6O//xufv/8Xp7//B6PD/y+rx/8vq 8P/T6vD/zunv/8fq8P/A6PD/yurx/7rn7//P6fD/x+rw/8Tp8P/B6O//zunv/8vo7/+95u//yufu/8Xm 7v+95+//u+Xt/8Hj7P+64+z/uuHr/7rf6f+y3ef/t9rl/7LY5P+1zd7/sbjU/8WWvf/Leqn/2IGw/9hy o//ZfKr/23Ok/95kmP/gbKD/4WSc/+Frnv/hZZj/4HOk/958qv/ee6r/332r/995qf/eeqn/3nSl/+B3 qP/dXpX/2mCX/9dTj//YU4//3W+k/91Tkv/gb6H/41SW/+ZHjP/lUJH/4m6o/+R6qf/mdKf/5nyo/+dy p//pYJb/6HKi/+eDrv/nha3/5pC1/+SHrv/lhKz/5oaw/+iLs//og67/6Iuz/+iGsP8AAAAAAAAAAAAA AADb7fGN2+3w/9rt8f/W7fL/1e3y/9fs8f/U7fL/0ezy/9Ts8f/W6/H/mOHr/znQ4f8wzN7/Nsrd/2HQ 4f/I5+7/0+vw/9Dr8f/N6vD/yenv/8fp8P/I6vH/x+nw/8Tp8P/I6fD/yurw/8zp7/+04ev/U8nd/y/G 2/8mwdj/Ib7W/x691v84yNz/jdfl/8nm7f+55u//wOfv/7nm7v+85u7/tObv/8Dn7/+45u//vufv/7/m 7//E5u7/yejv/8Xo7//X7PD/wunw/87r8P/L6vH/xOrw/8rp7//T6u//0uvw/8jq8P/J6vH/zenw/9Dq 8P/B6PD/w+jv/8jo7v/O5+3/x+ju/8Dn7//H5u3/ueTt/77i6/++4ev/uuHr/7vh6v+23uj/sNrl/7rV 3/+8x9j/v6TI/82Quv/TdKX/2m2e/9xZjf/fdaX/3l+V/957q//ffKv/4nOl/+Nkmf/jYpb/4YKv/+Jr n//hdKX/4Hyr/9+Arf/ffav/34iy/96Brv/egq7/32ad/992p//fZ53/21+X/9hIh//cWJT/4DZ//+F1 pv/jXpn/5VaX/+VVlv/kfK3/6FyP/+Z0ov/kha//5Yav/+d+qf/nfqn/5YWu/+d2ov/mf6r/5YGs/+aI r//lgar/53+q/+eGsP/niLH/5421/wAAAAAAAAAAdYCHANzs8BHb7fHl2u3x/9nu8v/X7fL/1+3y/9Lt 8v/S7fL/1Ozx/9Pr8f913Of/M83f/z7N3/8+xNv/ndzn/8jn7//U6vD/yuvx/9Lr8P/R6e//xujv/8rp 8P/L6fD/xOnv/8zp7//G6fD/zurw/83o7/+14Or/iNTj/27L3v9kzd7/T8nc/1DH2/9Vzd//tuHr/73m 7v+/5+//yuju/77l7f+/5+//xOnw/8Po7//G6O//yunw/8/p7//J6O//x+nw/8bp8P/F6PD/vujw/8vq 8P/F6vD/wujv/9jr7//C6PD/yOrw/8Ho8P/R6vD/y+nv/8fo7//J5+7/yOfu/8fo7v/B5+//veXu/8jk 6//H4un/x+Hp/8Xh6f+33un/tdjl/7bT3/+6uc//zJq6/9J/rf/YVo7/2mac/911o//ec6L/4Gud/+Ji mv/iXJP/4nuq/+F4qP/idab/42Wa/+JvoP/hcKT/4Xmp/+Fuof/geqr/4IWw/+CCr//eeaj/34ax/957 qf/fe6n/4Huq/+B4qf/gZp3/3GKZ/9tfmP/gWJP/4leO/+JvoP/kc6b/5W+i/+R/rv/oVZH/5Xej/+WD rf/kh7D/6HSi/+d6p//mga3/53qm/+d9qf/ngaz/5n6p/+WNtP/mjbP/5oOt/+WIsP/nkrj/AAAAAAAA AAAAAAAAAAAAANnt8Vfa7fL/2u7y/9fu8//X7fL/1u3y/9Xt8v/W7fL/x+rw/3Hc6P9Rz+D/eNXj/6Lc 5/++5Oz/1Orw/9br7//B6fD/y+rw/8zq8P/L6e//xOnw/8rq8P/L6vD/zOrw/8fp8P/O6vD/yuju/9Ho 7v/J5uz/t+Ps/8Lk6/+44ur/tOHq/5jZ5f+74+v/w+fu/83p7//F5+7/zOjv/8jo7//G6fD/xunw/7zo 8P/I6vD/zevw/8jp8P/I6fD/v+jv/8To7//L6fD/xejw/8Hn7/+65u//yenv/8bo7//A6O//vefv/87p 7/+85+//zejv/8/o7v/G5u7/w+bt/7zk7f+84uv/v+Hp/8Dg6f+13un/t9zm/7bV4f+7ttP/vJS//8xo nP/YaZz/3V2R/+BWjf/gWo//33Kj/992pv/jb6L/42+i/+Rdkf/jY5r/4mGY/+NnnP/ja5//4n+s/+J0 pP/ifKv/4nGi/+F3p//hfqz/4H+s/+CCrv/ghrH/4IKv/99/rf/ghbD/4HWm/+F3qP/hbKH/3mmd/91f l//hXpX/42GX/+Vwov/lapz/5X6r/+Zyov/mcqD/5Hyn/+WGsP/nfqn/53Cg/+d3pP/na5z/53uo/+Zt m//mgq3/5YSu/+aKsP/ngaz/55S5/+eHrv8AAAAAAAAAAAAAAAAAAAAA2/DyAtnt8qvZ7fL/2e3y/9nt 8v/W7fL/1u3y/9Xt8v/R6/H/oeHq/6/h6v/G5uz/0enu/9fr8P/W6/H/0+vw/87q8P/P6/H/0ezx/9Lr 8P/K6e//zOrw/8zr8f/K6vH/wujw/8bq8P/O6u//zunv/9Pp7v/Q6vD/1evw/8vq8P/M6fD/1Ovv/83p 7//O6e//yunv/8vq8P/I6vD/1uzx/8Po8P/B6fD/yurx/8Tp8P+65/D/uufv/9Pq7//F6PD/yunv/8Dm 7v/J6fD/yerw/8rp8P/J6e//zunv/8vo7//L6e//zenv/8To7//L6O7/x+bu/8fm7f/D5Oz/w+Lq/8Th 6f+/3+j/wt7m/7TT4v+0vdb/xpS+/9Bqn//XdKX/23Oj/955qP/hZ5r/40uC/+NlmP/iR4L/4nKk/+Rp nf/kYZf/5Wia/+Vjmv/lZ5n/5XKi/+Nrnv/jZJv/4n2s/+JonP/hcaT/4oGv/+Nnnf/ic6X/4YOw/+F1 pf/hgKz/4Xqp/9+Crv/hgK7/4nWm/+Jnn//ibqL/3Web/+E5ef/jaZz/5W2d/+Vvnv/kfKf/52SU/+dr nf/mfqr/5Xin/+hQhf/mb6D/5nil/+dfkv/ngqz/52GS/+Z7p//lfqr/5nai/+eCrf/mfaj/54mx/wAA AAAAAAAAAAAAAAAAAACAi4QA2ezxGNrt8uTa7vL/2u7y/9ju8v/V7fL/2O7y/9ft8f/P6/H/0+vw/9fs 8f/X7PH/2Ozx/9bs8f/S7PH/y+rw/9Hr8P/Q7PH/zuvx/87r8f/L6/H/v+rx/8bq8f/M6fD/w+nw/8jp 8P/L6e//zurv/8/p7//J6e//xunw/8vq8P/Q6/D/wejw/9Hr8f/U7PD/0uzx/8Tp8P/O6/H/zOrx/83r 8f/F6vH/yerw/8fq8f/T7PH/z+rw/8Tp8P/N6vD/1Ovw/9Ps8P/B6vH/zurx/8Xp8P/M6vD/zunv/8Pp 8P/N6e//v+fv/8bn7f/J5u3/wuTt/7/j7P/A4er/t9zo/7jU4v+6utP/uZfA/8x6p//Wc6P/21+S/9xp m//dapz/3m6i/+B0pP/jXpP/5F6T/+RpnP/kbqH/5EiC/+Rzo//kdKX/5WGV/+RjmP/jeKj/5GCV/+Nr nf/ieKj/4lWM/+GBrv/ifaz/5IGt/+Non//kfKv/43mp/+N+rf/jga7/44Wx/+OArP/jeqj/5HWm/+R6 qv/id6f/32CT/+Nzo//kWZD/5Xim/+R4pP/ldJ//5Xej/+RmmP/lfKf/52GU/+V/rP/mcqH/5naj/+Z9 qf/lfqr/5n6o/+RrnP/kibH/54mx/+eLs//okbj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA39/oi9vu 8v/Z7vL/2e7z/9nt8v/Z7fL/1e7y/9ju8v/U7PL/1Ozy/9Ts8f/T6/D/0u3x/9Pt8v/S6/H/0evw/8rr 8f/L6/H/zOvx/87r8f/M7PL/0Ovx/9Tr8P/N6/H/zevx/9Hr8P/S6/D/zOnv/8zp8P/H6fD/xOnw/9Ts 8P/J6vD/zuvx/9Dr8f/S7PH/y+vx/9ru8v/Y7fH/2O3y/9Xt8f/K6vD/y+rw/9Ps8f/U7fL/0+zx/9Hr 8P/O6/D/zuzx/8Pr8f/P7PH/yurw/8Ln7//G6O//wejw/8ro7//D5u3/veXt/8Dj6//F4+v/wuHp/7fa 5f+2xtn/xJS7/8ltpP/UWY7/2XKg/9t0pf/eX5T/3mue/957qv/eZ5z/4HWn/+Nrnv/jW5D/42+h/+Rr n//lUIf/5GOY/+Rnm//kW5D/5E+H/+N8q//jc6L/4nqp/+J7qf/kaZz/43ys/+N1pv/lYpv/5X6t/+Z+ rf/lfqz/5Xao/+WDsf/kgrD/5Xip/+WBrv/kear/5Xao/+V7qv/hdqX/41SJ/+Nxn//keqf/436q/+KB rf/jeaX/43Si/+VunP/mcKH/5nai/+Vbjv/kgq3/5mqc/+Vtn//kgKv/5HOg/+SErv/ne6j/54aw/+aT uP8AAAAAAAAAAAAAAAAAAAAAAAAAAOW9zgbots7Z4N3n/9ru8//Z7vP/1+7z/9vu8v/Y7fL/1+7y/9bu 8//T7fL/1Ozy/9Ts8f/T7PH/y+zy/9Xt8v/U7fL/0+zy/9bt8f/N6/H/1O3y/8br8f/c7vH/0evx/83r 8f/P7PL/yOvx/9bs8f/O6e//zenv/8zp8P/S6/D/2O3x/8Pp8f/P6/H/1+3x/9bt8v/Y7fL/1+7y/9Ht 8v/N6/H/0ezx/9ru8v/X7fH/2O3x/8vs8v/S7fL/2O3x/9nt8v/L6/H/wenx/8vr8P/N6vD/y+nv/8fo 7//I6O//vuXu/7zk7f/J5Ov/wOHq/8Th6f/A1+L/xa7J/9CFsP/Td6b/2nuo/9tunv/baJv/3Gqc/95o mv/fa57/32md/+Fzpf/iap3/5FSM/+VrnP/jYpf/5FeO/+Rllv/kX5X/43em/+R1pP/kd6b/42ic/+Jl mf/jdKb/436s/+Vjmf/lbaL/5nKm/+drn//meqz/52ig/+dwpP/od6n/6Ye3/+iHtP/oeqr/6Y25/+eI tf/mg7H/53qp/+N5qP/gY5P/4XCf/+GBrP/igaz/4n+r/+N8qf/igKz/43+q/+Ztnf/mZJf/5HGe/+WA q//me6n/5YCq/+Vtnv/keKX/5IGr/+dunv/ngaz/5YGt/wAAAAAAAAAAAAAAAAAAAAAAAAAA6LHLQuiv yv/nrMn/3+Lq/9vv8//Z7vP/2u7z/9nt8v/Y7fL/1e7z/9fu8//a7fH/2O3x/9jt8f/V7fL/1+3y/9Tt 8v/a7vP/1uzx/9Xs8v/Y7vL/0ezy/9ju8v/S7PL/2e3x/87s8v/P7PL/zuzx/9Lr8P/Q6/D/1ezx/9nt 8f/Q6/H/1ezx/9ft8f/O6/H/1O3y/9ft8v/O7PL/1O3y/9jt8v/d7vL/zezy/8zr8f/b7vL/zezy/8Pq 8f/X7PD/zurx/8Lp8f/L6vH/w+nw/8fp8P/L6e//xefv/77n7v/F5Ov/xuLq/8Pg6v/G3uf/xsHV/8SB qv/SVoz/2nup/9t3p//cXJH/3m6f/954p//fga7/4HOk/+Fsnf/jbKD/43ip/+VonP/mW5D/5VeP/+Rh lP/kcaP/5Hmp/+Rpm//kcqL/5Gue/+R5qf/kfa3/5XOk/+RXj//ngrH/52yh/+d0p//peKr/6ou3/+qI tv/qjbj/65vC/+yYv//rkbr/65e8/+uYvv/roMT/6pG5/+mVvP/ojbf/5n+s/+Bxnv/hc6H/4YGs/+J1 of/jfar/4num/+J8qv/ifKr/5Wyb/+Z3pP/kc6D/5XOi/+Vyov/leqb/5XSi/+Rsm//je6f/5oCq/+Z9 qv/mlrv/AAAAAAAAAAAAAAAAAAAAAAAAAADossuf6KrH/+eewf/mpsb/3uTr/9vu8v/a7/P/2u7y/9nu 8v/a7vL/1u7z/9ru8//Y7fL/2+7y/9nt8f/X7vL/2O7z/9bu8//c7vP/2O7y/9Lt8//Y7vP/2u7z/9Xt 8//i7/P/3O/z/9Xu8//W7vP/1e7y/9Ds8f/V7PL/0+zx/9bt8v/U7fL/0+zx/93u8v/V7PH/yerx/9zv 8v/J6/L/1u3y/9fu8v/X7fL/2e7y/9Hs8v/O7PL/0+zy/9Ls8f/Y7fH/0Ovw/9Dq7//L6e//w+jv/87p 7v/J5+7/w+Xt/8fk7P/E4Or/wMvc/8KuyP/Rf63/2mya/95ejf/dcqT/32qf/+Fzov/gYJj/4GOZ/+Fn nv/jb6P/5GKY/+U4eP/lT4r/52SZ/+dSjP/nYZb/5nmp/+VXj//lear/5V6W/+dqnf/ndaX/54Kx/+dy pv/ofq3/6G+h/+qMuf/qear/6nut/+yZwP/sibX/65O5/+yavf/slbn/7J2+/+uPr//pjKr/6Zi2/+eU sf/leqP/54eu/+mOtf/nh7H/44Cs/99tnP/hf6n/43yp/+OCr//kZ5j/42ma/+Jzov/lb6H/5GmZ/+J5 pv/ke6f/5XCd/+R5pv/kfaj/43ej/+N4pf/lcKD/5oOs/+WKsv8AAAAAAAAAAAAAAAAAAAAA6LLLC+iu yenprMj/6aPF/+ecwP/lo8P/3ePr/9vu8v/Z7vP/2e7y/9fu8//Y7vP/2O7z/9ju8//X7vP/2O/0/9rv 9P/c7/T/3e/z/93w8//c7/P/2O/z/9ru8//Z7vP/2u/0/93v8//c7/P/1u7z/9zw8//M7PL/4vDz/9ju 8//c7/P/3vDz/9fu8//b7/P/2e/y/9ju8v/U7fL/2O7y/8vs8v/W7vL/z+3z/9Ht8v/X7vP/1e3y/8br 8v/T7PH/z+rx/8rq8f/H6fD/xenw/8To7//B6O//xufu/8bl7f+74uz/wd3o/8rC2f/RhrX/1F6R/9tq m//ecaD/4X2s/+N0pf/jaJ7/5HWo/+V1p//lUYz/5m2i/+Vrn//nfq3/6E6G/+hsnf/pYpj/6XCj/+hS jP/odKb/6IGt/+iFsv/pkLn/6nel/+psnf/qfKn/6nup/+uSt//rhbD/7JG4/+uBqf/rhqv/66C5/+mc tf/pr77/6cHM/+jHzv/o0tb/5tTZ/+XV2f/j09j/3snP/9Orvf+/WYr/wzxk/+V4o//khLD/4Haj/+J1 ov/jbZ3/5Xel/+VjlP/japr/4nOj/+Rtn//kZpf/43up/+R0of/kdaL/5Gmc/+Rwnv/jhK//43Oj/+R9 qf/lh6//5Y20/wAAAAAAAAAAAAAAAAAAAADpsMtH6q/K/+msyf/pn8H/5p/B/+aSuv/mmbz/3uLr/9vu 8v/a7vP/2u7y/9vu8v/b7/P/2+/z/9rv8//Y7/P/2O/0/9jv8//c8PT/1+/z/9jv8//T7vP/1+7z/9zv 9P/c8PT/3e/0/9zw9P/W7/P/2/D0/9vw9P/e8PT/3vD0/9nv8//f8PT/2u/z/9zv9P/W7vP/z+3z/87t 8//Y7/P/0+7y/9Pu8//J7PL/1+3z/9Tt8v/T7fL/zOzx/9Ts8f/Q6/H/0ezw/8vq8P/J6fD/zuju/8bn 7v/I5e3/xuXs/8rf6f/Rwtj/3Im3/+GLuP/ib6D/42SX/+R7qf/ka6H/526f/+dXkf/piLT/52+j/+mA rf/nbaH/6H6r/+p+q//pa5z/6pe+/+qBrf/rfKn/6maW/+tzn//rdqP/6m6b/+uHrP/qe5//6YGg/+mW q//pq7v/6LbE/+jBy//oztX/6Nbb/+ja3f/p3d//6d/h/+rh4//q4uT/6uPk/+rk5P/q5OT/6uPk/+nh 4v/m29z/3crP/8OCn/+lGUL/22qT/+SKs//hhK7/4lyL/+VtnP/mZpf/5Wmb/+N1o//ieaf/5meY/+Vt nf/jeab/5Guc/+RyoP/mfan/5G6d/+OCrf/jdKT/5Xej/+WErv/llbj/AAAAAAAAAAAAAAAAAAAAAOy6 0ZfrrMn/6qPE/+mgwv/mnMH/55vA/+iSu//mmL7/4Nvl/9vu8v/c7/L/2u7y/9vv8//a7/P/2+/z/93v 8//d7/P/2O/z/9vv8//U7vT/1+/0/9bu8//Y7/T/2e7z/9bv8//a8PT/2/D0/9Tu8//V7vP/1O70/9vw 9P/g8PX/2+/z/9zw9P/X7vP/4PD0/9ju8//d8PP/1u7z/9bv9P/W7vP/0O3z/8/t8//T7PH/0+3y/87s 8f/M6/H/z+rw/87q8P/Q6e//wujv/8fn7v/I5u3/xuXt/8nk7P/K4er/17nU/+B+qf/ljrX/6JK7/+eK sv/pirP/54Sv/+l4pP/pcaL/6mKU/+p7pf/qbJ7/64Kr/+lynf/peZ7/6YOh/+mOq//opb7/6KvA/+ev v//nt8L/5r/K/+bJ0P/n1Nr/5trf/+fd4f/o3+L/6eHk/+ni5P/p4+T/6uTl/+rk5f/r5eb/6+bm/+vn 5//s6Oj/7Ojo/+zo6f/s6On/7Ojo/+zo6P/s6Oj/6+bm/+nh4P/h09T/y5m3/6sxYv/hhKr/5Y20/+N/ q//hbpv/5Wyb/+Vgkv/maZr/42CU/+V2pf/mYJP/5G6d/+R2pf/kc6H/5XOi/+ZjmP/lXpL/5HCg/+R8 qP/ld6X/5YSs/+aFr/8AAAAAAAAAAAAAAAAAAAAA7a/MzO2ryv/tp8f/66jI/+igxf/nmcD/6pS//+uT vv/pmcD/5cfb/93r8P/a7/P/2+/z/93v8//b7/P/2u/0/93v8//d7/P/2+/z/97v8//b7/P/3vD0/9rw 9P/b8PT/3fD0/9jw9P/c8PX/2/D0/+Lw9P/h8PP/2e/z/9vv9P/c8PT/3/H1/97x9P/j8fT/1+/0/9Lu 9P/Z7/T/0+7z/9nv8//V7vP/0u7z/9ft8v/S7PH/y+zx/87r8f/R6/D/zenv/8vo7v+/5u7/xOXt/73j 7P/H5e3/yOHq/9XG2P/ggKb/31SG/95zl//bYIn/1mWI/9Bpif/IXX3/vE5t/7FEZP+pOlb/nzdO/4sp P/96Kz3/u5qx/97P0v/j2t7/5t3g/+ff4f/o4eP/6ePk/+nl5v/q5eb/6ubn/+rn6P/r6Oj/6+jo/+vo 6P/s6en/7Onp/+zp6f/s6er/7Orq/+zq6v/t6ur/7erq/+3r6v/t6+v/7evr/+3r6//t6+r/7erq/+zp 6f/r5+f/6eHi/+HQ1f/Lm7r/zYWr/+aStP/mi7P/44Ks/+Jtm//kXo//5Wub/+VhlP/kYJL/5lKJ/+Vu nv/jcqH/5Gqb/+ZrnP/nbJ3/52OW/+Vwn//lapv/5Xum/+Z1pP/ncqD/54Ss/wAAAAAAAAAAAAAAAAAA AADusMqL7q/L/+6tyv/trsz/7K3M/+ykx//tl7//7Z/E/+yZvv/rncP/6KXE/+DZ5P/a7/P/2u/z/9vv 8//b7/P/2+/z/9zv8//a7/P/2u/z/9/w9P/c8PT/3vH1/97w9P/h8fX/3/H1/+Dx9f/g8fX/5fL1/+Px 9P/c7/T/4PH0/9nw9f/U7/X/3fH1/9zw9P/Z7/T/1u/0/9vv8//e7/P/2O70/9rv8//P7vP/1e3y/8vr 8f/P6vD/xunw/8To7//K5+3/xOXs/8Xm7f/I5ez/v+Lr/8Pi6//I4On/qb3H/1FIVP9BKC//NyYr/ykm J/8dJiX/HCcm/yAoKP8mKir/Kisr/ywrK/8rKir/Kigo/yYiIv9fU2X/2dLZ/+fj4//p5ub/6+fn/+vo 6f/r6er/7Orq/+zr6//s6+v/7evr/+3r6//t6+v/7evr/+3r6//t7Oz/7ezs/+3s7P/t7Oz/7ezs/+3s 7P/t7Oz/7ezs/+3s7P/t7Oz/7ezs/+3r6//t6ur/7Ojp/+vl5v/n3N//3cXP/9anv//mqcT/53+q/+aM tf/kgKv/4HOg/+N4pP/lZpX/5Wib/+R+q//mWo3/5Wyd/+Rsnf/lZpj/5lqP/+Zkl//lbJz/5XSj/+ZY jv/lcqD/5nqn/+hqmf/ndKH/AAAAAAAAAAAAAAAAIR0eAO6yxgbvscdB77zPnOq+zv/hm7H/4omm/+N8 oP/kjqn/436g/+KCov/cdJb/0nGT/8KaqP/G3OL/2u7y/9vv8//c7/P/3O/z/93v8//b7/P/3/Dz/9zv 8//c8PX/3/H0/9/w9P/g8fX/5fL1/9jw9f/e8fX/5vL1/+fy9f/i8vX/3/H1/9/x9f/c8fX/2vH0/9Pu 9P/Z7vT/3u/z/8/t8//O7vP/0O7z/8ns8v/K7PL/0ezx/8nr8P/O6u//y+bu/83n7f/K5e3/yOTr/8Tj 7P/B4ev/sNHd/3iPnP8uOUP/LDU8/y81OP8xNTf/MTM0/zI0Nf8yNDX/MjM0/zIzM/8yMjP/MjIz/zEy Mv8xMTH/MTAw/ysnJ/+tqbP/6Obn/+vq6v/s6+v/7ezs/+3s7P/t7Oz/7ezs/+3t7f/t7e3/7u3t/+7t 7f/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7Oz/7ezs/+3s7P/t6+z/7evr/+3p 6f/s5uf/6eDh/+PS2f/gvND/5KvF/+ibvf/ojrX/5oiy/+SEr//gcKD/5G+d/+ZelP/lapv/42OY/+R2 pP/kbJ3/5F2S/+N5pv/mbJ3/5VqO/+Nsnf/kcaD/5HCf/+N5pf/lfKf/52qX/+Z/q/8AAAAAAAAAAAAA AAAAAAAAAAAAAAAAAADz8vFJyMXG/1tbW/9LS0v/Q0RE/z09Pf84OTj/MzU0/zAxMf8tLS7/LCst/y80 OP+DmqL/xt7k/9ju8v/b7/P/3vD0/93v8//e7/P/3+/0/97w9P/g8fX/3fH1/+Hx9P/c8PT/1u70/9Xv 9P/X7/T/1+/0/9jv9P/c8PX/3PH1/9fw9P/X7/T/1e7z/9Ds8v/P7PL/0uvx/83s8v/N7PL/y+rw/83p 8P/G6O//x+fu/9Hn7f/P5u3/zeXs/8jk7P/F4uz/wuHr/63I0f9Za3f/LTg9/zE5Pv80OT3/NDk8/zU5 O/81ODv/NTg5/zU3OP80Njf/NDY2/zQ1Nf80NDT/NDQ0/zMzM/8yMjL/MjEx/2Fgaf/i4eX/7Ovq/+3s 7P/t7e3/7u3t/+7u7f/u7u3/7u7t/+7t7f/u7u3/7u7t/+7u7f/u7e7/7u3t/+7t7f/u7e3/7u3t/+7t 7f/u7e3/7u3t/+7t7P/u7Oz/7evs/+3r6//t6en/7Ofn/+rg4v/m1dr/5sPT/+u50v/qlLj/54+0/+eC r//nh7H/5ISu/+Num//kapr/5l+P/+VRh//kcaH/5Gaa/+Zklv/jX5L/5WCR/+Zhlv/lYpT/5HWk/+Ns nP/jcaD/42yb/+RyoP/jeKL/5oWt/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPX09V+ioqH/XFxc/1JS Uv9LS0v/R0dH/0RERP9CQkL/Pz8//z09Pv88PD3/Ozs9/zg6PP8sQEj/ip6m/9Hk7v/Z7vP/2+/z/93v 8//e7/T/3/D0/9/w9P/c7/T/3vD0/9vv9P/k8PT/3u/z/93v8//a7/P/2+/0/9vv9P/U7/P/1e7z/83u 9P/R7PH/0+zx/9Dr8f/Q7fL/0e3y/9Ls8v/U6/D/1erv/9Hn7v/K5+7/z+fs/87l7P/F4uz/yeHr/7/c 6v+NscL/N0hZ/zE9RP81PEL/OD1A/zg7Pv84Oz3/Nzo8/zc5O/83OTr/Njg4/zY3OP82Nzf/NjY3/zY2 Nv81NTb/NDQ1/zMzM/8yMjL/Li0s/8PCy//r6+v/7e3t/+7u7f/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u 7v/u7u7/7u7u/+7u7v/u7u7/7u3u/+7t7f/u7e3/7u3t/+7t7f/u7Oz/7uzs/+3r7P/t6uv/7Onp/+zm 5//q4OL/5tXb/+bD0//rtM3/66XE/+mDrv/ohK//6IOx/+iMtv/kfKj/4WqZ/+Jtnf/kZ5j/5HOk/+R6 p//mYZT/5z96/+RwoP/lTYL/5Gyf/+Rsnf/jYpf/422d/+Nvn//hdaH/4nel/+F/qP/lcZ7/AAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA8fDxdHx8fP9aWlv/UVFR/0xMTP9ISEj/RUVF/0NDQ/9BQUH/Pz9A/z0+ P/88PTz/Ojs8/zU6Pf8lMDr/mqfE/93m7P/g7PH/3u7z/9zu8//d7/P/3vD0/9/w9P/f8PT/3/D0/9/w 9P/d7/P/3e/0/9rv9P/b7/T/3e7z/9ru8//T7fL/0uzy/8/s8v/O7PL/0+zx/9Dr8f/P6/H/z+rw/9Hq 7//V6O7/0uft/8/l7f/R5Ov/0OTs/8ri6//I3en/y9nm/2Fzhv84Q0n/OkJF/zs/Q/87P0L/Oz5A/zs9 Pv86PD3/Ojs8/zk6O/85OTr/OTk6/zg5Ov84ODn/Nzc3/zY2Nv81NTX/MzQz/zMzM/8yMjL/lZWh/+rp 6//t7e3/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7t7v/u7e7/7u3t/+7t 7f/u7e3/7uzs/+3s7P/t6+v/7erq/+zo6P/r5OX/6d7h/+fS2v/mwdL/7LPO/+yev//plrn/6I2z/+iT uv/piLL/54Gu/+SFr//fcJ7/4XOh/+Rsm//kbZ7/5V+T/+Zek//mVon/42+g/+Nllv/jZ5n/5GGU/+Nm mP/ja5v/4W6f/+B4pf/hcqD/4XWh/+R8p/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADf3t9/cHBw/1pa Wv9SUlL/TU1N/0lJSf9GRkb/RERE/0JCQv9AQUH/Pz8//z0+Pv87PDz/ODs7/y01O/9meJT/2+Hq/+jr 7//s7/H/6e/y/+Tv8//h7/P/3+/z/9/v8//g7/P/3u/z/9rv9P/b7vT/2u7z/93u8//c7vP/3u/z/9rv 8//a7vP/0e3z/9Dt8v/T7fH/0e3y/9Hs8v/R6/H/z+ju/9Pl7P/T3uj/z9zp/8/W5P/Q1eP/1NXk/9vb 5v/r6+7/bHB3/0BGTP8/REb/QENF/z9BQv8+QEH/PkBB/z0+P/88PT3/PDw9/zs8Pf86Ozz/OTo7/zk5 Of83ODj/NjY2/zU2Nv80NDT/MzMz/zIyMv9qa3j/5+fq/+3t7f/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u 7v/u7u7/7u7u/+7u7v/u7e3/7u3t/+7t7f/u7e3/7uzt/+3s7P/t6+v/7erq/+zo6f/s5uj/6uHj/+fZ 3v/qzdr/68HU/+yyzP/tpMT/6o60/+mEr//pm7//6Iiz/+iJs//njLX/5IOu/990ov/gdKL/42aX/+VZ kP/mUon/5HSl/+NekP/idKP/4WiZ/+JxoP/iV43/42SX/+FrnP/gb6H/4WeX/99sm//gc5//4YGo/wAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAM7Oznxra2v/WVlZ/1JSUv9NTk7/SkpK/0dHR/9FRUX/Q0ND/0FC Qv9AQED/Pj8//zw9Pf85Ozv/NDc5/ztLYP/O2Ob/6ezu/+3w8f/t8PL/7fDy/+3v8v/s7/L/6O/y/+Xv 8v/k7vL/4u7y/+Dt8v/e7fL/3ezy/9vs8v/Z7PL/1+3y/9Xt8v/V6/H/1Ovx/9Lp7//T5u7/0uPs/9Td 6f/U1OP/1cXb/9S41f/QstL/16fM/96fx//ft9f/7ufs//Dw8f9zbXT/RklN/0VISf9DRUb/QkNF/0FD RP9AQkP/P0BA/z4/P/8+Pz//PT4//zw9Pf86Ozv/Ojo6/zg5Of83Nzf/NTY2/zU1Nf8zMzP/MjIy/zs7 RP/h4ef/7ezs/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u3t/+7t7f/u7e3/7uzs/+7s 7P/t7Oz/7err/+zo6f/r5uf/6uLk/+jc4f/m09v/6cfX/+y0zv/rnb//7Iux/+qavf/rnr//6Zq7/+iX vP/pl7z/6Yy0/+aGsP/jfKr/33ak/+B6pv/jc6P/5mKU/+ZXjv/kcqD/4meY/+Ftnv/fb57/4HGh/+Ji lP/hXpH/4GCU/99gk//iVov/32WX/95wnP/feaP/AAAAAAAAAAAAAAAAAAAAAEY9QADq2+AC1MvOpmtr a/9aWlr/U1NT/05OTv9LS0v/SEhI/0ZGRv9ERET/Q0ND/0FBQf8/QED/Pj4+/zs7PP82ODr/KC42/7vE 1v/q7O7/7/Hy/+7w8v/u8PL/7vDy/+3w8v/t7/L/7e/y/+zu8v/r7vH/6+3x/+ns7//k4Or/4Mjf/+PR 4f/h2eb/4trm/+PT4v/lxtz/57PT/+Wly//jkMD/4Ia8/9iFuP/dbav/3Vaj/9dNm//XS5j/3WCm/+iw 0v/x7/D/8PDy/4N7gf9NTVD/SUtM/0hJSv9FRkj/REVH/0NERf9CQ0T/QUJC/0BAQP8/Pz//PT4+/zw8 PP86Ozv/OTk5/zg4OP82Njb/NTU1/zQ0NP8zMjL/MzEy/9ra4f/t7Oz/7u3t/+7u7f/u7u7/7u7u/+7u 7v/u7e3/7u3t/+7t7f/u7e3/7uzs/+3s7P/t6+v/7erq/+zp6v/s5+j/6+Tl/+ne4f/n1tz/6MnX/+u/ 0//sq8f/65S5/+yLtP/rjLL/65S6/+uMtf/pi7L/6Yu1/+iGsP/oirP/5Ymz/+R7qf/edKL/4W6c/+J2 pf/lZ5f/5Uh//+Nxof/hc6D/4WKU/+Bqm//fZ5j/33Gh/99wof/fX5L/3GCT/99aj//dV4//3GOS/99z nv8AAAAAAAAAAAAAAAAAAAAAAAAAAOvM3FThx9L+b25u/1tbW/9UVFT/T09P/0xMTP9JSUn/R0dI/0VG Rv9ERET/Q0ND/0FCQv9AQUL/PT4+/zg5O/8wMzL/qLHG/+nr7f/v8fH/7/Hy/+/x8v/u8PL/7vDx/+3v 8f/t7/H/7e7x/+zu8P/s7e//7Ovu/+zp7P/oqcz/5Gep/+d2sv/pgLj/64S7/+pnqv/rV6L/6lWf/+hY nv/nN47/5TSH/+Mcc//jDGr/3zKB/9wreP/fIXX/67DN//Hv8P/x8fL/nZaa/1JPUf9MTk//SktM/0pL S/9ISUn/RkdH/0VGR/9ERUX/QkJC/0BBQf8/Pz//PT09/zs8PP86Ojr/ODg5/zc3N/81NTX/NDQ0/zMy Mv8xMDD/2Nfe/+zs7P/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7O3/7ezs/+3r7P/t6+v/7erq/+zo 6f/r5uj/6uTm/+nf4//n193/6czY/+zD1v/rrcf/6oy0/+uXu//pj7P/65a9/+uMtP/spcX/7Iiy/+ye wf/rocP/6Za8/+ePuP/libP/4nWl/99unf/iapr/4nup/+Rtnf/kZ5j/426f/+Jhk//hapv/32qc/95l lv/ca53/21+U/9thlv/aV4z/2VSK/9pckP/ZZJP/23Kb/wAAAAAAAAAAAAAAAAAAAADt0NsK7dHe1uOo vv92dXX/XV1d/1VVVf9QUFD/TU1N/0pKSv9JSUn/R0dH/0ZGRv9ERUX/Q0RE/0NDQ/9AQUH/Ozs8/zM0 Nf+dobT/6Ort//Dx8f/w8fL/8PHy/+/x8f/v8PH/7e/w/+3u8P/s7e//7Ozu/+zs7v/s6+3/7Onr/+vk 5//lhbv/41GZ/+Vjpf/pbKz/7Fqh/+1MoP/sa63/6jiN/+lKmf/mHXf/4yeA/+MSav/kFGz/4Btz/+Ad dv/qpcb/8u/w//Lw8f++tbn/WlJW/1NSU/9RUVH/T09P/0xNTv9LS0z/SUlJ/0dHR/9FRUX/Q0ND/0FB Qf8+Pj7/PT09/zs7O/85OTn/Nzc3/zY2Nv80NDT/MzIy/zIuL//a2eD/7Ovr/+3s7P/u7ez/7ezs/+3s 7P/t7Oz/7ezs/+3r6//t6ur/7Ojp/+zn6P/r5eb/6uLk/+je4P/m1dz/6sXW/+mtxf/smLz/7aHA/+yQ tf/tqsf/6oux/+ufwv/urcv/7rPO/+6pyP/umb//7Z7B/+qQt//qnL7/55C4/+aJsf/je6j/4HCg/+Nx n//kbp//43Sj/+Vil//jX5P/4WaY/99xof/daZr/3GaY/9xQhP/aW5D/2FKK/9hOhv/YVI3/2FGJ/9pZ j//db57/AAAAAAAAAAAAAAAAAAAAAO3R3T/svNH/4HSK/4eCgv9gYGD/V1dX/1FRUf9OTk7/TExM/0pK Sv9JSUn/SEhI/0hHR/9HR0f/RUZG/0RERf8/P0D/NTU2/5SYrf/p6u3/8PHw//Dw8f/v7/D/7u/w/+7v 8P/t7u//7e3v/+zs7v/s7O3/7Ovt/+zq7P/s6er/6+fo/+vW4v/jSKX/3jmS/+Zjpv/sV5//7WOl/+5k p//pNIX/6l+j/+c/hv/mQ4z/4y57/+IleP/iF3L/4QVm/+eYuv/y7+//8vDw/9zX2f9gVFj/WVdY/1VV Vf9UU1T/UlJT/09QUP9MTE3/SkpK/0hISP9FRUb/Q0JD/0BAQf8+Pj7/PDs8/zk5Of84Nzf/NjU2/zQ0 NP8yMTH/PDQ7/+Lg5f/r6ur/7evr/+3r6//t6+v/7erq/+3q6v/s6en/7Ojo/+vm5//q4+X/6N7i/+jY 3v/m0tv/57vM/+qpwf/slrn/7HSh/+yDrP/rhKz/7JO3/+uAqv/smLv/656//+2qyP/so8T/7qHC/++Q uv/vnML/7JK6/+qYvf/olrz/5Xyo/+J0o//gZpf/5Gua/+Vhk//lapv/42SV/+J5qP/fbJv/3m6f/9xk lv/ZXpH/2EiA/9ZUjf/YUoz/2VGM/91cl//eYJr/32Kc/+Fon/8AAAAAAAAAAAAAAAAAAAAA7c3cZ+mc vP/XL1j/qJmc/2NjY/9ZWVn/U1NT/1BPUP9NTU3/TEtM/0tKS/9KSkr/SkpK/0pKSv9LS0v/SUlJ/0ND Q/83Njf/mJqt/+np7P/t7u//7e7v/+3t7//t7e7/7e3u/+3t7v/t7O3/7Ozt/+zr7P/s6uv/6+jq/+vm 6f/q5Ob/6eDj/+J6q//ZCWj/4EuV/+txs//wg7z/72Gp/+19t//qa6T/6nWu/+hjn//lVJb/5T+K/+Ih dP/aD13/3GST/+3m6f/x7e7/7+zt/4Fxd/9gXF3/YF5f/11cXP9ZWVn/V1ZX/1NSU/9PT0//TExM/0lI Sf9GRUX/QkJC/z8/P/89PDz/OTg5/zc2N/80MzT/MzIy/zAuLv9pYnH/5uPl/+vo6P/r6Oj/6+jo/+vn 6P/r5uf/6uTm/+ni5f/p3+P/59vg/+fS2//ox9b/6rLK/+qux//tosL/7Ymx/+2HsP/thqv/7JC0/+uK sP/urMn/7p2//+2XvP/ur8v/7KXF/+6tzP/vncH/8aPE/+6LuP/tlLv/6pe8/+iTuv/lf6v/4nGh/+Jm mP/kdKP/42KT/+Run//ieKf/4HOk/95tnf/dYZP/2VyP/9dPiP/YUY3/2leS/91cmP/fYZv/32Cb/+Fm n//iYZz/42Ke/wAAAAAAAAAAAAAAAAAAAADt0+Bi6Jm4/9AQQ//AlqL/amho/1xbW/9WVVX/UlFR/09P T/9OTU3/TU1N/01NTf9OTk7/UVBR/1FRUf9RUFD/SUhI/zY1NP+gn7H/5+bp/+zr7P/t7O3/7ezt/+zr 7P/s6+z/7Ovs/+zq6//r6ev/6+fq/+rl6P/p4+b/5+Dj/+Ta3v/i0tz/4KnE/9w8eP/kRof/52Cw/+5X qf/wc7f/8JDB//CEuv/vjLv/75jC/+2Svv/pSpT/52ig/9AsY//JG1v/373P/+rh5//s5ur/vbG3/2hg Yv9nY2T/ZGJj/2FgYf9eXV3/WFhY/1FPT/9PTk//S0lK/0dFRv8+PDz/NzY2/zQyM/8zMDH/Mi8x/zEu L/8xLi7/KSIk/5iNnP/m4eP/6ePk/+ji4//o4eP/6N/i/+fc4P/m1dv/5tDZ/+bAzv/orsL/6qC+/+x6 n//rfqr/7J7A/+2iwv/sg6r/7Ze5/+yHq//rlrr/7aLB/+yRt//vq8j/7Zm7/+6ryf/tpsb/7arJ//Cr yP/viLL/753C/+6awP/rj7j/6Ja7/+SGsP/ha53/4m2d/+J5p//jcJ//5GeY/+Jyo//fc6T/3WiY/9ld j//WVoz/2ViS/91alf/fX5n/4GKc/+FhnP/hX5v/4mWf/+NgnP/jZqD/AAAAAAAAAAAAAAAAAAAAAO3P 3zPqpMH/zBdE/8uEkf9/cXf/YF1e/1hVVv9VUlP/UlBQ/1FOT/9QTk//UE9P/1JQUf9VVFT/WVhZ/1xa W/9OS0z/LiUk/66owP/n5ef/6ujp/+vp6v/r6Or/6ujp/+rn6f/q5uj/6eXo/+jj5//n4OT/5dvh/+PU 3f/iyNf/46/G/+aTs//rc6D/6mWW/+uHrf/phbD/7obC//Cfx//xZLv/8JXF//CMt//xnsP/74W1/+1d oP/rga//6pS5/8plg//Fc6X/38XY/+XX3v/h19z/fWhw/2JYXf9iXF//WVRX/05JSv9LRkj/OjM2/z02 OP83MjT/NjAy/zErLf8vKSv/LSYo/y0lKP8tJCf/Jx8i/yYfIf8mCAf/wq28/+HV2v/j0dn/49HY/+XL 1//lydT/6LzN/+qvyf/pp8T/6Xyj/+qAqP/rjbT/7X2m/+2CrP/qj7T/7qvI/+yHrf/tl7r/7aLC/+6y zP/sj7H/76PD/+2Xuf/upMH/7pm9/++xzf/uoML/76TE/++Xvf/unMD/7ZO7/+yXvP/nkbf/5Hup/+Bu nv/jW4z/4nin/+Nbjf/kV4v/4HOk/9xnmf/XU4b/0lCE/9dQiv/cTYr/4FeU/+Bim//hZZ3/40iI/+Nd mP/iW5j/4mig/+Foof8AAAAAAAAAAAAAAAAAAAAA7snXBu7I2d3XaYj/tjRL/66Fl/9nUFj/W0tQ/1JG Sv9TSUz/SUJE/01GSP9LRkf/RkBB/1dTVP9QTE3/Qjw+/0o+Qf8pDxz/w7bK/+Td4f/n4eP/6OHk/+fg 4//n3+P/59zh/+bb4f/l2OD/6NHd/+jB1P/nq8L/6p6//+yKsP/sbpz/7Za6/+yKsf/sgqr/7Ji7/+qH rv/sjrz/8XvE//GOvv/xqMr/8Z/D//CcwP/wp8f/7Yu7/+2Crf/snsD/6rnR/+Kvyf/Zn8X/2rrQ/9zI 1P+1nqn/QyYu/0ArMv9HLjf/NSUr/zkoLf82JSv/OCUr/0AnL/9KKTX/QSYw/2g9Tv9yR1f/VDA9/5Bb cP9XLDj/US05/4BMZf/Uo7v/37DF/+ewyP/mnbr/54uw/+mau//rkLP/65a7/+ugwf/sp8P/7KDA/+2h v//tmLn/7Y2y/+yZu//spsP/7arG/+2YuP/ti7P/7Zm7/++vy//vqsj/7qTE/+60zv/thq//8KjJ//Cv y//wscv/76bF/+2fwf/tpMX/65e8/+d/q//ibqD/4GiZ/+Nrnf/jZJf/41+T/+Fjlv/dZpn/2mCV/9RH e//TPXT/3VuU/+BalP/gWZT/4V+Z/+Jonv/kTYn/5FiU/+RKif/jWZb/4l+a/wAAAAAAAAAAAAAAAAAA AAAAAAAA7sLVi+q/0v/Pl6n/xoKi/3BEV/8+Iyv/PSMs/zwpLv8/LjP/Oikt/zgoLP8zJCn/UDtC/z0v M/9QND7/cVNg/5Nrgv/Wtc7/4svX/+nL2//lzNj/58rY/+fG1v/qvtX/6rrR/+ugvf/tfqn/7ZK5/+yJ rv/thq3/7X6p/+2Aqf/wttH/7Z29/+2Zu//upML/7aXC/+uWuv/yo8r/86DI//Kpy//yqcr/8Z3B//CZ v//vm7//7Xio/+ybv//ro8P/7KfH/+quyP/mqsf/353A/9qkv/+/dpX/u2mK/851lP+9c5L/pl15/6tr hf/Ie5z/x36c/9R+of/Of6L/1Yqo/9J8oP/TfqD/5Zi6/+KRsv/ic5f/6oqt/+qGrP/qgKj/7qnJ/+yX uf/roMH/6qPC/+p7o//qdaD/7KHA/+qIq//tqcb/63eh/+t8o//rnLv/6nmk/+6mxf/so8H/77LM/++r yf/vscz/7rLM/++rxv/unL3/77jR//Czzf/wqcj/8aXH//Cvy//uq8f/7qvJ/+2Vuv/qlbr/53yn/+Fo nP/hZZf/42eZ/+Raj//ia5//32GU/98+cP/UP2//10uD/91Hgv/fSYj/4FiU/+BgmP/hWJL/4VyX/+JQ jv/jXZf/5VqS/+Nemf/jZ5//AAAAAAAAAAAAAAAAAAAAAAAAAADuuc407rTM/um1y//mtMr/4avC/794 lP/AgZn/yYOh/7Jog//IhqL/oVx4/6ZWb//Vm7X/s11//9abtP/XmrP/5aTB/+q10f/rqMn/77LP/+2a uv/vpcf/7pS5/++gxP/wrc3/7oav/+6Msv/vn8D/8KzK//Cmxv/ukbP/75O4/+2Wuf/uqMX/7qnH/+t5 pP/urcn/7J29//Kvz//zqsz/86rL//Kpy//ylLr/8KXG//CVu//up8n/652//+yoxf/snL7/7Jy//+yb wP/pncD/6Ja8/+mVu//nh7H/6VGQ/+l3pf/pg7D/6Y22/+d9qv/pj7j/6F+X/+mLtP/ne6v/6p/D/+mQ uP/qga7/7JO8/+p4ov/tjLD/7Zy8/+2VuP/sia7/7p+9/+2qxv/us8z/7Jq6/+uVtf/spMH/7JO0/+6n xv/qiq7/7KbF/+62zv/to8L/76HE/+6uyv/vts7/7qTD/++zzP/usMj/76PC//Coxf/uqcb/8LbQ//C2 zv/wss3/76rI/+6uyv/up8f/7aDB/+qPtv/kb5//4Wye/+Jmlv/kVoz/41qL/+FdkP/eXpL/2leH/9dO hv/dT4r/31WO/+BEgf/gTov/4F6W/+BYkv/hYpr/4XSl/+Jdlv/jVJD/42CZ/+Jrov8AAAAAAAAAAAAA AAAAAAAAAAAAAOvK2gHuscvE7rLM/+yzzP/tr8v/7KjG/+2YvP/tmsD/65i+/+uoyP/rnsL/7JC5/+yC sP/ri7T/7Jm9/+ycwf/tjLX/76fI/++oyv/wqMv/76DD//CoyP/vnL//8J/A//Ciw//vpsT/74+0//Go x//vmLv/75q8/+6RtP/um7z/7Z68/+6qx//wtc//76zJ//Czzv/tmLz/8ajK//Oz0v/zqMr/8qzN//Gs y//wrMv/8J/D//Cmyf/vj7r/7ajG/+yiwv/rocL/65rA/+yhw//rlb3/7ZO8/+yTvP/ri7X/7JC5/+x9 rf/unML/7XWp/+xypP/sgrD/7Yuz/+6myP/uo8b/7Z7D//G20//vn8H/76nI//C00P/sjK//7Ze3/+6Z uf/sgaX/64Gn/+2iwv/to8L/6ZCw/+yiwf/tnb7/7Zm7/+yrx//wttD/7aC+/+6qxf/vocH/7rPO//C3 z//slLb/767J/+6mxf/wtM3/8bPO/+6hwf/wsMz/8LbP//Cyy//uq8f/77rR//Ctyv/tnsH/6Yiy/+Fv oP/hbp//4maX/+Nmm//hUof/3luN/9hWh//ZVIv/20+J/95Ri//fVZD/4V+V/+Fil//gX5b/4W6g/99n nP/fa57/4GGV/+Fpnf/haqD/42We/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO24zUvvssr97q3I/+6w y//vsM3/76zL//Cixv/wpMj/75/F/++jx//ve6//76fK/++nyf/uqMn/76vL//G00//xrs//8rHS//Gp y//yr8//8bfW/++Wu//yrcz/8aTF//Cgwv/xm77/8Ju8//Cpxv/vp8b/77HM//CxzP/wu9T/8LLN/++d vf/wr8v/8KnH//Clw//xn8X/87bU//Kjx//zpcf/8rDO//Knx//xrs7/8aHG//CXv//un8H/7a3I/+yo xv/tn8H/7KLB/+yqx//uq8r/763N/+2lyP/tqMr/7pzD/+6Jtf/vnMH/8Ji+//CszP/uh7L/7oKt//Gx 0P/yttP/873Y//K81v/xsMz/8LPO/++uyf/uoL7/76jG/+2Xt//tn73/6568/+ysxv/rqMT/767K/++n w//ui6//7q/K/++nw//qdJ7/767K/++lxP/vq8f/77XM/+yCrP/vsMr/77vT//C1zv/xtc//8bvT//Cm xv/xtM3/8LTO//C60f/xrsr/76XD/+yYu//ld6X/4W2f/+Jdkf/jZZn/4mab/+Bfkv/ZWoz/1ViI/9tP h//cU43/3k2H/+FYkv/iaJ7/4nan/+FnnP/gZ53/32Sb/9xjmP/dZpf/32SY/+Nqnv/kX5b/AAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA78DiAe62zLnvrsn/77HK/++syP/vtM//8K3N//CXv//wqsv/8KPG//Gj yP/xnsT/8abJ//Gwz//xq8z/8rLS//Ox0f/yoMT/87LR//Kdw//yqsv/8a/P//GpyP/whLD/8Y20//CV uv/wkbT/8K/L//Crx//wnLz/8afG//GqyP/yudP/8KHA//G+1v/wocH/8Z/A//CXvv/zo8j/86fJ//Ol yP/zpcf/8pvA//Kqy//yp8n/8Z7F//Ccwv/urcn/7anG/+6cwP/uoML/7avI/+2qyf/wrMr/8KrK/++w zf/vtdD/8LDO//Gtzv/xqcr/8afJ//K31P/yt9X/88Hb//Gqy//zuNP/8qvL//Kzz//wrsr/77fQ/+6u yP/xu9T/76rH/+2zzP/tsMv/7K7H/+++1f/tgqX/752//+6lwf/uqcb/8KvG/+6jwP/wu9P/7Yyw//Cl wv/vq8f/8LjR//G60v/wvNP/8K3J//G1z//yqcn/8rnS//Gmxv/ysc7/8rvT//CbwP/up8T/6o2y/+Fs nf/iYZT/5FiO/+NUi//iY5X/4F2Q/9lhk//cV47/3FmQ/99pnP/hZpj/5GOX/+NNif/ja6H/4mWc/+JZ k//hWpL/3muf/9xom//eW47/4FKF/+REgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHnLYA7rnNJu61 zPTvssv/76nG//G1z//wuND/8LHM//G61P/xtdH/8rXR//Kuzf/yr9D/8rTR//K31P/yn8X/8qTH//Ku zf/xrMz/8rTS//Gtzv/xtNL/8aHE//GGsP/yrcv/8JC2//Gpx//yttH/8bLN//GgwP/xpsX/8abF//Kn xv/zss7/8rXQ//LC2f/xlLr/75u9//KYv//zqMr/9KjK//Otzf/yq8v/8qrK//Okx//ynsP/8J7D/+6j xP/urcj/7qbG/+6dv//uosP/7arH/+6oxv/vmb3/8bPQ//G40//xvdf/8LLQ//Gz0P/woMH/8bHO//Kx 0P/xvNb/8bbS//Gnx//xpsf/8afG/+6MsP/wu9P/77HK/+6nwv/tosD/77vT/+640P/vtM3/77rR/+2i v//upsT/7rLL/+6vyf/umrr/7Yuw//C1zf/tmbr/8LTN/+2Yu//xuNH/8KzI//G+1P/yudP/8rvS//Gl xf/xuNH/8q/M//OoyP/yqsn/8LTO/+2iwf/mfKb/4Wmc/+VhlP/mWpH/5FyP/+JDdf/YRHT/3l6U/+Bc lP/hYpb/4G2e/+Nxov/lbKD/5mqd/+ZTjf/lXZT/5Ham/+JlnP/gap7/32+h/95hlP/fOmv/5XGh/wAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7rvPeO+5z//wqMb/8K3K//Gkxf/ws87/8cDX//Gs y//ysc3/8qLH//KtzP/yr87/8rTS//Cnx//yq83/8a3N//Gy0f/ysND/8Ju///Gav//xp8j/8Yy1//Kp yP/xrMr/75K1//K71f/whq//8rPO//K71P/yss//863M//OLtP/we6n/87jT//O0z//ukLf/8ajJ//Kh xP/zq8z/86/O//Ovzv/yqsv/8qzM//KexP/xncP/8aDG//Clxf/ursr/7qfF/+6kxP/up8f/7bDM/++a v//wqcn/76XF/++pyP/xutb/8bTR/++cwf/wlr3/8bHO//G10f/xsM3/8a7N//CUuf/ysc3/8KHB//C+ 1f/vsMz/7qjF//C81f/vudH/7qnF/+6xyv/uoLz/8LfQ//Cxy//vt9D/8L3U//Cvyf/vqcb/8LTO/++s yP/vtM3/8cHW//K10P/xnsH/8a3M//K60//ypcf/8KvI//HC1//xts7/8rDL//GryP/vssv/65S3/+Rd jv/mTof/51GI/+Y/dv/iZpf/22OQ/9dIef/kX5b/5mWZ/+V2o//jb6D/5HCh/+Zuof/nYZb/51SJ/+dz pf/ld6f/5GSZ/+JckP/fOnX/32GS/99XiP/kaZv/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AADqtM2K7rTM//Cuyv/xqMf/8a3L//Gxzf/wsMz/8qjJ//KpyP/yr8//8qbI//K31P/yttP/8rjV//G0 0//ytdL/87fV//Klx//yqcz/8Z7D//O20v/yscz/8H6p//Kvzf/yvNb/8qfF//GNtf/yocL/87TQ//Gi wf/yttD/86zK//Oxz//0vNb/9LPP/+6Zvv/vkbj/8Ze9//GszP/ynsT/8qvL//K00f/yqcv/8qrL//Gm yv/xmMD/8ZnB/++pyP/wp8f/77HM/+6iw//uq8n/7q7L/++ewf/xr83/7qbG//G00f/xuNP/8KfG//G9 1v/xstD/8KjJ//Ktzv/xpcf/8r/Y//Kxzv/yrcv/8KXC//G50v/vrcf/8LzU/++1zv/uqsX/8MDX/+6g vP/xpMT/8KjF//G2z//uqcX/8LbQ//CyzP/xutL/8bTP//G90//uosD/8bjR//K1z//zvtT/867L//Ko x//wv9P/8b/V//K50f/yp8j/8KvI/+2oxP/mh67/4mOV/+ZakP/nUIf/5UuB/9xMev/SVX7/4FSF/+l1 pf/ndaX/43il/+V2o//maZr/5nmo/+hBfv/obJ//5n2r/+V2pv/ldaX/43Oj/+FMf//eXo//3lmL/+Nk lv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6cHTBeqxzOTrpcb/8LfP//CzzP/wtM//8arI//Gz z//xp8j/8bLO//Gkx//yn8T/86nL//Kjx//yrs7/8qPH//K00v/yp8n/8qLI//COuP/ylbv/87LP//Kn x//ypMX/8Ymy//O20v/xmLz/8qXF//Kty//0vtf/8r7W//TG3P/0sc7/9bXS//W81//1vNX/7qTF/+52 pv/vnMD/76rJ//Cxzv/xrs3/8qjJ//Oqyv/zpMf/8qPI//Gdw//ylsD/8pnC//Cxzf/wrsv/8KbH/++s yf/vsc7/7qTF/++kx//vr8z/8LHO//Cqyv/xpsf/8afK//Cyz//xtdL/8rvX/++ox//yu9X/8rnT//Kt y//xq8n/8LDK/++1z//wwNb/8LjR//C20P/xvdX/8b/W//Clwf/vscv/8LXO//C60//ytM//8aTE//Gr yP/wm7//8LLN//K/1f/xsM3/8rfQ//Osy//zosT/8qrK//HD1v/ysM3/8rTN//K5z//vqMX/6pe4/+Jt nf/ibJz/5V+R/+k1cP/jSnz/1Tli/9hUfv/obaD/7H6s/+iKtP/mhq7/54ez/+R3o//lhK7/52CR/+dw n//me6j/5m+e/+Z9qf/lgK3/4mSU/9o9bv/fbpj/4VaK/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9Q VwDqt84+6qnH/+qjxP/rn8H/8LTN//Gyzf/wttD/8bPO//Kwz//xs8//8bLQ//O21P/yrc3/8rDP//Ky 0f/yq8z/8rTS//Gawf/yp8n/8Z7D//Opyf/ztdH/8q3L//O41P/zsc//87TR//KtzP/zvtf/8p/B//Ou zf/ztM7/9cne//S20v/1yd7/9sHb//a+2P/wo8X/8KfJ/+6ewf/vn8L/8KbH//Chw//xoMP/8qbH//OV vf/zlsD/8qDF//Gawv/xmMH/8afK//GvzP/wrMn/763L//G81v/vsc3/76/M//Cvzf/xstL/8LHP//Cp yf/xp8f/8rjT//G51P/zwNr/873Y//Kxz//zxNz/88DY//O91v/xq8j/8bvU//G+1f/vscr/8LfQ//Gx zP/ytND/8K7I//HB1v/xwtj/8cLY//Kqx//xqcj/8bvT//C3zv/xs87/8a/K//G60v/yudH/8qXG//G0 zf/xu9H/8rjS//K60//yuM//8LzQ/+2nxP/kd6L/4XCf/+JyoP/nUob/50h+/+Fgjv/YYIr/3kx9/+tc k//sdab/6oix/+Zomv/leqf/5IKu/+N5pv/mgaz/5omy/+R6pv/mcJ3/5meX/+RbkP/keaX/3WWR/91o kv/gTH//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOquyn3rqcj/66TF/+mRuf/rqcX/8LnQ//Gr yf/xtM7/8bDP//Kry//xtdH/8K3N//Gcw//ypsj/8rPR//Krzf/yt9X/8rTS//KjyP/yqcz/8qvK//Kv zf/zvdb/86XG//Knxv/yqMn/87rU//CRt//zv9j/87jT//O00P/0x93/9MXc//XI3v/2yd//9sXd//Kt zP/yuNT/8KXH//CuzP/vlLn/75u+//CnyP/yqMn/8p3C//GYwP/xn8T/8Z/F//Glyf/ymsH/8qTJ//Gl xP/xr8z/8a/M//Gx0P/xutT/8brV//Cxz//xrs7/8bHR//CnyP/xocb/8rDO//S/2v/yttH/87DO//TK 3//0x93/88Ta//Gsyv/ysc7/8r/W//HA1//xxdr/8bbP//GlwP/vkrj/8LnS//HB1//zt9D/87PN//Gt yf/xutL/8rvU//HA1//xxtr/8rrS//Kwzf/xwNX/8cHV//LA1f/zttD/87XO//G0zf/vtMv/6YGn/+Vt m//lZZb/5G2b/+dPgv/mXo//4WyZ/9VMdP/iN2v/7GSZ/+18qv/rfqv/6IGq/+aCrf/khrH/5HOh/+Zy o//mZpj/5YOt/+R6pv/leqX/5mCR/+Nbi//db5v/3GGQ/+Fjkv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAA7LHMpOutyv/rnsL/6ZC3/+uixP/upMT/8bfP//Gsyv/xuNL/8bfS//Guzf/xutX/8rzW//K3 0//ys9L/8qjK//Oz0//yttP/87PQ//Kpyf/ystD/88HZ//O+1//yp8f/9MHa//K00f/yttL/877X//Sz 0P/0qMj/9KfI//S20f/1yN7/9cPa//fP4//3yd//8rnT//Gfw//xo8T/8avL//Gmxv/vss//7pu+//CK tP/xiLP/8Z/D//Gcw//yn8T/8aXJ//Klx//znMP/85zC//GpyP/wr8z/8bTQ//Gxzv/yttL/8q3L//Cv zv/ys9H/8q3O//K41f/zp8r/87bT//OmyP/0r83/867L//XH3f/0x9z/87rU//Ovy//yqMf/8r/X//O9 1//yr8z/8KTC//LC2v/wv9b/8cLY//Kuyv/xr8v/8bLO//K50//yxNn/87jR//Oty//zvdX/8rXP//G/ 1P/xu9H/8cPV//HE1v/xv9L/77bN/+qQtP/oc6H/6G+e/+hqmv/oZZj/52WX/+dnmf/gU4T/2laD/+E1 a//sTYj/7nyr/+x+rP/oirL/5oSu/+aCrv/ng63/52mZ/+d3o//kha//44iw/+N+qf/jQnb/3jlo/9tf iv/cZI7/4W6c/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADssMvA7KjH/+uav//og63/54qw/+2b v//upsX/8bzT//K50v/xtdD/8azM//G10f/ytdL/8rTR//Orzf/zsM//87LR//O72P/zqcz/85nB//XD 2//0ttL/9LjT//Oew//ztdL/863N//K61P/yuNP/8qLE//S/2P/zosX/863N//S81v/0sM7/9bzV//XG 3P/xttD/8bHN//Ggw//xt9L/8KHE//Ckxf/wnb//8rPR//Cix//wocb/8JW9//Gcwv/ypsn/8qPH//Kg xf/zlb3/8qHF//Gtyv/wp8j/8KbI//Gy0P/xss//8Za+//K10//yu9X/87HQ//OrzP/zrM3/9LzX//Oq yf/znMH/9Mfd//PA1//zyd7/8r/X//K91f/yvtf/8qvJ//Osy//ywdj/88je//LA1//xwtj/8cHW//LB 1//yt9D/877V//O10P/zjbn/86DE//Oyzv/zvNP/87jQ//LB1v/ywtX/8sDU//G80P/ujrP/63Wl/+t0 pf/rbJ7/6nSl/+p0pv/rap3/6GSX/+FXhv/dZJH/4TRq/+tGhP/uhbH/7Xyq/+iRtv/mfqr/53Oh/+d6 p//oeqj/53Ke/+V6pv/ihK3/44Ot/+J+p//ea5T/2WKH/99znf/keKb/AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAOyxy9HtqMf/7KDD/+d7qP/njrP/64Ww/+2Xvf/unMD/8rbP//K0z//xudP/8rLP//O5 1f/zt9P/87fU//Smyf/0qcr/867P//Oqzf/0qcr/9KXH//W81v/0p8j/9LTR//O+2P/yncL/86zM//O4 0//yttL/8r7X//Gryv/yt9P/8rHP//Oz0P/yr83/8rTQ//CdwP/wq8n/8a7M//Czz//xqcn/8bHN//Gk xf/yqcr/8arL//Gcwf/vncL/8ZK9//KVvv/ynMT/86XL//Kkx//znML/85fA/++kxf/wocT/8KLE//Gp yf/xrMz/8rDO//K41f/xp8r/86jK//Kjx//yu9b/87DP//S81v/1yN7/9cTa//S/2P/0w9r/87/Y//O3 0v/yvtb/8sDY//LC2f/zvdX/87LP//O+1v/yvNT/87vU//Gty//ywNb/87LP//Oxz//ztND/87zT//K1 z//zuND/87nP//LF1v/xuc//8I22/+6Otv/shrH/7Hyq/+1wo//uZZn/7WKY/+xJhv/oUon/4E18/91i jf/fQHD/6kJ//+5onf/ub6H/6Iy0/+iUuv/ogqv/532q/+d5pf/mi7P/5G2d/+N3o//heqT/3GmU/9hZ hP/bcZn/44ew/+Rqnv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7LPM1O2qyP/sk7z/6I63/+aQ tv/rpsX/65u//+2cwP/tnb//8bHM//K50v/yutT/87XS//O41P/zsdD/86/R//OozP/ztdL/87jU//Su zf/1xdv/9b3X//Sxz//0psj/9LzX//Onyv/0o8b/8p7C//O41P/yt9P/8rfT//K30//zrMz/87PR//Kn yv/xss//8KXG//GuzP/xocT/8bXQ//CvzP/xt9L/8rXQ//O30//xr83/8bTR//Cewv/wo8b/8Y24//Gd w//xm8L/8p/F//Kcw//zkbz/8pS+//Ctyv/wqMn/8LHO//CvzP/xqcr/8a7N//GrzP/ypsj/8qzM//K4 0//yrs3/86zM//Snyf/1vNb/9cTa//S61P/0yt//9KrK//O+1//ywtn/88jd//LA1//zwtj/88LZ//PC 2P/zwtn/87zU//O71P/zss7/8sXZ//Szz//zudH/9LjQ//O+0//yvdL/87HN//Kew//wmL3/74y2/+6D sP/uap3/7mie/+5roP/uXJf/7VWR/+pglv/jOmv/1zpi/9grVP/kLWb/7EqJ/+uCrf/ni7L/6IKs/+iB rP/pdKL/6W+d/+V2ov/ic57/4nmk/91jkP/bbJn/1Ex1/9lUgf/kd6b/5lWK/wAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAADttM7Q7ajI/+2Vvf/oi7b/5oyz/+eVuv/qocL/7Jq9/+2cwf/ukrv/76HC//K0 z//yu9T/8rfS//O30//zsM7/87fU//O41f/0stH/9LHO//a71v/1stD/9bjU//Sixv/zttL/87LQ//Oy z//zutX/873X//K30//yutX/8qfJ//Opy//zrMz/8qrK//K00f/yrc7/86nL//K41P/xrcz/8bHP//C4 0v/xoML/8qXF//Kuzf/yxtz/8rzW//Gy0P/xoMP/8rfU//Cawf/wnsT/8azN//Kjyf/ynsX/8qDH//Kq yv/xrsv/8avL//Gpyf/wss7/8KvM//Gqyv/xrMv/8anK//Kszf/zrs7/9LDO//Sz0f/1udX/9cTb//W8 1f/1uNT/88DZ//PF3P/0xdv/9L7X//PC2P/0wNf/873W//PE2v/zvNT/87/X//O40v/zxNn/9LjR//PA 1f/zvtP/873U//Sqy//0oMT/86HF//Kfwv/wkrr/73Ok/+9zpf/vbKH/72Kb/+9dl//uXZf/7FaR/+U7 cv/cP2z/1Ddc/90/bP/oRHz/6ZS3/+eDrP/odaL/52yf/+dOg//nX5D/4mmY/+Ftm//fX4//2U+B/9tm l//aYY//3lqM/+Rgkv/mXZL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO20zbvuqsj/7p7C/+qM t//leaX/4Xij/+eUuP/rkbT/7Yax/+6Otv/tjLP/7Ju//+6lxf/ysMz/87HO//Kxz//yqsz/86zM//Ot zf/0qMv/9K7O//Wdxv/1udT/9L7Y//S81f/zwNn/873X//O30v/zvdf/8rvV//O40//ywdn/87fR//O+ 1//0vtf/87/X//Suz//0psr/9LjU//Opy//ytdL/8bnT//Gxzf/ys8//8bfR//PG3P/zxdr/8bzV//K6 1P/ypsf/8rLP//O51f/xo8f/8aHI//GdxP/yncT/8p/F//Gbwf/xq8r/8bLO//Cyzv/wsM3/8K3M//Gr yv/xrcv/8bbS//Kxzv/zqsv/87LQ//Oxzv/1vdb/9cfd//TH3f/0x9z/9cjd//TB2P/0xtv/9MTb//W9 1//0vNX/88PZ//TD2f/0wNf/9MTZ//TD2P/1wNf/9bPN//Soyf/0qsr/9KjJ//Sdxf/zpcf/85/E//KP uv/xgK//8HSm//Bwo//waJ//8FiW/+9Skf/uS4r/6kmF/+I0aP/dVoL/10Rr/+R4oP/mZJL/5maV/+ZI fP/kdqT/5HCf/+M1bP/haJn/3mqe/9tWjP/YTIL/21GI/91XiP/kW5L/5VaQ/+dAff8AAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA7bTNle2kxf/uocT/7J3B/+eArP/ljLX/4n+q/+aGrf/pd6T/7Iuy/+qP tP/ogKr/5Ymu/+J7oP/spcP/8rDO//Kvzf/zrc3/863N//Onyv/zq8z/9K7N//S51f/1wtr/9bPR//TE 2v/zxtz/8sHY//LF2//zwtr/8sXb//TH3P/1v9f/9cPa//W61f/0sdD/9KbJ//Soy//0qsz/9K3O//O8 1//ztdH/8qrK//CqyP/xrMn/88fd//TG2//zudP/9c3h//PC2P/ztdH/87jT//S81f/zsM3/8qXJ//Gj yP/wpMn/8KjL//KZwv/xosf/8rrU//K91f/wt9H/8b3W//G30f/xuNL/8bXR//Oryv/0qsv/87jS//S0 0P/1wtn/9cLa//XN4P/1zuD/9cbb//TO4P/1yN3/9cTa//XF2v/1wNf/9cXa//XC2P/0vNX/9LvU//Oo x//0pMX/867L//Gcvv/ys8//8qXG//Gtyv/xo8T/8Jm9//GKtf/yf63/8Xmo//Fnn//wX5r/8FWU/+9R kf/tVJD/6VWL/+Rik//ZWIL/22WO/9k9Z//eV4X/31iK/91EeP/fZ5n/3EV6/9lRhv/WQ3b/0jpp/9dE dv/eU4b/4T53/+ZXj//mWZL/5lqO/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtuM9l767K/+6n xv/toMP/6pK5/+iPuP/jdKL/4nOd/99bi//eWob/4W+Y/+SLsv/jgqz/4X2o/99nlP/pjLT/75y///Gs yf/ytdD/867O//Oqy//0rMz/9KzM//Sy0P/1s9D/9rvV//a91//2xdv/9s3f//fJ3v/3zN//98fd//e+ 1//1uNT/9LDP//OtzP/0osf/9KnL//SkyP/0psn/9LHQ//Sy0P/0uNT/8rjT//LH3P/0zeH/87rT//S/ 1//1xNv/9LzW//TJ3v/0yN3/9Mbb//Oxzf/zsc7/86vM//Goy//zuNT/9LDQ//Ohxf/zr83/9crf//S9 1f/0xdr/88DX//LA1v/yutP/87jS//Syzv/1ttD/9bvU//bH3P/20eH/9tXl//bR4v/11OT/9dXk//TO 3//1zN7/9cXa//S81f/0ttL/86vK//O60//zutL/8pS7//Omxv/xocH/8LHN/++Zvf/wpMX/8LHN/++n xv/uoML/7pu+//KMtf/yd6n/8XGl//Fsov/wXZn/712a/+9Zlf/tW5X/6G6g/+Flkf/bV4T/2kh7/9My ZP/XRXv/10h9/9dCe//WQXn/2EuD/9tNhP/ZP3P/4FeN/+NOiP/mWY7/50V+/+Zqnf/laZ3/AAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO2xyiburcn+7qnI/+6jxf/sncD/7Ju//+d1o//mf6j/5o20/99n k//kfaf/5YSt/+eLs//niLH/6Y61/+uLtf/tkLn/73qq//CEsP/xe6n/8pS6//OgxP/zrs3/9LDN//Sr y//1rs3/9qrL//asy//0tM//9K3L//Sexf/1lsP/9ZPB//WrzP/zuNP/87TR//Okxv/0qcn/9LDO//Sx z//0rMz/87HP//O10f/xsc//76nI//K/1//zw9j/9Mjc//O40f/0utT/9Mjd//TF2//0yN3/9Mfb//XO 4f/0yt7/9Mbb//S+1f/0u9T/9bfU//S40//1xNr/9LnT//Svzf/0ttH/8pi8//TE2v/yscz/9Mba//XO 4P/0wtf/9cfb//TK3f/1yt7/9Mjc//TF2f/0xNr/9L/X//TC2v/0wdj/87LO//OvzP/znMD/8pe9//Kk xP/ynsL/8aDE//Ckxf/vq8r/8KPF//Gwzf/ym8L/8a7M//Kjxf/xnMH/8Ze9//J6rP/yd6n/8XCk//Fm n//waKD/8Gig/+91qf/sY5n/6GGT/+Rck//bOXP/3EaC/9xRi//TKl//0CVV/9c7cf/dWY//30+H/94n Yf/mTo3/5zZ0/+dnmf/nXJL/5UuD/+h6pf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA88HSAe+0 ztPupMX/757C/+6ewv/ulLz/7Yq4/+uJsv/qjbX/6Ymx/+mIsP/pf6n/7Ji9/+yKtf/ui7f/7X6u/++C sP/wear/8Ia0//CJuP/zcqn/832y//SEtf/0jLn/9JrE//WUwf/1jrz/9pTC//alyf/0rMv/8qTH//Oe xf/1psn/9aHI//WgyP/zr87/86zK//Glx//yqcr/8abH//Gwzf/ylbz/8Z3A/++Yvv/xttH/9MLZ//TG 2//zw9n/9Mve//TH3P/1zeD/9c3g//XM3v/1yt//9Mve//S+1v/0wdj/9MLZ//XL4P/0wNj/86XG//XJ 3v/0xdv/9MLZ//S71P/0xdr/9MXb//O+1//zy97/88fc//PF2//0xNv/8p7A//Oty//zwdn/8rHN//O+ 1v/zrsz/9LLQ//OuzP/0w9r/8pzB//Oewf/zrc7/8q7N//Kryf/xn8P/8a3M//Kxz//yqsv/86TI//KZ wP/zq8r/86bH//Ouy//zn8P/8n2w//J/rv/ydaf/8W2j//FooP/xc6n/8Im1/+1onf/rZZv/52KY/+M1 cv/gQ3z/4EmE/946cP/gUIb/4VaO/+A3cv/kTIj/5jd3/+g4ef/oPXz/52md/+d6qP/ndKP/6X2p/wAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7rXNe++uy//wnMD/76TG//Cgxf/wkLv/74q1/+2F sf/tp8f/7Iy1/+6WvP/ujLf/7oay/++Otf/umr7/8XGk//CFs//ylr7/8pjB//N+sf/0frP/9H2y//SL uv/1jbz/9ZbC//aiyP/3qcv/963O//evzv/2ss748a3K4/Kixv/0qsv/9avM//Sexv/zosX/8rjR//K2 0f/ys9D/8Z3C//KTvP/zoMT/8rPQ//PA1//0xdr/9MTa//TF2//0z+H/9dDj//TJ3v/0wNf/9czf//XP 4v/1y9//9cXb//bR4//1xNv/9c/h//XN4P/1xNr/9c3h//XI3P/0vtb/9L/X//XI3v/0rcz/9MDY//TD 2//ytc//8rPO//S71v/0sM3/87rT//Kvy//yxdr/9MLa//S81v/zosX/87DO//Ggw//yrMz/86zM//Kc wf/xqMn/8anI//Gtzf/ypsj/8qPG//Ory//yqMn/87TR//Opyv/0rcz/9KjK//Swzf/yoMP/8oCv//J6 rP/xd6j/8Xmq//F/rv/umb//63yp/+tkmv/qWJH/6F6V/+Vblf/lUIr/5jdy/+Zkm//ma6L/5VGK/+Zu of/nVo3/6F6T/+lyov/nZ5n/6FKJ/+mGrf/pbZz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AADtw9Ua7rPM9fClxf/wocP/8Jm///Cdwv/vk7z/75zA/+6mxv/unsL/75G5/++awP/vlbr/75m9/++S uv/xlLv/8Z7D//KqzP/0kLv/9JTC//WDtv/1grb/9ZC///WPvv/2nsX/96TI//eszP/3rc3/967M/vay z2vww9UN8bPOfvKuzfP0qcv/9avM//Sfxv/zuNL/877W//O40//yvNX/8rHO//O20f/zwtn/88PZ//S8 1f/0wtf/9cvf//TD2f/1z+H/9MTa//S30f/1xNv/9cve//XM4P/2z+L/9cXb//XD2f/1xNr/9s7h//XG 3P/1yd7/87PP//O50//0rsz/9LvV//Okxv/zqcn/87TQ//O50//zutX/87bS//Oewv/ysM3/8bDN//Gu zf/xqsn/87HQ//Oawf/yr87/8qPG//Kgxf/ylL3/8abI//Gz0P/xt9P/8bTQ//Gsyv/yss//8rLP//Ou zf/zsc7/9KrK//Ozzv/zs8//867N//Oxzv/ylLv/8oiz//KCr//xhLL/8Za9/+yQt//oeqf/6VSL/+pj l//naJ3/5Wug/+dXkP/oTIn/5mWZ/+ZWjv/nTYb/6IKw/+dwoP/nXJD/6Gmb/+hsm//peKb/52WV/+mE rP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtvNGT7rbP/++ox//wn8L/8J3B//Gf wv/woMT/76DD/++nx//vmr//76LD/++avv/wmsD/8anJ//KLtf/ypMn/9KvO//Wiyf/1jLv/9Yu7//WI u//1jL//9pTA//aiyP/3qcv/963N//eszf/3utKe7NnNAAAAAAAAAAAA8b/UG/K20Jjzp8n19KnL//Sj yP/zvNT/87vU//O91v/zuNP/87nS//O91f/zvtb/87rU//O50v/0xtr/9dDi//XP4f/0udP/9c/h//XC 2f/0vtX/9tXl//XK3v/2zuH/9szf//bL3//2zuD/9cre//XI3f/zvdX/9MHZ//O20//zrs3/8qLF//Kj xf/ypcf/8qTG//Knx//yo8b/8abH//CUuv/wn8P/8bXT//Gpy//yqMn/8GGZ//GNuf/xoMT/8ZnA//KW vv/zpMj/8a7N//Kry//zrs3/9ZnD//SqzP/zs9D/9KbI//Wfx//0q8z/86/M//O30f/0rcz/87DN//On x//yjbf/8oy2//KOuP/wlrz/6o+3/+iFr//pcJ//6W6f/+lsnv/ncaP/50eC/+l5qf/neqr/50+F/+hT if/pbqD/6WWX/+h+q//odqP/65e8/+qKr//tp8b/65G1/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAoIWQAO7E1Rntuc/r76/L/++wzP/woML/8Z/C//Cdwf/xnMH/8KfH//Ccv//ypMb/8KfJ//Gm yP/zosf/86DF//Ov0P/0rdD/9bLT//Wky//2j7//9Ym7//aTwf/2msT/96jK//etzf/3rs7/97fRwfe0 0Ql9aXEAAAAAAAAAAACOe4MAAAAAAPG60iDzss6O86bI8fSqzP/0xNr/9MDX//S91f/zuNH/88bb//PD 2f/zutP/9MXa//XK3v/1yd3/9cnd//XP4P/1zd//9dLi//XL3f/1z+D/9dDh//XO4f/2z+L/9cLZ//bV 5f/21eX/9MLY//KwzP/zutX/8Zu///KszP/wiLb/8aLG//Guzf/wiLX/8ZC7//GLuf/xmcH/8rDP//Kf wv/yr8//8qTH//GQu//xqsv/8aHH//GfxP/xrcz/8qDE//KuzP/xss//8bTP//Osy//zqsv/86fI//Oq yf/zss7/863N//Oty//ztdD/87LO//Owzf/zss//8rLP//Kjw//ylLv/8Za///CNtP/qjLP/6YGt/+p/ rP/paJv/6VyT/+mGsv/pgK3/6G+i/+hZj//pgq7/53un/+yYvf/qbJr/6X+r/+ykxP/qhK3/7Ja3/+2l w//tob//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO++0l/wr8v+77LN//Ct yv/xp8n/8K3N//Ggwv/xsM7/86DF//OZwf/yr9D/87DR//Wfxf/0qMr/9a/R//Wx0v/2sNL/9qbN//WV wv/2lsP/9pjD//ekyf/3qMv/96vN//exz8z2uNEUrIuVAAAAAAAAAAAAAAAAAAAAAAAAAAAAqpCZAAAA AADxuc8b8rDLg/Kwy+3zw9j/9MTZ//TC2P/0xdv/88fb//PD2v/0xNr/9cre//XG2v/1ydz/9tXl//bP 4P/21+b/9tXl//XM3//2z+L/9tLi//bY5//20+P/9dDi//S51P/zpcj/87PR//KexP/xmcH/8ZrB//Gc wv/xoMT/75O6/++ewv/wpMf/75G6/+6av//vfq7/8JK8//CBsv/wiLT/8Z/E//CUvP/wncL/8ajI//Cq yf/xn8P/8azK//Gzzv/xudP/8rvU//Kyzf/zvNT/8rHN//O20P/zttD/87HP//Szz//zsc7/9K3N//Wr zP/0t9H/9LjQ//OcwP/ymcD/75/B/+yZvf/rirP/6n6r/+mMtf/pfqr/64+4/+pglf/rgq3/6m+f/+uK s//pjrb/7Zu+/+tjlP/tn8H/7Ju8/+yMsv/wt9H/75q8//CvzP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAArIiYA7qu3AfG60Y7xt9D/8LnT//Koyv/yrc3/8rDP//Oszf/0msL/9afJ//Wy 0f/0ttX/9bLS//Wx0v/2u9f/9rPS//a01P/2pMv/9pjE//aex//3osj/96XK//epy//3ttHL9r3VFgAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bXNHvC1zajyudL988TZ//TG 2v/0xdn/9MXa//TH2//0yNv/9MXZ//XI3P/20OH/9tbm//bU4//21+b/9tXk//bR4v/21uX/9tPj//bV 5f/1wdj/9MDZ//KWvf/xnML/8JS9//GPvP/wdKn/8KXI/++Uvf/wqcr/8LTR/++kx//wsM//8LDO//Gm x//ym77/8ZzC//Gz0P/wqsr/8KzL//Gxzv/xpMb/8LXQ//G50v/0psn/9K/O//K+1v/zudL/87rT//O2 0f/yutL/87bQ//Oxzv/zs87/87PP//O40f/0uNL/9LXQ//O00P/0r87/867N//Khxf/wrMr/7aLC/+6X u//tnL//65zA/+yZvf/tocT/7G6d/+2Gs//tmr7/7JC3/++nyP/vqcb/7pu8/+2hwf/uq8j/8bHO//Gt yP/yt9D/877U/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA88fWA/K6 0pnzutT/87jU//Sszf/0tNL/9bHR//Wny//1stL/9a/Q//W21f/2u9j/9q/R//a10v/2s9P/9q7Q//am y//2nMb/96LK//eky//3qMz997LQnvfJ2g28macAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAABKJjgAAAAAAPC1zzHwt9Cm8bXQ9PG50v/yuNH/9MXa//TI2//0yt7/9Mjb//TG 2v/1zd//9c/h//bV5P/21OT/9tLi//bX5f/20+P/9s/h//TH3P/zvtf/8rfT//K31P/xqcr/8KnM//Ck x//wmsD/76LH/++pyv/vm7//8LTR//Cwzf/wqsn/8K/N//GQuv/xu9T/8a3M//Kryv/yqsr/8rTQ//Og xf/zn8X/85zE//OuzP/zs9D/9LfS//Suzv/0ss//87bQ//O00P/zrsz/87nS//O+1f/0vtb/9KbJ//Sh x//0rM3/9JzF//OWwP/zpsr/86HF//Gxzf/wttD/7qDB/++qyf/vrMr/7aDC/+2LtP/ue6b/8KXH/++j xP/wpcX/8bbR/++LsP/wjbX/8KDC//O/2f/zwtj/873V//S91f/ztM//AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9crZAvS60370ttH59bLQ//W41P/1stH/9rLS//as zP/1qcz/9rTT//a61//2uNX/97TS//e21P/3rc7/96rN//eoy//3qMz/96jM4Pez0FXyw8EBw5yrAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE049AAAA AADwuM8a8LnRbfG10MXxttD38rfS//K20v/zsM//9LvU//S/1f/0w9j/9cvd//XL3v/2z+D/9c3f//bU 5f/1zeD/9MTa//Soy//ystD/8LDO//CmyP/wnML/8ajJ//Cnyv/vqcr/8LbS/++pyv/umb3/8LrU//C1 z//xrsv/8LLO//Gxzv/xqcj/8bDN//KoyP/xpcf/8pK+//Sfxv/0n8f/9KnL//OlyP/zr83/863N//O3 0f/zttD/9L/V//TJ3f/1tdL/9cPb//Sszf/0stH/9IK1//OPvf/zibj/8oWz//Kpy//zmsP/863M//HA 1v/yutT/8bzU/++fwf/vqsn/8K7N//Gxzf/xr83/8rnU//Kxzv/ysc//8aDB//XF3f/0yN3/9Mje//S9 1f/1y9//9cfc//XH3P8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAB6Zm8AAAAAAPS2zz30vdTO9bjT//a10v/2udX/9rDP//a41f/3vtn/97HR//e+2f/3vNf/97nV//e0 0//3s9L/97HP5ve00Hr2s8wOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZHSwAAAAAAAAAAAPG40B3yutJh8bnRqfG6 0uXyt9H/87fR//O40v/0t9H/9LjS//S50v/0vtX/9b/X//TA2P/zrM7/85zF//Kgxv/xr83/76XG//Ce xP/ylsD/8JG8//CexP/vpsj/8LLP//CnyP/vqMr/8KrK//GdxP/wrMv/8aXH//Gfw//woMT/8JS///OT wP/zncT/85nC//Kkx//zqMn/86zL//Ozz//zudP/9MXa//XN4P/0xNv/9c3i//Omyf/0p8r/9LvX//Sx 0f/0rc3/8p/F//S61v/zoMX/87bT//Ogxv/zrsz/87bR//TG2v/0xNn/9MXa//O/1//0y9//8rPQ//TE 2//0x93/9Mfc//O/1v/1y+D/9b3X//XF2v/20OL/9c7h//bK3f/1wNb/9tXl/wAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPS90gb1yNtQ9cLYrva/ 1/T2vdb/9sDZ//e61f/3rs//97vW//fC2v/3wNj298Taufa/1mT1wNYPAAAAAFkAIgAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAASDtBAAAAAAAAAAAA8cTXCPHB1ibyvdNd8rrTkPK807/zvNPn8rfR/PO9 1P/zv9X/9LzV//S91//0w9r/8qXJ//Gyz//wrsv/77HN/++dwP/xqMn/8a/M//Cryf/wq8r/8afI//Cp yf/xqMj/8pO+//Ghxv/wnsT/8J3E//Ghxf/yosX/86HG//Okx//0qcr/9bfT//Wy0P/1xNv/9cDZ//XF 3P/0v9j/87jU//TI3v/0wtv/9L7Y//S81//0psn/9JvE//Sfxf/0uNX/9LbU//SmyP/0wNn/8rnT//PC 2v/0uNT/9LnU//TD2v/1y93/9Mre//bO4P/1zuH/9tDi//TL3//1y9//9cne//bN4P/1xNv/99fn//bM 4P/32uj/9s3f//fU5P/32Ob///4AAH/AAAA/////////+P/+AAAeAAAAB/////////D//AAAAAAAAAD/ ///////g//4AAAAAAAAAP///////wP/+AAAAAAAAAA///////4D//gAAAAAAAAAD//////+A//8AAAAA AAAAAP//////AP//AAAAAAAAAAB//////gD//wAAAAAAAAAAH/////wA//+AAAAAAAAAAA/////4AP// gAAAAAAAAAAD////8AD//4AAAAAAAAAAAf///+AA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAA AAD//4AAAAAAAAAAAAAAAAAA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAA AAAAAAAA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAAAAAAAAAA///AAAAA AAAAAAAAAAAAAP//wAAAAAAAAAAAAAAAAAD//8AAAAAAAAAAAAAAAAAA//+AAAAAAAAAAAAAAAAAAP// gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAA AAD//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAAAAD//gAAAAAAAAAA AAAAAAAA//4AAAAAAAAAAAAAAAAAAP/+AAAAAAAAAAAAAAAAAAD//gAAAAAAAAAAAAAAAAAA//wAAAAA AAAAAAAAAAAAAP/8AAAAAAAAAAAAAAAAAAD//AAAAAAAAAAAAAAAAAAA//wAAAAAAAAAAAAAAAAAAP/8 AAAAAAAAAAAAAAAAAAD8eAAAAAAAAAAAAAAAAAAA/HgAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAA AAD4AAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAAA AAAAAAAAwAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAA AAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAA AAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAOAA AAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAA AAD8AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAA AAAAAAAA8AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAA AAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAPwA AAAAAAAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAPwAAAAAAAAAAAAAAAAA AAD4AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAA AAAAAAAA8AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAA AAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPwA AAAAAAAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAA AAD/AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAA AAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAA AAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4A AAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAA AAD/AAAAAAAAAAAAAAAAAAAA/4AAAAcAAAAAAAAAAAAAAP+AAAAHwAAAAAAAAAAAAAD/wAAAD/AAAAAA AAAAAAAA/8AAAB/8AAAAAAAAAAAAAP/gAAA//wAAAAAAAAAAAAD/8AAAf//AAAAAAAAAAAAA//wAAf// +AAAAAAAAAAAAP/+AAf///8AAAAAAAAAAAA= ================================================ FILE: source-code/source/plugins/Novidia/Novidia.vcxproj ================================================ Debug x64 Release x64 16.0 Win32Proj {47181a1d-c22c-4c9c-b4e0-cb6ce886a1d8} Novidia 10.0 DynamicLibrary true v142 Unicode DynamicLibrary false v142 true Unicode true .dva false .dva Level3 true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true ..\..\..\dependencies\GPUModel;..\..\..\dependencies\xdelta3;..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\detours\include; Console true ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) opengl32.lib;detours.lib;syelog.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true ..\..\..\dependencies\GPUModel;..\..\..\dependencies\xdelta3;..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\detours\include; Console true true true ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) opengl32.lib;detours.lib;syelog.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) ================================================ FILE: source-code/source/plugins/Novidia/Novidia.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Header Files Header Files Header Files Header Files ================================================ FILE: source-code/source/plugins/Novidia/src/crc/crc.h ================================================ /* ** CRC.H - header file for SNIPPETS CRC and checksum functions */ #ifndef CRC__H #define CRC__H #include /* For size_t */ #include "sniptype.h" /* For BYTE, WORD, DWORD */ /* ** File: ARCCRC16.C */ void init_crc_table(void); WORD crc_calc(WORD crc, char *buf, unsigned nbytes); void do_file(char *fn); /* ** File: CRC-16.C */ WORD crc16(char *data_p, WORD length); /* ** File: CRC-16F.C */ WORD updcrc(WORD icrc, BYTE *icp, size_t icnt); /* ** File: CRC_32.C */ #define UPDC32(octet,crc) (crc_32_tab[((crc)\ ^ ((BYTE)octet)) & 0xff] ^ ((crc) >> 8)) DWORD updateCRC32(unsigned char ch, DWORD crc); Boolean_T crc32file(char *name, DWORD *crc, long *charcnt); DWORD crc32buf(char *buf, size_t len); /* ** File: CHECKSUM.C */ unsigned checksum(void *buffer, size_t len, unsigned int seed); /* ** File: CHECKEXE.C */ void checkexe(char *fname); #endif /* CRC__H */ ================================================ FILE: source-code/source/plugins/Novidia/src/crc/crc_32.c ================================================ /* Crc - 32 BIT ANSI X3.66 CRC checksum files */ #include #include "crc.h" #ifdef __TURBOC__ #pragma warn -cln #endif /**********************************************************************\ |* Demonstration program to compute the 32-bit CRC used as the frame *| |* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| |* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| |* protocol). The 32-bit FCS was added via the Federal Register, *| |* 1 June 1982, p.23798. I presume but don't know for certain that *| |* this polynomial is or will be included in CCITT V.41, which *| |* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| |* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| |* errors by a factor of 10^-5 over 16-bit FCS. *| \**********************************************************************/ /* Need an unsigned type capable of holding 32 bits; */ typedef DWORD UNS_32_BITS; /* Copyright (C) 1986 Gary S. Brown. You may use this program, or code or tables extracted from it, as desired without restriction.*/ /* First, the polynomial itself and its table of feedback terms. The */ /* polynomial is */ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ /* Note that we take it "backwards" and put the highest-order term in */ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ /* the MSB being 1. */ /* Note that the usual hardware shift register implementation, which */ /* is what we're using (we're merely optimizing it by doing eight-bit */ /* chunks at a time) shifts bits into the lowest-order term. In our */ /* implementation, that means shifting towards the right. Why do we */ /* do it this way? Because the calculated CRC must be transmitted in */ /* order from highest-order term to lowest-order term. UARTs transmit */ /* characters in order from LSB to MSB. By storing the CRC this way, */ /* we hand it to the UART in the order low-byte to high-byte; the UART */ /* sends each low-bit to hight-bit; and the result is transmission bit */ /* by bit from highest- to lowest-order term without requiring any bit */ /* shuffling on our part. Reception works similarly. */ /* The feedback terms table consists of 256, 32-bit entries. Notes: */ /* */ /* 1. The table can be generated at runtime if desired; code to do so */ /* is shown later. It might not be obvious, but the feedback */ /* terms simply represent the results of eight shift/xor opera- */ /* tions for all combinations of data and CRC register values. */ /* */ /* 2. The CRC accumulation logic is the same for all CRC polynomials, */ /* be they sixteen or thirty-two bits wide. You simply choose the */ /* appropriate table. Alternatively, because the table can be */ /* generated at runtime, you can start by generating the table for */ /* the polynomial in question and use exactly the same "updcrc", */ /* if your application needn't simultaneously handle two CRC */ /* polynomials. (Note, however, that XMODEM is strange.) */ /* */ /* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ /* of course, 32-bit entries work OK if the high 16 bits are zero. */ /* */ /* 4. The values must be right-shifted by eight bits by the "updcrc" */ /* logic; the shift must be unsigned (bring in zeroes). On some */ /* hardware you could probably optimize the shift in assembler by */ /* using byte-swap instructions. */ static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; DWORD updateCRC32(unsigned char ch, DWORD crc) { return UPDC32(ch, crc); } Boolean_T crc32file(char *name, DWORD *crc, long *charcnt) { FILE *fin; register DWORD oldcrc32; register int c; oldcrc32 = 0xFFFFFFFF; *charcnt = 0; #ifdef MSDOS if ((fin=fopen(name, "rb"))==NULL) #else if ((fopen_s(&fin, name, "rb"))!=0) // modded for fopen_s to avoid enabling unsafe fopen #endif { perror(name); return Error_; } while ((c=getc(fin))!=EOF) { ++*charcnt; oldcrc32 = UPDC32(c, oldcrc32); } if (ferror(fin)) { perror(name); *charcnt = -1; } fclose(fin); *crc = oldcrc32 = ~oldcrc32; return Success_; } DWORD crc32buf(char *buf, size_t len) { register DWORD oldcrc32; oldcrc32 = 0xFFFFFFFF; for ( ; len; --len, ++buf) { oldcrc32 = UPDC32(*buf, oldcrc32); } return ~oldcrc32; } #ifdef TEST main(int argc, char *argv[]) { DWORD crc; long charcnt; register errors = 0; while(--argc > 0) { errors |= crc32file(*++argv, &crc, &charcnt); printf("%08lX %7ld %s\n", crc, charcnt, *argv); } return(errors != 0); } #endif /* TEST */ ================================================ FILE: source-code/source/plugins/Novidia/src/crc/sniptype.h ================================================ /* ** SNIPTYPE.H - Include file for SNIPPETS data types and commonly used macros */ #ifndef SNIPTYPE__H #define SNIPTYPE__H #include /* For free() */ #include /* For NULL & strlen() */ typedef enum {Error_ = -1, Success_, False_ = 0, True_} Boolean_T; #if defined(__unix__) typedef unsigned char BYTE; typedef unsigned long DWORD; typedef unsigned short WORD; #if !defined(FAR) #define FAR #endif #if !defined(NEAR) #define NEAR #endif #if !defined(HUGE) #define HUGE #endif #if !defined(PASCAL) #define PASCAL #endif #if !defined(CDECL) #define CDECL #endif #if !defined(INTERRUPT) #define INTERRUPT #endif #elif !defined(WIN32) && !defined(_WIN32) && !defined(__NT__) \ && !defined(_WINDOWS) #if !defined(OS2) typedef unsigned char BYTE; typedef unsigned long DWORD; #endif typedef unsigned short WORD; #else #define WIN32_LEAN_AND_MEAN #define NOGDI #define NOSERVICE #undef INC_OLE1 #undef INC_OLE2 #include #define HUGE #endif typedef union { signed char c; BYTE b; } VAR8_; typedef union { VAR8_ v8[2]; signed short s; WORD w; } VAR16_; typedef union { VAR16_ v16[2]; signed long l; DWORD dw; float f; void *p; } VAR32_; typedef union { VAR32_ v32[2]; double d; } VAR64_; #define NUL '\0' #define LAST_CHAR(s) (((char *)s)[strlen(s) - 1]) #define TOBOOL(x) (!(!(x))) #define FREE(p) (free(p),(p)=NULL) #endif /* SNIPTYPE__H */ ================================================ FILE: source-code/source/plugins/Novidia/src/dllmain.cpp ================================================ #include "framework.h" #include "glStuff.h" #include #include extern "C" { // well, only good for 64 bit now, ont that is matters lol #define SIZEOF_SIZE_T 8 #define SIZEOF_UNSIGNED_LONG_LONG 8 #include #include #include "crc/crc.h" } // upload to the SSBO instead after processing // two versions because apparently TexSubImage can cause major stuttering void h_uploadModelTransformBuf_TexImage(DWORD* a1, int a2) { if (a2 > 0x100) return; uploadModelTransformBuf(a1, a2); glActiveTexture(GL_TEXTURE8); glBindTexture(GL_TEXTURE_1D, buf_tex); // can't change tex size without making shader sad :( glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 0x3000 / sizeof(float) / 4, 0, tex_upload_format, GL_FLOAT, *(float**)0x1411a3330); glActiveTexture(GL_TEXTURE0); } void h_uploadModelTransformBuf_TexSubImage(DWORD* a1, int a2) { if (a2 > 0x100) return; uploadModelTransformBuf(a1, a2); glActiveTexture(GL_TEXTURE8); glBindTexture(GL_TEXTURE_1D, buf_tex); glTexSubImage1D(GL_TEXTURE_1D, 0, 0, a2 * 3, tex_upload_format, GL_FLOAT, *(float**)0x1411a3330); glActiveTexture(GL_TEXTURE0); } void h_uploadModelTransformBuf_NoUpload(DWORD* a1, int a2) { glActiveTexture(GL_TEXTURE8); glBindTexture(GL_TEXTURE_1D, buf_tex); glActiveTexture(GL_TEXTURE0); } // just a crash fix void h_glBindBuffer(GLenum target, GLuint buffer) { // if not okay, it's param buffer data if (!checkBufferTargetOk(target)) { return; } glBindBuffer(target, buffer); } // just a crash fix void h_glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { // if not okay, it's param buffer data if (!checkBufferTargetOk(target)) { return; } glBufferData(target, size, data, usage); } PROC h_wglGetProcAddress(LPCSTR Arg1) { PROC res = wGlGetProcAddress_forhook(Arg1); if (res == nullptr) return (PROC)stub; return res; } // used as an entry point after GL context is created void h_glutSetCursor(int cursor) { if (!loadGlAddresses()) { printf("[Novidia] Aborting loading\n"); //MessageBoxA(NULL, "!", NULL, NULL); } else { struct { void* target; void* hook; } hookFuncs[] = { {&glBindBuffer, h_glBindBuffer}, {&glBindBufferARB, h_glBindBuffer}, {&glBufferData, h_glBufferData}, {&glBufferDataARB, h_glBufferData}, //{&glDrawElements, h_glDrawElements}, //{&glDrawRangeElements, h_glDrawRangeElements}, }; for (auto fn : hookFuncs) { hookGlFunc((PROC*)fn.target, fn.hook); } //glActiveTexture(GL_TEXTURE8); glGenTextures(1, &buf_tex); printf("[Novidia] Buffer texture id: %d\n", buf_tex); glBindTexture(GL_TEXTURE_1D, buf_tex); if (enable_chara_skinning && use_TexSubImage) glTexStorage1D(GL_TEXTURE_1D, 1, GL_RGBA32F, 0x3000 / sizeof(float) / 4); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // BGRA texture uploads seem to run a little faster // ideally just asking the driver what to use would be fine, // but my driver says GL_RGBA is better (contrary to my testing) if (force_BGRA_upload) { tex_upload_format = GL_BGRA; } else { // ask the driver which image format to use for uploads glGetInternalformativ(GL_TEXTURE_1D, GL_RGBA32F, GL_TEXTURE_IMAGE_FORMAT, 1, &tex_upload_format); printf("[Novidia] Driver preferred texture upload format: %d\n", tex_upload_format); } if (tex_upload_format == GL_BGRA) { printf("[Novidia] Using BGRA texture uploads\n"); // set swizzling to make shader read as if it's RGBA still glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_SWIZZLE_B, GL_RED); } else { tex_upload_format = GL_RGBA; printf("[Novidia] Using RGBA texture uploads\n"); } if (!enable_chara_skinning) { struct vec4 { float x; float y; float z; float w; }; struct mtx { vec4 xMul; vec4 yMul; vec4 zMul; }; /* mtx no_anim_mtx = { {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, }; */ mtx no_anim_mtx = { {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, }; float uploadBuf[0x3000 / sizeof(float)]; for (int i = 0; i < sizeof(uploadBuf) / sizeof(float); i += sizeof(no_anim_mtx) / sizeof(float)) { // yes, I really could just memset it to all zeros lol memcpy(&uploadBuf[i], &no_anim_mtx, sizeof(no_anim_mtx)); } glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 0x3000 / sizeof(float) / 4, 0, tex_upload_format, GL_FLOAT, uploadBuf); } } DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); printf("[Novidia] Unhooking glutSetCursor\n"); DetourDetach(&(PVOID&)glutSetCursor, h_glutSetCursor); DetourTransactionCommit(); glutSetCursor(cursor); } int64_t hookedGetFileSize(MsString* path) { // store original size for use later or to return in case of error int64_t ogsize = divaGetFileSize(path); std::string pathStr = std::string(path->GetCharBuf()); static std::string shdfarc = "shader.farc"; // identify whether current file is shader or not bool fileIsShader = false; if (pathStr.length() >= shdfarc.length()) { fileIsShader = (0 == pathStr.compare(pathStr.length() - shdfarc.length(), shdfarc.length(), shdfarc)); } if (!fileIsShader) { return ogsize; } // reset some stuff when reprocessing shader farc (should never happen) if (shader_farc_data) { free(shader_farc_data); shader_farc_data = NULL; shader_farc_data_size = 0; shader_farc_path = ""; shader_file_handle = NULL; } // local vars declared early to allow use of goto FILE* ogfile; void* ogdata = NULL; DWORD crc; wchar_t crcstr[9]; std::wstring vcd_path; DWORD dwAttrib; FILE* vcdfile; long vcdsize; void* vcddata = NULL; void* outbuf = NULL; usize_t outbuf_size; usize_t outbuf_data_size; int xd3err; // if shader, open it and read data //if (fopen_s(&ogfile, path->GetCharBuf(), "rb") != 0) ogfile = divaFsopen(path->GetCharBuf(), "rb", _SH_DENYNO); if (ogfile == nullptr) { MessageBoxW(NULL, L"Error opening shader.farc.", L"Novidia", NULL); goto fail; } ogdata = malloc(ogsize); //if (fread(ogdata, 1, ogsize, ogfile) != ogsize) if (divaFread(ogdata, 1, ogsize, ogfile) != ogsize) { MessageBoxW(NULL, L"Error reading shader.farc.", L"Novidia", NULL); goto fail; } //fclose(ogfile); divaFclose(ogfile); // need to use diva's fclose if using diva's fsopen and fread // crc32 the shader data to find a vcdiff patch file crc = crc32buf((char*)ogdata, ogsize); swprintf_s(crcstr, L"%08x", crc); //MessageBoxW(NULL, crcstr, L"Novidia", NULL); vcd_path = DirPath() + L"\\plugins\\Novidia Shaders\\" + crcstr + L".vcdiff"; dwAttrib = GetFileAttributesW(vcd_path.c_str()); if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { MessageBoxW(NULL, L"Unable to find shader vcdiff file.", L"Novidia", NULL); MessageBoxW(NULL, vcd_path.c_str(), L"Novidia", NULL); goto fail; } // try opening and reading said vcdiff patch if (_wfopen_s(&vcdfile, vcd_path.c_str(), L"rb") != 0) { MessageBoxW(NULL, L"Error opening shader vcdiff file.", L"Novidia", NULL); MessageBoxW(NULL, vcd_path.c_str(), L"Novidia", NULL); goto fail; } // get size of the file from having already opened it, skipping whatever the game does fseek(vcdfile, 0, SEEK_END); // seek to end of file vcdsize = ftell(vcdfile); // get current file pointer fseek(vcdfile, 0, SEEK_SET); // seek back to beginning of file vcddata = malloc(vcdsize); if (fread(vcddata, 1, vcdsize, vcdfile) != vcdsize) { MessageBoxW(NULL, L"Error reading shader vcdiff file.", L"Novidia", NULL); MessageBoxW(NULL, vcd_path.c_str(), L"Novidia", NULL); goto fail; } fclose(vcdfile); // allocate an output buffer and patch shader into it (needs to be done now to know correct size) outbuf_size = 64 * 1024 * 1024; // 64M should be enough outbuf = malloc(outbuf_size); outbuf_data_size; xd3err = xd3_decode_memory((uint8_t*)vcddata, vcdsize, (uint8_t*)ogdata, ogsize, (uint8_t*)outbuf, &outbuf_data_size, outbuf_size, 0); if (xd3err != 0) { MessageBoxW(NULL, L"Error applying shader vcdiff file.", L"Novidia", NULL); MessageBoxA(NULL, xd3_strerror(xd3err), "Novidia", NULL); goto fail; } wprintf(L"[Novidia] Patched shader.farc using %s.vcdiff\n", crcstr); // done successfully! cleanup and save results free(ogdata); free(vcddata); shader_farc_data = outbuf; shader_farc_data_size = outbuf_data_size; shader_farc_path = pathStr; return outbuf_data_size; fail: if (ogdata) free(ogdata); if (vcddata) free(vcddata); if (outbuf) free(outbuf); return ogsize; } FILE* hookedFsopen(const char* path, const char* mode, int shflag) { FILE* res = divaFsopen(path, mode, shflag); if (strcmp(path, shader_farc_path.c_str()) == 0) { shader_file_handle = res; } return res; } int64_t hookedFread(void* dst, int64_t size, int64_t count, FILE* file) { if (file != shader_file_handle) { return divaFread(dst, size, count, file); } size_t size_bytes = size * count; if ((size_bytes > shader_farc_data_size) || !shader_farc_data) { return divaFread(dst, size, count, file); // this is an error -- the game wants more data than we have for some reason, or size has a value but not our buffer } memcpy(dst, shader_farc_data, size_bytes); shader_file_handle = NULL; // easy way to avoid risk of unexpected reuse // optionally, could free the stored farc data here, but it only uses 64MB so why bother? /* free(shader_farc_data); // no longer need to keep this around so free it and save the RAM shader_farc_data = NULL; // clear associated data too, because there's no longer a processed shader shader_farc_data_size = 0; shader_farc_path = ""; */ printf("[Novidia] Shader patch applied\n"); return size_bytes; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { loadConfig(); if (!disable_amd_check) { std::string gpuName = GPUModel::getGpuName(); if (gpuName != "AMD") { // detected Nvidia GPU printf("[Novidia] Detected Non-AMD GPU! Quitting!\n"); return TRUE; } } DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); printf("[Novidia] Hooking glutSetCursor\n"); DetourAttach(&(PVOID&)glutSetCursor, h_glutSetCursor); printf("[Novidia] Hooking wglGetProcAddress\n"); DetourAttach(&(PVOID&)wGlGetProcAddress_forhook, h_wglGetProcAddress); printf("[Novidia] Hooking uploadModelTransformBuf\n"); if (enable_chara_skinning) { if (use_TexSubImage) DetourAttach(&(PVOID&)uploadModelTransformBuf, h_uploadModelTransformBuf_TexSubImage); else DetourAttach(&(PVOID&)uploadModelTransformBuf, h_uploadModelTransformBuf_TexImage); } else { DetourAttach(&(PVOID&)uploadModelTransformBuf, h_uploadModelTransformBuf_NoUpload); } if (enable_shader_deltas) { printf("[Novidia] Hooking divaGetFileSize\n"); DetourAttach(&(PVOID&)divaGetFileSize, hookedGetFileSize); printf("[Novidia] Hooking divaFsopen\n"); DetourAttach(&(PVOID&)divaFsopen, hookedFsopen); printf("[Novidia] Hooking divaFread\n"); DetourAttach(&(PVOID&)divaFread, hookedFread); } DetourTransactionCommit(); /* if (shader_amd_farc) { const char* shaderpath = "./rom/shader_amd.farc"; InjectCode((void*)0x140a41018, std::vector(shaderpath, shaderpath + strlen(shaderpath))); } */ } return TRUE; } using namespace PluginConfig; PluginConfigOption config[] = { { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"disable_amd_check", L"general", CONFIG_FILE, L"Disable AMD Check", L"On systems with both AMD and Nvidia graphics, the plugin may disable functionality due to detecting a non-AMD GPU.\nSet this to forcefully enable functionality.", false, false } }, { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"enable_chara_skinning", L"general", CONFIG_FILE, L"Enable Chara Skinning", L"If you really need to get extra performance, you can disable uploading skinning data. (character models will disappear)", true, false } }, { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"use_TexSubImage", L"general", CONFIG_FILE, L"Use glTexSubImage", L"glTexSubImage should offer higher performance, but stuttering has been reported when it is used.\nTry disabling this if you have issues.", true, false } }, { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"force_BGRA_upload", L"general", CONFIG_FILE, L"Force BGRA Texture Uploads", L"BGRA format uploads seem to run faster (on some hardware), but drivers may suggest RGBA instead.\nUsing this forces uploads to use the BGRA format.\n\nDisabling this may decrease or improve performance.", true, false } }, { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"shader_delta_patches", L"general", CONFIG_FILE, L"Apply shader vcdiff patches", L"Novidia can automatically apply pre-generated delta patch files to shaders.\nLeave this enabled for current and future versions of AMDPack.", true, false } }, }; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"Novidia"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"Novidia by somewhatlurker\n\nPerforms some model skinning transformations in an alternate way to enable functionality on non-Nvidia hardware.\nAlso fixes crashing on non-Nvidia hardware."; } extern "C" __declspec(dllexport) PluginConfigArray GetPluginOptions(void) { return PluginConfigArray{ _countof(config), config }; } ================================================ FILE: source-code/source/plugins/Novidia/src/framework.h ================================================ #pragma once //#define WIN32_LEAN_AND_MEAN //#include //#include #include #include "glStuff.h" // use this as a hook to perform initialisation void(__cdecl* glutSetCursor)(int cursor) = *(void(__cdecl**)(int))0x140966068; void(__cdecl* uploadModelTransformBuf)(DWORD* a1, int a2) = (void(__cdecl*)(DWORD * a1, int a2))0x140444fa0; bool& performTransform = *(bool*)0x14cc57bb0; // vars that will contain the requiered info about GL buffers to perform the transform GLuint buf_tex; // check if a buffer target is okay to allow on non-Nvidia platforms // (used to prevent crashes in glBindBuffer and glBufferData) // only parameter buffer NV targets cause issues bool checkBufferTargetOk(GLenum target) { return !(target == GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV || target == GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV); } int __stdcall stub() { return 1; } bool disable_amd_check; bool enable_chara_skinning; bool use_TexSubImage; bool force_BGRA_upload; GLint tex_upload_format; struct MsString { union { char* string_ptr; char string_buf[16]; }; uint64_t len; uint64_t bufsize; char* GetCharBuf() { if (bufsize > 0xf && string_ptr != nullptr) return string_ptr; else return string_buf; }; void SetCharBuf(char* newcontent) { len = strlen(newcontent); bufsize = len; if (len > 0xf) { string_ptr = _strdup(newcontent); } else { strcpy_s(string_buf, newcontent); } } }; std::string shader_farc_path = ""; void* shader_farc_data = NULL; int64_t shader_farc_data_size; FILE* shader_file_handle = NULL; bool enable_shader_deltas; int64_t(*divaGetFileSize)(MsString* path) = (int64_t(*)(MsString* path))0x1400abb20; FILE* (*divaFsopen)(const char* path, const char* mode, int shflag) = (FILE* (*)(const char* path, const char* mode, int shflag))0x14085a17c; int64_t(*divaFread)(void* dst, int64_t size, int64_t count, FILE* file) = (int64_t(*)(void* dst, int64_t size, int64_t count, FILE* file))0x14085a6c4; int(*divaFclose)(FILE* file) = (int(*)(FILE* file))0x140846e9c; // not hooked, just so it can be called std::wstring ExePath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); return std::wstring(buffer); } std::wstring DirPath() { std::wstring exepath = ExePath(); std::wstring::size_type pos = exepath.find_last_of(L"\\/"); return exepath.substr(0, pos); } std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\Novidia.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); void loadConfig() { disable_amd_check = GetPrivateProfileIntW(L"general", L"disable_amd_check", 0, CONFIG_FILE) > 0 ? true : false; enable_chara_skinning = GetPrivateProfileIntW(L"general", L"enable_chara_skinning", 1, CONFIG_FILE) > 0 ? true : false; use_TexSubImage = GetPrivateProfileIntW(L"general", L"use_TexSubImage", 1, CONFIG_FILE) > 0 ? true : false; force_BGRA_upload = GetPrivateProfileIntW(L"general", L"force_BGRA_upload", 1, CONFIG_FILE) > 0 ? true : false; enable_shader_deltas = GetPrivateProfileIntW(L"general", L"shader_delta_patches", 1, CONFIG_FILE) > 0 ? true : false; if (GetPrivateProfileIntW(L"general", L"shader_amd_farc", 0, CONFIG_FILE) > 0) { MessageBoxA(NULL, "Attention: Use of shader_amd.farc has been discontinued and will no longer work. MAMD mdata is not required and can be deleted.\n\nIf you use modded shaders, amd-tools has been updated so it can generate new patches. Please check the readme for more information.", "Novidia", 0); WritePrivateProfileStringW(L"general", L"shader_amd_farc", L"0", CONFIG_FILE); } } void InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } //bool hasConflicts() //{ // printf("[Novidia] Checking for conflicts...\n"); // // HMODULE* hModules = new HMODULE[USHRT_MAX]; // HANDLE hProcess; // DWORD cbNeeded; // // hProcess = GetCurrentProcess(); // // if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) { // for (unsigned long long i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { // auto pNameFunc = (LPCWSTR(*)())GetProcAddress(hModules[i], "GetPluginName"); // if (pNameFunc) { // LPCWSTR name = pNameFunc(); // if (name && lstrcmpW(name, L"DivaGL") == 0) // { // // detected DivaGL // printf("[Novidia] Detected DivaGL! Quitting!\n"); //#ifdef _DEBUG // MessageBoxExW(NULL, L"Detected DivaGL! Quitting!\n", L"Novidia", MB_OK, 0); //#endif // delete[] hModules; // return true; // } // } // } // } // // printf("[Novidia] No conflicts found.\n"); // delete[] hModules; // return false; //} ================================================ FILE: source-code/source/plugins/Novidia/src/glStuff.h ================================================ #pragma once #include #include #include HMODULE ogl32 = GetModuleHandle(L"opengl32.dll"); PROC(*wGlGetProcAddress_forhook)(LPCSTR) = (PROC(*)(LPCSTR))(GetProcAddress(ogl32, "wglGetProcAddress")); // should probably just use GL.h, but I'm avoiding it to let me call hooked stuff as normal typedef uint32_t GLenum, GLuint, GLsizei, GLbitfield; typedef int32_t GLint; typedef uint64_t GLsizeiptr; typedef int64_t GLintptr, GLint64; typedef bool GLboolean; typedef char GLchar; #define GL_FALSE 0 #define GL_NO_ERROR 0 #define GL_TEXTURE_1D 0x0de0 #define GL_TEXTURE_2D 0x0de1 #define GL_FLOAT 0x1406 #define GL_RED 0x1903 #define GL_GREEN 0x1904 #define GL_BLUE 0x1905 #define GL_ALPHA 0x1906 #define GL_RGBA 0x1908 #define GL_NEAREST 0x2600 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_BGRA 0x80e1 #define GL_CLAMP_TO_BORDER 0x812d #define GL_CLAMP_TO_EDGE 0x812f #define GL_TEXTURE_IMAGE_FORMAT 0x828f #define GL_TEXTURE0 0x84c0 #define GL_TEXTURE8 0x84c8 #define GL_BUFFER_SIZE 0x8764 #define GL_RGBA32F 0x8814 #define GL_RGBA16F 0x881a #define GL_ARRAY_BUFFER 0x8892 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_READ_ONLY 0x88b8 #define GL_STREAM_DRAW 0x88e0 #define GL_STREAM_COPY 0x88e2 #define GL_COMPILE_STATUS 0x8b81 #define GL_LINK_STATUS 0x8b82 #define GL_CURRENT_PROGRAM 0x8b8d #define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8da2 #define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8da4 #define GL_TEXTURE_SWIZZLE_R 0x8e42 #define GL_TEXTURE_SWIZZLE_G 0x8e43 #define GL_TEXTURE_SWIZZLE_B 0x8e44 #define GL_TEXTURE_SWIZZLE_A 0x8e45 #define GL_TEXTURE_SWIZZLE_RGBA 0x8e46 #define GL_SHADER_STORAGE_BUFFER 0x90d2 #define GL_COMPUTE_SHADER 0x91b9 #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 #define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 //void(__cdecl** p_glActiveTexture)(GLenum texture) = (void(__cdecl**)(GLenum texture))0x1411a3db8; void(__cdecl* glGenTextures)(GLsizei n, GLuint* textures) = *(void(__cdecl**)(GLsizei, GLuint*))0x140965ad8; void(__cdecl* glBindTexture)(GLenum target, GLuint texture) = *(void(__cdecl**)(GLenum, GLuint))0x140965bf8; void(__cdecl* glTexParameteri)(GLenum target, GLenum pname, GLint param) = *(void(__cdecl**)(GLenum, GLenum, GLint))0x140965a18; void(__cdecl* glTexImage1D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void* data) = *(void(__cdecl**)(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, const void*))0x140965b58; void(__cdecl* glTexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels) = (void(__cdecl*)(GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const void*))GetProcAddress(ogl32, "glTexSubImage1D"); // these are all imported using wglGetProcAddress and can't be initialised until after the OpenGL context is created void(__cdecl* glActiveTexture)(GLenum texture); void(__cdecl* glTexStorage1D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); void(__cdecl* glGetInternalformativ)(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params); void(__cdecl* glBindBuffer)(GLenum target, GLuint buffer); void(__cdecl* glBindBufferARB)(GLenum target, GLuint buffer); void(__cdecl* glBufferData)(GLenum target, GLsizeiptr size, const void* data, GLenum usage); void(__cdecl* glBufferDataARB)(GLenum target, GLsizeiptr size, const void* data, GLenum usage); // just used for a nicer time getting addresses and hooking struct { void* ptr; const char* name; bool dynamic; } glFuncs[] = { {&glGenTextures, "glGenTextures", false}, {&glBindTexture, "glBindTexture", false}, {&glTexParameteri, "glTexParameteri", false}, {&glTexImage1D, "glTexImage1D", false}, {&glTexSubImage1D, "glTexSubImage1D", false}, {&glActiveTexture, "glActiveTexture", true}, {&glTexStorage1D, "glTexStorage1D", true}, {&glGetInternalformativ, "glGetInternalformativ", true}, {&glBindBuffer, "glBindBuffer", true}, {&glBindBufferARB, "glBindBufferARB", true}, {&glBufferData, "glBufferData", true}, {&glBufferDataARB, "glBufferDataARB", true}, }; bool loadGlAddresses() { bool ret = true; for (auto fn : glFuncs) { if (fn.dynamic) { *(PROC*)(fn.ptr) = wGlGetProcAddress_forhook(fn.name); if (*(PROC*)(fn.ptr) == nullptr) { printf("[Novidia] Failed to load address of %s\n", fn.name); ret = false; MessageBoxA(NULL, fn.name, NULL, NULL); } } } return ret; } const char* getGlFuncName(void* func) { const char* name = NULL; for (auto fn : glFuncs) { if (func == *(PROC*)(fn.ptr)) name = fn.name; } return name; } bool hookGlFunc(PROC* target, void* hook) { const char* name = getGlFuncName(*target); if (name == nullptr) { printf("[Novidia] Invalid hook target at %p\n", *target); return false; } DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); printf("[Novidia] Hooking %s\n", name); DetourAttach(&(PVOID&)*target, hook); DetourTransactionCommit(); return true; } ================================================ FILE: source-code/source/plugins/Patches/PatchApplier.h ================================================ #pragma once // PatchApplier provides the stuff for implementing patches for the specific game version class PatchApplier { public: virtual void ApplyPatches() {}; }; ================================================ FILE: source-code/source/plugins/Patches/PatchApplier600.h ================================================ #pragma once #include #include "PatchApplier.h" #include "framework.h" class PatchApplier600 : public PatchApplier { virtual void ApplyPatches() { const struct { void* Address; std::vector Data; } patches_600[] = { // Always return true for the SelCredit enter SelPv check { (void*)0x000000014037A560, { 0xB0, 0x01, 0xC3, 0x90, 0x90, 0x90 } }, // Just completely ignore all SYSTEM_STARTUP errors { (void*)0x00000001403DC590, { 0xC3 } }, // Always exit TASK_MODE_APP_ERROR on the first frame { (void*)0x00000001403DE8B7, { 0x90, 0x90 } }, { (void*)0x00000001403DE8D3, { 0x89, 0xD1, 0x90 } }, // Ignore the EngineClear variable to clear the framebuffer at all resolutions { (void*)0x00000001404E7470, { 0x90, 0x90 } }, { (void*)0x00000001404E7505, { 0x90, 0x90 } }, // Write ram files to the current directory instead of Y : / SBZV / ram { (void*)0x0000000140648AE9, { 0xE9, 0xD8, 0x00 } }, // Change mdata path from "C:/Mount/Option" to "mdata/" { (void*)0x0000000140A51058, { 0x6D, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x00 } }, { (void*)0x0000000140648A8E, { 0x06 } }, // Skip parts of the network check state { (void*)0x000000014064D391, { 0xE9, 0x22, 0x03, 0x00 } }, // Set the initial DHCP WAIT timer value to 0 { (void*)0x000000014064E0C7, { 0x00, 0x00 } }, // Ignore SYSTEM_STARTUP Location Server checks { (void*)0x000000014064EE82, { 0x90, 0x90 } }, // Toon Shader Fix by lybxlpsv { (void*)0x00000001404E813F, { 0x90 } }, { (void*)0x00000001404E8140, { 0x90 } }, // Toon Shader Outline Fix by lybxlpsv { (void*)0x000000014061C6B2, { 0x01 } }, // Skip unnecessary checks { (void*)0x0000000140207FB0, { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 } }, { (void*)0x000000014064A400, { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 } }, // Disables call to glutFitWindowSizeToDesktop, prevents window automatic resize { (void*)0x000000014018CE06, { 0x90, 0x90, 0x90, 0x90, 0x90 } }, // Allow modifier mode selection (by Team Shimapan) { (void*)0x00000001405A7C03, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, { (void*)0x00000001405A6B45, { 0x90, 0x90 } }, // allow modifier modes to work without use_card { (void*)0x00000001405A7B9A,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, { (void*)0x000000014012F2CA,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, // enable module selector without use_card // { (void*)0x00000001405C513B,{ 0x01 } }, // no // Force Hide IDs { (void*)0x000000014096D840, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, { (void*)0x000000014096D850, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // fix TouchReaction // get some more space by optimizing this code for size /*{ (void*)0x000000014067D1F2,{ 0x7E } }, // MOVQ XMM0,qword ptr [0x168 + RSP] (change to MOVQ) { (void*)(0x000000014067D1F2 + 0x7),{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x6C } }, // MOVQ qword ptr [RSP + 0x6c],XMM0 { (void*)(0x000000014067D1F2 + 0xD),{ 0xC7, 0x44, 0x24, 0x74, 0x00, 0x00, 0x00, 0x00 } }, // MOV dword ptr [RSP + 0x74],0x0 { (void*)(0x000000014067D1F2 + 0x15),{ 0xEB, 0x0E } }, // JMP 0x1406a2007 (to rest of function as usual) // unsure // add new code { (void*)(0x000000014067D1F2 + 0x17),{ 0x66, 0x48, 0x0F, 0x6E, 0xC2 } }, // MOVQ XMM0,RDX (load touch pos) { (void*)(0x000000014067D1F2 + 0x1C),{ 0xEB, 0x5D } }, // JMP 0x1406a205d // unsure { (void*)(0x000000014067D1F2 + 0x7B),{ 0x0F, 0x2A, 0x0D, 0xB8, 0x6A, 0x31, 0x00 } }, // CVTPI2PS XMM1,qword ptr [0x1409b8b1c] (load 1280x720) // unsuew { (void*)(0x000000014067D1F2 + 0x82),{ 0x0F, 0x12, 0x51, 0x1C } }, // MOVLPS XMM2,qword ptr [RCX + 0x1c] (load actual res) { (void*)(0x000000014067D1F2 + 0x86),{ 0xE9, 0x14, 0xFF, 0xFF, 0xFF } }, // JMP 0x1406a1f81 // unsure { (void*)(0x000000014067D1F2 - 0x61),{ 0x0F, 0x59, 0xC1 } }, // MULPS XMM0,XMM1 { (void*)(0x000000014067D1F2 - 0x61),{ 0x0F, 0x5E, 0xC2 } }, // DIVPS XMM0,XMM2 { (void*)(0x000000014067D1F2 - 0x5B),{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x10 } }, // MOVQ qword ptr [RSP+0x10],XMM0 { (void*)(0x000000014067D1F2 - 0x55),{ 0xEB, 0x06 } }, // JMP 0x1406a1f95 (back to original function) // unsure // jmp to new code { (void*)(0x000000014067D1F2 - 0x52),{ 0xEB, 0x67 } },*/ // JMP 0x1406a1ff9 // unsure }; for (size_t i = 0; i < _countof(patches_600); i++) InjectCode(patches_600[i].Address, patches_600[i].Data); // The old stereo patch... // Use 2 channels instead of 4 if (nStereo) { InjectCode((void*)0x0000000140A4A588, { 0x02 }); printf("[Patches] Stereo patch enabled\n"); } // Disable AA if (!nTAA) { // set TAA var (shouldn't be needed but whatever) //*(byte*)0x00000001411AB67C = 0; // no // make constructor/init not set TAA {DWORD oldProtect, bck; VirtualProtect((BYTE*)0x000000014049258D, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x000000014049258D + 0) = 0x90; *((byte*)0x000000014049258D + 1) = 0x90; *((byte*)0x000000014049258D + 2) = 0x90; VirtualProtect((BYTE*)0x000000014049258D, 3, oldProtect, &bck); } // not sure, but it's somewhere in TaskPvGame init // just make it set TAA to 0 instead of 1 to avoid possible issues {DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001400FF48D, 1, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001400FF48D + 0) = 0x00; VirtualProtect((BYTE*)0x00000001400FF48D, 1, oldProtect, &bck); } // prevent re-enabling after taking photos {DWORD oldProtect, bck; VirtualProtect((BYTE*)0x0000000140476EC8, 1, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x0000000140476EC8 + 0) = 0x00; VirtualProtect((BYTE*)0x0000000140476EC8, 1, oldProtect, &bck); } printf("[Patches] TAA disabled\n"); } if (!nMLAA) { // set MLAA var (shouldn't be needed but whatever) //*(byte*)0x00000001411AB680 = 0; // no // make constructor/init not set MLAA {DWORD oldProtect, bck; VirtualProtect((BYTE*)0x000000014049258A, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x000000014049258A + 0) = 0x90; *((byte*)0x000000014049258A + 1) = 0x90; *((byte*)0x000000014049258A + 2) = 0x90; VirtualProtect((BYTE*)0x000000014049258A, 3, oldProtect, &bck); } printf("[Patches] MLAA disabled\n"); } // Replace the hardcoded videos with MP4s, if they exist if (nMP4Movies) { patchMovieExt("adv_cfm_cm", (void*)0x0000000140989ED5); patchMovieExt("adv_sega_cm", (void*)0x0000000140989EF6); patchMovieExt("diva_adv02", (void*)0x00000001409C537D); patchMovieExt("diva_adv", (void*)0x00000001409C53AB); } // Hide "FREE PLAY" if (nHideFreeplay) { InjectCode((void*)0x0000000140388A5B, { 0x06, 0xB6 }); printf("[Patches] Hide FREE PLAY/CREDIT(S) enabled\n"); } // Enable "FREE PLAY" mode if (nFreeplay || nHideFreeplay) { InjectCode((void*)0x00000001403A1B1A, { 0x75 }); printf("[Patches] Show FREE PLAY instead of CREDIT(S)\n"); if (nPDLoaderText && !nHideFreeplay) { InjectCode((void*)0x00000001409BC188, { 'U', 'N', 'S', 'U', 'P', 'P', 'O', 'R', 'T', 'E', 'D', '\0' }); printf("[Patches] Show PD Loader text\n"); } } // Use GLUT_CURSOR_RIGHT_ARROW instead of GLUT_CURSOR_NONE if (nCursor) { /*InjectCode((void*)0x000000014018B44A, { 0x00 }); InjectCode((void*)0x00000001402E7FE5, { 0xeb }); // Disable debug cursor // unsure printf("[Patches] Cursor enabled\n");*/ } // Override status icon states to be invalid (hides them) if (nHideStatusIcons || nStatusIcons > 0) { std::vector cardIcon = { 0xFD, 0x0A }; std::vector networkIcon = { 0x9E, 0x1E }; if (nHideStatusIcons || nStatusIcons == 1 || nStatusIcons >= 5) // 1 or invalid for hidden { cardIcon = { 0xFD, 0x0A }; networkIcon = { 0x9E, 0x1E }; printf("[Patches] Status icons hidden\n"); } else if (nStatusIcons == 2) // 2 for error icons { cardIcon = { 0xFA, 0x0A }; networkIcon = { 0x9F, 0x1E }; printf("[Patches] Status icons set to error state\n"); } else if (nStatusIcons == 3) // 3 for OK icons { cardIcon = { 0xFC, 0x0A }; networkIcon = { 0xA0, 0x1E }; printf("[Patches] Status icons set to OK state\n"); } else if (nStatusIcons == 4) // 4 for partial OK icons { cardIcon = { 0xFB, 0x0A }; networkIcon = { 0xA1, 0x1E }; printf("[Patches] Status icons set to partial OK state\n"); } // card icon InjectCode((void*)0x00000001403A0C9E, cardIcon); // error state InjectCode((void*)0x00000001403A0CA3, cardIcon); // OK state // network icon InjectCode((void*)0x00000001403A107B, networkIcon); // error state InjectCode((void*)0x00000001403A1085, networkIcon); // OK state InjectCode((void*)0x00000001403A109B, networkIcon); // partial state InjectCode((void*)0x00000001403A10D5, { 0x48, 0xE9 }); // never show the error code for partial connection // I was going to use this with a string, but the assignment wasn't behaving well and making separate prints was easier than figuring it out // printf("[Patches] Status icons %s\n", iconType); } // Removes PV watermark if (nHidePVWatermark) { InjectCode((void*)0x00000001409D9798, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); printf("[Patches] PV watermark hidden\n"); } // Disable the PV screen photo UI if (nNoPVUi) { InjectCode((void*)0x0000000140476DB1, { 0xEB, 0x6F }); // skip button panel image (JMP 0x14048FB02) // unsure // patch minimum PV UI state to 1 instead of 0 // hook check for lyrics enabled (UI state < 2) to change UI state 0 into 1 // dump new code in the skipped button panel condition InjectCode((void*)0x0000000140476DB3, { 0xC7, 0x83, 0x58, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }); // MOV dword ptr [0x158 + RBX],0x1 InjectCode((void*)0x0000000140476DBD, { 0xC6, 0x80, 0x3A, 0xD1, 0x02, 0x00, 0x01 }); // MOV byte ptr [0x2d13a + RAX],0x1 InjectCode((void*)0x0000000140476DC4, { 0xE9, 0x8B, 0xFB, 0xFF, 0xFF }); // JMP 0x14048F634 // unsure InjectCode((void*)0x000000014047694D, { 0xE9, 0x61, 0x04, 0x00, 0x00 }); // JMP 0x14048FA93 // unsure printf("[Patches] PV UI disabled\n"); } // Don't show volume control if (nHideVolCtrl) { // skip SE button InjectCode((void*)0x000000014096CD28, { 0xC0, 0xD3 }); // skip volume sliders button InjectCode((void*)0x0000000140A4A3D8, { 0xE0, 0x50 }); printf("[Patches] Volume control hidden\n"); } // Skip loading (and therefore displaying) song lyrics if (nNoLyrics) { InjectCode((void*)0x00000001404CE362, { 0x00, 0x00 }); InjectCode((void*)0x00000001404CE29E, { 0x48, 0xE9 }); // ensure first iteration doesn't run // unsure printf("[Patches] Lyrics disabled\n"); } // Skip loading (and therefore displaying) song movies if (nNoMovies) { InjectCode((void*)0x00000001404D1C6B, { 0x48, 0xE9 }); // unsure InjectCode((void*)0x00000001404D1B61, { 0x48, 0xE9 }); // unsure printf("[Patches] Movies disabled\n"); } // Disable error banner if (nNoError) { // Disable Errors Banner InjectCode((void*)0x00000001403A0DCB, { 0x90, 0x90 }); printf("[Patches] Errors Banner disabled\n"); } // Disable timer if (nNoTimer) { // Freeze mode selection timer InjectCode((void*)0x00000001405456DE, { 0x90, 0x90, 0x90 }); // Freeze PV selection timer InjectCode((void*)0x000000014059B21F, { 0x90, 0x90, 0x90, 0x90 }); } // Disable timer sprite if (nNoTimerSprite) { InjectCode((void*)0x00000001409883A8, { 0x00 }); // time_loop InjectCode((void*)0x0000000140A01E20, { 0x00 }); // time_in InjectCode((void*)0x0000000140A01E28, { 0x00 }); // time_out } // Enhanced Stage Manager if (nEStageManager > 0) { // Replace the function that provides the number of stages and compact some of it InjectCode((void*)0x0000000140371E50, { 0x48, 0x8B, 0x88, 0x40, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8B, 0xD0, 0x48, 0x8B, 0x88, 0x48, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x28, 0x8B, 0x88, 0x50, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x30, 0x8B, 0x88, 0x54, 0x01, 0x00, 0x00, 0x8B, 0x80, 0x58, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x38, 0x8B, 0x82, 0x5C, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x34, 0x89, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x82, 0x60, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8B, 0x82, 0x68, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x82, 0x70, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x50, 0x8B, 0x82, 0x78, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x58, 0x84, 0xC0, 0x74, 0x2A, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0xC1, 0xE8, 0x20, 0x85, 0xC0, 0x75, 0x1D, 0xE8, 0xD9, 0xD9, 0xE5, 0xFF, 0x48, 0x85, 0xC0, 0x74, 0x13, 0x48, 0x8D, 0x48, 0x10, 0xE8, 0xFB, 0xD3, 0xE5, 0xFF, 0xB9, 0x03, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x0F, 0x45, 0xD9, 0x8B, 0x1D, 0x1B, 0x0C, 0x00, 0x00, 0x83, 0x3D, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x74, 0x06, 0x8B, 0x1D, 0x10, 0x0C, 0x00, 0x00, 0x8B, 0xC3, 0x48, 0x83, 0xC4, 0x60, 0x5B, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); // unsure // Jump to another section by addding some code to replace the values (Jump 1) InjectCode((void*)(0x0000000140371E50 + 0x104), { 0xE9, 0x87, 0x0B, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); // unsure // Jump to another section by addding some code to replace the values (Replace 1/2) while some reserving space for values InjectCode((void*)(0x0000000140371E50 + 0xC50), { 0xFF, 0x05, 0x76, 0x00, 0x00, 0x00, 0x8B, 0x0D, 0x70, 0x00, 0x00, 0x00, 0xBA, 0x02, 0x00, 0x00, 0x00, 0x83, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0xFF, 0xC2, 0x39, 0xD1, 0x0F, 0x4D, 0xCA, 0x89, 0x48, 0x08, 0xB9, 0x0E, 0x00, 0x00, 0x00, 0xE8, 0x92, 0x98, 0xE0, 0xFF, 0xB0, 0x01, 0x48, 0x83, 0xC4, 0x28, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x44, 0x89, 0x61, 0x08, 0x44, 0x88, 0x61, 0x0C, 0x4C, 0x89, 0x61, 0x10, 0x44, 0x89, 0x25, 0x29, 0x00, 0x00, 0x00, 0xE9, 0x68, 0xF4, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); // unsure // Use the value from our own address instead of the original one InjectCode((void*)0x00000001403DDABF, { 0x48, 0x8D, 0x05, 0x4A, 0x18, 0xDA, 0x00, 0x8B, 0x1D, 0x00, 0x56 }); // unsure // Jump to another section by addding some code to replace the values (Jump 2) InjectCode((void*)(0x00000001403F65AF + 0x89), { 0xE9, 0x03, 0x55, 0xF9, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); // unsure DWORD StageCountProtect; VirtualProtect((int32_t*)0x140372B10, 0x10, PAGE_EXECUTE_READWRITE, &StageCountProtect); // unsure int* ESM = (int*)0x0000000140372B10; // unsure if (nEStageManagerEncore) ESM[1] = nEStageManager; else ESM[0] = nEStageManager; ESM[2] = nEStageManagerEncore; printf("[Patches] Enhanced Stage Manager enabled\n"); } // OpenGL Patches //if (nOGLPatchA) //{ // // (call cs:glGetError) -> (xor eax, eax); (nop); (nop); (nop); (nop); // InjectCode((void*)0x000000014067842D, { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 }); //} //if (nOGLPatchB) //{ // // (js loc_14069BC32) -> (nop)... // InjectCode((void*)0x0000000140676D04, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); //} // Unlock PSEUDO modules (which will all default to Miku, unless we also patch them to match the first performer) if (nUnlockPseudo) { InjectCode((void*)0x00000001409E71C0, { 0x00 }); InjectCode((void*)0x00000001409E71D0, { 0x00 }); InjectCode((void*)0x00000001409E71E0, { 0x00 }); InjectCode((void*)0x00000001409E71F0, { 0x00 }); InjectCode((void*)0x00000001409E7200, { 0x00 }); } // Enable card button by somewhatlurker (pretty much just eye candy for now) if (nCard) { InjectCode((void*)0x00000001405449EB, { 0x90, 0x90 }); } // The original slider update needs to run for hardware sliders to work -- only patch it when using emulation if (!nHardwareSlider) { // Don't update the touch slider state so we can write our own InjectCode((void*)0x00000001405F0C5B, { 0x90, 0x90, 0x90, 0x8B, 0x42, 0xE0, 0x90, 0x90, 0x90 }); } } }; ================================================ FILE: source-code/source/plugins/Patches/PatchApplier710.h ================================================ #pragma once #pragma once #include #include "PatchApplier.h" #include "framework.h" class PatchApplier710 : public PatchApplier { virtual void ApplyPatches() { const struct { void* Address; std::vector Data; } patches_710[] = { // Just completely ignore all SYSTEM_STARTUP errors { (void*)0x00000001403F5080, { 0xC3 } }, // Always exit TASK_MODE_APP_ERROR on the first frame { (void*)0x00000001403F73A7, { 0x90, 0x90 } }, { (void*)0x00000001403F73C3, { 0x89, 0xD1, 0x90 } }, // Ignore the EngineClear variable to clear the framebuffer at all resolutions { (void*)0x0000000140501480, { 0x90, 0x90 } }, { (void*)0x0000000140501515, { 0x90, 0x90 } }, // Write ram files to the current directory instead of Y : / SBZV / ram { (void*)0x000000014066CF09, { 0xE9, 0xD8, 0x00 } }, // Change mdata path from "C:/Mount/Option" to "mdata/" { (void*)0x0000000140A8CA18, { 0x6D, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x00 } }, { (void*)0x000000014066CEAE, { 0x06 } }, // Skip parts of the network check state { (void*)0x00000001406717B1, { 0xE9, 0x22, 0x03, 0x00 } }, // Set the initial DHCP WAIT timer value to 0 { (void*)0x00000001406724E7, { 0x00, 0x00 } }, // Ignore SYSTEM_STARTUP Location Server checks { (void*)0x00000001406732A2, { 0x90, 0x90 } }, // Toon Shader Fix by lybxlpsv { (void*)0x000000014050214F, { 0x90 } }, { (void*)0x0000000140502150, { 0x90 } }, // Toon Shader Outline Fix by lybxlpsv { (void*)0x0000000140641102, { 0x01 } }, // Skip unnecessary checks { (void*)0x0000000140210820, { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 } }, { (void*)0x000000014066E820, { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 } }, // Disables call to glutFitWindowSizeToDesktop, prevents window automatic resize { (void*)0x0000000140194E06, { 0x90, 0x90, 0x90, 0x90, 0x90 } }, // Allow modifier mode selection (by Team Shimapan) { (void*)0x00000001405CB1B3, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, { (void*)0x00000001405CA0F5, { 0x90, 0x90 } }, // allow modifier modes to work without use_card { (void*)0x00000001405CB14A,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, { (void*)0x0000000140136CFA,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, // enable module selector without use_card { (void*)0x00000001405C513B,{ 0x01 } }, // fix back button { (void*)0x0000000140578FB8, { 0xE9, 0x73, 0xFF, 0xFF, 0xFF } }, // Force Hide IDs { (void*)0x00000001409A5918, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, { (void*)0x00000001409A5928, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // fix TouchReaction // get some more space by optimizing this code for size { (void*)0x00000001406A1FE2,{ 0x7E } }, // MOVQ XMM0,qword ptr [0x168 + RSP] (change to MOVQ) { (void*)0x00000001406A1FE9,{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x6C } }, // MOVQ qword ptr [RSP + 0x6c],XMM0 { (void*)0x00000001406A1FEF,{ 0xC7, 0x44, 0x24, 0x74, 0x00, 0x00, 0x00, 0x00 } }, // MOV dword ptr [RSP + 0x74],0x0 { (void*)0x00000001406A1FF7,{ 0xEB, 0x0E } }, // JMP 0x1406a2007 (to rest of function as usual) // add new code { (void*)0x00000001406A1FF9,{ 0x66, 0x48, 0x0F, 0x6E, 0xC2 } }, // MOVQ XMM0,RDX (load touch pos) { (void*)0x00000001406A1FFE,{ 0xEB, 0x5D } }, // JMP 0x1406a205d { (void*)0x00000001406A205D,{ 0x0F, 0x2A, 0x0D, 0xB8, 0x6A, 0x31, 0x00 } }, // CVTPI2PS XMM1,qword ptr [0x1409b8b1c] (load 1280x720) { (void*)0x00000001406A2064,{ 0x0F, 0x12, 0x51, 0x1C } }, // MOVLPS XMM2,qword ptr [RCX + 0x1c] (load actual res) { (void*)0x00000001406A2068,{ 0xE9, 0x14, 0xFF, 0xFF, 0xFF } }, // JMP 0x1406a1f81 { (void*)0x00000001406A1F81,{ 0x0F, 0x59, 0xC1 } }, // MULPS XMM0,XMM1 { (void*)0x00000001406A1F84,{ 0x0F, 0x5E, 0xC2 } }, // DIVPS XMM0,XMM2 { (void*)0x00000001406A1F87,{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x10 } }, // MOVQ qword ptr [RSP+0x10],XMM0 { (void*)0x00000001406A1F8D,{ 0xEB, 0x06 } }, // JMP 0x1406a1f95 (back to original function) // jmp to new code { (void*)0x00000001406A1F90,{ 0xEB, 0x67 } }, // JMP 0x1406a1ff9 }; for (size_t i = 0; i < _countof(patches_710); i++) InjectCode(patches_710[i].Address, patches_710[i].Data); // The old stereo patch... // Use 2 channels instead of 4 if (nStereo) { InjectCode((void*)0x0000000140A860C0, { 0x02 }); printf("[Patches] Stereo patch enabled\n"); } // Disable AA if (!nTAA) { // set TAA var (shouldn't be needed but whatever) *(byte*)0x00000001411AB67C = 0; // make constructor/init not set TAA {DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001404AB11D, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001404AB11D + 0) = 0x90; *((byte*)0x00000001404AB11D + 1) = 0x90; *((byte*)0x00000001404AB11D + 2) = 0x90; VirtualProtect((BYTE*)0x00000001404AB11D, 3, oldProtect, &bck); } // not sure, but it's somewhere in TaskPvGame init // just make it set TAA to 0 instead of 1 to avoid possible issues {DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001401063CE, 1, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001401063CE + 0) = 0x00; VirtualProtect((BYTE*)0x00000001401063CE, 1, oldProtect, &bck); } // prevent re-enabling after taking photos {DWORD oldProtect, bck; VirtualProtect((BYTE*)0x000000014048FBA9, 1, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x000000014048FBA9 + 0) = 0x00; VirtualProtect((BYTE*)0x000000014048FBA9, 1, oldProtect, &bck); } printf("[Patches] TAA disabled\n"); } if (!nMLAA) { // set MLAA var (shouldn't be needed but whatever) *(byte*)0x00000001411AB680 = 0; // make constructor/init not set MLAA {DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001404AB11A, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001404AB11A + 0) = 0x90; *((byte*)0x00000001404AB11A + 1) = 0x90; *((byte*)0x00000001404AB11A + 2) = 0x90; VirtualProtect((BYTE*)0x00000001404AB11A, 3, oldProtect, &bck); } printf("[Patches] MLAA disabled\n"); } // gamma if (nGamma != 100 && nGamma != 0) { float gamma_float = (float)nGamma / 100.0f; InjectCode((void*)(0x1404a863b), { *((uint8_t*)(&gamma_float)), *((uint8_t*)(&gamma_float) + 1), *((uint8_t*)(&gamma_float) + 2), *((uint8_t*)(&gamma_float) + 3) }); printf("[Patches] Gamma: %f\n", gamma_float); } // Replace the hardcoded videos with MP4s, if they exist if (nMP4Movies) { patchMovieExt("adv_cm_01", (void*)0x00000001409A53CC); patchMovieExt("adv_cm_02", (void*)0x00000001409A53E4); patchMovieExt("adv_cm_03", (void*)0x00000001409A53FC); patchMovieExt("adv_cfm_cm", (void*)0x00000001409C22CD); patchMovieExt("adv_sega_cm", (void*)0x00000001409C22EE); patchMovieExt("diva_adv02", (void*)0x00000001409FF455); patchMovieExt("diva_adv", (void*)0x00000001409FF483); } // Hide "FREE PLAY" if (nHideFreeplay) { InjectCode((void*)0x00000001403BABEF, { 0x06, 0xB6 }); printf("[Patches] Hide FREE PLAY/CREDIT(S) enabled\n"); } // Enable "FREE PLAY" mode if (nFreeplay || nHideFreeplay) { // Always return true for the SelCredit enter SelPv check InjectCode((void*)0x0000000140393610, { 0xB0, 0x01, 0xC3, 0x90, 0x90, 0x90 }); InjectCode((void*)0x00000001403BABEA, { 0x75 }); printf("[Patches] Show FREE PLAY instead of CREDIT(S)\n"); if (nPDLoaderText && !nHideFreeplay) { InjectCode((void*)0x00000001409F61F0, { 0x50, 0x44, 0x20, 0x4C, 0x6F, 0x61, 0x64, 0x65, 0x72, 0x20, 't', 'e', 's', 't', 0x00}); printf("[Patches] Show PD Loader text\n"); } } // Use GLUT_CURSOR_RIGHT_ARROW instead of GLUT_CURSOR_NONE if (nCursor) { InjectCode((void*)0x000000014019341B, { 0x00 }); InjectCode((void*)0x00000001403012b5, { 0xeb }); // Disable debug cursor printf("[Patches] Cursor enabled\n"); } // Override status icon states to be invalid (hides them) if (nHideStatusIcons || nStatusIcons > 0) { std::vector cardIcon = { 0xFD, 0x0A }; std::vector networkIcon = { 0x9E, 0x1E }; if (nHideStatusIcons || nStatusIcons == 1 || nStatusIcons >= 5) // 1 or invalid for hidden { cardIcon = { 0xFD, 0x0A }; networkIcon = { 0x9E, 0x1E }; printf("[Patches] Status icons hidden\n"); } else if (nStatusIcons == 2) // 2 for error icons { cardIcon = { 0xFA, 0x0A }; networkIcon = { 0x9F, 0x1E }; printf("[Patches] Status icons set to error state\n"); } else if (nStatusIcons == 3) // 3 for OK icons { cardIcon = { 0xFC, 0x0A }; networkIcon = { 0xA0, 0x1E }; printf("[Patches] Status icons set to OK state\n"); } else if (nStatusIcons == 4) // 4 for partial OK icons { cardIcon = { 0xFB, 0x0A }; networkIcon = { 0xA1, 0x1E }; printf("[Patches] Status icons set to partial OK state\n"); } // card icon InjectCode((void*)0x00000001403B9D6E, cardIcon); // error state InjectCode((void*)0x00000001403B9D73, cardIcon); // OK state // network icon InjectCode((void*)0x00000001403BA14B, networkIcon); // error state InjectCode((void*)0x00000001403BA155, networkIcon); // OK state InjectCode((void*)0x00000001403BA16B, networkIcon); // partial state InjectCode((void*)0x00000001403BA1A5, { 0x48, 0xE9 }); // never show the error code for partial connection // I was going to use this with a string, but the assignment wasn't behaving well and making separate prints was easier than figuring it out // printf("[Patches] Status icons %s\n", iconType); } // Removes PV watermark if (nHidePVWatermark) { InjectCode((void*)0x0000000140A13A88, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); printf("[Patches] PV watermark hidden\n"); } // Disable the PV screen photo UI if (nNoPVUi) { InjectCode((void*)0x000000014048FA91, { 0xEB, 0x6F }); // skip button panel image (JMP 0x14048FB02) // patch minimum PV UI state to 1 instead of 0 // hook check for lyrics enabled (UI state < 2) to change UI state 0 into 1 // dump new code in the skipped button panel condition InjectCode((void*)0x000000014048FA93, { 0xC7, 0x83, 0x58, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }); // MOV dword ptr [0x158 + RBX],0x1 InjectCode((void*)0x000000014048FA9D, { 0xC6, 0x80, 0x3A, 0xD1, 0x02, 0x00, 0x01 }); // MOV byte ptr [0x2d13a + RAX],0x1 InjectCode((void*)0x000000014048FAA4, { 0xE9, 0x8B, 0xFB, 0xFF, 0xFF }); // JMP 0x14048F634 InjectCode((void*)0x000000014048F62D, { 0xE9, 0x61, 0x04, 0x00, 0x00 }); // JMP 0x14048FA93 printf("[Patches] PV UI disabled\n"); } // Don't show volume control if (nHideVolCtrl) { // skip SE button InjectCode((void*)0x00000001409A4D60, { 0xC0, 0xD3 }); // skip volume sliders button InjectCode((void*)0x0000000140A85F10, { 0xE0, 0x50 }); printf("[Patches] Volume control hidden\n"); } // Skip loading (and therefore displaying) song lyrics if (nNoLyrics) { InjectCode((void*)0x00000001404E7A25, { 0x00, 0x00 }); InjectCode((void*)0x00000001404E7950, { 0x48, 0xE9 }); // ensure first iteration doesn't run printf("[Patches] Lyrics disabled\n"); } // Skip loading (and therefore displaying) song movies if (nNoMovies) { InjectCode((void*)0x00000001404EB584, { 0x48, 0xE9 }); InjectCode((void*)0x00000001404EB471, { 0x48, 0xE9 }); printf("[Patches] Movies disabled\n"); } // Disable error banner if (nNoError) { // Disable Errors Banner InjectCode((void*)0x00000001403B9E9B, { 0x90, 0x90 }); printf("[Patches] Errors Banner disabled\n"); } // Disable timer if (nNoTimer) { // Freeze mode selection timer InjectCode((void*)0x0000000140566B9E, { 0x90, 0x90, 0x90 }); // Freeze PV selection timer InjectCode((void*)0x00000001405BDFBF, { 0x90, 0x90, 0x90, 0x90 }); } // Disable timer sprite if (nNoTimerSprite) { InjectCode((void*)0x00000001409C0758, { 0x00 }); // time_loop InjectCode((void*)0x0000000140A3D3F0, { 0x00 }); // time_in InjectCode((void*)0x0000000140A3D3F8, { 0x00 }); // time_out } // Enhanced Stage Manager if (nEStageManager > 0) { // Replace the function that provides the number of stages and compact some of it InjectCode((void*)0x000000014038AEF0, { 0x48, 0x8B, 0x88, 0x40, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8B, 0xD0, 0x48, 0x8B, 0x88, 0x48, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x28, 0x8B, 0x88, 0x50, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x30, 0x8B, 0x88, 0x54, 0x01, 0x00, 0x00, 0x8B, 0x80, 0x58, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x38, 0x8B, 0x82, 0x5C, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x34, 0x89, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x82, 0x60, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8B, 0x82, 0x68, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x82, 0x70, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x50, 0x8B, 0x82, 0x78, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x58, 0x84, 0xC0, 0x74, 0x2A, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0xC1, 0xE8, 0x20, 0x85, 0xC0, 0x75, 0x1D, 0xE8, 0xD9, 0xD9, 0xE5, 0xFF, 0x48, 0x85, 0xC0, 0x74, 0x13, 0x48, 0x8D, 0x48, 0x10, 0xE8, 0xFB, 0xD3, 0xE5, 0xFF, 0xB9, 0x03, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x0F, 0x45, 0xD9, 0x8B, 0x1D, 0x1B, 0x0C, 0x00, 0x00, 0x83, 0x3D, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x74, 0x06, 0x8B, 0x1D, 0x10, 0x0C, 0x00, 0x00, 0x8B, 0xC3, 0x48, 0x83, 0xC4, 0x60, 0x5B, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); // Jump to another section by addding some code to replace the values (Jump 1) InjectCode((void*)0x000000014038AFF4, { 0xE9, 0x87, 0x0B, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); // Jump to another section by addding some code to replace the values (Replace 1/2) while some reserving space for values InjectCode((void*)0x000000014038BB40, { 0xFF, 0x05, 0x76, 0x00, 0x00, 0x00, 0x8B, 0x0D, 0x70, 0x00, 0x00, 0x00, 0xBA, 0x02, 0x00, 0x00, 0x00, 0x83, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0xFF, 0xC2, 0x39, 0xD1, 0x0F, 0x4D, 0xCA, 0x89, 0x48, 0x08, 0xB9, 0x0E, 0x00, 0x00, 0x00, 0xE8, 0x92, 0x98, 0xE0, 0xFF, 0xB0, 0x01, 0x48, 0x83, 0xC4, 0x28, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x44, 0x89, 0x61, 0x08, 0x44, 0x88, 0x61, 0x0C, 0x4C, 0x89, 0x61, 0x10, 0x44, 0x89, 0x25, 0x29, 0x00, 0x00, 0x00, 0xE9, 0x68, 0xF4, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); // Use the value from our own address instead of the original one InjectCode((void*)0x00000001403F65AF, { 0x48, 0x8D, 0x05, 0x4A, 0x18, 0xDA, 0x00, 0x8B, 0x1D, 0x00, 0x56 }); // Jump to another section by addding some code to replace the values (Jump 2) InjectCode((void*)0x00000001403F6638, { 0xE9, 0x03, 0x55, 0xF9, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); DWORD StageCountProtect; VirtualProtect((int32_t*)0x14038BBB0, 0x10, PAGE_EXECUTE_READWRITE, &StageCountProtect); int* ESM = (int*)0x000000014038BBB0; if (nEStageManagerEncore) ESM[1] = nEStageManager; else ESM[0] = nEStageManager; ESM[2] = nEStageManagerEncore; printf("[Patches] Enhanced Stage Manager enabled\n"); } //// OpenGL Patches //if (nOGLPatchA) //{ // // (call cs:glGetError) -> (xor eax, eax); (nop); (nop); (nop); (nop); // InjectCode((void*)0x000000014069D21D, { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 }); //} //if (nOGLPatchB) //{ // // (js loc_14069BC32) -> (nop)... // InjectCode((void*)0x000000014069BAF4, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); //} // // Unlock PSEUDO modules (which will all default to Miku, unless we also patch them to match the first performer) if (nUnlockPseudo) { InjectCode((void*)0x0000000140A21770, { 0x00 }); InjectCode((void*)0x0000000140A21780, { 0x00 }); InjectCode((void*)0x0000000140A21790, { 0x00 }); InjectCode((void*)0x0000000140A217A0, { 0x00 }); InjectCode((void*)0x0000000140A217B0, { 0x00 }); } // Enable card button by somewhatlurker (pretty much just eye candy for now) if (nCard) { InjectCode((void*)0x0000000140565E6B, { 0x90, 0x90 }); } // The original slider update needs to run for hardware sliders to work -- only patch it when using emulation if (!nHardwareSlider) { // Don't update the touch slider state so we can write our own InjectCode((void*)0x000000014061579B, { 0x90, 0x90, 0x90, 0x8B, 0x42, 0xE0, 0x90, 0x90, 0x90 }); } // Quick start if (!nUseDivahookBat) { if (nQuickStart == 1) // skip the card/guest screen { InjectCode((void*)0x0000000140578EA9, { 0xE9, 0x8E, 0x00, 0x00, 0x00 }); } else if (nQuickStart == 2) // skip everything; normal mode { InjectCode((void*)0x0000000140578EA9, { 0xE9, 0xF1, 0x00, 0x00, 0x00 }); InjectCode((void*)0x0000000140578E9D, { 0xC7, 0x47, 0x68, 0x28, 0x00, 0x00, 0x00 }); // skip back button error } } // Disable scrolling sound effect if (nNoScrollingSfx) { InjectCode((void*)0x00000001405C84B3, { 0x90, 0x90, 0x90, 0x90, 0x90 }); } if (nEnablePvCustomization) { // Disable hand scaling if (nNoHandScaling) { InjectCode((void*)0x0000000140120709, { 0xE9, 0x82, 0x0A, 0x00 }); } // Default hand size if (nDefaultHandSize >= 10000 && nDefaultHandSize <= 1000000) { printf("[Patches] Changing default hand size...\n"); const float num = (float)nDefaultHandSize / 10000.0; DWORD oldProtect; float* addr1 = (float*)(0x140506B59); float* addr2 = (float*)(0x140506B60); /*float* addr3 = (float*)(0x140506B67); float* addr4 = (float*)(0x140506B71);*/ VirtualProtect(addr1, 4, PAGE_EXECUTE_READWRITE, &oldProtect); VirtualProtect(addr2, 4, PAGE_EXECUTE_READWRITE, &oldProtect); /*VirtualProtect(addr3, 4, PAGE_EXECUTE_READWRITE, &oldProtect); VirtualProtect(addr4, 4, PAGE_EXECUTE_READWRITE, &oldProtect);*/ *addr1 = *addr2 /*= *addr3 = *addr4*/ = num; VirtualProtect(addr1, 4, oldProtect, nullptr); VirtualProtect(addr2, 4, oldProtect, nullptr); /*VirtualProtect(addr3, 4, oldProtect, nullptr); VirtualProtect(addr4, 4, oldProtect, nullptr);*/ printf("[Patches] New default hand size: %f\n", num); } // Force mouth animations { if (nForceMouth == 1) // PDA { printf("[Patches] Forcing PDA mouth...\n"); int* mouth_table = (int*)(0x1409A1DC0); DWORD oldProtect; VirtualProtect(mouth_table, 44, PAGE_EXECUTE_READWRITE, &oldProtect); for (int i = 0; i < 11; i++) { mouth_table[i]++; } VirtualProtect(mouth_table, 44, oldProtect, nullptr); printf("[Patches] PDA mouth forced\n"); } else if (nForceMouth == 2) // FT { printf("[Patches] Forcing FT mouth...\n"); int* mouth_table_oldid = (int*)(0x1409A1E1C); DWORD oldProtect; VirtualProtect(mouth_table_oldid, 44, PAGE_EXECUTE_READWRITE, &oldProtect); for (int i = 0; i < 11; i++) { mouth_table_oldid[i]--; } VirtualProtect(mouth_table_oldid, 44, oldProtect, nullptr); printf("[Patches] FT mouth forced\n"); } } // Force expressions { if (nForceExpressions == 1) // PDA { printf("[Patches] Forcing PDA expressions...\n"); int* exp_table = (int*)(0x140A21900); DWORD oldProtect; VirtualProtect(exp_table, 104, PAGE_EXECUTE_READWRITE, &oldProtect); for (int i = 0; i < 26; i++) { exp_table[i] += 2; } VirtualProtect(exp_table, 104, oldProtect, nullptr); printf("[Patches] PDA expressions forced\n"); } else if (nForceExpressions == 2) // FT { printf("[Patches] Forcing FT expressions...\n"); int* exp_table_oldid = (int*)(0x140A219D0); DWORD oldProtect; VirtualProtect(exp_table_oldid, 104, PAGE_EXECUTE_READWRITE, &oldProtect); for (int i = 0; i < 26; i++) { exp_table_oldid[i] -= 2; } VirtualProtect(exp_table_oldid, 104, oldProtect, nullptr); printf("[Patches] FT expressions forced\n"); } } // Force look animations { if (nForceLook == 1) // PDA { printf("[Patches] Forcing PDA look...\n"); int* look_table = (int*)(0x1409A1D70); DWORD oldProtect; VirtualProtect(look_table, 36, PAGE_EXECUTE_READWRITE, &oldProtect); for (int i = 0; i < 9; i++) { look_table[i]++; } VirtualProtect(look_table, 36, oldProtect, nullptr); printf("[Patches] PDA look forced\n"); } else if (nForceLook == 2) // FT { printf("[Patches] Forcing FT look...\n"); int* look_table_oldid = (int*)(0x1409A1D9C); DWORD oldProtect; VirtualProtect(look_table_oldid, 36, PAGE_EXECUTE_READWRITE, &oldProtect); for (int i = 0; i < 9; i++) { look_table_oldid[i]--; } VirtualProtect(look_table_oldid, 36, oldProtect, nullptr); printf("[Patches] FT look forced\n"); } } } // Sing missed notes if (nSingMissed) { InjectCode((void*)0x140109044, { 0xEB }); // Breaks border: // InjectCode((void*)0x140109096, { 0xEB }); } // NPR1 { if (nNpr1 == 1) // force on { InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E }); InjectCode((void*)0x0000000140502FC6, { 0x01, 0x00, 0x00, 0x00, 0xC3 }); printf("[Patches] NPR1 forced\n"); } else if (nNpr1 == 2) // force off { InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E }); InjectCode((void*)0x0000000140502FC6, { 0x00, 0x00, 0x00, 0x00, 0xC3 }); printf("[Patches] NPR1 disabled\n"); } } // Depth of Field if (!nDoF) { InjectCode((void*)0x00000001409476AB, { 0x90, 0x90, 0x90, 0x90, 0x90 }); InjectCode((void*)0x00000001411AB650, { 0b00000001 }); } // MAG filter if (nMAG > 0) { //InjectCode((void*)0x00000001404AB142, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); unsigned char filter; switch (nMAG) { case 1: // nearest filter = 0; InjectCode((void*)0x00000001404ACE56, { 0x90, 0x90 }); break; case 2: // sharpen filter = 3; // sharpen(4tap) break; case 3: // cone filter = 5; // cone(2tap) break; default: filter = 1; } //InjectCode((void*)0x00000001404A864F, { filter }); //InjectCode((void*)0x00000001411AC518, { filter }); InjectCode((void*)0x00000001404ACE8E, { 0xB9, filter, 0x00, 0x00 }); InjectCode((void*)0x00000001404ACE93, { 0x90 }); } // Reflections if (!nReflections) { InjectCode((void*)0x1406477C6, { 0xE9, 0xE9, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90 }); InjectCode((void*)0x1411ADAFC, { 0x00 }); } // Shadows if (!nShadows) { //InjectCode((void*)0x140502B44, { 0x90, 0x90, 0x90 }); //InjectCode((void*)0x140502BB2, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); InjectCode((void*)0x140502766, { 0x00 }); InjectCode((void*)0x1411AD438, { 0x00 }); InjectCode((void*)0x1411AD320, { 0x00 }); } // Punch-through transparency if (!nPunchthrough) { InjectCode((void*)0x1411AD43D, { 0x00 }); } // Glare if (!nGlare) { InjectCode((void*)0x1404B2168, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); } // Shader if (!nShader) { InjectCode((void*)0x140C9C48E, { 0x00 }); } // 2D if (n2D) { //InjectCode((void*)0x140502B44, { 0x90, 0x90, 0x90 }); InjectCode((void*)0x140502BB2, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); InjectCode((void*)0x140502A3C, { 0x90, 0x90, 0x90, 0x90, 0x90 }); /*InjectCode((void*)0x1411AD320, { 0x00 }); // shadow InjectCode((void*)0x1411AD323, { 0x00 }); // reflect InjectCode((void*)0x1411AD321, { 0x00 }); // SS_SSS InjectCode((void*)0x1411AD325, { 0x00 }); // preprocess InjectCode((void*)0x1411AD328, { 0x00 }); // 3D*/ InjectCode((void*)0x1411AD32A, { 0x01 }); // post process InjectCode((void*)0x1411AD32B, { 0x01 }); // sprite InjectCode((void*)0x140A07920, { 0x00 }); // ignore objset } //// Prevent data deletion //if (nNoDelete) //{ // InjectCode((void*)(0x1406FEF80 + 0x1DB), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407113F0 + 0x13C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140712270 + 0x6C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140712580 + 0x4C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140712580 + 0x7C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140713470 + 0x104), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407135B0 + 0x102), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407135B0 + 0x135), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407135B0 + 0x232), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140713810 + 0x3E8), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140713D00 + 0x677), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x1D2), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x218), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x22A), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140720910 + 0x25C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140723EE0 + 0xEC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140870DE0 + 0x4), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1406FEF80 + 0x1DB), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407113F0 + 0x13C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140712270 + 0x6E), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140712580 + 0x4C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140712580 + 0x7C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140713470 + 0x104), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407135B0 + 0x102), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407135B0 + 0x135), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407135B0 + 0x232), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140713810 + 0x3E8), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140713D00 + 0x677), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x1D2), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x218), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x22A), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140720910 + 0x25C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140723EE0 + 0xEC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140870DE0 + 0x4), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x14081B6A4), { 0xC3 }); // InjectCode((void*)(0x1406E1090 + 0x43C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140718250 + 0x176), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140718750 + 0xC9), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407193E0 + 0xFC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1406E1090 + 0x43C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140718250 + 0x176), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x140718750 + 0xC9), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x1407193E0 + 0xFC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // InjectCode((void*)(0x14081B67A), { 0xC3 }); //} // patch refract and reflect buffer sizes if (nRefractResWidth != 512 || nRefractResHeight != 256) { InjectCode((void*)(0x140a24424), std::vector((uint8_t*)&nRefractResWidth, (uint8_t*)((int64_t)&nRefractResWidth + 4))); InjectCode((void*)(0x140a24428), std::vector((uint8_t*)&nRefractResHeight, (uint8_t*)((int64_t)&nRefractResHeight + 4))); printf("[Patches] Refraction resolution patched.\n"); } if (nReflectResWidth != 512 || nReflectResHeight != 256) { InjectCode((void*)(0x140a2443c), std::vector((uint8_t*)&nReflectResWidth, (uint8_t*)((int64_t)&nReflectResWidth + 4))); InjectCode((void*)(0x140a24440), std::vector((uint8_t*)&nReflectResHeight, (uint8_t*)((int64_t)&nReflectResHeight + 4))); // for large reflect resolutions, adjust blur effect amount to not lose the effect // scaling is based on a 1024 width instead of the original 512px // because we don't wanna make it too blurry when just being used to smooth jaggies if (nReflectResWidth >= 2048) { int blurAmount = nReflectResWidth / 1024; // multiply blur setting // ECX has blur amount, EDX has blur type InjectCode((void*)(0x140503000), { 0x89, 0x15, 0x3a, 0xa3, 0xca, 0x00 }); // MOV dword ptr [0x1411ad340], EDX InjectCode((void*)(0x140503006), { 0xb8 }); // MOV EAX, blurAmount InjectCode((void*)(0x140503007), std::vector((uint8_t*)&blurAmount, (uint8_t*)((int64_t)&blurAmount + 4))); InjectCode((void*)(0x14050300b), { 0xf7, 0xe1 }); // MUL (EDX:EAX,)ECX InjectCode((void*)(0x14050300d), { 0xeb, 0x09 }); // JMP 0x140503018 InjectCode((void*)(0x140503018), { 0x89, 0x05, 0x1e, 0xa3, 0xca, 0x00 }); // MOV dword ptr [0x1411ad33c], EAX InjectCode((void*)(0x14050301e), { 0xc3 }); // RET // divide dwgui blur amount getting // RDX gets type, RCX gets amount InjectCode((void*)(0x140502910), { 0x48, 0x85, 0xd2 }); // TEST RDX, RDX InjectCode((void*)(0x140502913), { 0x74, 0x08 }); // JZ 0x14050291d InjectCode((void*)(0x140502915), { 0x8b, 0x05, 0x25, 0xaa, 0xca, 0x00 }); // MOV EAX, dword ptr [0x1411ad340] InjectCode((void*)(0x14050291b), { 0x89, 0x02 }); // MOV dword ptr [RDX], EAX InjectCode((void*)(0x14050291d), { 0x48, 0x85, 0xc9 }); // TEST RCX, RCX InjectCode((void*)(0x140502920), { 0x74, 0x2d }); // JZ 0x14050294f InjectCode((void*)(0x140502922), { 0x8b, 0x05, 0x14, 0xaa, 0xca, 0x00 }); // MOV EAX, dword ptr [0x1411ad33c] InjectCode((void*)(0x140502928), { 0xeb, 0x0d }); // JMP 0x140502937 InjectCode((void*)(0x140502937), { 0x49, 0xc7, 0xc0 }); // MOV R8, blurAmount InjectCode((void*)(0x14050293a), std::vector((uint8_t*)&blurAmount, (uint8_t*)((int64_t)&blurAmount + 4))); InjectCode((void*)(0x14050293e), { 0xeb, 0x08 }); // JMP 0x140502948 InjectCode((void*)(0x140502948), { 0x31, 0xd2 }); // XOR EDX,EDX InjectCode((void*)(0x14050294a), { 0x49, 0xf7, 0xf0 }); // DIV (EDX:EAX,)R8 InjectCode((void*)(0x14050294d), { 0x89, 0x01 }); // MOV dword ptr [RCX], EAX InjectCode((void*)(0x14050294f), { 0xc3 }); // RET } printf("[Patches] Reflection resolution patched.\n"); } if (nShadowResWidth != 2048 || nShadowResHeight != 2048) { InjectUint((void*)(0x140A81E04), nShadowResHeight); InjectUint((void*)(0x140A81E08), nShadowResWidth); printf("[Patches] Shadow resolution patched.\n"); } // lag compensation if (nLagCompensation > 0 && nLagCompensation <= 500) { InjectCode((void*)(0x14011e44e), { 0xf3, 0x0f, 0x10, 0x05, 0x8a, 0xcf, 0x9c, 0x00 }); // hijack xmm0 InjectCode((void*)(0x14011e46b), { 0xf3, 0x0f, 0x11, 0x44, 0x24, 0x20 }); // get value from xmm0 instead of xmm1 float startPos = (float)nLagCompensation / 1000.0f; InjectCode((void*)(0x140aeB3e0), { *((uint8_t*)(&startPos)), *((uint8_t*)(&startPos) + 1), *((uint8_t*)(&startPos) + 2), *((uint8_t*)(&startPos) + 3) }); printf("[Patches] Lag Compensation: %f\n", startPos); } } }; ================================================ FILE: source-code/source/plugins/Patches/Patches.vcxproj ================================================  Debug x64 Release x64 16.0 {3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C} Win32Proj Patches 10.0 DynamicLibrary true v142 Unicode DynamicLibrary false v142 true Unicode false .dva true .dva NotUsing Level3 MaxSpeed true true true NDEBUG;PATCHES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true pch.h stdcpp17 ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\freeglut\include;..\..\..\dependencies\freeglut\include;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) MultiThreadedDLL -d2FH4- %(AdditionalOptions) Windows true true true false ..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) NotUsing Level3 Disabled true _DEBUG;PATCHES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\freeglut\include;..\..\..\dependencies\freeglut\include;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) stdcpp17 -d2FH4- %(AdditionalOptions) Windows true false ..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/plugins/Patches/Patches.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files ================================================ FILE: source-code/source/plugins/Patches/databank.cpp ================================================ #include #include #include #include #include "databank.h" #include "urlutil.h" namespace Databank { bool PvList::readFromStr(std::string& str) { std::string decoded = urlDecode(urlDecode(str)); std::vector tokens; std::stringstream ss(decoded); std::string token; while (std::getline(ss, token, ',')) { if (!token.empty()) { tokens.push_back(token); } } if (tokens.size() % 7 != 0) { std::cerr << "[Patches] Databank error: Token count (" << tokens.size() << ") is not a multiple of 7." << std::endl; return false; } for (size_t i = 0; i < tokens.size(); i += 7) { try { PvEntry entry; std::tuple id(std::stoi(tokens[i]), std::stoi(tokens[i + 2])); entry.unk1 = std::stoi(tokens[i + 1]); entry.advStart = tokens[i + 3]; entry.advEnd = tokens[i + 4]; entry.start = tokens[i + 5]; entry.end = tokens[i + 6]; entries.insert({ id, entry }); } catch (const std::exception& e) { std::cerr << "[Patches] Databank parse error: " << e.what() << std::endl; return false; } } return true; } bool PvList::readFromFile(const std::string& filename) { try { std::ifstream file(filename, std::ios::in | std::ios::binary); if (!file) { std::cerr << "[Patches] Failed to open databank " + filename << std::endl; return false; } std::string contents = std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator()); return readFromStr(contents); } catch (const std::exception& e) { std::cerr << "[Patches] Databank file read error: " << e.what() << std::endl; return false; } } void PvList::addEntry(int id, int extra, PvEntry& entry) { entries.insert({ std::tuple(id, extra), entry }); } void PvList::generateMissingEntries() { PvEntry entry = PvEntry(); for (int i = 0; i <= 999; i++) { entry.advStart = "2000-01-01"; entry.advEnd = "2029-01-01"; entry.start = "2000-01-01"; entry.end = "2029-01-01"; entries.insert({ std::tuple(i, 0), entry }); entries.insert({ std::tuple(i, 1), entry }); } } std::string PvList::finalize() { std::ostringstream csvStream; if (entries.empty()) { return "%2A%2A%2A"; // *** //checksum = "5341"; } else { bool first = true; for (const auto& entryMap : entries) { std::ostringstream entryStream; if (!first) { csvStream << ","; } first = false; const PvEntry& entry = entryMap.second; entryStream << std::get<0>(entryMap.first) << "," << entry.unk1 << "," << std::get<1>(entryMap.first) << "," << entry.advStart << "," << entry.advEnd << "," << entry.start << "," << entry.end; csvStream << urlEncode(entryStream.str()); } return urlEncode(csvStream.str()); //checksum = std::to_string(crc16_ccitt(finalString)); } } } ================================================ FILE: source-code/source/plugins/Patches/databank.h ================================================ #pragma once #include #include "databank.h" namespace Databank { struct PvEntry { int unk1 = 1; std::string advStart, advEnd, start, end; }; class PvList { protected: std::map, PvEntry> entries; public: bool readFromStr(std::string& str); bool readFromFile(const std::string& filename); void addEntry(int id, int extra, PvEntry& entry); void generateMissingEntries(); std::string finalize(); }; } ================================================ FILE: source-code/source/plugins/Patches/dllmain.cpp ================================================ #include "windows.h" #include "vector" #include #include #include #include #include #include #include #include #include #include "PluginConfigApi.h" #include "PatchApplier.h" #include "PatchApplier600.h" #include "PatchApplier710.h" #include "framework.h" #include "storage.h" #include "databank.h" #pragma comment(lib, "detours.lib") unsigned short game_version = 710; void InjectCode(void* address, const std::vector data); void ApplyPatches(); void ApplyCustomPatches(std::wstring CPATCH_FILE_STRING); constexpr uint64_t PVLIST_INIT_ADDRESS = 0x000000014001EC80; void(__fastcall* divaPvListInitializer)(void* pvListContainer) = (void(__fastcall*)(void* pvListContainer))PVLIST_INIT_ADDRESS; void initPvListContainerHook(); HMODULE *hModulePtr; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: hModulePtr = &hModule; if (*(char*)0x140A570F0 == '6') game_version = 600; ApplyPatches(); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } void ApplyPatches() { if (game_version == 710) { const char* exe_ver_string = (const char*)0x140A92CB8; if (strcmp(exe_ver_string, "7.10.00") != 0) { MessageBoxW(nullptr, L"Game version not 7.10. Please verify your files.", L"Patches", MB_ICONERROR); exit(1); } } std::string version_string = std::to_string(game_version); version_string.insert(version_string.begin()+1, '.'); std::cout << "[Patches] Game version " + version_string << std::endl; PatchApplier* pa; switch (game_version) { case 600: pa = new PatchApplier600; break; default: pa = new PatchApplier710; } pa->ApplyPatches(); printf("[Patches] Patches applied\n"); if (nCustomPatches) { std::cout << "[Patches] Reading custom patches...\n"; try { for (std::filesystem::path p : std::filesystem::directory_iterator("../patches")) { if (std::filesystem::path(p).filename().string()._Starts_with("._")) continue; // exclude macOS metadata std::string extension = std::filesystem::path(p).extension().string(); if ((extension == ".p" || extension == ".P" || extension == ".p2" || extension == ".P2") && GetPrivateProfileIntW(L"plugins", std::filesystem::path(p).filename().c_str(), TRUE, CONFIG_FILE)) { std::cout << "[Patches] Reading custom patch file: " << std::filesystem::path(p).filename().string() << std::endl; ApplyCustomPatches(std::filesystem::path(p).wstring()); } else std::cout << "[Patches] Skipping disabled patch file: " << std::filesystem::path(p).filename().string() << std::endl; } } catch (const std::filesystem::filesystem_error &e) { std::cout << "[Patches] File system error " << e.what() << " " << e.path1() << " " << e.path2() << " " << e.code() << std::endl; } std::cout << "[Patches] All custom patches applied\n"; } if (nAutoDatabank) { initPvListContainerHook(); } } void ApplyCustomPatches(std::wstring CPATCH_FILE_STRING) { LPCWSTR CPATCH_FILE = CPATCH_FILE_STRING.c_str(); std::ifstream fileStream(CPATCH_FILE_STRING); if (!fileStream.is_open()) return; std::string line; // check for BOM std::getline(fileStream, line); if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0) fileStream.seekg(3); else fileStream.seekg(0); while (std::getline(fileStream, line)) { if (line[0] == '#') { std::cout << "[Patches]" << line.substr(1, line.size()-1) << std::endl; continue; } if (line == "IGNORE") break; if (line.find(':') == std::string::npos || (line[0] == '/' && line[1] == '/')) continue; std::vector commentHSplit = SplitString(line, "#"); std::vector commentDSSplit = SplitString(commentHSplit[0], "//"); std::vector colonSplit = SplitString(commentDSSplit[0], ":"); if (colonSplit.size() != 2) continue; bool echo = true; if (colonSplit[0].at(0) == '@') { echo = false; colonSplit[0].at(0) = ' '; } long long int address; std::istringstream iss(colonSplit[0]); iss >> std::setbase(16) >> address; if (address == 0) std::cout << "[Patches] Custom patch address wrong: " << std::hex << address << std::endl; if (colonSplit[1].at(0) == '!') { if (echo) std::cout << "[Patches] Patching: " << std::hex << address << ":!"; std::vector fullColonSplit = SplitString(line, ":"); for (int i = 1; i < fullColonSplit[1].size(); i++) { unsigned char byte_u = fullColonSplit[1].at(i); if(byte_u=='\\' && i patch = { byte_u }; InjectCode((void*)address, patch); address++; } if (echo) std::cout << std::endl; } else { std::vector bytes = SplitString(colonSplit[1], " "); if (bytes.size() < 1) continue; std::string comment_string = ""; int comment_counter = 0; if (commentHSplit.size() > 1) { bool ignore = 1; for (std::string comment : commentHSplit) { if (ignore) { ignore = 0; continue; } comment_string = comment_string + comment; } } if (echo) std::cout << "[Patches] Patching: " << std::hex << address << ":"; for (std::string bytestring : bytes) { int byte; std::istringstream issb(bytestring); issb >> std::setbase(16) >> byte; unsigned char byte_u = byte; if (echo) { std::cout << std::hex << byte << " "; if (comment_counter < comment_string.length()) { std::cout << "(" << comment_string.at(comment_counter) << ") "; comment_counter++; } } std::vector patch = { byte_u }; InjectCode((void*)address, patch); address++; } if (echo) std::cout << std::endl; else if (comment_string.length() > 0) { std::cout << "[Patches]"; if (comment_string.at(0) != ' ') std::cout << ' '; std::cout << comment_string << std::endl; } } } fileStream.close(); } Databank::PvList lists[5] = {}; void hookedPvListInitializer(void* pvListContainer) { Storage::FileRecord* records = (Storage::FileRecord*)((uint64_t)pvListContainer + 0xA0); for (int i = 0; i <= 4; i++) { std::regex pattern("(PvList" + std::to_string(i) +"_SBZV_7.10_.*_.*\\.dat)"); try { for (const auto& entry : std::filesystem::directory_iterator("ram/databank/")) { if (entry.is_regular_file() && std::regex_match(entry.path().filename().string(), pattern)) { std::string path = entry.path().string(); std::cout << "[Patches] Reading databank: " << path << std::endl; lists[i].readFromFile(path); } } } catch (const std::filesystem::filesystem_error& e) { std::cerr << "[Patches] Databank filesystem error: " << e.what() << std::endl; } if (i != 4) lists[i].generateMissingEntries(); std::string finalString = lists[i].finalize(); Storage::customAddStringContainer(&records[i], finalString.c_str()); } *(uint8_t*)(0x140CDB1D9) = 0x01; // enables databank } void initPvListContainerHook() { if (game_version != 710) return; DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaPvListInitializer, (PVOID)(hookedPvListInitializer)); DetourTransactionCommit(); std::cout << "[Patch] Auto Databank enabled" << std::endl; } using namespace PluginConfig; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"Patches"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"Applies patches/tweaks to the game before it starts.\nThis plugin is required."; } ================================================ FILE: source-code/source/plugins/Patches/framework.h ================================================ #pragma once #include "windows.h" #include #include typedef uint16_t(__fastcall* p_crc16_ccitt)(void* data, int len); p_crc16_ccitt o_crc16_ccitt = (p_crc16_ccitt)0x140011A90; uint16_t crc16_ccitt(std::string& str) { return o_crc16_ccitt(str.data(), str.size()); } std::string TrimString(const std::string& str, const std::string& whitespace) { const size_t strBegin = str.find_first_not_of(whitespace); if (strBegin == std::string::npos) return ""; const size_t strEnd = str.find_last_not_of(whitespace); const size_t strRange = strEnd - strBegin + 1; return str.substr(strBegin, strRange); } std::vector SplitString(const std::string& str, const std::string& delim) { std::vector tokens; size_t prev = 0, pos = 0; do { pos = str.find(delim, prev); if (pos == std::string::npos) pos = str.length(); std::string token = str.substr(prev, pos - prev); if (!token.empty()) tokens.push_back(token); prev = pos + delim.length(); } while (pos < str.length() && prev < str.length()); return tokens; } void InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } void InjectUint(void* address, const uint32_t data) { DWORD oldProtect; VirtualProtect(address, 4, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, &data, 4); VirtualProtect(address, 4, oldProtect, nullptr); } // patchMovieExt will modify an extension to mp4 only if the file exists on disk as an mp4 void patchMovieExt(std::string moviefile, void* address) { bool isinmdata = 0; try { for (std::filesystem::path p : std::filesystem::directory_iterator("../mdata")) { if (std::filesystem::path(p).filename().string().at(0) != 'M' || std::filesystem::path(p).filename().string().length() > 4) continue; if (std::filesystem::exists(p.string() + "/rom/movie/" + moviefile + ".mp4")) { isinmdata = 1; //std::cout << "[Patches] Movie " << moviefile << ".mp4 found in M" << ss.str() << std::endl; break; } } } catch (const std::filesystem::filesystem_error& e) { std::cout << "[Patches] File system error " << e.what() << " " << e.path1() << " " << e.path2() << " " << e.code() << std::endl; } if (isinmdata || std::filesystem::exists("../rom/movie/" + moviefile + ".mp4")) { InjectCode(address, { 0x6D, 0x70, 0x34 }); std::cout << "[Patches] Movie " << moviefile << " patched to mp4\n"; return; } //std::cout << "[Patches] Movie " << moviefile << " NOT patched to mp4\n"; return; } const LPCWSTR CONFIG_FILE = L".\\config.ini"; auto nCursor = GetPrivateProfileIntW(L"patches", L"cursor", TRUE, CONFIG_FILE); auto nHideFreeplay = GetPrivateProfileIntW(L"patches", L"hide_freeplay", FALSE, CONFIG_FILE); auto nFreeplay = GetPrivateProfileIntW(L"patches", L"freeplay", TRUE, CONFIG_FILE); auto nPDLoaderText = GetPrivateProfileIntW(L"patches", L"pdloadertext", TRUE, CONFIG_FILE); auto nHideStatusIcons = GetPrivateProfileIntW(L"patches", L"hide_status_icons", FALSE, CONFIG_FILE); auto nStatusIcons = GetPrivateProfileIntW(L"patches", L"status_icons", 0, CONFIG_FILE); auto nHidePVWatermark = GetPrivateProfileIntW(L"patches", L"hide_pv_watermark", FALSE, CONFIG_FILE); auto nNoPVUi = GetPrivateProfileIntW(L"patches", L"no_pv_ui", FALSE, CONFIG_FILE); auto nHideVolCtrl = GetPrivateProfileIntW(L"patches", L"hide_volume", FALSE, CONFIG_FILE); auto nNoLyrics = GetPrivateProfileIntW(L"patches", L"no_lyrics", FALSE, CONFIG_FILE); auto nNoMovies = GetPrivateProfileIntW(L"patches", L"no_movies", FALSE, CONFIG_FILE); auto nMP4Movies = GetPrivateProfileIntW(L"patches", L"mp4_movies", FALSE, CONFIG_FILE); auto nNoError = GetPrivateProfileIntW(L"patches", L"no_error", FALSE, CONFIG_FILE); auto nNoTimer = GetPrivateProfileIntW(L"patches", L"no_timer", TRUE, CONFIG_FILE); auto nNoTimerSprite = GetPrivateProfileIntW(L"patches", L"no_timer_sprite", TRUE, CONFIG_FILE); auto nAutoDatabank = GetPrivateProfileIntW(L"patches", L"auto_databank", TRUE, CONFIG_FILE); auto nEStageManager = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager", 0, CONFIG_FILE); auto nEStageManagerEncore = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager_encore", TRUE, CONFIG_FILE); auto nUnlockPseudo = GetPrivateProfileIntW(L"patches", L"unlock_pseudo", FALSE, CONFIG_FILE); auto nCard = GetPrivateProfileIntW(L"patches", L"card", TRUE, CONFIG_FILE); auto nHardwareSlider = GetPrivateProfileIntW(L"patches", L"hardware_slider", FALSE, CONFIG_FILE); auto nTAA = GetPrivateProfileIntW(L"graphics", L"taa", TRUE, CONFIG_FILE); auto nMLAA = GetPrivateProfileIntW(L"graphics", L"mlaa", TRUE, CONFIG_FILE); auto nDoF = GetPrivateProfileIntW(L"graphics", L"dof", TRUE, CONFIG_FILE); auto nMAG = GetPrivateProfileIntW(L"graphics", L"mag", 0, CONFIG_FILE); auto nGamma = GetPrivateProfileIntW(L"graphics", L"gamma", 100, CONFIG_FILE); auto nStereo = GetPrivateProfileIntW(L"patches", L"stereo", TRUE, CONFIG_FILE); auto nCustomPatches = GetPrivateProfileIntW(L"patches", L"custom_patches", TRUE, CONFIG_FILE); auto nQuickStart = GetPrivateProfileIntW(L"patches", L"quick_start", 0, CONFIG_FILE); auto nNoScrollingSfx = GetPrivateProfileIntW(L"patches", L"no_scrolling_sfx", FALSE, CONFIG_FILE); auto nEnablePvCustomization = GetPrivateProfileIntW(L"patches", L"enable_pv_customization", FALSE, CONFIG_FILE); auto nNoHandScaling = GetPrivateProfileIntW(L"patches", L"no_hand_scaling", FALSE, CONFIG_FILE); auto nDefaultHandSize = GetPrivateProfileIntW(L"patches", L"default_hand_size_uint", 0, CONFIG_FILE); auto nSingMissed = GetPrivateProfileIntW(L"patches", L"sing_missed", FALSE, CONFIG_FILE); auto nForceMouth = GetPrivateProfileIntW(L"patches", L"force_mouth", 0, CONFIG_FILE); auto nForceExpressions = GetPrivateProfileIntW(L"patches", L"force_expressions", 0, CONFIG_FILE); auto nForceLook = GetPrivateProfileIntW(L"patches", L"force_look", 0, CONFIG_FILE); auto nNpr1 = GetPrivateProfileIntW(L"graphics", L"npr1", 0, CONFIG_FILE); auto nReflections = GetPrivateProfileIntW(L"graphics", L"reflections", TRUE, CONFIG_FILE); auto nShadows = GetPrivateProfileIntW(L"graphics", L"shadows", TRUE, CONFIG_FILE); auto nPunchthrough = GetPrivateProfileIntW(L"graphics", L"punchthrough", TRUE, CONFIG_FILE); auto nGlare = GetPrivateProfileIntW(L"graphics", L"glare", TRUE, CONFIG_FILE); auto nShader = GetPrivateProfileIntW(L"graphics", L"shader", TRUE, CONFIG_FILE); auto n2D = GetPrivateProfileIntW(L"graphics", L"2D", FALSE, CONFIG_FILE); auto nReflectResWidth = GetPrivateProfileIntW(L"graphics", L"reflect_res_width", 512, CONFIG_FILE); auto nReflectResHeight = GetPrivateProfileIntW(L"graphics", L"reflect_res_height", 256, CONFIG_FILE); auto nRefractResWidth = GetPrivateProfileIntW(L"graphics", L"refract_res_width", 512, CONFIG_FILE); auto nRefractResHeight = GetPrivateProfileIntW(L"graphics", L"refract_res_height", 256, CONFIG_FILE); auto nShadowResWidth = GetPrivateProfileIntW(L"graphics", L"shadow_res_width", 2048, CONFIG_FILE); auto nShadowResHeight = GetPrivateProfileIntW(L"graphics", L"shadow_res_height", 2048, CONFIG_FILE); auto nLagCompensation = GetPrivateProfileIntW(L"graphics", L"lag_compensation", 0, CONFIG_FILE); auto nUseDivahookBat = GetPrivateProfileIntW(L"launcher", L"use_divahook_bat", FALSE, CONFIG_FILE); ================================================ FILE: source-code/source/plugins/Patches/storage.h ================================================ #pragma once #include namespace Storage { struct FileRecord { union { void* pData; // used if allocSize is >= 16 char inlineData[16]; // used if allocSize is < 16; [8-15] not normally cleared when expanded }; uint64_t dataLength = 0; uint64_t allocSize = 15; }; //void(__fastcall* divaAddStringContainer)(void*, void**) = (void(__fastcall*)(void* container, void** src))0x01400C0A40; void customAddStringContainer(void* container, const char* str) { uint64_t addr = (uint64_t)container; while (*(uint64_t*)addr != 0) { addr += sizeof(FileRecord); } FileRecord* record = (FileRecord*)addr; size_t length = strlen(str) + 1; if (length > 0 && length < 16) { memcpy_s(record->inlineData, length, str, length); record->dataLength = length; record->allocSize = 0; } else if (length >= 16) { char* alloc = (char*)malloc(length); memcpy_s(alloc, length, str, length); record->pData = alloc; record->dataLength = length; record->allocSize = length; } } }; ================================================ FILE: source-code/source/plugins/Patches/urlutil.h ================================================ #pragma once #include #include #include std::string urlDecode(const std::string& encoded) { std::string decoded; char ch; for (size_t i = 0; i < encoded.length(); i++) { if (encoded[i] == '%') { if (i + 2 < encoded.length()) { std::string hex = encoded.substr(i + 1, 2); ch = static_cast(std::strtol(hex.c_str(), nullptr, 16)); decoded.push_back(ch); i += 2; } else { decoded.push_back('%'); } } else if (encoded[i] == '+') { decoded.push_back(' '); } else { decoded.push_back(encoded[i]); } } return decoded; } std::string urlEncode(const std::string& str) { std::ostringstream escaped; escaped.fill('0'); escaped << std::hex; for (unsigned char c : str) { if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { escaped << c; } else { escaped << '%' << std::setw(2) << std::uppercase << static_cast(c); } } return escaped.str(); } ================================================ FILE: source-code/source/plugins/Render/Render.vcxproj ================================================  Debug x64 Release x64 16.0 {89F87459-768F-4638-9267-0F90CD74452D} Win32Proj Render 10.0 DynamicLibrary true v142 Unicode DynamicLibrary false v142 true Unicode false .dva true .dva NotUsing Level3 MaxSpeed true true true NDEBUG;RENDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\freeglut\include;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) stdcpp17 MultiThreadedDLL -d2FH4- %(AdditionalOptions) Windows true true true false ..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) NotUsing Level3 Disabled true _DEBUG;RENDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true stdcpp17 ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\freeglut\include;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) -d2FH4- %(AdditionalOptions) Windows true false ..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/plugins/Render/Render.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Source Files ================================================ FILE: source-code/source/plugins/Render/dllmain.cpp ================================================ #include "framework.h" #include #pragma comment(lib, "detours.lib") #include #include #include #include #include #include #include #include #include "PluginConfigApi.h" using namespace std::chrono; unsigned short game_version = 710; void exitGameClean(int) { switch (game_version) { case 600: *(bool*)0x0000000140E8DF20 = true; // 6.00 break; default: *(bool*)0x0000000140EDA6B0 = true; // 7.10 } } int hookedCreateWindow(const char* title, void(__cdecl* exit_function)(int)) { SetProcessDPIAware(); // trick Optimus into switching to the NVIDIA GPU if (cuInit != NULL) cuInit(0); if (nDisplay == 2) // fullscreen { char GameModeString[24]; sprintf_s(GameModeString, sizeof(GameModeString), "%dx%d:%d@%d", nWidth, nHeight, nBitDepth, nRefreshRate); glutGameModeString(GameModeString); if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) { printf("[Render Manager] Game mode (exclusive fullscreen) enabled.\n"); printf(GameModeString); printf("\n"); glutEnterGameMode(); } else { printf("[Render Manager] Requested display mode not supported. Using non-exclusive fullscreen instead.\n"); printf(GameModeString); printf("\n"); switch (game_version) { case 600: *fullScreenFlag_600 = 1; break; default: *fullScreenFlag_710 = 1; } __glutCreateWindowWithExit(title, exitGameClean); } } else // windowed or borderless { switch (game_version) { case 600: *fullScreenFlag_600 = 0; break; default: *fullScreenFlag_710 = 0; } RECT xy; SystemParametersInfo(SPI_GETWORKAREA, 0, &xy, 0); int screenWidth = xy.right - xy.left; int screenHeight = xy.bottom - xy.top; if (nWidth > screenWidth) { screenWidth = GetSystemMetrics(SM_CXSCREEN); xy.left = 0; } if (nHeight > screenHeight) { screenHeight = GetSystemMetrics(SM_CYSCREEN); xy.top = 0; } int wndX = xy.left + (screenWidth - nWidth) / 2; int wndY = xy.top + (screenHeight - nHeight) / 2; glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(nWidth, nHeight); glutInitWindowPosition(wndX, wndY); __glutCreateWindowWithExit(title, exitGameClean); if (nDisplay == 1 || nDisplay == 3) // borderless mode { // support borderless mode even with original copy of glut HDC hDev = wglGetCurrentDC(); // get handle to current opengl device context HWND hWnd = WindowFromDC(hDev); // convert it to a window handle LONG_PTR wndStyle = WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // set no border (visible to ensure something is shown immediately) if (nDisplay == 1) { wndStyle |= WS_POPUP; printf("[Render Manager] Popup enabled.\n"); } SetWindowLongPtr(hWnd, GWL_STYLE, wndStyle); SetWindowPos(hWnd, HWND_TOP, wndX, wndY, nWidth, nHeight, SWP_FRAMECHANGED); // adjust position to apply new style printf("[Render Manager] Borderless mode.\n"); } else { printf("[Render Manager] Windowed mode.\n"); } } return true; } __int64 hookedParseParameters(int a1, __int64* a2) { // Force -wqhd if Custom Internal Resolution is enabled if (nIntRes) switch (game_version) { case 600: *resolutionType_600 = 15; break; //default: // *resolutionType_710 = 15; } // Return to the original function switch (game_version) { case 600: return divaParseParameters_600(a1, a2); break; //default: // return divaParseParameters_710(a1, a2); } } time_point sleepUntil = high_resolution_clock::now(); time_point nextUpdate = high_resolution_clock::now(); nanoseconds expectedFrameDuration; nanoseconds sleepWindow(2500000); __int64 __fastcall limiterFuncNormal(__int64 a1) { auto timeNow = high_resolution_clock::now(); if (timeNow < nextUpdate) return 0; timeNow = high_resolution_clock::now(); // increment nextUpdate by fixed interval to unsure timing accuracy between frames // (ignore time spent outside the update) nextUpdate += expectedFrameDuration; // if dropping frames, run as fast as possible // and also change nextUpdate's timing to match current time // (so frame n+2 will be at least 1/nFpsLimit seconds from frame n+1) if (nextUpdate < timeNow) nextUpdate = timeNow; switch (game_version) { case 600: return divaEngineUpdate_600(a1); default: return divaEngineUpdate_710(a1); } } __int64 __fastcall limiterFuncLight(__int64 a1) { auto timeNow = high_resolution_clock::now(); // sleep until the approximate correct time to save CPU usage, // then change to instantly returning when timing is more critical if (timeNow < sleepUntil) { std::this_thread::sleep_until(sleepUntil); if (nVerboseLimiter) { timeNow = high_resolution_clock::now(); nanoseconds timeDifference = (timeNow - sleepUntil); if (timeDifference > sleepWindow) // no need for abs because it doesn't matter if this is early { printf("FPS LIMITER SLEEP TIME OUTSIDE ALLOWED WINDOW\n"); printf(" Target sleep until time: %lld, Actual time: %lld\n", sleepUntil.time_since_epoch().count(), timeNow.time_since_epoch().count()); printf(" (Difference: %lld, Window: %lld)\n", timeDifference.count(), sleepWindow.count()); } } } if (timeNow < nextUpdate) return 0; timeNow = high_resolution_clock::now(); // increment nextUpdate by fixed interval to unsure timing accuracy between frames // (ignore time spent outside the update) nextUpdate += expectedFrameDuration; // if dropping frames, run as fast as possible // and also change nextUpdate's timing to match current time // (so frame n+2 will be at least 1/nFpsLimit seconds from frame n+1) if (nextUpdate < timeNow) nextUpdate = timeNow; sleepUntil = nextUpdate - sleepWindow; switch (game_version) { case 600: return divaEngineUpdate_600(a1); default: return divaEngineUpdate_710(a1); } } #define WRITE_MEMORY_INT(address, data) \ { \ DWORD oldProtect, bck; \ VirtualProtect((BYTE*)(address), 4, PAGE_EXECUTE_READWRITE, &oldProtect); \ *((int*)(address)) = (data); \ VirtualProtect((BYTE*)(address), 4, oldProtect, &bck); \ } void __fastcall hookedInitRender(int ssaa, int hd_res, int ss_alpha_mask, __int8 npr) { if (nIntRes) { const __int64 widthAddress = 0x0000000140EDA8B0 + 0x0C; const __int64 heightAddress = 0x0000000140EDA8B0 + 0x10; const __int64 intWidthAddress = 0x0000000140EDA8D8 + 0x0C; const __int64 intHeightAddress = 0x0000000140EDA8D8 + 0x10; int originalWidth = *(int*)widthAddress; int originalHeight = *(int*)heightAddress; int originalIntWidth = *(int*)intWidthAddress; int originalIntHeight = *(int*)intHeightAddress; WRITE_MEMORY_INT(widthAddress, nIntResWidth); WRITE_MEMORY_INT(heightAddress, nIntResHeight); WRITE_MEMORY_INT(intWidthAddress, nIntResWidth); WRITE_MEMORY_INT(intHeightAddress, nIntResHeight); divaInitRender_710(ssaa, hd_res, ss_alpha_mask, npr); WRITE_MEMORY_INT(widthAddress, originalWidth); WRITE_MEMORY_INT(heightAddress, originalHeight); WRITE_MEMORY_INT(intWidthAddress, originalIntWidth); WRITE_MEMORY_INT(intHeightAddress, originalIntHeight); } else divaInitRender_710(ssaa, hd_res, ss_alpha_mask, npr); } __int64 __fastcall hookedEngineUpdate(__int64 a1) { if (nFpsLimit < 1) switch (game_version) { case 600: return divaEngineUpdate_600(a1); default: return divaEngineUpdate_710(a1); } else if (nUseLightLimiter) return limiterFuncLight(a1); else return limiterFuncNormal(a1); } extern "C" __declspec(dllexport) int getFramerateLimit(void) { return nFpsLimit; } extern "C" __declspec(dllexport) void setFramerateLimit(int framerate) { nFpsLimit = framerate; if (nFpsLimit < 1) expectedFrameDuration = nanoseconds(0); else expectedFrameDuration = nanoseconds(1000000000 / nFpsLimit); return; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { if (*(char*)0x140A570F0 == '6') game_version = 600; DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); switch (game_version) { case 600: DetourAttach(&(PVOID&)divaCreateWindow_600, hookedCreateWindow); break; default: DetourAttach(&(PVOID&)divaCreateWindow_710, hookedCreateWindow); } DetourTransactionCommit(); switch (game_version) { case 600: DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaParseParameters_600, hookedParseParameters); DetourTransactionCommit(); break; //default: // DetourAttach(&(PVOID&)divaParseParameters_710, hookedParseParameters); } // set sleep time resolution to 2ms or device minimum (whichever's lower) TIMECAPS tc; if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) == MMSYSERR_NOERROR) { UINT wTimerRes = min(max(tc.wPeriodMin, 2), tc.wPeriodMax); timeBeginPeriod(wTimerRes); } setFramerateLimit(nFpsLimit); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); switch (game_version) { case 600: DetourAttach(&(PVOID&)divaEngineUpdate_600, hookedEngineUpdate); break; default: DetourAttach(&(PVOID&)divaEngineUpdate_710, hookedEngineUpdate); } DetourTransactionCommit(); // if window is set to screen res, process that now so it can be used for auto internal res if (nWidth == -1 || nHeight == -1) { nWidth = GetSystemMetrics(SM_CXSCREEN); nHeight = GetSystemMetrics(SM_CYSCREEN); } if (nIntRes) { // if -1 use window resolution if (nIntResWidth == -1 || nIntResHeight == -1) { nIntResWidth = nWidth; nIntResHeight = nHeight; } printf("[Render] Custom internal resolution enabled\n"); printf("[Render] X: %d Y: %d\n", nIntResWidth, nIntResHeight); switch (game_version) { case 600: WRITE_MEMORY_INT(0x0000000140980954, nIntResWidth); WRITE_MEMORY_INT(0x0000000140980958, nIntResWidth); break; default: DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaInitRender_710, hookedInitRender); DetourTransactionCommit(); } } } return TRUE; } using namespace PluginConfig; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"Render"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"Applies window mode/size and FPS limiting."; } ================================================ FILE: source-code/source/plugins/Render/framework.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include #include static int(__cdecl* divaCreateWindow_710)(const char* title, void(__cdecl* exitfunc)(int)) = (int(__cdecl*)(const char* title, void(__cdecl * exitfunc)(int)))0x140194D00; void(__fastcall* divaInitRender_710)(int ssaa, int hd_res, int ss_alpha_mask, __int8 npr) = (void(__fastcall *)(int ssaa, int hd_res, int ss_alpha_mask, __int8 npr))0x0000000140502A10; //__int64 (__fastcall* divaParseParameters_710)(int a1, __int64* a2) = (__int64(__fastcall*)(int a1, __int64* a2))0x140193630; __int64(__fastcall* divaEngineUpdate_710)(__int64 a1) = (__int64(__fastcall*)(__int64 a1))0x140194CD0; uint8_t* fullScreenFlag_710 = (uint8_t*)0x140EDA5D1; //DWORD* resolutionType_710 = (DWORD*)0x140EDA5D4; static int(__cdecl* divaCreateWindow_600)(const char* title, void(__cdecl* exitfunc)(int)) = (int(__cdecl*)(const char* title, void(__cdecl * exitfunc)(int)))0x14018CD00; __int64(__fastcall* divaParseParameters_600)(int a1, __int64* a2) = (__int64(__fastcall*)(int a1, __int64* a2))0x14018B660; __int64(__fastcall* divaEngineUpdate_600)(__int64 a1) = (__int64(__fastcall*)(__int64 a1))0x14018CCD0; uint8_t* fullScreenFlag_600 = (uint8_t*)0x140E8DE41; DWORD* resolutionType_600 = (DWORD*)0x140E8DE44; using namespace std; wstring DirPath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); wstring::size_type pos = wstring(buffer).find_last_of(L"\\/"); return wstring(buffer).substr(0, pos); } wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\config.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); int nDisplay = GetPrivateProfileIntW(L"resolution", L"display", 0, CONFIG_FILE); int nWidth = GetPrivateProfileIntW(L"resolution", L"width", 1280, CONFIG_FILE); int nHeight = GetPrivateProfileIntW(L"resolution", L"height", 720, CONFIG_FILE); int nIntRes = GetPrivateProfileIntW(L"resolution", L"r.enable", FALSE, CONFIG_FILE); int nIntResWidth = GetPrivateProfileIntW(L"resolution", L"r.width", 1280, CONFIG_FILE); int nIntResHeight = GetPrivateProfileIntW(L"resolution", L"r.height", 720, CONFIG_FILE); int nBitDepth = GetPrivateProfileIntW(L"resolution", L"bitdepth", 32, CONFIG_FILE); int nRefreshRate = GetPrivateProfileIntW(L"resolution", L"refreshrate", 60, CONFIG_FILE); int nFpsLimit = GetPrivateProfileIntW(L"graphics", L"fps.limit", 60, CONFIG_FILE); int nUseLightLimiter = GetPrivateProfileIntW(L"graphics", L"fps.limit.lightmode", TRUE, CONFIG_FILE); int nVerboseLimiter = GetPrivateProfileIntW(L"graphics", L"fps.limit.verbose", FALSE, CONFIG_FILE); // used to trick Optimus into switching to the NVIDIA GPU HMODULE nvcudaModule = LoadLibraryW(L"nvcuda.dll"); // cuInit actually returns a CUresult, but we don't really care about it void(WINAPI * cuInit)(unsigned int flags) = (void(WINAPI*)(unsigned int flags))GetProcAddress(nvcudaModule, "cuInit"); ================================================ FILE: source-code/source/plugins/ShaderPatch/ShaderPatch.vcxproj ================================================  Debug x64 Release x64 {C07E495E-A16F-48FA-80E4-0296B5234F0B} ShaderPatch 10.0 DynamicLibrary true v142 MultiByte DynamicLibrary false v142 true MultiByte .dva .dva Level3 Disabled true ..\..\..\dependencies\GPUModel;..\..\..\dependencies\detours\include;..\..\..\dependencies\PluginConfigApi -d2FH4- %(AdditionalOptions) ..\..\..\dependencies\detours\lib -d2:-FH4- %(AdditionalOptions) Level3 MaxSpeed true true true ..\..\..\dependencies\GPUModel;..\..\..\dependencies\detours\include;..\..\..\dependencies\PluginConfigApi MultiThreadedDLL -d2FH4- %(AdditionalOptions) true true ..\..\..\dependencies\detours\lib -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/plugins/ShaderPatch/ShaderPatch.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Header Files ================================================ FILE: source-code/source/plugins/ShaderPatch/src/dllmain.cpp ================================================ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include "framework.h" #include "PluginConfigApi.h" #include "GPUModel.h" #include "detours.h" #pragma comment(lib, "detours.lib") #include #include void InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } void NopBytes(void* address, unsigned int num) { std::vector newbytes = {}; for (unsigned int i = 0; i < num; ++i) newbytes.push_back(0x90); InjectCode(address, newbytes); } void LoadData() { std::ifstream fileStream(DATA_FILE_STRING); if (!fileStream.is_open()) return; std::string line; std::string section = "patches"; std::string lastComment; bool isInComment = false; // check for BOM std::getline(fileStream, line); if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0) fileStream.seekg(3); else fileStream.seekg(0); while (std::getline(fileStream, line)) { // detect comments first to make comment exit logic easier int commentStartPos; if ((commentStartPos = 1, line.size() >= 1 && line[0] == '#') || (commentStartPos = 2, line.size() >= 2 && line.rfind("//", 0) == 0)) { line.erase(0, commentStartPos); line = TrimString(line, " \t"); if (isInComment) { lastComment += "\n" + line; } else { lastComment = line; isInComment = true; } continue; } isInComment = false; if (line.size() <= 0) // skip empty lines { lastComment = ""; // consume the last comment continue; } if (line[0] == '[') // section name { size_t endIdx = line.find(']'); section = line.substr(1, endIdx - 1); std::transform(section.begin(), section.end(), section.begin(), ::tolower); lastComment = ""; // consume the last comment continue; } std::vector equalSplit = SplitString(line, "="); if (equalSplit.size() < 2) { lastComment = ""; // consume the last comment continue; } if (section == "patches") { ShaderPatchInfo patch = ShaderPatchInfo(); patch.fileRegex = equalSplit[0]; std::vector rules = SplitString(equalSplit[1], "||"); if (rules.size() < 1) continue; // probably will never trigger but whatever for (std::string &rule : rules) { if (rule.size() >= 5 && rule.rfind("arch:", 0) == 0) { rule.erase(0, 5); patch.archs = SplitString(rule, ","); } else if (rule.size() >= 4 && rule.rfind("cfg:", 0) == 0) { rule.erase(0, 4); // force cfg key to lower because ini shouldn't be case sensitive std::transform(rule.begin(), rule.end(), rule.begin(), ::tolower); patch.cfg = rule; } else if (rule.size() >= 5 && rule.rfind("from:", 0) == 0) { rule.erase(0, 5); patch.dataRegex = rule; } else if (rule.size() >= 3 && rule.rfind("to:", 0) == 0) { rule.erase(0, 3); rule = StringReplace(rule, "\\n", "\n"); patch.dataReplace = rule; } } lastComment = ""; // consume the last comment patchesVec.push_back(patch); } else if (section == "config") { // force cfg key to lower because ini shouldn't be case sensitive std::transform(equalSplit[0].begin(), equalSplit[0].end(), equalSplit[0].begin(), ::tolower); equalSplit[0] = TrimString(equalSplit[0], " \t"); equalSplit[1] = TrimString(equalSplit[1], " \t"); dataCfgMap[equalSplit[0]] = strpair(equalSplit[1], lastComment); lastComment = ""; // consume the last comment } } fileStream.close(); } // always call this after LoadData void LoadUserCfg() { // copy default config into userconfig to avoid having to read from multiple maps while patching for (std::map::iterator iter = dataCfgMap.begin(); iter != dataCfgMap.end(); ++iter) { userCfgMap[iter->first] = iter->second.first; } std::ifstream fileStream(CONFIG_FILE_STRING); if (!fileStream.is_open()) return; std::string line; std::string section = "config"; // check for BOM std::getline(fileStream, line); if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0) fileStream.seekg(3); else fileStream.seekg(0); while (std::getline(fileStream, line)) { if (line.size() <= 0) // skip empty lines { continue; } // skip comments if ((line.size() >= 1 && line[0] == '#') || (line.size() >= 2 && line.rfind("//", 0) == 0)) { continue; } if (line[0] == '[') // section name { size_t endIdx = line.find(']'); section = line.substr(1, endIdx - 1); std::transform(section.begin(), section.end(), section.begin(), ::tolower); continue; } std::vector equalSplit = SplitString(line, "="); if (equalSplit.size() < 2) { continue; } if (section == "config") { // force cfg key to lower because ini shouldn't be case sensitive std::transform(equalSplit[0].begin(), equalSplit[0].end(), equalSplit[0].begin(), ::tolower); equalSplit[0] = TrimString(equalSplit[0], " \t"); equalSplit[1] = TrimString(equalSplit[1], " \t"); userCfgMap[equalSplit[0]] = equalSplit[1]; } } fileStream.close(); } void hookedLoadFromFarcThunk(FArchivedFile** ppFile) { loadFromFarcThunk(ppFile); if (ppFile == nullptr || *ppFile == nullptr) return; FArchivedFile &file = **ppFile; if (file.notLoadedFlag != 0) return; std::string modifiedStr = ""; for (ShaderPatchInfo &patch : patchesVec) { bool archMatches = false; if (patch.archs.size() > 0) { for (std::string &arch : patch.archs) { if (gpuName.size() >= arch.size() && gpuName.rfind(arch, 0) == 0) { archMatches = true; break; } } } else { archMatches = true; } bool cfgMatches = false; if (patch.cfg.length() == 0 || // patch has no config setting (userCfgMap.find(patch.cfg) != userCfgMap.end() && userCfgMap[patch.cfg] != "0")) // patch has a toggle and is not set to 0 { cfgMatches = true; } if (archMatches && cfgMatches && std::regex_match(file.fileName.GetCharBuf(), patch.fileRegex)) { if (modifiedStr.length() == 0) modifiedStr = std::string(file.data, file.dataSize); modifiedStr = std::regex_replace(modifiedStr, patch.dataRegex, patch.dataReplace); modifiedStr = StringReplace(modifiedStr, "", file.fileName.GetCharBuf()); if (patch.cfg.length() > 0) // patch has a config setting { int valNum = 0; std::string valKey; while (valNum++, valKey = patch.cfg + "_val" + std::to_string(valNum), userCfgMap.find(valKey) != userCfgMap.end()) // loop until there's no more config values set { modifiedStr = StringReplace(modifiedStr, "", userCfgMap[valKey]); } } } } if (modifiedStr.length() > 0) { //free(file.data); file.data = _strdup(modifiedStr.c_str()); file.dataSize = modifiedStr.size(); printf("[ShaderPatch] Patched %s\n", file.fileName.GetCharBuf()); } } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { // install a thunk to hook InjectCode((void*)0x1405e5991, { 0x48, 0x83, 0xec, 0x28 }); // SUB RSP, 0x28 InjectCode((void*)0x1405e5995, { 0xe8, 0x56, 0xe8, 0xb9, 0xff }); // CALL 0x1401841f0 InjectCode((void*)0x1405e599a, { 0x48, 0x83, 0xc4, 0x28 }); // ADD RSP, 0x28 InjectCode((void*)0x1405e599e, { 0xc3 }); // RET InjectCode((void*)0x1405e534a, { 0xe8, 0x42, 0x06, 0x00, 0x00 }); // CALL 0x1405e5991 DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)loadFromFarcThunk, (PVOID)hookedLoadFromFarcThunk); DetourTransactionCommit(); gpuName = GPUModel::getGpuName(); printf("[ShaderPatch] Detected GPU: %s\n", gpuName.c_str()); //Sleep(2000); LoadData(); LoadUserCfg(); } return TRUE; } using namespace PluginConfig; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"ShaderPatch"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"Automatically patches shaders"; } std::vector configVec; extern "C" __declspec(dllexport) PluginConfigArray GetPluginOptions(void) { LoadData(); LoadUserCfg(); for (std::map::iterator iter = dataCfgMap.begin(); iter != dataCfgMap.end(); ++iter) { std::string k = iter->first; std::string v = iter->second.first; std::string c = iter->second.second; if (k.size() < 6 || k.substr(k.size() - 5, 4) != "_val") { WCHAR utf16key[128]; WCHAR utf16val[128]; WCHAR utf16comment[512]; // count values to approximate the group size int valNum = 0; int valCount = 0; std::string valKey; while (valNum++, valKey = k + "_val" + std::to_string(valNum), dataCfgMap.find(valKey) != dataCfgMap.end()) // loop until there's no more config values set { valCount++; } MultiByteToWideChar(CP_UTF8, 0, k.c_str(), -1, utf16key, 128); MultiByteToWideChar(CP_UTF8, 0, c.c_str(), -1, utf16comment, 512); LPCWSTR ttDup = _wcsdup(utf16comment); configVec.push_back({ CONFIG_GROUP_START, new PluginConfigGroupData{ _wcsdup(utf16key), 45 + valCount * 25 } }); configVec.push_back({ CONFIG_BOOLEAN, new PluginConfigBooleanData{ _wcsdup(utf16key), L"config", CONFIG_FILE, L"Enable", ttDup, v == "0" ? false : true, false } }); // could use userCfgMap here, but launcher handles that anyway valNum = 0; while (valNum++, valKey = k + "_val" + std::to_string(valNum), dataCfgMap.find(valKey) != dataCfgMap.end()) // loop until there's no more config values set { MultiByteToWideChar(CP_UTF8, 0, valKey.c_str(), -1, utf16key, 128); MultiByteToWideChar(CP_UTF8, 0, dataCfgMap[valKey].first.c_str(), -1, utf16val, 128); // could use userCfgMap here, but launcher handles that anyway std::wstring name; if (dataCfgMap[valKey].second.size() > 0) { MultiByteToWideChar(CP_UTF8, 0, dataCfgMap[valKey].second.c_str(), -1, utf16comment, 512); name = utf16comment; name += L":"; ; } else { name = std::wstring(L"Value ") + std::to_wstring(valNum) + L":"; } configVec.push_back({ CONFIG_STRING, new PluginConfigStringData{ _wcsdup(utf16key), L"config", CONFIG_FILE, _wcsdup(name.c_str()), ttDup, _wcsdup(utf16val), false } }); } configVec.push_back({ CONFIG_GROUP_END, NULL }); configVec.push_back({ CONFIG_SPACER, new PluginConfigSpacerData{ 10 } }); } } return PluginConfigArray{ (int)configVec.size(), &configVec[0] }; } ================================================ FILE: source-code/source/plugins/ShaderPatch/src/framework.h ================================================ #pragma once //#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers //#include //#include #include #include #include #include #include #include struct ShaderPatchInfo { std::regex fileRegex; std::regex dataRegex; std::string dataReplace; std::vector archs; std::string cfg; }; std::vector patchesVec; typedef std::pair strpair; std::map dataCfgMap; // default config file entries std::map userCfgMap; // user config file entries #pragma pack(push, 1) struct MsString { union { char* string_ptr; char string_buf[16]; }; uint64_t unk; uint64_t size; char* GetCharBuf() { if (size > 0xf && string_ptr != nullptr) return string_ptr; else return string_buf; }; }; struct FArchivedFile { uint8_t padding00[0x10]; uint8_t notLoadedFlag; uint8_t padding11[0x07]; MsString farcPath; MsString fileName; uint8_t padding58[0x38]; uint64_t dataSize; char* data; }; #pragma pack(pop) void (__stdcall* loadFromFarcThunk)(FArchivedFile** file) = (void(__stdcall*)(FArchivedFile** file))0x1405e5991; std::string gpuName; std::vector SplitString(const std::string& str, const std::string& delim) { std::vector tokens; size_t prev = 0, pos = 0; do { pos = str.find(delim, prev); if (pos == std::string::npos) pos = str.length(); std::string token = str.substr(prev, pos - prev); if (!token.empty()) tokens.push_back(token); prev = pos + delim.length(); } while (pos < str.length() && prev < str.length()); return tokens; } std::string TrimString(const std::string& str, const std::string& whitespace) { const size_t strBegin = str.find_first_not_of(whitespace); if (strBegin == std::string::npos) return ""; const size_t strEnd = str.find_last_not_of(whitespace); const size_t strRange = strEnd - strBegin + 1; return str.substr(strBegin, strRange); } std::string StringReplace(const std::string& str, const std::string& srch, const std::string& repl) { size_t pos = 0; std::string outstr = str; while (true) { pos = outstr.find(srch, pos); if (pos == std::string::npos) break; outstr.replace(pos, srch.length(), repl); } return outstr; } std::wstring ExePath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); return std::wstring(buffer); } std::wstring DirPath() { std::wstring exepath = ExePath(); std::wstring::size_type pos = exepath.find_last_of(L"\\/"); return exepath.substr(0, pos); } std::wstring DATA_FILE_STRING = DirPath() + L"\\plugins\\ShaderPatch.ini"; LPCWSTR DATA_FILE = DATA_FILE_STRING.c_str(); std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\ShaderPatchConfig.ini"; LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); //bool hasConflicts() //{ // printf("[ShaderPatch] Checking for conflicts...\n"); // // HMODULE* hModules = new HMODULE[USHRT_MAX]; // HANDLE hProcess; // DWORD cbNeeded; // // hProcess = GetCurrentProcess(); // // if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) { // for (unsigned long long i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { // auto pNameFunc = (LPCWSTR(*)())GetProcAddress(hModules[i], "GetPluginName"); // if (pNameFunc) { // LPCWSTR name = pNameFunc(); // if (name && lstrcmpW(name, L"DivaGL") == 0) // { // // detected DivaGL // printf("[ShaderPatch] Detected DivaGL! Quitting!\n"); //#ifdef _DEBUG // MessageBoxExW(NULL, L"Detected DivaGL! Quitting!\n", L"ShaderPatch", MB_OK, 0); //#endif // delete[] hModules; // return true; // } // } // } // } // // printf("[ShaderPatch] No conflicts found.\n"); // delete[] hModules; // return false; //} ================================================ FILE: source-code/source/plugins/TLAC/Components/CameraController.cpp ================================================ #include "CameraController.h" #include #include "Input/InputState.h" #include "ComponentsManager.h" #include "../framework.h" #include "../Input/Mouse/Mouse.h" #include "../Input/Keyboard/Keyboard.h" #include "../Input/Bindings/KeyboardBinding.h" #define GLUT_CURSOR_RIGHT_ARROW 0x0000 #define GLUT_CURSOR_NONE 0x0065 using namespace TLAC::Input; using namespace TLAC::Utilities; namespace TLAC::Components { CameraController::CameraController() { } CameraController::~CameraController() { delete ToggleBinding; delete ForwardBinding; delete BackwardBinding; delete LeftBinding; delete RightBinding; delete UpBinding; delete DownBinding; delete ClockwiseBinding; delete CounterClockwiseBinding; delete ZoomInBinding; delete ZoomOutBinding; delete FastBinding; delete SlowBinding; } const char* CameraController::GetDisplayName() { return "camera_controller"; } void CameraController::Initialize(ComponentsManager* manager) { componentsManager = manager; printf("[TLAC] CameraController::Initialize(): Initialized\n"); for (int i = 0; i < sizeof(cameraSetterAddresses) / sizeof(void*); i++) { DWORD oldProtect; VirtualProtect((void*)cameraSetterAddresses[i], sizeof(uint8_t), PAGE_EXECUTE_READWRITE, &oldProtect); originalSetterBytes[i] = *(uint8_t*)cameraSetterAddresses[i]; } ToggleBinding = new Binding(); ToggleBinding->AddBinding(new KeyboardBinding(VK_F3, true)); ForwardBinding = new Binding(); ForwardBinding->AddBinding(new KeyboardBinding('W', true)); BackwardBinding = new Binding(); BackwardBinding->AddBinding(new KeyboardBinding('S', true)); LeftBinding = new Binding(); LeftBinding->AddBinding(new KeyboardBinding('A', true)); RightBinding = new Binding(); RightBinding->AddBinding(new KeyboardBinding('D', true)); UpBinding = new Binding(); UpBinding->AddBinding(new KeyboardBinding(VK_SPACE, true)); DownBinding = new Binding(); DownBinding->AddBinding(new KeyboardBinding(VK_CONTROL, true)); ClockwiseBinding = new Binding(); ClockwiseBinding->AddBinding(new KeyboardBinding('E', true)); CounterClockwiseBinding = new Binding(); CounterClockwiseBinding->AddBinding(new KeyboardBinding('Q', true)); ZoomInBinding = new Binding(); ZoomInBinding->AddBinding(new KeyboardBinding('R', true)); ZoomOutBinding = new Binding(); ZoomOutBinding->AddBinding(new KeyboardBinding('F', true)); FastBinding = new Binding(); FastBinding->AddBinding(new KeyboardBinding(VK_SHIFT, true)); SlowBinding = new Binding(); SlowBinding->AddBinding(new KeyboardBinding(VK_MENU, true)); camera = (Camera*)CAMERA_ADDRESS; } void CameraController::Update() { return; } void CameraController::UpdateInput() { if (ToggleBinding->AnyTapped()) { SetControls(!GetIsEnabled()); return; } if (!GetIsEnabled()) return; auto keyboard = Keyboard::GetInstance(); auto mouse = Mouse::GetInstance(); bool forward = ForwardBinding->AnyDown(); bool backward = BackwardBinding->AnyDown(); bool left = LeftBinding->AnyDown(); bool right = RightBinding->AnyDown(); bool up = UpBinding->AnyDown(); bool down = DownBinding->AnyDown(); bool fast = FastBinding->AnyDown(); bool slow = SlowBinding->AnyDown(); bool clockwise = ClockwiseBinding->AnyDown(); bool counterclockwise = CounterClockwiseBinding->AnyDown(); bool zoomin = ZoomInBinding->AnyDown(); bool zoomout = ZoomOutBinding->AnyDown(); float speed = GetElapsedTime() * (fast ? fastSpeed : slow ? slowSpeed : normalSpeed); if (forward ^ backward) camera->Position += PointFromAngle(verticalRotation + (forward ? +0.0f : -180.0f), speed); if (left ^ right) camera->Position += PointFromAngle(verticalRotation + (right ? +90.0f : -90.0f), speed); if (up ^ down) camera->Position.Y += speed * (up ? +0.25f : -0.25f); if (clockwise ^ counterclockwise) camera->Rotation += speed * (clockwise ? -1.0f : +1.0f); if (zoomin ^ zoomout) { camera->HorizontalFov += speed * (zoomin ? -1.0f : +1.0f); camera->HorizontalFov = std::clamp(camera->HorizontalFov, +1.0f, +170.0f); } if (mouse->HasMoved()) { SetMouseWindowCenter(); auto delta = mouse->GetDeltaPosition(); verticalRotation += delta.x * sensitivity; horizontalRotation -= delta.y * (sensitivity / 5.0f); horizontalRotation = std::clamp(horizontalRotation, -75.0f, +75.0f); } ((InputState*)*(uint64_t*)INPUT_STATE_PTR_ADDRESS)->HideCursor(); Vec2 focus = PointFromAngle(verticalRotation, 1.0f); camera->Focus.X = camera->Position.X + focus.X; camera->Focus.Z = camera->Position.Z + focus.Y; camera->Focus.Y = camera->Position.Y + PointFromAngle(horizontalRotation, 5.0f).X; } void CameraController::SetControls(bool value) { if (GetIsEnabled() == value) return; SetIsEnabled(value); componentsManager->SetUpdateGameInput(!value); printf("[TLAC] CameraController::SetControls(): enabled = %s\n", GetIsEnabled() ? "true" : "false"); typedef void __stdcall _glutSetCursor(int); auto glutSetCursor = (_glutSetCursor*)GLUT_SET_CURSOR_ADDRESS; // hide cursor glutSetCursor(value ? GLUT_CURSOR_NONE : GLUT_CURSOR_RIGHT_ARROW); if (value) { // disable camera setters for (int i = 0; i < sizeof(cameraSetterAddresses) / sizeof(void*); i++) *(uint8_t*)cameraSetterAddresses[i] = RET_OPCODE; // set initial camera angle Vec2 camXz = Vec2(camera->Position.X, camera->Position.Z); Vec2 focusXz = Vec2(camera->Focus.X, camera->Focus.Z); verticalRotation = AngleFromPoints(camXz, focusXz); horizontalRotation = 0; camera->Rotation = defaultRotation; camera->HorizontalFov = defaultFov; } else { // restore camera setters for (int i = 0; i < sizeof(cameraSetterAddresses) / sizeof(void*); i++) *(uint8_t*)cameraSetterAddresses[i] = originalSetterBytes[i]; } } void CameraController::SetMouseWindowCenter() { RECT windowRect = framework::GetWindowBounds(); int centerX = windowRect.left + (windowRect.right - windowRect.left) / 2; int centerY = windowRect.top + (windowRect.bottom - windowRect.top) / 2; Mouse::GetInstance()->SetPosition(centerX, centerY); } bool CameraController::GetIsEnabled() { return isEnabled; } void CameraController::SetIsEnabled(bool value) { isEnabled = value; } } ================================================ FILE: source-code/source/plugins/TLAC/Components/CameraController.h ================================================ #pragma once #include "EmulatorComponent.h" #include "../Constants.h" #include "../Input/Bindings/Binding.h" #include "../Utilities/Math.h" namespace TLAC::Components { struct Camera { Utilities::Vec3 Position; Utilities::Vec3 Focus; float Rotation; float HorizontalFov; float VerticalFov; }; class CameraController : public EmulatorComponent { public: Input::Binding* ToggleBinding; Input::Binding* ForwardBinding; Input::Binding* BackwardBinding; Input::Binding* LeftBinding; Input::Binding* RightBinding; Input::Binding* UpBinding; Input::Binding* DownBinding; Input::Binding* FastBinding; Input::Binding* SlowBinding; Input::Binding* ClockwiseBinding; Input::Binding* CounterClockwiseBinding; Input::Binding* ZoomInBinding; Input::Binding* ZoomOutBinding; CameraController(); ~CameraController(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateInput() override; void SetControls(bool value); bool GetIsEnabled(); private: const float fastSpeed = 0.1f; const float slowSpeed = 0.0005f; const float normalSpeed = 0.005f; const float defaultRotation = 0.0f; const float defaultFov = 70.0f; const float sensitivity = 0.25f; ComponentsManager* componentsManager; float verticalRotation; float horizontalRotation; bool isEnabled; Camera* camera; uint8_t originalSetterBytes[4]; void* cameraSetterAddresses[4] = { (void*)CAMERA_POS_SETTER_ADDRESS, (void*)CAMERA_INTR_SETTER_ADDRESS, (void*)CAMERA_ROT_SETTER_ADDRESS, (void*)CAMERA_PERS_SETTER_ADDRESS, }; void SetMouseWindowCenter(); void SetIsEnabled(bool value); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/ComponentsManager.cpp ================================================ #include "ComponentsManager.h" #include "../FileSystem/ConfigFile.h" #include "../framework.h" #include "Input/InputEmulator.h" #include "Input/TouchSliderEmulator.h" #include "Input/TouchPanelEmulator.h" #include "PlayerDataManager.h" #include "FrameRateManager.h" #include "FastLoader.h" #include "CameraController.h" #include "DebugComponent.h" #include "ScaleComponent.h" #include "ScoreSaver.h" #include "Pause.h" #include "GameTargets/TargetInspector.h" using ConfigFile = TLAC::FileSystem::ConfigFile; namespace TLAC::Components { typedef void EngineUpdateInput(void*); ComponentsManager::ComponentsManager() { } ComponentsManager::~ComponentsManager() { } void ComponentsManager::ParseAddComponents() { EmulatorComponent* allComponents[] { new TargetInspector(), new InputEmulator(), new TouchSliderEmulator(), new TouchPanelEmulator(), new Pause(), // ensure pause is always immediately after input emulators so it can swallow inputs new PlayerDataManager(), new FrameRateManager(), new FastLoader(), new ScaleComponent(), new ScoreSaver(), new CameraController(), new DebugComponent(), }; ConfigFile componentsConfig(framework::GetModuleDirectory(), COMPONENTS_CONFIG_FILE_NAME); bool success = componentsConfig.OpenRead(); if (!success) { printf("ComponentsManager::ParseAddComponents(): Unable to parse %s\n", COMPONENTS_CONFIG_FILE_NAME.c_str()); return; } size_t componentCount = sizeof(allComponents) / sizeof(EmulatorComponent*); components.reserve(componentCount); std::string trueString = "true", falseString = "false"; for (int i = 0; i < componentCount; i++) { std::string* value; auto name = allComponents[i]->GetDisplayName(); //printf("ComponentsManager::ParseAddComponents(): searching name: %s\n", name); if (componentsConfig.TryGetValue(name, &value)) { //printf("ComponentsManager::ParseAddComponents(): %s found\n", name); if (*value == trueString) { //printf("ComponentsManager::ParseAddComponents(): enabling %s...\n", name); components.push_back(allComponents[i]); } else if (*value == falseString) { //printf("ComponentsManager::ParseAddComponents(): disabling %s...\n", name); } else { //printf("ComponentsManager::ParseAddComponents(): invalid value %s for component %s\n", value, name); } delete value; } else { //printf("ParseAddComponents(): component %s not found\n", name); delete allComponents[i]; } } } void ComponentsManager::Initialize() { dwGuiDisplay = (DwGuiDisplay*) * (uint64_t*)DW_GUI_DISPLAY_INSTANCE_PTR_ADDRESS; ParseAddComponents(); updateStopwatch.Start(); for (auto& component : components) component->Initialize(this); } void ComponentsManager::Update() { elpasedTime = updateStopwatch.Restart(); for (auto& component : components) { component->SetElapsedTime(elpasedTime); component->Update(); } } void ComponentsManager::UpdateInput() { if (!GetIsInputEmulatorUsed()) { uint64_t* inputStatePtr = (uint64_t*)INPUT_STATE_PTR_ADDRESS; // poll input using the original PollInput function we overwrote with the update hook instead if (inputStatePtr != nullptr) ((EngineUpdateInput*)ENGINE_UPDATE_INPUT_ADDRESS)((void*)* inputStatePtr); } for (auto& component : components) component->UpdateInput(); } void ComponentsManager::UpdatePostInput() { for (auto& component : components) { component->UpdatePostInput(); } } void ComponentsManager::UpdateDraw2D() { for (auto& component : components) { component->UpdateDraw2D(); } } void ComponentsManager::OnFocusGain() { for (auto& component : components) component->OnFocusGain(); } void ComponentsManager::OnFocusLost() { for (auto& component : components) component->OnFocusLost(); } void ComponentsManager::Dispose() { for (auto& component : components) delete component; } } ================================================ FILE: source-code/source/plugins/TLAC/Components/ComponentsManager.h ================================================ #pragma once #include "EmulatorComponent.h" #include "../Utilities/Stopwatch.h" #include #include namespace TLAC::Components { const std::string COMPONENTS_CONFIG_FILE_NAME = "components.ini"; // Incomplete type struct DwGuiDisplay { void* vftable; void* active; void* cap; void* on; void* move; void* widget; }; class ComponentsManager { public: ComponentsManager(); ~ComponentsManager(); void Initialize(); void Update(); void UpdateInput(); void UpdatePostInput(); void UpdateDraw2D(); void OnFocusGain(); void OnFocusLost(); void Dispose(); inline bool GetIsInputEmulatorUsed() { return isInputEmulatorUsed; }; inline void SetIsInputEmulatorUsed(bool value) { isInputEmulatorUsed = value; }; inline bool GetUpdateGameInput() { return updateGameInput; }; inline void SetUpdateGameInput(bool value) { updateGameInput = value; } inline bool IsDwGuiActive() { return dwGuiDisplay->active != nullptr; }; inline bool IsDwGuiHovered() { return dwGuiDisplay->on != nullptr; }; private: DwGuiDisplay* dwGuiDisplay; bool isInputEmulatorUsed = false; bool updateGameInput = true; float elpasedTime; Utilities::Stopwatch updateStopwatch; std::vector components; void ParseAddComponents(); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/CustomPlayerData.h ================================================ #pragma once #include #include namespace TLAC::Components { struct CustomPlayerData { std::string *PlayerName; std::string* LevelName; int VocaloidPoints; int LevelNum; int LevelPlateId; int LevelPlateEffect; int SkinEquip; int BtnSeEquip; int SlideSeEquip; int ChainslideSeEquip; int SlidertouchSeEquip; int ModuleEquip0; int ModuleEquip1; int ModuleEquip2; int ModuleEquip3; int ModuleEquip4; int ModuleEquip5; int ModuleEquipCmn0; int ModuleEquipCmn1; int ModuleEquipCmn2; int ModuleEquipCmn3; int ModuleEquipCmn4; int ModuleEquipCmn5; int ActionVol; int ActionSlideVol; int UsePVEquip; int UsePVSFXEquip; int UsePVSkinEquip; bool ShowGreatClearBorder; bool ShowExcellentClearBorder; bool ShowRivalClearBorder; bool UseCard; bool GameModifierOptions; bool ActionSE; std::vector Mylist[3]; }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/DebugComponent.cpp ================================================ #include "DebugComponent.h" #include "../Constants.h" namespace TLAC::Components { const char* GameStateNames[] = { "STARTUP", "ADVERTISE", "GAME", "DATA_TEST", "TEST_MODE", "APP_ERROR", "MAX", }; const char* SubGameStateNames[] = { "DATA_INITIALIZE", "SYSTEM_STARTUP", "SYSTEM_STARTUP_ERROR", "WARNING", "LOGO", "RATING", "DEMO", "TITLE", "RANKING", "SCORE_RANKING", "CM", "PHOTO_MODE_DEMO", "SELECTOR", "GAME_MAIN", "GAME_SEL", "STAGE_RESULT", "SCREEN_SHOT_SEL", "SCREEN_SHOT_RESULT", "GAME_OVER", "DATA_TEST_MAIN", "DATA_TEST_MISC", "DATA_TEST_OBJ", "DATA_TEST_STG", "DATA_TEST_MOT", "DATA_TEST_COLLISION", "DATA_TEST_SPR", "DATA_TEST_AET", "DATA_TEST_AUTH_3D", "DATA_TEST_CHR", "DATA_TEST_ITEM", "DATA_TEST_PERF", "DATA_TEST_PVSCRIPT", "DATA_TEST_PRINT", "DATA_TEST_CARD", "DATA_TEST_OPD", "DATA_TEST_SLIDER", "DATA_TEST_GLITTER", "DATA_TEST_GRAPHICS", "DATA_TEST_COLLECTION_CARD", "TEST_MODE_MAIN", "APP_ERROR", "MAX", }; const char* DataTestNames[] = { "MAIN TEST", "MISC TEST", "OBJECT TEST", "STAGE TEST", "MOTION TEST", "COLLISION TEST", "SPRITE TEST", "2DAUTH TEST", "3DAUTH TEST", "CHARA TEST", "ITEM TEST", "PERFORMANCE TEST", "PVSCRIPT TEST", "PRINT TEST", "CARD TEST", "OPD TEST", "SLIDER TEST", "GLITTER TEST", "GRAPHICS TEST", "COLLECTION CARD TEST", }; typedef void ChangeGameState(GameState); ChangeGameState* changeGameState = (ChangeGameState*)CHANGE_MODE_ADDRESS; typedef void ChangeSubState(GameState, SubGameState); ChangeSubState* changeSubState = (ChangeSubState*)CHANGE_SUB_MODE_ADDRESS; DebugComponent::DebugComponent() { } DebugComponent::~DebugComponent() { } const char* DebugComponent::GetDisplayName() { return "debug_component"; } void DebugComponent::Initialize(ComponentsManager*) { printf("[TLAC] DebugComponent::Initialize(): Initialized\n"); InjectPatches(); HWND consoleHandle = GetConsoleWindow(); ShowWindow(consoleHandle, SW_SHOW); // In case the FrameRateManager isn't enabled DWORD oldProtect; VirtualProtect((void*)AET_FRAME_DURATION_ADDRESS, sizeof(float), PAGE_EXECUTE_READWRITE, &oldProtect); } void DebugComponent::Update() { if (dataTestMain) { Input::Keyboard::GetInstance()->PollInput(); UpdateDataTestMain(); } } void DebugComponent::UpdateInput() { auto keyboard = Input::Keyboard::GetInstance(); // fast forward menus if (keyboard->IsDown(VK_SHIFT)) { float* frameDuration = (float*)AET_FRAME_DURATION_ADDRESS; if (keyboard->IsDown(VK_TAB)) *frameDuration = 1.0f / (GetGameFrameRate() / aetSpeedUpFactor); else if (keyboard->IsReleased(VK_TAB)) *frameDuration = 1.0f / 60.0f; } for (size_t i = 0; i < _countof(gameStateKeyMappings); i++) { if (keyboard->IsTapped(gameStateKeyMappings[i].KeyCode)) InternalChangeGameState(gameStateKeyMappings[i].State); } } void DebugComponent::InjectPatches() { const struct { void* Address; std::initializer_list Data; } patches[] = { // Prevent the DATA_TEST game state from exiting on the first frame { (void*)0x0000000140284B01, { 0x00 } }, // Enable dw_gui sprite draw calls { (void*)0x0000000140192601, { 0x00 } }, // Update the dw_gui display { (void*)0x0000000140302600, { 0xB0, 0x01 } }, // Draw the dw_gui display { (void*)0x0000000140302610, { 0xB0, 0x01 } }, // Enable the dw_gui widgets { (void*)0x0000000140192D00, { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 } }, }; for (size_t i = 0; i < _countof(patches); i++) InjectCode(patches[i].Address, patches[i].Data); } void DebugComponent::SetConsoleForeground() { HWND consoleHandle = GetConsoleWindow(); ShowWindow(consoleHandle, SW_SHOW); if (consoleHandle == NULL) return; WINDOWPLACEMENT place = { sizeof(WINDOWPLACEMENT) }; GetWindowPlacement(consoleHandle, &place); switch (place.showCmd) { case SW_SHOWMAXIMIZED: ShowWindow(consoleHandle, SW_SHOWMAXIMIZED); break; case SW_SHOWMINIMIZED: ShowWindow(consoleHandle, SW_RESTORE); break; default: ShowWindow(consoleHandle, SW_NORMAL); break; } SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); SetForegroundWindow(consoleHandle); } void DebugComponent::PrintDataTestMain() { system("cls"); printf(" DATA TEST MAIN:\n\n"); for (int i = SUB_DATA_TEST_MISC; i <= SUB_DATA_TEST_COLLECTION_CARD; i++) printf("%s %s\n", i == selectionIndex ? "->" : " ", DataTestNames[i - SUB_DATA_TEST_MAIN]); printf("\n"); SetConsoleForeground(); } void DebugComponent::InternalChangeGameState(GameState state) { changeGameState(state); printDataTestMain = dataTestMain = (state == GS_DATA_TEST); } void DebugComponent::UpdateDataTestMain() { auto keyboard = Input::Keyboard::GetInstance(); if (keyboard->IsIntervalTapped(VK_UP)) { selectionIndex--; printDataTestMain = true; } if (keyboard->IsIntervalTapped(VK_DOWN)) { selectionIndex++; printDataTestMain = true; } if (selectionIndex > SUB_DATA_TEST_COLLECTION_CARD) selectionIndex = SUB_DATA_TEST_MISC; if (selectionIndex < SUB_DATA_TEST_MISC) selectionIndex = SUB_DATA_TEST_COLLECTION_CARD; if (keyboard->IsTapped(VK_RETURN)) { dataTestMain = false; printf("[%s] -> [%s]\n", SubGameStateNames[SUB_DATA_TEST_MAIN], SubGameStateNames[selectionIndex]); changeSubState(GS_DATA_TEST, (SubGameState)selectionIndex); } if (printDataTestMain) { PrintDataTestMain(); printDataTestMain = false; } } void DebugComponent::InjectCode(void* address, const std::initializer_list &data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.begin(), byteCount); } } ================================================ FILE: source-code/source/plugins/TLAC/Components/DebugComponent.h ================================================ #pragma once #include "EmulatorComponent.h" #include "GameState.h" #include "../Input/Keyboard/Keyboard.h" namespace TLAC::Components { class DebugComponent : public EmulatorComponent { public: DebugComponent(); ~DebugComponent(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateInput() override; private: const float aetSpeedUpFactor = 4.0f; bool dataTestMain = false; bool printDataTestMain = false; int selectionIndex = SUB_DATA_TEST_MISC; const struct { BYTE KeyCode; GameState State; } gameStateKeyMappings[5] = { { VK_F4, GS_ADVERTISE }, { VK_F5, GS_GAME }, { VK_F6, GS_DATA_TEST }, { VK_F7, GS_TEST_MODE }, { VK_F8, GS_APP_ERROR }, }; void InjectPatches(); void SetConsoleForeground(); void PrintDataTestMain(); void InternalChangeGameState(GameState state); void UpdateDataTestMain(); void InjectCode(void* address, const std::initializer_list &data); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/EmulatorComponent.cpp ================================================ #include "EmulatorComponent.h" #include "../Constants.h" namespace TLAC::Components { EmulatorComponent::EmulatorComponent() { } EmulatorComponent::~EmulatorComponent() { } void EmulatorComponent::SetElapsedTime(float value) { elapsedTime = value; } float EmulatorComponent::GetElapsedTime() { return elapsedTime == 0.0f ? (1000.0f / 60.0f) : elapsedTime; } float EmulatorComponent::GetFrameRate() { return 1000.0f / GetElapsedTime(); } float EmulatorComponent::GetGameFrameRate() { return *(float*)FRAME_RATE_ADDRESS; } } ================================================ FILE: source-code/source/plugins/TLAC/Components/EmulatorComponent.h ================================================ #pragma once namespace TLAC::Components { class ComponentsManager; class EmulatorComponent { public: EmulatorComponent(); ~EmulatorComponent(); virtual const char* GetDisplayName() = 0; virtual void Initialize(ComponentsManager*) = 0; virtual void Update() = 0; virtual void UpdateInput() {}; virtual void UpdatePostInput() {}; virtual void UpdateDraw2D() {}; virtual void OnFocusGain() {}; virtual void OnFocusLost() {}; void SetElapsedTime(float value); float GetElapsedTime(); float GetFrameRate(); float GetGameFrameRate(); private: float elapsedTime; }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/FastLoader.cpp ================================================ #include "FastLoader.h" #include "../FileSystem/ConfigFile.h" #include "../Constants.h" #include #include "../framework.h" namespace TLAC::Components { FastLoader::FastLoader() { } FastLoader::~FastLoader() { } const char* FastLoader::GetDisplayName() { return "fast_loader"; } void FastLoader::Initialize(ComponentsManager*) { TLAC::FileSystem::ConfigFile componentsConfig(TLAC::framework::GetModuleDirectory(), COMPONENTS_CONFIG_FILE_NAME); bool success = componentsConfig.OpenRead(); if (success) { int speed = componentsConfig.GetIntegerValue("fast_loader_speed"); if (speed >= 2 && speed <= 1024) updatesPerFrame = speed; } printf("[Fast Loader] Speed: %d\n", updatesPerFrame); } void FastLoader::Update() { if (dataInitialized) return; previousGameState = currentGameState; currentGameState = *(GameState*)CURRENT_GAME_STATE_ADDRESS; if (currentGameState == GS_STARTUP) { typedef void UpdateTask(); UpdateTask* updateTask = (UpdateTask*)UPDATE_TASKS_ADDRESS; // speed up TaskSystemStartup for (int i = 0; i < updatesPerFrame; i++) updateTask(); constexpr int DATA_INITIALIZED = 3; // skip TaskDataInit *(int*)(DATA_INIT_STATE_ADDRESS) = DATA_INITIALIZED; // skip TaskWarning *(int*)(SYSTEM_WARNING_ELAPSED_ADDRESS) = 3939; } else if (previousGameState == GS_STARTUP) { dataInitialized = true; printf("[TLAC] FastLoader::Update(): Data Initialized\n"); } } void FastLoader::UpdateInput() { return; } } ================================================ FILE: source-code/source/plugins/TLAC/Components/FastLoader.h ================================================ #pragma once #include "EmulatorComponent.h" #include "GameState.h" #include namespace TLAC::Components { class FastLoader : public EmulatorComponent { public: FastLoader(); ~FastLoader(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateInput() override; private: const std::string COMPONENTS_CONFIG_FILE_NAME = "components.ini"; int updatesPerFrame = 39; GameState currentGameState; GameState previousGameState; bool dataInitialized = false; }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/FrameRateManager.cpp ================================================ #include "FrameRateManager.h" #include "../Constants.h" #include "GameState.h" #include #include #include "../framework.h" #include #include "detours.h" namespace TLAC::Components { FrameRateManager::FrameRateManager() { std::string utf8path = TLAC::framework::GetModuleDirectory() + "/config.ini"; WCHAR utf16buf[256]; MultiByteToWideChar(CP_UTF8, 0, utf8path.c_str(), -1, utf16buf, 256); float nMotionRate = GetPrivateProfileIntW(L"graphics", L"frm.motion.rate", 300, utf16buf); motionSpeedMultiplier = nMotionRate / 60.0f; } FrameRateManager::~FrameRateManager() { } const char* FrameRateManager::GetDisplayName() { return "frame_rate_manager"; } float FrameRateManager::fspeed_error = 0; // compensation value for use in this frame float FrameRateManager::fspeed_error_next = 0; // save a compensation value to be used in the next frame float FrameRateManager::fspeedhook_lastresult = 0; // used by the ageage hair patch to be lazy and avoid setting up for a proper call float(*divaGetFrameSpeed)() = (float(*)())0x140192D50; // a version of the original function that tries to round the output to more closely match chara motion timings float hookedGetFrameSpeed() { float frameSpeed = divaGetFrameSpeed(); // below is somewhat based (in concept) on 140194ad0 (motion quantisation thingy func) // add the error compensation from last frame frameSpeed += FrameRateManager::fspeed_error; // separate whole and fractional parts of speed // float speed_rounded = floorf(frameSpeed); // float speed_remainder = frameSpeed - speed_rounded; float speed_rounded; float speed_remainder = modff(frameSpeed, &speed_rounded); // save the remainder as error compensation for next frame // use == 0 to detect new frame and vars must be written if (FrameRateManager::fspeed_error_next == 0) { FrameRateManager::fspeed_error_next = speed_remainder; FrameRateManager::fspeedhook_lastresult = speed_rounded; } return speed_rounded; } void FrameRateManager::Initialize(ComponentsManager*) { pvFrameRate = (float*)PV_FRAME_RATE_ADDRESS; frameSpeed = (float*)FRAME_SPEED_ADDRESS; aetFrameDuration = (float*)AET_FRAME_DURATION_ADDRESS; // The default is expected to be 1.0 / 60.0 defaultAetFrameDuration = *aetFrameDuration; // This const variable is stored inside a data segment so we don't want to throw any access violations DWORD oldProtect; VirtualProtect((void*)AET_FRAME_DURATION_ADDRESS, sizeof(float), PAGE_EXECUTE_READWRITE, &oldProtect); // fix auto speed for high fps InjectCode((void*)0x140192d7b, { 0x90, 0x90, 0x90 }); // fix frame speed slider initial value (should ignore effect of auto speed) InjectCode((void*)0x140338f2f, { 0xf3, 0x0f, 0x10, 0x0d, 0x61, 0x18, 0xba, 0x00 }); // MOVSS XMM1, dword ptr [0x140eda798] (raw framespeed) InjectCode((void*)0x140338f37, { 0x48, 0x8b, 0x8f, 0x80, 0x01, 0x00, 0x00 }); // MOV RCX, qword ptr [0x180 + RDI] InjectCode((void*)0x140338ebe, { 0xf3, 0x0f, 0x10, 0x0d, 0xd2, 0x18, 0xba, 0x00 }); // MOVSS XMM1, dword ptr [0x140eda798] (raw framespeed) InjectCode((void*)0x140338ec6, { 0x48, 0x8b, 0x05, 0xfb, 0xb1, 0xe5, 0x00 }); // MOV RAX, qword ptr [0x1411940c8] InjectCode((void*)0x140338ecd, { 0x48, 0x8b, 0x88, 0x80, 0x01, 0x00, 0x00 }); // MOV RCX, qword ptr [0x180 + RAX] // fix AETs InjectCode((void*)0x140170394, { 0xF3, 0x0F, 0x5E, 0x05, 0x34, 0xA3, 0xD6, 0x00 }); // DIVSS XMM0, dword ptr [0x140eda6d0] (framerate) // fix edit PV AETs (thanks lyb) InjectCode((void*)0x140192d30, { 0xF3, 0x0F, 0x10, 0x05, 0x5C, 0x02, 0x00, 0x00 }); // MOVSS XMM0, dword ptr [0x140192f94] // fix ageage hair effect InjectCode((void*)0x14054352f, { // MOV R9, &fspeedhook_lastresult 0x49, 0xB9, (uint8_t)((uint64_t)&fspeedhook_lastresult & 0xFF), (uint8_t)(((uint64_t)&fspeedhook_lastresult >> 8) & 0xFF), (uint8_t)(((uint64_t)&fspeedhook_lastresult >> 16) & 0xFF), (uint8_t)(((uint64_t)&fspeedhook_lastresult >> 24) & 0xFF), (uint8_t)(((uint64_t)&fspeedhook_lastresult >> 32) & 0xFF), (uint8_t)(((uint64_t)&fspeedhook_lastresult >> 40) & 0xFF), (uint8_t)(((uint64_t)&fspeedhook_lastresult >> 48) & 0xFF), (uint8_t)(((uint64_t)&fspeedhook_lastresult >> 56) & 0xFF), }); InjectCode((void*)0x140543539, { 0xF3, 0x41, 0x0F, 0x59, 0x19 }); // MULSS XMM3, dword ptr [R9] InjectCode((void*)0x14054353e, { 0xEB, 0xB0 }); // JMP 0x1405434f0 // fix wind effect InjectCode((void*)0x14053ca71, { 0xEB, 0x3F }); // JMP 0x14053cab2 InjectCode((void*)0x14053cab2, { 0xF3, 0x0F, 0x10, 0x05, 0xFA, 0x53, 0x46, 0x00 }); // MOVSS XMM0, dword ptr [0x1409a1eb4] (60.0f) InjectCode((void*)0x14053caba, { 0xE9, 0x42, 0xFE, 0xFF, 0xFF }); // JMP 0x14053c901 InjectCode((void*)0x14053c901, { 0xF3, 0x0F, 0x5E, 0x05, 0xC7, 0xDD, 0x99, 0x00 }); // DIVSS XMM0, dword ptr [0x140eda6d0] (framerate) InjectCode((void*)0x14053c909, { 0xE9, 0x68, 0x01, 0x00, 0x00 }); // JMP 0x14053ca76 // replace divaGetFrameSpeed with a version that rounds the output to fix issues DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaGetFrameSpeed, hookedGetFrameSpeed); DetourTransactionCommit(); } void FrameRateManager::Update() { // *aetFrameDuration = 1.0f / GetGameFrameRate(); if (*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME) { *pvFrameRate = 60.0f * motionSpeedMultiplier; } else { *pvFrameRate = 60.0f; } if (*(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN || *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_DEMO) { // enable dynamic framerate *(bool*)USE_AUTO_FRAMESPEED_ADDRESS = true; // target framerate *(float*)AUTO_FRAMESPEED_TARGET_FRAMERATE_ADDRESS = *pvFrameRate; // trying to fix meltdown's water //if ((uint64_t*)0x1411943f8 != nullptr) //*(float*)(*(uint64_t*)0x1411943f8 + 0x1c) = (60.0f / GetGameFrameRate()) / 15.0f; //*(float*)(*(uint64_t*)0x1411943f8 + 0x10) = *(float*)(*(uint64_t*)0x1411943f8); } else { // enable dynamic framerate *(bool*)USE_AUTO_FRAMESPEED_ADDRESS = true; // target framerate *(float*)AUTO_FRAMESPEED_TARGET_FRAMERATE_ADDRESS = 60.0f; } } void FrameRateManager::UpdateDraw2D() { // cycle the framespeed timing error once per frame fspeed_error = fspeed_error_next; fspeed_error_next = 0; } void FrameRateManager::InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } } ================================================ FILE: source-code/source/plugins/TLAC/Components/FrameRateManager.h ================================================ #pragma once #include "EmulatorComponent.h" #include namespace TLAC::Components { class FrameRateManager : public EmulatorComponent { public: FrameRateManager(); ~FrameRateManager(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateDraw2D() override; static float fspeed_error; // compensation value for use in this frame static float fspeed_error_next; // save a compensation value to be used in the next frame static float fspeedhook_lastresult; // used by the ageage hair patch to be lazy and avoid setting up for a proper call private: float *pvFrameRate; float *frameSpeed; float *aetFrameDuration; float defaultAetFrameDuration; float motionSpeedMultiplier = 5.0; void InjectCode(void* address, const std::vector data); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/GameState.h ================================================ #pragma once #include namespace TLAC::Components { enum GameState : uint32_t { GS_STARTUP, GS_ADVERTISE, GS_GAME, GS_DATA_TEST, GS_TEST_MODE, GS_APP_ERROR, GS_MAX, }; enum SubGameState : uint32_t { SUB_DATA_INITIALIZE, SUB_SYSTEM_STARTUP, SUB_SYSTEM_STARTUP_ERROR, SUB_WARNING, SUB_LOGO, SUB_RATING, SUB_DEMO, SUB_TITLE, SUB_RANKING, SUB_SCORE_RANKING, SUB_CM, SUB_PHOTO_MODE_DEMO, SUB_SELECTOR, SUB_GAME_MAIN, SUB_GAME_SEL, SUB_STAGE_RESULT, SUB_SCREEN_SHOT_SEL, SUB_SCREEN_SHOT_RESULT, SUB_GAME_OVER, SUB_DATA_TEST_MAIN, SUB_DATA_TEST_MISC, SUB_DATA_TEST_OBJ, SUB_DATA_TEST_STG, SUB_DATA_TEST_MOT, SUB_DATA_TEST_COLLISION, SUB_DATA_TEST_SPR, SUB_DATA_TEST_AET, SUB_DATA_TEST_AUTH_3D, SUB_DATA_TEST_CHR, SUB_DATA_TEST_ITEM, SUB_DATA_TEST_PERF, SUB_DATA_TEST_PVSCRIPT, SUB_DATA_TEST_PRINT, SUB_DATA_TEST_CARD, SUB_DATA_TEST_OPD, SUB_DATA_TEST_SLIDER, SUB_DATA_TEST_GLITTER, SUB_DATA_TEST_GRAPHICS, SUB_DATA_TEST_COLLECTION_CARD, SUB_TEST_MODE_MAIN, SUB_APP_ERROR, SUB_MAX, }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/GameTargets/HoldState.h ================================================ #pragma once namespace TLAC::Components { enum HoldState { HOLD_NONE, HOLD_SANKAKU = 64, HOLD_MARU = 128, HOLD_BATSU = 256, HOLD_SHIKAKU = 512, }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/GameTargets/TargetHitStates.h ================================================ #pragma once namespace TLAC::Components { enum TargetHitStates : int32_t { COOL, FINE, SAFE, SAD, COOL_WRONG, // unsure FINE_WRONG, // unsure SAFE_WRONG, // unsure SAD_WRONG, // unsure WORST, NONE = 21, }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/GameTargets/TargetInspector.cpp ================================================ #include "TargetInspector.h" namespace TLAC::Components { bool TargetInspector::repressTbl[maxTargetSlots]; bool TargetInspector::ShouldVibrate; TargetInspector::TargetInspector() { } TargetInspector::~TargetInspector() { } void TargetInspector::Initialize(ComponentsManager*) { tgtStates = (TargetState*)TGT_STATES_BASE_ADDRESS; } void TargetInspector::Update() { UpdateRepressTbl(); UpdateShouldVibrate(); } const char* TargetInspector::GetDisplayName() { return "target_inspector"; } void TargetInspector::UpdateRepressTbl() { for (int i = 0; i < maxTargetSlots; ++i) { repressTbl[i] = IsWithinRange(tgtStates[i].tgtRemainingTime) && HasNotBeenHit(tgtStates[i].tgtHitState) && !IsSlide(tgtStates[i].tgtType); } } void TargetInspector::UpdateShouldVibrate() { for (int i = 0; i < maxTargetSlots; ++i) { if (IsWithinRange(tgtStates[i].tgtRemainingTime) && (tgtStates[i].tgtType == SLIDE_LONG_L || tgtStates[i].tgtType == SLIDE_LONG_R) && tgtStates[i].tgtHitState == NONE) { //printf("%d\n", tgtStates[i].tgtHitState); ShouldVibrate = true; return; } } ShouldVibrate = false; } bool TargetInspector::IsWithinRange(float time) { return time < timingThreshold && time > -timingThreshold && time != 0; } bool TargetInspector::HasNotBeenHit(int hitState) { return hitState == NONE; } bool TargetInspector::IsSlide(int type) { return (type >= SLIDE_L && type <= SLIDE_LONG_R) || type >= SLIDE_L_CH; } bool TargetInspector::IsAnyRepress() { for (int i = 0; i < maxTargetSlots; ++i) { if (repressTbl[i]) return true; } return false; } } ================================================ FILE: source-code/source/plugins/TLAC/Components/GameTargets/TargetInspector.h ================================================ #pragma once #include "../EmulatorComponent.h" #include "../Input/InputEmulator.h" #include "../../Constants.h" #include "TargetHitStates.h" #include "TargetState.h" namespace TLAC::Components { const int maxTargetSlots = 64; class TargetInspector : public EmulatorComponent { public: TargetInspector(); ~TargetInspector(); static bool repressTbl[maxTargetSlots]; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual const char* GetDisplayName() override; static bool IsAnyRepress(); static bool ShouldVibrate; private: //const uint64_t offset = 0x4A8; const float timingThreshold = 0.13f; // PS4 estimate TargetState* tgtStates; bool IsSlide(int); bool IsWithinRange(float); bool HasNotBeenHit(int); void UpdateRepressTbl(); void UpdateShouldVibrate(); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/GameTargets/TargetState.h ================================================ #pragma once namespace TLAC::Components { struct TargetState { // seems to be some kind of linked list.. // not sure if these are for all active targets or just used in some functions TargetState* prev; TargetState* next; byte padding10[0x4]; TargetTypes tgtType; float tgtRemainingTime; byte padding1C[0x434]; byte ToBeRemoved; // FromList byte padding451[0xB]; TargetHitStates tgtHitState; byte padding460[0x48]; }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/GameTargets/TargetTypes.h ================================================ #pragma once namespace TLAC::Components { enum TargetTypes : int32_t { SANKAKU, MARU, BATSU, SHIKAKU, SANKAKU_H, MARU_H, BATSU_H, SHIKAKU_H, SLIDE_L = 12, SLIDE_R, SLIDE_LONG_L = 15, SLIDE_LONG_R, SANKAKU_CH = 18, MARU_CH, BATSU_CH, SHIKAKU_CH, SLIDE_L_CH = 23, SLIDE_R_CH, }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/InputBufferType.h ================================================ #pragma once namespace TLAC::Components { enum InputBufferType { InputBufferType_Tapped, InputBufferType_Released, InputBufferType_Down, InputBufferType_DoubleTapped, InputBufferType_IntervalTapped, InputBufferType_Max, }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp ================================================ #include #include "windows.h" #include "InputEmulator.h" #include "../ComponentsManager.h" #include "../../Constants.h" #include "../../framework.h" #include "../../Input/Bindings/KeyboardBinding.h" #include "../../Input/Bindings/XinputBinding.h" #include "../../Input/Bindings/MouseBinding.h" #include "../../Input/Bindings/Ds4Binding.h" #include "../../Input/Bindings/DVLBinding.h" #include "../../Input/KeyConfig/Config.h" #include "../../Utilities/Operations.h" #include "../../Utilities/EnumBitwiseOperations.h" #include "../../FileSystem/ConfigFile.h" #include "../GameState.h" #include "../Pause.h" #include "../../Utils.h" const std::string KEY_CONFIG_FILE_NAME = "keyconfig.ini"; using namespace TLAC::Input; using namespace TLAC::Input::KeyConfig; using namespace TLAC::Utilities; namespace TLAC::Components { InputEmulator::InputEmulator() { } InputEmulator::~InputEmulator() { delete TestBinding; delete ServiceBinding; delete StartBinding; delete SankakuBinding; delete ShikakuBinding; delete BatsuBinding; delete MaruBinding; delete LeftBinding; delete RightBinding; delete MenuLBinding; delete MenuRBinding; delete MenuCircleBinding; } const char* InputEmulator::GetDisplayName() { return "input_emulator"; } void InputEmulator::Initialize(ComponentsManager* manager) { componentsManager = manager; componentsManager->SetIsInputEmulatorUsed(true); inputState = GetInputStatePtr((void*)INPUT_STATE_PTR_ADDRESS); inputState->HideCursor(); TestBinding = new Binding(); ServiceBinding = new Binding(); Sw1Binding = new Binding(); Sw2Binding = new Binding(); StartBinding = new Binding(); SankakuBinding = new Binding(); ShikakuBinding = new Binding(); BatsuBinding = new Binding(); MaruBinding = new Binding(); LeftBinding = new Binding(); RightBinding = new Binding(); MenuLBinding = new Binding(); MenuRBinding = new Binding(); MenuCircleBinding = new Binding(); CoinBinding = new Binding(); ToonBinding = new Binding(); WireframeBinding = new Binding(); FileSystem::ConfigFile configFile(framework::GetModuleDirectory(), KEY_CONFIG_FILE_NAME); configFile.OpenRead(); Config::BindConfigKeys(configFile.ConfigMap, "JVS_TEST", *TestBinding, { "F1" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_SERVICE", *ServiceBinding, { "F2" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_SW1", *Sw1Binding, { "F11" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_SW2", *Sw2Binding, { "F12" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_START", *StartBinding, { "Enter" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_TRIANGLE", *SankakuBinding, { "W", "I" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_SQUARE", *ShikakuBinding, { "A", "J" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_CROSS", *BatsuBinding, { "S", "K" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_CIRCLE", *MaruBinding, { "D", "L" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_LEFT", *LeftBinding, { "Q", "U" }); Config::BindConfigKeys(configFile.ConfigMap, "JVS_RIGHT", *RightBinding, { "E", "O" }); Config::BindConfigKeys(configFile.ConfigMap, "MENU_L", *MenuLBinding, { "Left", "Up" }); Config::BindConfigKeys(configFile.ConfigMap, "MENU_R", *MenuRBinding, { "Down", "Right" }); Config::BindConfigKeys(configFile.ConfigMap, "MENU_CIRCLE", *MenuCircleBinding, { "D", "L", "Spacebar" }); Config::BindConfigKeys(configFile.ConfigMap, "TOON", *ToonBinding, { "F9" }); Config::BindConfigKeys(configFile.ConfigMap, "COIN", *CoinBinding, { "F10" }); Config::BindConfigKeys(configFile.ConfigMap, "WIREFRAME", *WireframeBinding, { "Backspace" }); mouseScrollPvSelection = configFile.GetBooleanValue("mouse_scroll_pv_selection"); TestBinding->AddBinding(new DivallerBinding(DivallerButton::DVL_L3)); ServiceBinding->AddBinding(new DivallerBinding(DivallerButton::DVL_L2)); CoinBinding->AddBinding(new DivallerBinding(DivallerButton::DVL_L1)); StartBinding->AddBinding(new DivallerBinding(DivallerButton::DVL_FN)); SankakuBinding->AddBinding(new DivallerBinding(DivallerButton::DVL_TRIANGLE)); ShikakuBinding->AddBinding(new DivallerBinding(DivallerButton::DVL_SQUARE)); BatsuBinding->AddBinding(new DivallerBinding(DivallerButton::DVL_CROSS)); MaruBinding->AddBinding(new DivallerBinding(DivallerButton::DVL_CIRCLE)); } void InputEmulator::Update() { return; } void InputEmulator::OnFocusLost() { // to prevent buttons from being "stuck" inputState->ClearState(); inputState->HideCursor(); } void InputEmulator::UpdateInput() { if (!componentsManager->GetUpdateGameInput()) return; if (!componentsManager->IsDwGuiActive()) { UpdateJvsInput(); if (mouseScrollPvSelection && !componentsManager->IsDwGuiHovered()) UpdateMousePvScroll(); } UpdateDwGuiInput(); } void InputEmulator::UpdateJvsInput() { auto tappedFunc = [](void* binding) { return ((Binding*)binding)->AnyTapped(); }; auto releasedFunc = [](void* binding) { return ((Binding*)binding)->AnyReleased(); }; auto downFunc = [](void* binding) { return ((Binding*)binding)->AnyDown(); }; lastDownState = inputState->Down.Buttons; inputState->Tapped.Buttons = GetJvsButtonsState(tappedFunc); inputState->Released.Buttons = GetJvsButtonsState(releasedFunc); inputState->Down.Buttons = GetJvsButtonsState(downFunc); inputState->DoubleTapped.Buttons = GetJvsButtonsState(tappedFunc); inputState->IntervalTapped.Buttons = GetJvsButtonsState(tappedFunc); // if not interacting with L and R, use values from the slider instead if ( ( (inputState->Tapped.Buttons | inputState->Released.Buttons | inputState->Down.Buttons) & (JVS_L | JVS_R) ) == 0) { UpdateSliderLR(); } SetMetaButtons(); UpdateHoldState(); heldButtons = GetButtonFromHold(); if ((lastDownState &= inputState->Tapped.Buttons) != 0) { inputState->Down.Buttons ^= inputState->Tapped.Buttons; if (IsHold() && !TargetInspector::IsAnyRepress()) inputState->Down.Buttons |= heldButtons; } // repress held down buttons to not block input //inputState->Down.Buttons ^= inputState->Tapped.Buttons; if (CoinBinding->AnyTapped()) addCoin(); if (ToonBinding->AnyTapped()) toggleNpr1(); if (WireframeBinding->AnyTapped()) toggleWireframe(); } HoldState InputEmulator::GetHoldState() { return (HoldState) * ((int*)HOLD_STATE_ADDRESS); } int InputEmulator::GetMaxHoldState() { return *(int*)MAX_HOLD_STATE_ADDRESS; } bool InputEmulator::IsHold() { return ((holdState != HOLD_NONE) && (GetMaxHoldState() != 1)); } void InputEmulator::UpdateHoldState() { holdState = GetHoldState(); for (int i = 0; i < 4; ++i) { int holdId = 1 << (i + 6); if ((holdId & holdState) != 0) holdTbl[i] = 1; else holdTbl[i] = 0; } } void InputEmulator::UpdateDwGuiInput() { auto keyboard = Keyboard::GetInstance(); auto mouse = Mouse::GetInstance(); auto pos = mouse->GetRelativePosition(); inputState->MouseX = (int)pos.x; inputState->MouseY = (int)pos.y; auto deltaPos = mouse->GetDeltaPosition(); inputState->MouseDeltaX = (int)deltaPos.x; inputState->MouseDeltaY = (int)deltaPos.y; inputState->Key = GetKeyState(); for (int i = 0; i < sizeof(keyBits) / sizeof(KeyBit); i++) UpdateInputBit(keyBits[i].Bit, keyBits[i].KeyCode); for (int i = InputBufferType_Tapped; i < InputBufferType_Max; i++) { inputState->SetBit(scrollUpBit, mouse->GetIsScrolledUp(), (InputBufferType)i); inputState->SetBit(scrollDownBit, mouse->GetIsScrolledDown(), (InputBufferType)i); } } void InputEmulator::UpdateMousePvScroll() { // I originally wanted to use a MouseBinding set to JVS_LEFT / JVS_RIGHT // but that ended up being too slow because a PV slot can only be scrolled to once the scroll animation has finished playing int* slotsToScroll = (int*)PV_SEL_SLOTS_TO_SCROLL; int* modulesToScroll = (int*)MODULE_SEL_SLOTS_TO_SCROLL; auto mouse = Mouse::GetInstance(); if (mouse->GetIsScrolledUp()) { if (*(int*)PV_SEL_SLOTS_CONST < 26) *slotsToScroll -= 1; if (*(int*)MODULE_IS_RECOMMENDED == 0) *modulesToScroll -= 1; } if (mouse->GetIsScrolledDown()) { if (*(int*)PV_SEL_SLOTS_CONST < 26) *slotsToScroll += 1; if (*(int*)MODULE_IS_RECOMMENDED == 0) *modulesToScroll += 1; } } InputState* InputEmulator::GetInputStatePtr(void* address) { return (InputState*)(*(uint64_t*)address); } JvsButtons InputEmulator::GetJvsButtonsState(bool(*buttonTestFunc)(void*)) { JvsButtons buttons = JVS_NONE; if ((Pause::pause || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && buttonTestFunc(MenuLBinding)) { buttons |= JVS_L; return buttons; } if ((Pause::pause || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && buttonTestFunc(MenuRBinding)) { buttons |= JVS_R; return buttons; } if ((Pause::pause || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && buttonTestFunc(MenuCircleBinding)) { buttons |= JVS_CIRCLE; return buttons; } if (buttonTestFunc(TestBinding)) buttons |= JVS_TEST; if (buttonTestFunc(ServiceBinding)) buttons |= JVS_SERVICE; if (buttonTestFunc(Sw1Binding)) buttons |= JVS_SW1; if (buttonTestFunc(Sw2Binding)) buttons |= JVS_SW2; if (buttonTestFunc(StartBinding)) buttons |= JVS_START; if (buttonTestFunc(SankakuBinding)) buttons |= JVS_TRIANGLE; if (buttonTestFunc(ShikakuBinding)) buttons |= JVS_SQUARE; if (buttonTestFunc(BatsuBinding)) buttons |= JVS_CROSS; if (buttonTestFunc(MaruBinding)) buttons |= JVS_CIRCLE; if (buttonTestFunc(LeftBinding)) buttons |= JVS_L; if (buttonTestFunc(RightBinding)) buttons |= JVS_R; return buttons; } JvsButtons InputEmulator::GetButtonFromHold() { JvsButtons buttons = JVS_NONE; if (holdTbl[0]) buttons |= JVS_TRIANGLE; if (holdTbl[1]) buttons |= JVS_CIRCLE; if (holdTbl[2]) buttons |= JVS_CROSS; if (holdTbl[3]) buttons |= JVS_SQUARE; return buttons; } char InputEmulator::GetKeyState() { auto keyboard = Keyboard::GetInstance(); bool upper = keyboard->IsDown(VK_SHIFT); constexpr char caseDifference = 'A' - 'a'; char inputKey = 0x00; for (char key = '0'; key < 'Z'; key++) { if (keyboard->IsIntervalTapped(key)) inputKey = (upper || key < 'A') ? key : (key - caseDifference); } if (keyboard->IsIntervalTapped(VK_BACK)) inputKey = 0x08; if (keyboard->IsIntervalTapped(VK_TAB)) inputKey = 0x09; if (keyboard->IsIntervalTapped(VK_SPACE)) inputKey = 0x20; if (keyboard->IsDoubleTapped(VK_ESCAPE)) *(bool*)SHOULD_EXIT_BOOL_ADDRESS = true; return inputKey; } void InputEmulator::UpdateInputBit(uint32_t bit, uint8_t keycode) { auto keyboard = Keyboard::GetInstance(); inputState->SetBit(bit, keyboard->IsTapped(keycode), InputBufferType_Tapped); inputState->SetBit(bit, keyboard->IsReleased(keycode), InputBufferType_Released); inputState->SetBit(bit, keyboard->IsDown(keycode), InputBufferType_Down); inputState->SetBit(bit, keyboard->IsDoubleTapped(keycode), InputBufferType_DoubleTapped); inputState->SetBit(bit, keyboard->IsIntervalTapped(keycode), InputBufferType_IntervalTapped); } typedef uint8_t getSliderSensorFunc(void*, int); void InputEmulator::UpdateSliderLR() { getSliderSensorFunc* getSliderSensorTapped = (getSliderSensorFunc*)GET_SLIDER_TAPPED_ADDRESS; getSliderSensorFunc* getSliderSensorReleased = (getSliderSensorFunc*)GET_SLIDER_RELEASED_ADDRESS; getSliderSensorFunc* getSliderSensorDown = (getSliderSensorFunc*)GET_SLIDER_DOWN_ADDRESS; if (getSliderSensorTapped((void*)SLIDER_CTRL_TASK_ADDRESS, 36)) inputState->Tapped.Buttons |= JVS_L; else inputState->Tapped.Buttons &= ~JVS_L; if (getSliderSensorReleased((void*)SLIDER_CTRL_TASK_ADDRESS, 36)) inputState->Released.Buttons |= JVS_L; else inputState->Released.Buttons &= ~JVS_L; if (getSliderSensorDown((void*)SLIDER_CTRL_TASK_ADDRESS, 36)) inputState->Down.Buttons |= JVS_L; else inputState->Down.Buttons &= ~JVS_L; if (getSliderSensorTapped((void*)SLIDER_CTRL_TASK_ADDRESS, 37)) inputState->Tapped.Buttons |= JVS_R; else inputState->Tapped.Buttons &= ~JVS_R; if (getSliderSensorReleased((void*)SLIDER_CTRL_TASK_ADDRESS, 37)) inputState->Released.Buttons |= JVS_R; else inputState->Released.Buttons &= ~JVS_R; if (getSliderSensorDown((void*)SLIDER_CTRL_TASK_ADDRESS, 37)) inputState->Down.Buttons |= JVS_R; else inputState->Down.Buttons &= ~JVS_R; } void InputEmulator::SetMetaButtons() { // bit 0x6e is used to skip a bunch of screens if ((inputState->Down.Buttons & (JVS_L | JVS_R)) == 0) // ask sega, okay? idk why this is needed { if ((inputState->Tapped.Buttons & (JVS_START | JVS_TRIANGLE | JVS_SQUARE | JVS_CROSS | JVS_CIRCLE)) != 0) inputState->SetBit(0x6e, true, InputBufferType_Tapped); else inputState->SetBit(0x6e, false, InputBufferType_Tapped); if ((inputState->Down.Buttons & (JVS_START | JVS_TRIANGLE | JVS_SQUARE | JVS_CROSS | JVS_CIRCLE)) != 0) inputState->SetBit(0x6e, true, InputBufferType_Down); else inputState->SetBit(0x6e, false, InputBufferType_Down); if ((inputState->Released.Buttons & (JVS_START | JVS_TRIANGLE | JVS_SQUARE | JVS_CROSS | JVS_CIRCLE)) != 0) inputState->SetBit(0x6e, true, InputBufferType_Released); else inputState->SetBit(0x6e, false, InputBufferType_Released); } } void InputEmulator::addCoin() { printf("[TLAC] Adding coin\n"); unsigned char* credits = (unsigned char*)0x14CD93788; if (*credits < 9) { *(unsigned char*)0x14CD93A9C = 1; (*credits)++; (*(unsigned char*)0x14CD93A98)++; if ((*(unsigned char*)0x14CD93A98) == 0) (*(unsigned char*)0x14CD93A98)++; } } void InputEmulator::toggleNpr1() { switch(*(byte*)0x0000000140502FC6) { case 0xC3: // default -> force on InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E }); InjectCode((void*)0x0000000140502FC6, { 0x01, 0x00, 0x00, 0x00, 0xC3 }); *(byte*)0x00000001411AD638 = 1; printf("[TLAC] NPR1 forced\n"); break; case 0x01: // default -> force off InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E }); InjectCode((void*)0x0000000140502FC6, { 0x00, 0x00, 0x00, 0x00, 0xC3 }); *(byte*)0x00000001411AD638 = 0; printf("[TLAC] NPR1 disabled\n"); break; default: // force off -> default InjectCode((void*)0x0000000140502FC0, { 0x89, 0x0D, 0x72 }); InjectCode((void*)0x0000000140502FC6, { 0xC3, 0xCC, 0xCC, 0xCC, 0xCC }); printf("[TLAC] NPR1 restored\n"); } } void InputEmulator::toggleWireframe() { static bool wireframeEnabled = false; if (!wireframeEnabled) { // inject samyuu's wireframe code InjectCode((void*)0x00000000140500BE6, { 0xBA, 0x01, 0x1B, 0x00, 0x00, // mov edx,00001B01 0xB9, 0x08, 0x04, 0x00, 0x00, // mov ecx,00000408 0xE8, 0xE1, 0x5A, 0x3B, 0x00, // call 1408B66D6 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); wireframeEnabled = true; printf("[TLAC] Wireframe enabled\n"); } else { InjectCode((void*)0x00000000140500BE6, { 0xB9, 0x1C, 0x00, 0x00, 0x00, 0xE8, 0x30, 0x7C, 0xF3, 0xFF, 0xB9, 0x1B, 0x00, 0x00, 0x00, 0x8B, 0xD8, 0xE8, 0x24, 0x7C, 0xF3, 0xFF, 0xB9, 0x1A, 0x00, 0x00, 0x00 }); wireframeEnabled = false; printf("[TLAC] Wireframe disabled\n"); } } } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/InputEmulator.h ================================================ #pragma once #include #include #include "InputState.h" #include "../EmulatorComponent.h" #include "../../Input/Bindings/Binding.h" #include "../GameTargets/TargetTypes.h" #include "../GameTargets/TargetHitStates.h" #include "../GameTargets/HoldState.h" #include "../GameTargets/TargetInspector.h" namespace TLAC::Components { struct KeyBit { uint32_t Bit; uint8_t KeyCode; }; class InputEmulator : public EmulatorComponent { public: Input::Binding* TestBinding; Input::Binding* ServiceBinding; Input::Binding* Sw1Binding; Input::Binding* Sw2Binding; Input::Binding* StartBinding; Input::Binding* SankakuBinding; Input::Binding* ShikakuBinding; Input::Binding* BatsuBinding; Input::Binding* MaruBinding; Input::Binding* LeftBinding; Input::Binding* RightBinding; Input::Binding* MenuLBinding; Input::Binding* MenuRBinding; Input::Binding* MenuCircleBinding; Input::Binding* CoinBinding; Input::Binding* ToonBinding; Input::Binding* WireframeBinding; InputEmulator(); ~InputEmulator(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateInput() override; virtual void OnFocusLost() override; private: ComponentsManager* componentsManager; bool mouseScrollPvSelection = false; const uint32_t scrollUpBit = 99; const uint32_t scrollDownBit = 100; KeyBit keyBits[20] = { { 5, VK_LEFT }, { 6, VK_RIGHT }, { 29, VK_SPACE }, { 39, 'A' }, { 43, 'E' }, { 42, 'D' }, { 55, 'Q' }, { 57, 'S' }, // unsure { 61, 'W' }, { 63, 'Y' }, { 84, 'L' }, // unsure { 80, VK_RETURN }, { 81, VK_SHIFT }, { 82, VK_CONTROL }, { 83, VK_MENU }, { 91, VK_UP }, { 93, VK_DOWN }, { 96, MK_LBUTTON }, { 97, VK_MBUTTON }, { 98, MK_RBUTTON }, }; InputState* inputState; JvsButtons lastDownState; JvsButtons heldButtons; int holdTbl[4]; HoldState holdState; void UpdateJvsInput(); void UpdateDwGuiInput(); void UpdateMousePvScroll(); void UpdateHoldState(); InputState* GetInputStatePtr(void* address); JvsButtons GetJvsButtonsState(bool(*buttonTestFunc)(void*)); JvsButtons GetButtonFromHold(); char GetKeyState(); HoldState GetHoldState(); int GetMaxHoldState(); bool IsHold(); void UpdateInputBit(uint32_t bit, uint8_t keycode); void UpdateSliderLR(); void SetMetaButtons(); void addCoin(); void toggleNpr1(); void toggleWireframe(); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/InputState.cpp ================================================ #include "InputState.h" #include #include namespace TLAC::Components { void InputState::ClearState() { memset(this, 0, sizeof(InputState)); } void InputState::HideCursor() { MouseX = INT32_MIN; MouseY = INT32_MIN; MouseDeltaX = 0; MouseDeltaY = 0; } void InputState::SetBit(uint32_t bit, bool value, InputBufferType inputType) { uint8_t* data = GetInputBuffer(inputType); if (data == nullptr || bit < 0 || bit >= MAX_BUTTON_BIT) return; int byteIndex = (bit / 8); int bitIndex = (bit % 8); BYTE mask = (1 << bitIndex); data[byteIndex] = value ? (data[byteIndex] | mask) : (data[byteIndex] & ~mask); } uint8_t* InputState::GetInputBuffer(InputBufferType inputType) { switch (inputType) { case InputBufferType_Tapped: return (uint8_t*)&Tapped; case InputBufferType_Released: return (uint8_t*)&Released; case InputBufferType_Down: return (uint8_t*)&Down; case InputBufferType_DoubleTapped: return (uint8_t*)&DoubleTapped; case InputBufferType_IntervalTapped: return (uint8_t*)&IntervalTapped; default: return nullptr; } } } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/InputState.h ================================================ #pragma once #include "JvsButtons.h" #include "InputBufferType.h" namespace TLAC::Components { const int MAX_BUTTON_BIT = 0x6F; // The button state is larger than the size of a register // but only the first 32 bits are used during normal gameplay // so this will provide the convenience of still being able to access them through a bit field union ButtonState { JvsButtons Buttons; uint32_t State[4]; }; // total sizeof() == 0x20E0 struct InputState { ButtonState Tapped; ButtonState Released; ButtonState Down; uint32_t Padding_20[4]; ButtonState DoubleTapped; uint32_t Padding_30[4]; ButtonState IntervalTapped; uint32_t Padding_38[12]; int32_t MouseX; int32_t MouseY; int32_t MouseDeltaX; int32_t MouseDeltaY; uint32_t Padding_AC[8]; uint8_t Padding_D0[3]; char Key; void ClearState(); void HideCursor(); void SetBit(uint32_t bit, bool value, InputBufferType inputType); uint8_t* GetInputBuffer(InputBufferType inputType); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/JvsButtons.h ================================================ #pragma once #include namespace TLAC::Components { enum JvsButtons : uint32_t { JVS_NONE = 0 << 0x00, // 0x0 JVS_TEST = 1 << 0x00, // 0x1 JVS_SERVICE = 1 << 0x01, // 0x2 JVS_START = 1 << 0x02, // 0x4 JVS_TRIANGLE = 1 << 0x07, // 0x80 JVS_SQUARE = 1 << 0x08, // 0x100 JVS_CROSS = 1 << 0x09, // 0x200 JVS_CIRCLE = 1 << 0x0A, // 0x400 JVS_L = 1 << 0x0B, // 0x800 JVS_R = 1 << 0x0C, // 0x1000 JVS_SW1 = 1 << 0x12, // 0x40000 JVS_SW2 = 1 << 0x13, // 0x80000 }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/TouchPanelEmulator.cpp ================================================ #include "TouchPanelEmulator.h" #include #include #include #include "../ComponentsManager.h" #include "../../Constants.h" #include "../../framework.h" #include "../../Input/Mouse/Mouse.h" #include "../../Input/Keyboard/Keyboard.h" using namespace TLAC::Input; namespace TLAC::Components { TouchPanelEmulator::TouchPanelEmulator() { } TouchPanelEmulator::~TouchPanelEmulator() { } const char* TouchPanelEmulator::GetDisplayName() { return "touch_panel_emulator"; } void TouchPanelEmulator::Initialize(ComponentsManager* manager) { componentsManager = manager; state = GetTouchStatePtr((void*)TASK_TOUCH_ADDRESS); // Make touches on actual touchscreens more responsive const DWORD_PTR dwHwndTabletProperty = TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves) TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle) TABLET_DISABLE_FLICKS; // disables pen flicks (back, forward, drag down, drag up) SetProp(TLAC::framework::DivaWindowHandle, MICROSOFT_TABLETPENSERVICE_PROPERTY, reinterpret_cast(dwHwndTabletProperty)); } void TouchPanelEmulator::Update() { state->ConnectionState = 1; } void TouchPanelEmulator::UpdateInput() { if (!componentsManager->GetUpdateGameInput() || componentsManager->IsDwGuiActive() || componentsManager->IsDwGuiHovered()) return; // TODO: rescale TouchReaction aet position auto keyboard = Keyboard::GetInstance(); auto pos = Mouse::GetInstance()->GetRelativePosition(); state->XPosition = (float)pos.x; state->YPosition = (float)pos.y; bool down = keyboard->IsDown(VK_LBUTTON); bool released = keyboard->IsReleased(VK_LBUTTON); state->ContactType = (down ? 0x2 : released ? 0x1 : 0x0); state->Pressure = (float)(state->ContactType != 0); } TouchPanelState* TouchPanelEmulator::GetTouchStatePtr(void *address) { return (TouchPanelState*)address; } } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/TouchPanelEmulator.h ================================================ #pragma once #include "../EmulatorComponent.h" #include "TouchPanelState.h" namespace TLAC::Components { class TouchPanelEmulator : public EmulatorComponent { public: TouchPanelEmulator(); ~TouchPanelEmulator(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateInput() override; private: ComponentsManager* componentsManager; TouchPanelState* state; TouchPanelState* GetTouchStatePtr(void *address); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/TouchPanelState.h ================================================ #pragma once namespace TLAC::Components { struct TouchPanelState { int Padding00[0x1E]; int ConnectionState; int Padding01[0x06]; float XPosition; float YPosition; float Pressure; int ContactType; }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/TouchSliderEmulator.cpp ================================================ #include "TouchSliderEmulator.h" #include "../ComponentsManager.h" #include "../../Constants.h" #include "../../framework.h" #include "../../Input/Mouse/Mouse.h" #include "../../Input/Keyboard/Keyboard.h" #include "../../Input/Bindings/KeyboardBinding.h" #include "../../Input/KeyConfig/Config.h" #include "../../Input/DirectInput/Ds4/DualShock4.h" #include "../../Input/Divaller/Divaller.h" #include "../../FileSystem/ConfigFile.h" #include "../../Utilities/Math.h" #include #include #include "../GameState.h" using namespace TLAC::Input; using namespace TLAC::Input::KeyConfig; using namespace TLAC::Utilities; namespace TLAC::Components { const std::string KEY_CONFIG_FILE_NAME = "keyconfig.ini"; TouchSliderEmulator* TouchSliderEmulator::LatestInstance; TouchSliderEmulator::TouchSliderEmulator() { LatestInstance = this; } TouchSliderEmulator::~TouchSliderEmulator() { delete LeftSideSlideLeft; delete LeftSideSlideRight; delete RightSideSlideLeft; delete RightSideSlideRight; } const char* TouchSliderEmulator::GetDisplayName() { return "touch_slider_emulator"; } void TouchSliderEmulator::Initialize(ComponentsManager* manager) { componentsManager = manager; sliderState = (TouchSliderState*)SLIDER_CTRL_TASK_ADDRESS; touchSliderEmulatorIsEnabled = true; LeftSideSlideLeft = new Binding(); LeftSideSlideRight = new Binding(); RightSideSlideLeft = new Binding(); RightSideSlideRight = new Binding(); FileSystem::ConfigFile configFile(framework::GetModuleDirectory(), KEY_CONFIG_FILE_NAME); configFile.OpenRead(); usePs4OfficialSlider = configFile.GetBooleanValue("ps4_official_slider"); enableInMenus = configFile.GetBooleanValue("slider_in_menus"); if (usePs4OfficialSlider) { DualShock4* ds4 = DualShock4::GetInstance(); if (ds4 == nullptr) DualShock4::rawMode = true; // set raw mode for future instances if no current instance else ds4->SetRawMode(true); // if is a current instance, set raw mode on it (also sets for future instances) } else { DualShock4* ds4 = DualShock4::GetInstance(); if (ds4 == nullptr) DualShock4::rawMode = false; // set raw mode for future instances if no current instance else ds4->SetRawMode(false); // if is a current instance, set raw mode on it (also sets for future instances) Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_LEFT", *LeftSideSlideLeft, { "Q" }); Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_RIGHT", *LeftSideSlideRight, { "E" }); Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_LEFT", *RightSideSlideLeft, { "U" }); Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_RIGHT", *RightSideSlideRight, { "O" }); float touchSliderEmulationSpeed = configFile.GetFloatValue("touch_slider_emulation_speed"); if (touchSliderEmulationSpeed != 0.0f) sliderSpeed = touchSliderEmulationSpeed; } } void TouchSliderEmulator::Update() { sliderState->State = SLIDER_OK; } void TouchSliderEmulator::UpdateInput() { if (!componentsManager->GetUpdateGameInput() || componentsManager->IsDwGuiActive() || (!enableInMenus && !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN))) return; if (Input::Divaller::GetInstance() != nullptr) { ApplyBitfieldState(Input::Divaller::GetInstance()->GetSlider()); } else if (usePs4OfficialSlider) { DualShock4* ds4 = DualShock4::GetInstance(); if (ds4 == nullptr) return; Joystick ls = ds4->GetLeftStick(); Joystick rs = ds4->GetRightStick(); uint32_t state = 0; // DualShock4 normalises sticks to floats -- this undoes that //printf("left stick: %9.6f, %9.6f, ", ls.XAxis, ls.YAxis); state |= (uint8_t)((ls.XAxis + 1.0 + 0.001) * 127.5) ^ 0b10000000; // 0.001 to prevent rounding errors //printf("%d, ", (int)(state ^ 0b10000000)); state |= ((uint8_t)((ls.YAxis + 1.0 + 0.001) * 127.5) ^ 0b10000000) << 8; //printf("%d\n", (int)((state >> 8) ^ 0b10000000)); state |= ((uint8_t)((rs.XAxis + 1.0 + 0.001) * 127.5) ^ 0b10000000) << 16; state |= ((uint8_t)((rs.YAxis + 1.0 + 0.001) * 127.5) ^ 0b10000000) << 24; ApplyBitfieldState(state); } else { sliderIncrement = GetElapsedTime() / sliderSpeed; constexpr float sensorStep = (1.0f / SLIDER_SENSORS); EmulateSliderInput(LeftSideSlideLeft, LeftSideSlideRight, ContactPoints[0], 0.0f, 0.5f); EmulateSliderInput(RightSideSlideLeft, RightSideSlideRight, ContactPoints[1], 0.5f + sensorStep, 1.0f + sensorStep); sliderState->ResetSensors(TouchSliderState::SENSOR_SET_MODE_SECTIONS); for (int i = 0; i < CONTACT_POINTS; i++) ApplyContactPoint(ContactPoints[i], i); } } void TouchSliderEmulator::OnFocusLost() { if (usePs4OfficialSlider || Input::Divaller::GetInstance() != nullptr) sliderState->ResetSensors(TouchSliderState::SENSOR_SET_MODE_RAW); else sliderState->ResetSensors(TouchSliderState::SENSOR_SET_MODE_SECTIONS); } // EmulateSliderInput and ApplyContactPoint are used for analog stick/button slider emulation void TouchSliderEmulator::EmulateSliderInput(Binding *leftBinding, Binding *rightBinding, ContactPoint &contactPoint, float start, float end) { bool leftDown = leftBinding->AnyDown(); bool rightDown = rightBinding->AnyDown(); if (leftDown) contactPoint.Position -= sliderIncrement; else if (rightDown) contactPoint.Position += sliderIncrement; if (contactPoint.Position < start) contactPoint.Position = end; if (contactPoint.Position > end) contactPoint.Position = start; bool leftTapped = leftBinding->AnyTapped(); bool rightTapped = rightBinding->AnyTapped(); if (leftTapped || rightTapped) contactPoint.Position = (start + end) / 2.0f; contactPoint.InContact = leftDown || rightDown; } void TouchSliderEmulator::ApplyContactPoint(ContactPoint& contactPoint, int section) { sliderState->SectionTouched[section] = contactPoint.InContact; int pressure = contactPoint.InContact ? FULL_PRESSURE : NO_PRESSURE; float position = std::clamp(contactPoint.Position, 0.0f, 1.0f); if (contactPoint.InContact) { int sensor = (int)(position * (SLIDER_SENSORS - 1)); sliderState->SetSensor(sensor, pressure, TouchSliderState::SENSOR_SET_MODE_SECTIONS); } constexpr float startRange = -1.0f; constexpr float endRange = +1.0f; sliderState->SectionPositions[section] = contactPoint.InContact ? (ConvertRange(0.0f, 1.0f, startRange, endRange, position)) : 0.0f; } // ApplyBitfieldState is used for setting raw slider data void TouchSliderEmulator::ApplyBitfieldState(uint32_t state) { for (int i = 0; i < 32; i++) { if (state & (1 << (31 - i))) sliderState->SetSensor(i, FULL_PRESSURE, TouchSliderState::SENSOR_SET_MODE_RAW); else sliderState->SetSensor(i, NO_PRESSURE, TouchSliderState::SENSOR_SET_MODE_RAW); } } } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/TouchSliderEmulator.h ================================================ #pragma once #include "../EmulatorComponent.h" #include "TouchSliderState.h" #include "../../Input/Bindings/Binding.h" namespace TLAC::Components { constexpr int SLIDER_INPUTS = 4; constexpr int CONTACT_POINTS = 2; struct ContactPoint { float Position; bool InContact; }; class TouchSliderEmulator : public EmulatorComponent { public: static TouchSliderEmulator* LatestInstance; Input::Binding* LeftSideSlideLeft; Input::Binding* LeftSideSlideRight; Input::Binding* RightSideSlideLeft; Input::Binding* RightSideSlideRight; bool usePs4OfficialSlider; bool enableInMenus; TouchSliderEmulator(); ~TouchSliderEmulator(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateInput() override; virtual void OnFocusLost() override; bool isSliderTouched() { for (int i = 0; i < 32; i++) if (sliderState->SensorTouched[i].IsTouched) return true; return false; } private: ComponentsManager* componentsManager; float sliderSpeed = 750.0f; float sliderIncrement; TouchSliderState *sliderState; ContactPoint ContactPoints[CONTACT_POINTS]; void EmulateSliderInput(Input::Binding *leftBinding, Input::Binding *rightBinding, ContactPoint &contactPoint, float start, float end); void ApplyContactPoint(ContactPoint &contactPoint, int section); void ApplyBitfieldState(uint32_t state); }; inline bool touchSliderEmulatorIsEnabled = false; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/TouchSliderState.cpp ================================================ #include "TouchSliderState.h" namespace TLAC::Components { void TouchSliderState::SetSensor(int index, int value, SliderSensorSetMode mode) { if (index < 0 || index >= SLIDER_SENSORS) return; if (mode == SENSOR_SET_MODE_RAW) { if (SerialState == nullptr) return; uint32_t* ph = SerialState->sliderSerialResponse.sensors[index].pressureHistory; ph[3] = ph[2]; ph[2] = ph[1]; ph[1] = ph[0]; ph[0] = value; SerialState->sliderSerialResponse.scanMode = 1; SerialState->sliderSerialResponse.scanCount = 1; SerialState->sliderResponseCnt = 1; } else { SensorPressureLevels[index] = value; SensorTouched[index].IsTouched = value > 0; } } void TouchSliderState::ResetSensors(SliderSensorSetMode mode) { for (int i = 0; i < SLIDER_SENSORS; i++) SetSensor(i, NO_PRESSURE, mode); } } ================================================ FILE: source-code/source/plugins/TLAC/Components/Input/TouchSliderState.h ================================================ #pragma once #include #define SLIDER_OK 3 #define SLIDER_SECTIONS 4 #define SLIDER_SENSORS 32 #define NO_PRESSURE 0 #define FULL_PRESSURE 180 namespace TLAC::Components { struct TouchSliderSerialState { uint8_t padding[0x1960]; int sliderResponseCnt; struct { int scanMode; int scanCount; struct { uint32_t pressureHistory[4]; // first: current, second: last sample, ... } sensors[SLIDER_SENSORS]; } sliderSerialResponse; struct { int scanMode; int scanCount; struct { uint32_t pressureHistory[4]; // first: current, second: last sample, ... } sensors[SLIDER_SENSORS]; } sliderSerialResponseCopy; // the other one is copied here by the game, feel free to ignore it }; struct TouchSliderState { uint8_t Padding0000[104]; TouchSliderSerialState* SerialState; int32_t State; uint8_t Padding0074[20 + 12]; int32_t SensorPressureLevels[SLIDER_SENSORS]; uint8_t Padding0108[52 - 12]; float SectionPositions[SLIDER_SECTIONS]; int SectionConnections[SLIDER_SECTIONS]; uint8_t Padding015C[4]; bool SectionTouched[SLIDER_SECTIONS]; uint8_t Padding013C[3128 - 52 - 40]; struct { uint8_t Padding00[2]; bool IsTouched; uint8_t Padding[45]; } SensorTouched[SLIDER_SENSORS]; // two different places to be set depending on operation mode now // stick/button based emulation directly controls sections and raw slider emulation controls fake serial inputs enum SliderSensorSetMode { SENSOR_SET_MODE_SECTIONS, SENSOR_SET_MODE_RAW }; void SetSensor(int index, int value, SliderSensorSetMode mode); void ResetSensors(SliderSensorSetMode mode); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/Pause.cpp ================================================ #include "Pause.h" #include "../Constants.h" #include "GameState.h" #include "ComponentsManager.h" #include "../Utilities/Drawing.h" #include "GL/glut.h" #include "detours.h" #include #include #include #include "../FileSystem/ConfigFile.h" #include "../framework.h" namespace TLAC::Components { using TLAC::Utilities::Drawing; bool Pause::pause = false; bool Pause::isPaused = false; bool Pause::giveUp = false; bool Pause::autoPause = false; bool Pause::ignoreAutoPause = false; bool Pause::autoReplay = false; bool Pause::showUI = true; int Pause::selResultAet1 = 0; int Pause::selResultAet2 = 0; int Pause::selResultAet3 = 0; int Pause::selResultAet4 = 0; int Pause::triangleAet = 0; int Pause::squareAet = 0; int Pause::crossAet = 0; int Pause::circleAet = 0; int Pause::curMenuPos = 0; std::vector> Pause::menuHistory; Pause::menusets Pause::curMenuSet = MENUSET_MAIN; std::chrono::time_point Pause::menuItemMoveTime; std::vector Pause::origAetMovOp; float_t Pause::origDeltaFrameHistory = 0.0f; int32_t Pause::origDeltaFrameHistoryInt = 0; uint8_t* Pause::aetMovPatchAddress = (uint8_t*)0x1401703b3; std::vector Pause::origFramespeedOp; uint8_t* Pause::framespeedPatchAddress = (uint8_t*)0x140192D50; float_t* Pause::deltaFrameHistoryAddress = (float_t*)0x140EDA6C0; int32_t* Pause::deltaFrameHistoryIntAddress = (int32_t*)0x140EDA6C4; std::vector Pause::origAgeageHairOp; uint8_t* Pause::ageageHairPatchAddress = (uint8_t*)0x14054352c; std::vector Pause::streamPlayStates; bool(*divaGiveUpFunc)(void*) = (bool(*)(void* cls))GIVEUP_FUNC_ADDRESS; void(*divaPVEndFunc)(uint64_t, char, char) = (void(*)(uint64_t, char, char))0x140108260; char(*divaScriptCommandFunc)(uint64_t, uint64_t, uint64_t, void*, void*, char, char) = (char(*)(uint64_t, uint64_t, uint64_t, void*, void*, char, char))0x14011CBA0; PlayerData* Pause::playerData; InputState* Pause::inputState; TouchSliderState* Pause::sliderState; TouchPanelState* Pause::panelState; ComponentsManager* Pause::componentsManager; JvsButtons Pause::filteredButtons; int Pause::lastTouchType = 0; std::vector Pause::menu = { { "PAUSED", { { "RESUME", unpause, false }, { "RESTART", restart, false }, { "SE VOLUME", sevolorpvmenu, false }, { "GIVE UP", giveup, false }, } }, { "SE VOLUME", { { "+", sevolplus, true }, { "XX", menuback, false }, { "-", sevolminus, true }, } }, { "PV OPTIONS", { { "XX", pvloop, false }, { "XX", pvignoreautopause, false }, } }, }; Pause::Pause() { } Pause::~Pause() { } const char* Pause::GetDisplayName() { return "pause"; } void Pause::saveOldPatchOps() { origAetMovOp.resize(8); memcpy(origAetMovOp.data(), aetMovPatchAddress, 8); origFramespeedOp.resize(4); memcpy(origFramespeedOp.data(), framespeedPatchAddress, 4); origAgeageHairOp.resize(3); memcpy(origAgeageHairOp.data(), ageageHairPatchAddress, 3); } void Pause::Initialize(ComponentsManager* manager) { inputState = (InputState*)(*(uint64_t*)INPUT_STATE_PTR_ADDRESS); playerData = (PlayerData*)PLAYER_DATA_ADDRESS; sliderState = (TouchSliderState*)SLIDER_CTRL_TASK_ADDRESS; panelState = (TouchPanelState*)TASK_TOUCH_ADDRESS; componentsManager = manager; TLAC::FileSystem::ConfigFile config(TLAC::framework::GetModuleDirectory(), "keyconfig.ini"); config.OpenRead(); autoPause = config.GetBooleanValue("autopause"); saveOldPatchOps(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaGiveUpFunc, hookedGiveUpFunc); DetourTransactionCommit(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaPVEndFunc, hookedDivaPVEndFunc); DetourTransactionCommit(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaScriptCommandFunc, hookedScriptCommandFunc); DetourTransactionCommit(); } void Pause::Update() { } // put these here because my local VS was being a bitch and compiling the place that uses them wrong when they were inline // updating VS would probably fix it, but this was quicker // -somewhatlurker int* resWidth = (int*)RESOLUTION_WIDTH_ADDRESS; int* resHeight = (int*)RESOLUTION_HEIGHT_ADDRESS; void Pause::UpdatePostInput() { if (pause) { // enter pause mode on state transition if (!isPaused) { ((void(*)())DSC_PAUSE_FUNC_ADDRESS)(); saveOldPatchOps(); InjectCode(aetMovPatchAddress, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); InjectCode(framespeedPatchAddress, { 0x0f, 0x57, 0xc0, 0xc3 }); // XORPS XMM0,XMM0; RET InjectCode(ageageHairPatchAddress, { 0x0f, 0x57, 0xdb }); // XORPS XMM3,XMM3 origDeltaFrameHistory = *deltaFrameHistoryAddress; origDeltaFrameHistoryInt = *deltaFrameHistoryIntAddress; *deltaFrameHistoryAddress = 0.0f; *deltaFrameHistoryIntAddress = 0; uint64_t audioMixerAddr = *(uint64_t*)(AUDIO_MAIN_CLASS_ADDRESS + 0x70); uint64_t audioStreamsAddress = *(uint64_t*)(audioMixerAddr + 0x18); int nAudioStreams = *(uint64_t*)(audioMixerAddr + 0x20); for (int i = 0; i < nAudioStreams; i++) { uint32_t* playstate = (uint32_t*)(audioStreamsAddress + i * 0x50 + 0x18); if (i < streamPlayStates.size()) streamPlayStates[i] = *playstate; else streamPlayStates.push_back(*playstate); *playstate = 0; } // block all buttons from being passed to game filteredButtons = allButtons; setMenuPos(MENUSET_MAIN, 0); menuHistory.resize(0); showUI = true; isPaused = true; } // always exit pause if key is tapped or no longer in game somehow if (isPauseKeyTapped() || !isInGame()) { pause = false; } else { // note: use exact button comparisons instead of only single bits to avoid macros if (inputState->Tapped.Buttons == JVS_SQUARE) { showUI = !showUI; if (showUI) { menuItemMoveTime = std::chrono::high_resolution_clock::now(); // restart animations } else { // clear these from the screen too /* Drawing::destroyAetLayer(selResultAet1); Drawing::destroyAetLayer(selResultAet2); Drawing::destroyAetLayer(selResultAet3); Drawing::destroyAetLayer(selResultAet4); */ Drawing::destroyAetLayer(triangleAet); Drawing::destroyAetLayer(squareAet); Drawing::destroyAetLayer(crossAet); Drawing::destroyAetLayer(circleAet); } } /* for testing `-ss` stuff if (inputState->Tapped.Buttons == JVS_TRIANGLE) { void** ScreenShotImplAddr = (void**)0x1412016d0; Drawing::MsString path; // just a small struct from TLAC::Utilities::Drawing::MsString path.SetCharBuf("blahblahblah"); ((void(*)(void* impl, Drawing::MsString* path, int width, int height))0x140557210)(*ScreenShotImplAddr, &path, 1280, 720); } */ // only process menu events when UI is visible if (showUI) { if (inputState->Tapped.Buttons == JVS_L) setMenuPos(curMenuSet, curMenuPos - 1); if (inputState->Tapped.Buttons == JVS_R) setMenuPos(curMenuSet, curMenuPos + 1); if (inputState->Tapped.Buttons == JVS_CROSS) { if (curMenuSet == MENUSET_MAIN) { pause = false; } else { menuback(); } } if (inputState->Tapped.Buttons == JVS_CIRCLE) menu[curMenuSet].items[curMenuPos].callback(); if (!componentsManager->IsDwGuiActive()) // not sure if this check is necessary, but it doesn't hurt { if (panelState->ContactType == 2 && lastTouchType != 2) // down and was not down before { for (int i = 0; i < menu[curMenuSet].items.size(); i++) { Drawing::Point itemCoords = getMenuItemCoords(curMenuSet, i); Drawing::Point touchCoords = { panelState->XPosition, panelState->YPosition }; touchCoords.x *= 1280.0f / *resWidth; // convert to 720p coords touchCoords.y *= 720.0f / *resHeight; if (touchCoords.x >= itemCoords.x - menuItemWidth / 2 && touchCoords.x <= itemCoords.x + menuItemWidth / 2 && touchCoords.y >= itemCoords.y - menuItemHeight / 2 && touchCoords.y <= itemCoords.y + menuItemHeight / 2) { setMenuPos(curMenuSet, i); menu[curMenuSet].items[i].callback(); break; } } } } switch (curMenuSet) { case MENUSET_SEVOL: { const char volformat[] = "%d"; size_t size = snprintf(nullptr, 0, volformat, playerData->act_vol) + 1; char* buf = new char[size]; snprintf(buf, size, volformat, playerData->act_vol); menu[MENUSET_SEVOL].items[1].name = buf; delete[] buf; break; } case MENUSET_PV: { char* buf1 = new char[11]; snprintf(buf1, 11, "PV LOOP: %s", autoReplay ? "Y" : "N"); menu[MENUSET_PV].items[0].name = buf1; delete[] buf1; char* buf2 = new char[12]; snprintf(buf2, 12, "NO PAUSE: %s", ignoreAutoPause ? "Y" : "N"); menu[MENUSET_PV].items[1].name = buf2; delete[] buf2; break; } case MENUSET_MAIN: { menu[MENUSET_MAIN].items[2].name = isInPV() ? menu[MENUSET_PV].name : menu[MENUSET_SEVOL].name; break; } } } } // no slider while paused // this is simpler than buttons because slider doesn't trigger on press, it triggers on movement // (therefore per-button blocking isn't needed) // SENSOR_SET_MODE_SECTIONS matches old behaviour sliderState->ResetSensors(TouchSliderState::SENSOR_SET_MODE_SECTIONS); } else { // exit pause mode on state transition if (isPaused) { ((void(*)())DSC_UNPAUSE_FUNC_ADDRESS)(); InjectCode(aetMovPatchAddress, origAetMovOp); InjectCode(framespeedPatchAddress, origFramespeedOp); InjectCode(ageageHairPatchAddress, origAgeageHairOp); *deltaFrameHistoryAddress = origDeltaFrameHistory; *deltaFrameHistoryIntAddress = origDeltaFrameHistoryInt; uint64_t audioMixerAddr = *(uint64_t*)(AUDIO_MAIN_CLASS_ADDRESS + 0x70); uint64_t audioStreamsAddress = *(uint64_t*)(audioMixerAddr + 0x18); int nAudioStreams = *(uint64_t*)(audioMixerAddr + 0x20); for (int i = 0; i < nAudioStreams; i++) { uint32_t* playstate = (uint32_t*)(audioStreamsAddress + i * 0x50 + 0x18); if (i < streamPlayStates.size()) *playstate = streamPlayStates[i]; } /* Drawing::destroyAetLayer(selResultAet1); Drawing::destroyAetLayer(selResultAet2); Drawing::destroyAetLayer(selResultAet3); Drawing::destroyAetLayer(selResultAet4); */ Drawing::destroyAetLayer(triangleAet); Drawing::destroyAetLayer(squareAet); Drawing::destroyAetLayer(crossAet); Drawing::destroyAetLayer(circleAet); isPaused = false; } // buttons that have been tapped no longer need to be filtered (doing this with down broke retriggering) filteredButtons = (JvsButtons)(filteredButtons & ~inputState->Tapped.Buttons); // only enter pause if in game if (isInGame()) { if (isPauseKeyTapped()) { pause = true; } } else { // ensure giveUp isn't retained after already quitting giveUp = false; } } // swallow filtered button inputs inputState->Tapped.Buttons = (JvsButtons)(inputState->Tapped.Buttons & ~filteredButtons); inputState->DoubleTapped.Buttons = (JvsButtons)(inputState->DoubleTapped.Buttons & ~filteredButtons); inputState->Down.Buttons = (JvsButtons)(inputState->Down.Buttons & ~filteredButtons); inputState->Released.Buttons = (JvsButtons)(inputState->Released.Buttons & ~filteredButtons); inputState->IntervalTapped.Buttons = (JvsButtons)(inputState->IntervalTapped.Buttons & ~filteredButtons); lastTouchType = panelState->ContactType; // ensure the PV-only temporary values aren't retained if ((autoReplay || ignoreAutoPause) && *(uint8_t*)PV_LOADING_STATE_ADDRESS < 8) { ignoreAutoPause = false; autoReplay = false; } } // returns the midpoint of a menu button Drawing::Point Pause::getMenuItemCoords(menusets set, int pos) { const float slant = 35.0f / 199.0f; int menuOriginY = menuY - (menuItemTotalHeight * menu[set].items.size() - menuItemPadding) / 2 + menuItemHeight / 2; if (set != MENUSET_MAIN) { menuOriginY += menuItemTotalHeight * 1.2 / 2; } int menuOriginX = menuX + (menuY - menuOriginY) * slant; Drawing::Point out; out.x = menuOriginX - (menuItemTotalHeight * pos * slant); out.y = menuOriginY + menuItemTotalHeight * pos; return out; } void Pause::UpdateDraw2D() { if (isPaused && showUI) { // setup draw objects Drawing::FontInfo fontInfo(0x11); Drawing::DrawParams dtParams(&fontInfo); dtParams.layer = bgLayer; Drawing::Point aetScale = { 0.65, 0.65 }; Drawing::Point aetLoc = { (1280 - aetScale.x * 1280) / 2, (720 - aetScale.y * 720) / 2 }; // get aspect ratio float aspect = *(float*)UI_ASPECT_RATIO; // bg rect float bgWidth = aspect * 720 + 2; // add a couple of pixels to protect against rounding errors float bgLeft = -(bgWidth - 1280) / 2; // 0,0 is in the corner of a 720p view.. half of the extra over 1280 wide is the horizontal offset to centre the bg Drawing::RectangleBounds rect; rect = { bgLeft, 0, bgWidth, 720 }; dtParams.colour = 0xc0000000; dtParams.fillColour = dtParams.colour; Drawing::fillRectangle(&dtParams, rect); // pause icon /* const int pauseWidth = 80; const int pauseHeight = 110; const int pauseGap = 20; const int pausePosX = 32; const int pausePosY = 32; const int pausePartWidth = (pauseWidth - pauseGap) / 2; const int pauseX1 = pausePosX; const int pauseX2 = pausePosX + pausePartWidth + pauseGap; const int pauseY1 = pausePosY; dtParams.colour = 0x80ffffff; dtParams.fillColour = 0x80ffffff; rect = { pauseX1, pauseY1, pausePartWidth, pauseHeight }; Drawing::fillRectangle(&dtParams, &rect); rect = { pauseX2, pauseY1, pausePartWidth, pauseHeight }; Drawing::fillRectangle(&dtParams, &rect); */ dtParams.layer = contentLayer; // bg box /* static int selResultFile = 0; if (selResultFile == 0) { //keyWinFile = Drawing::findAetFileId("AET_KEY_WIN_MAIN"); selResultFile = Drawing::findAetFileId("AET_SEL_RESULT_MAIN"); //printf("keyWinFile: %d\n", keyWinFile); } Drawing::destroyAetLayer(selResultAet1); Drawing::destroyAetLayer(selResultAet2); Drawing::destroyAetLayer(selResultAet3); Drawing::destroyAetLayer(selResultAet4); if (selResultFile != -1) { //keyWinAet = Drawing::createAetLayer(keyWinFile, dtParams.layer, CREATEAET_20000, "win_in", aetLoc, 0, nullptr, nullptr, 3.7, 3.7, aetScale, 0); aetScale = { 0.47f, 0.47f }; aetLoc = { (1280 - aetScale.x * 1280) / 2, (720 - aetScale.y * 720) / 2 + 72 * aetScale.y }; float animPos = 7.2; selResultAet1 = Drawing::createAetLayer(selResultFile, dtParams.layer, CREATEAET_20000, "window_in", aetLoc, 0, nullptr, nullptr, animPos, animPos, aetScale, 0); selResultAet2 = Drawing::createAetLayer(selResultFile, dtParams.layer, CREATEAET_20000, "window_in", aetLoc, 0, nullptr, nullptr, animPos, animPos, aetScale, 0); selResultAet3 = Drawing::createAetLayer(selResultFile, dtParams.layer, CREATEAET_20000, "window_in", aetLoc, 0, nullptr, nullptr, animPos, animPos, aetScale, 0); selResultAet4 = Drawing::createAetLayer(selResultFile, dtParams.layer, CREATEAET_20000, "window_in", aetLoc, 0, nullptr, nullptr, animPos, animPos, aetScale, 0); } */ dtParams.colour = 0xffffff00; Drawing::drawPolyline(&dtParams, { { 537, 255 }, { 794, 255 }, { 759, 454 }, { 744, 466 }, { 487, 466 }, { 522, 267 }, { 537, 255 }, }); Drawing::drawPolyline(&dtParams, { { 537 - .7f, 255 - 2 }, { 794 + 2.38f, 255 - 2 }, { 759 + 2.1f, 454 + 1.15f }, { 744 + .7f, 466 + 2 }, { 487 - 2.38f, 466 + 2 }, { 522 - 2.1f, 267 - 1.15f }, { 537 - .7f, 255 - 2 }, }); Drawing::drawPolyline(&dtParams, { { 548, 258 }, { 768, 258 }, { 774, 265 }, { 770, 286 }, { 764, 286 }, { 737, 435 }, { 743, 435 }, { 739, 456 }, { 733, 463 }, { 513, 463 }, { 507, 456 }, { 511, 435 }, { 517, 435 }, { 544, 286 }, { 538, 286 }, { 542, 265 }, { 548, 258 }, }); Drawing::Point menuCoords = getMenuItemCoords(curMenuSet, curMenuPos); // selection cursor const float selectBoxWidth = menuItemWidth; const float selectBoxHeight = menuItemHeight; const float selectBoxThickness = 2; float selectBoxX = menuCoords.x - selectBoxWidth / 2; float selectBoxY = menuCoords.y - menuItemHeight / 2; dtParams.colour = 0xc0ffff00; dtParams.fillColour = 0xc0ffff00; //rect = { selectBoxX, selectBoxY, selectBoxWidth, selectBoxHeight }; //Drawing::drawRectangle(&dtParams, rect, selectBoxThickness); const float slant = 35.0f / 199.0f; Drawing::drawPolyline(&dtParams, { { selectBoxX + (selectBoxHeight - 8) * slant + 8 * 15 / 12, selectBoxY }, { selectBoxX + selectBoxWidth, selectBoxY }, { selectBoxX + selectBoxWidth - (selectBoxHeight - 8) * slant, selectBoxY + selectBoxHeight - 8 }, { selectBoxX + selectBoxWidth - (selectBoxHeight - 8) * slant - 8 * 15 / 12, selectBoxY + selectBoxHeight }, { selectBoxX, selectBoxY + selectBoxHeight }, { selectBoxX + (selectBoxHeight - 8) * slant, selectBoxY + 8 }, { selectBoxX + (selectBoxHeight - 8) * slant + 8 * 15 / 12, selectBoxY }, }); Drawing::drawPolyline(&dtParams, { { selectBoxX + (selectBoxHeight - 8) * slant + 8 * 15 / 12 - .7f, selectBoxY - 2 }, { selectBoxX + selectBoxWidth + 2.38f, selectBoxY - 2 }, { selectBoxX + selectBoxWidth - (selectBoxHeight - 8) * slant + 2.1f, selectBoxY + selectBoxHeight - 8 + 1.15f }, { selectBoxX + selectBoxWidth - (selectBoxHeight - 8) * slant - 8 * 15 / 12 + .7f, selectBoxY + selectBoxHeight + 2 }, { selectBoxX - 2.38f, selectBoxY + selectBoxHeight + 2 }, { selectBoxX + (selectBoxHeight - 8) * slant - 2.1f, selectBoxY + 8 - 1.15f }, { selectBoxX + (selectBoxHeight - 8) * slant + 8 * 15 / 12 - .7f, selectBoxY - 2 }, }); // menu fontInfo.setSize(menuTextSize, menuTextSize); if (curMenuSet != MENUSET_MAIN) { dtParams.textCurrentLoc = { menuX + 90 * slant, menuY - 90 }; dtParams.lineOriginLoc.y = dtParams.textCurrentLoc.y; dtParams.colour = 0xffffffff; Drawing::drawText(&dtParams, (Drawing::drawTextFlags)(Drawing::DRAWTEXT_ALIGN_CENTRE | Drawing::DRAWTEXT_STROKE), menu[curMenuSet].name); } for (int i = 0; i < menu[curMenuSet].items.size(); i++) { menuCoords = getMenuItemCoords(curMenuSet, i); dtParams.textCurrentLoc = { menuCoords.x, menuCoords.y - menuTextSize / 2 }; dtParams.lineOriginLoc = dtParams.textCurrentLoc; if (i == curMenuPos) { uint8_t alpha = (cosf(getMenuAnimPos() * 6.283185f) * 0.15 + 0.85) * 255; dtParams.colour = 0x00ffff00 | (alpha << 24); } else { dtParams.colour = 0xffffffff; } Drawing::drawText(&dtParams, (Drawing::drawTextFlags)(Drawing::DRAWTEXT_ALIGN_CENTRE), menu[curMenuSet].items[i].name); } // key legend Drawing::destroyAetLayer(triangleAet); Drawing::destroyAetLayer(squareAet); Drawing::destroyAetLayer(crossAet); Drawing::destroyAetLayer(circleAet); float textLeft; if (aspect > 16.0f / 9.0f) textLeft = 32; else textLeft = (1280 - bgWidth) / 2 + 32; // 0,0 is in the corner of a 720p view.. half of the difference to 1280 wide is the horizontal offset to the window corner fontInfo.setSize(18, 18); dtParams.textCurrentLoc = { textLeft, 720 - 40 }; dtParams.lineOriginLoc = dtParams.textCurrentLoc; const float spriteSize = 18; const float halfSpriteSize = spriteSize / 2; aetLoc = { 0, dtParams.textCurrentLoc.y + halfSpriteSize }; // the aets are centered on their location, so fudge this a little aetScale = { spriteSize / 64, spriteSize / 64 }; // just approximated dtParams.colour = 0xffffffff; Drawing::drawTextW(&dtParams, (Drawing::drawTextFlags)(Drawing::DRAWTEXT_ENABLE_XADVANCE), L"↑↓/LR:Move "); aetLoc.x = dtParams.textCurrentLoc.x + halfSpriteSize; squareAet = Drawing::createAetLayer(3, dtParams.layer, Drawing::CREATEAET_20000, "button_shikaku", aetLoc, 0, nullptr, nullptr, 0, 0, aetScale, nullptr); dtParams.textCurrentLoc.x += spriteSize; Drawing::drawTextW(&dtParams, (Drawing::drawTextFlags)(Drawing::DRAWTEXT_ENABLE_XADVANCE), L":Hide Menu "); aetLoc.x = dtParams.textCurrentLoc.x + halfSpriteSize; crossAet = Drawing::createAetLayer(3, dtParams.layer, Drawing::CREATEAET_20000, "button_batsu", aetLoc, 0, nullptr, nullptr, 0, 0, aetScale, nullptr); dtParams.textCurrentLoc.x += spriteSize; if (menuHistory.size() == 0) Drawing::drawTextW(&dtParams, (Drawing::drawTextFlags)(Drawing::DRAWTEXT_ENABLE_XADVANCE), L":Close "); else Drawing::drawTextW(&dtParams, (Drawing::drawTextFlags)(Drawing::DRAWTEXT_ENABLE_XADVANCE), L":Back "); aetLoc.x = dtParams.textCurrentLoc.x + halfSpriteSize; circleAet = Drawing::createAetLayer(3, dtParams.layer, Drawing::CREATEAET_20000, "button_maru", aetLoc, 0, nullptr, nullptr, 0, 0, aetScale, nullptr); dtParams.textCurrentLoc.x += spriteSize; Drawing::drawTextW(&dtParams, (Drawing::drawTextFlags)(Drawing::DRAWTEXT_ENABLE_XADVANCE), L":Select"); } } void Pause::OnFocusLost() { if (autoPause && isInGame() && !ignoreAutoPause) pause = true; } bool Pause::isPauseKeyTapped() { return inputState->Tapped.Buttons & JVS_START; } bool Pause::isInGame() { return *(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN && *(uint8_t*)PV_STATE_ADDRESS == 1; } bool Pause::hookedGiveUpFunc(void* cls) { if (giveUp || divaGiveUpFunc(cls)) { giveUp = false; pause = false; return true; } return false; } void Pause::hookedDivaPVEndFunc(uint64_t p1, char p2, char p3) { if (autoReplay && isInPV()) { printf("[TLAC] END triggered, restarting the PV\n"); restart(); } else { divaPVEndFunc(p1, p2, p3); } } char Pause::hookedScriptCommandFunc(uint64_t p1, uint64_t p2, uint64_t p3, void* p4, void* p5, char p6, char p7) { if (autoReplay) { int position = *(int*)(p1 + 180012); int cmd = *(int*)(p1 + 4 * position + 12); // printf("ARG: %lld, %lld, %lld, %p, %p, %d, %d - POS: %d, CMD: %d\n", p1, p2, p3, p4, p5, p6, p7, position, cmd); if (cmd == 83) { printf("[TLAC] END_FADEOUT triggered but ignored\n"); // fix stucking at restart and the PV Script Command Error *(int*)(p1 + 180012) = position + 3; return 1; } } return divaScriptCommandFunc(p1, p2, p3, p4, p5, p6, p7); } void Pause::setSEVolume(int amount) { playerData->act_vol += amount; if (playerData->act_vol < 0) playerData->act_vol = 0; if (playerData->act_vol > 100) playerData->act_vol = 100; playerData->act_slide_vol = playerData->act_vol; } void Pause::setMenuPos(menusets set, int pos, bool updateHistory) { menusets newMenuSet; if (set >= 0 && set < menu.size()) newMenuSet = set; else newMenuSet = MENUSET_MAIN; if (updateHistory && newMenuSet != curMenuSet) menuHistory.push_back(std::pair(curMenuSet, curMenuPos)); curMenuSet = newMenuSet; if (pos < 0) pos = menu[curMenuSet].items.size() - 1; else if (pos >= menu[curMenuSet].items.size()) pos = 0; curMenuPos = pos; menuItemMoveTime = std::chrono::high_resolution_clock::now(); // restart animations } float Pause::getMenuAnimPos() { const int duration = 1500000000; // 1.5s return (float)((std::chrono::high_resolution_clock::now() - menuItemMoveTime) % std::chrono::nanoseconds(duration)).count() / (float)duration; } void Pause::InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } } ================================================ FILE: source-code/source/plugins/TLAC/Components/Pause.h ================================================ #pragma once #include "../Constants.h" #include "EmulatorComponent.h" #include "PlayerData.h" #include "GameState.h" #include "../Utilities/Drawing.h" #include "Input/InputState.h" #include "Input/TouchSliderState.h" #include "Input/TouchPanelState.h" #include #include #include namespace TLAC::Components { class Pause : public EmulatorComponent { public: Pause(); ~Pause(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdatePostInput() override; virtual void UpdateDraw2D() override; virtual void OnFocusLost() override; static bool pause; // set pause to change pause state static bool giveUp; // set give up to end current song static bool autoPause; // pause when window loses focus static bool ignoreAutoPause; // ignore pause on PV static bool autoReplay; // loop PV private: // this is a mess of static so that menuItems can work static bool isPauseKeyTapped(); static bool isInGame(); static std::vector streamPlayStates; static void InjectCode(void* address, const std::vector data); static bool isPaused; // tracks internal state static void saveOldPatchOps(); static std::vector origAetMovOp; static uint8_t* aetMovPatchAddress; static std::vector origFramespeedOp; static uint8_t* framespeedPatchAddress; static float_t origDeltaFrameHistory; static int32_t origDeltaFrameHistoryInt; static float_t* deltaFrameHistoryAddress; static int32_t* deltaFrameHistoryIntAddress; static std::vector origAgeageHairOp; static uint8_t* ageageHairPatchAddress; static bool hookedGiveUpFunc(void* cls); static void hookedDivaPVEndFunc(uint64_t, char, char); static char hookedScriptCommandFunc(uint64_t, uint64_t, uint64_t, void*, void*, char, char); static void setSEVolume(int amount); static PlayerData* playerData; static InputState* inputState; static TouchSliderState* sliderState; static TouchPanelState* panelState; static ComponentsManager* componentsManager; static const JvsButtons allButtons = (JvsButtons)(JVS_START | JVS_TRIANGLE | JVS_SQUARE | JVS_CROSS | JVS_CIRCLE | JVS_L | JVS_R); // deliberately only has control panel buttons static JvsButtons filteredButtons; static int lastTouchType; static const int menuX = 640; static const int menuY = 360; static const int menuItemWidth = 180; static const int menuItemHeight = 36; static const int menuItemPadding = 12; static const int menuItemTotalHeight = menuItemHeight + menuItemPadding; static const int menuTextSize = 24; static const uint32_t bgLayer = 0x18; static const uint32_t contentLayer = 0x19; // same as startup screen static bool showUI; static int selResultAet1; static int selResultAet2; static int selResultAet3; static int selResultAet4; static int triangleAet; static int squareAet; static int crossAet; static int circleAet; enum menusets { MENUSET_MAIN = 0, MENUSET_SEVOL = 1, MENUSET_PV = 2, }; struct menuItem { std::string name; void(*callback)(); bool keyRepeat; // unimplemented menuItem(std::string _name, void(*_callback)(), bool _keyRepeat) { name = _name; callback = _callback; keyRepeat = _keyRepeat; } }; struct menuSet { std::string name; std::vector items; }; static int curMenuPos; static std::vector> menuHistory; // used for implementing back button in menus static menusets curMenuSet; static std::chrono::time_point menuItemMoveTime; // used for animation // static void mainmenu() { setMenuPos(MENUSET_MAIN, 0); menuHistory.resize(0); }; static void menuback() { if (menuHistory.size() == 0) { // mainmenu(); unpause(); } else { std::pair menuPos = menuHistory.back(); menuHistory.pop_back(); setMenuPos(menuPos.first, menuPos.second, false); } } static void unpause() { pause = false; }; static void restart() { // fix the percent calculation if restarted while in the challenge time bool isInChallengeTime = *(bool*)(0x140C94438 + 38); if (isInChallengeTime) { uint64_t baseA1 = 0x140cdd8d0; void(*doResetChallenge)(uint64_t, uint64_t, uint64_t) = (void(*)(uint64_t, uint64_t, uint64_t))0x14011B010; doResetChallenge(baseA1 + 180088, baseA1 + 180088, 0); // it is used in 14011BEA0 after the challenge time starts or ends // and looks like required to do the reset process properly *(bool*)(baseA1 + 180181) = 1; } /* 140d0b510+2 = 0, 140d0b510+14 = 8 for restart also 140cdd8d0+8 (something less than 0x1a but idk what) -- controls a switch statement in FUN_1400fddc0 0x18: PV seems good, audio good, chart and score broken? -- timing resets, notes don't 0x14: PVs a little bugged (not major), chart and scoring fine, life still doesn't reset 0x10: life resets now, but old graphics don't clear 0x15: same as 0x14 0x16: doesn't actually reset???? 0x17: crash 0x12: like 0x10 but life isn't cleared case 0x11 seems to clear life case 0x15 seems to clear score (maybe note data) case 0x18 seems to fix timing patch 0x15 at 1401038cd (was 0x12), 0x18 at 140103b94 (was 0x16) then call with 0x11 hopefully it'll work percentage doesn't fully reset by the looks of it???? rip (actually was hold and slide scores -- fixed by manually clearing them now) */ // inject flow overrides to switch cases in FUN_1400fddc0 InjectCode((void*)0x1401038cd, { 0x15 }); InjectCode((void*)0x140103b94, { 0x18 }); bool hasTaskMovie[2] = { false, false }; bool waitTaskMovie = false; size_t(*taskMovieGet)(int32_t) = (size_t(*)(int32_t))0x14041ED30; // reset movie position for (int i = 0; i < 2; i++) { size_t taskMovie = taskMovieGet(i); if (taskMovie) { size_t taskMoviePlayer = *(size_t*)(taskMovie + 0xB8); if (taskMoviePlayer) { size_t iPlayer = *(size_t*)(taskMoviePlayer + 0x10); if (iPlayer) { size_t iPlayerVtable = *(size_t*)(iPlayer + 0x00); int(*iPlayer__SetCurrentPosition)(size_t, double) = (int(*)(size_t, double)) * (size_t*)(iPlayerVtable + 0x60); iPlayer__SetCurrentPosition(iPlayer, 0.0); *(bool*)(taskMovie + 0xD1) = true; hasTaskMovie[i] = true; waitTaskMovie = true; } } } } // set parameters *(uint8_t*)PV_STATE_ADDRESS = 0; *(uint8_t*)PV_LOADING_STATE_ADDRESS = 8; *(int*)PV_INNER_LOADING_STATE_ADDRESS = 0x11; void(*doLoading)(uint64_t) = (void(*)(uint64_t))0x1400fddc0; // do loading until definitely done while (*(int*)PV_INNER_LOADING_STATE_ADDRESS < 0x18) { doLoading(0x140cdd8d0); } // wait till movie resets bool(*taskMovieCheckDisp)(size_t) = (bool(*)(size_t))0x14041F0E0; while (waitTaskMovie) { waitTaskMovie = false; for (int i = 0; i < 2; i++) { if (!hasTaskMovie[i]) continue; size_t taskMovie = taskMovieGet(i); if (taskMovie && !taskMovieCheckDisp(taskMovie)) waitTaskMovie = true; } } // for some reason the above doesn't reset all scoring stuff *(int*)0x140D0A9BC = 0; // total holds *(int*)0x140D0A9B8 = 0; // hold + multi *(int*)0x140D0A9C0 = 0; // slide *(uint8_t*)0x140D0A50C = 0; // not clear flag // only reset chance time while in normal mode if (!isInPV(false)) { *(char*)0x140D0AA0F = 0; // chance time } // reset give up/end flags // because the code above doesn't reset them // and causing you to complete with MISSxTAKE // if you restarted after give up triggered *(char*)0x140D0AA09 = 0; *(char*)0x140D0AA0E = 0; *(char*)0x140D0AA20 = 0; *(char*)0x140D0AA35 = 0; // revert patches and unpause InjectCode((void*)0x1401038cd, { 0x12 }); InjectCode((void*)0x140103b94, { 0x16 }); unpause(); } static void giveup() { ignoreAutoPause = false; autoReplay = false; giveUp = true; }; static void sevolorpvmenu() { setMenuPos(isInPV() ? MENUSET_PV : MENUSET_SEVOL, 1); }; static void pvloop() { autoReplay = !autoReplay; } static void pvignoreautopause() { ignoreAutoPause = !ignoreAutoPause; } static void sevolplus() { setSEVolume(10); }; static void sevolminus() { setSEVolume(-10); }; static bool isInPV(bool checkIsInGame = true) { if (checkIsInGame && !isInGame()) { return false; } return *(char*)0x140C94438 == 2; } // contents are in Pause.cpp because they can't be inline here for a static (const) array/vec static std::vector menu; static void setMenuPos(menusets set, int pos, bool updateHistory = true); static float getMenuAnimPos(); static TLAC::Utilities::Drawing::Point getMenuItemCoords(menusets set, int pos); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/PlayerData.h ================================================ #pragma once #include struct PlayerData { int8_t use_card; int8_t freeplay; int8_t field_2; int8_t field_3; int32_t card_type; int32_t field_8; int32_t field_C; int32_t field_10; int32_t field_14; int32_t field_18; int32_t field_1C; int32_t field_20; int32_t field_24; int32_t field_28; int32_t field_2C; int32_t field_30; int32_t field_34; int32_t field_38; int32_t field_3C; int32_t field_40; int32_t field_44; int32_t field_48; int32_t field_4C; int32_t field_50; int32_t field_54; int32_t field_58; int32_t field_5C; int32_t field_60; int32_t field_64; int32_t field_68; int32_t field_6C; int32_t field_70; int32_t field_74; int32_t field_78; int32_t field_7C; int32_t field_80; int32_t field_84; int32_t field_88; int32_t field_8C; int32_t field_90; int32_t field_94; int32_t field_98; int32_t field_9C; int32_t field_A0; int32_t field_A4; int32_t field_A8; int32_t field_AC; int32_t field_B0; int32_t field_B4; int32_t field_B8; int32_t field_BC; int32_t field_C0; int32_t field_C4; int32_t field_C8; int32_t field_CC; int32_t play_data_id; int32_t accept_index; int32_t start_index; int32_t field_DC; char* player_name; int32_t field_E8; int32_t field_EC; int32_t field_F0; int32_t field_F4; int32_t field_F8; int32_t field_FC; char* level_name; int32_t field_108; int32_t field_10C; int32_t field_110; int32_t field_114; int32_t field_118; int32_t field_11C; int32_t level; int32_t level_plate_id; int32_t level_plate_effect; int32_t vocaloid_point; int32_t hp_vol; int32_t act_toggle; int32_t act_vol; int32_t act_slide_vol; int32_t field_140; int32_t field_144; int32_t field_148; int32_t field_14C; int32_t field_150; int32_t field_154; int32_t field_158; int32_t field_15C; int32_t field_160; int32_t field_164; int32_t field_168; int32_t field_16C; int32_t field_170; //170 int32_t field_174; int32_t field_178; int32_t field_17C; int32_t field_180; int32_t field_184; //184 int32_t field_188; int32_t field_18C; int32_t field_190; int32_t field_194; int32_t field_198; //198 int32_t field_19C; int32_t field_1A0; int32_t field_1A4; int32_t field_1A8; int32_t field_1AC; //1AC int32_t field_1B0; int32_t field_1B4; int32_t field_1B8; int32_t field_1BC; int32_t module_equip0; //1C0 int32_t module_equip1; //1C4 int32_t module_equip2; //1C8 int32_t module_equip3; //1CC int32_t module_equip4; //1D0 int32_t module_equip5; //1D4 int32_t module_equip_cmn0; //1D8 int32_t module_equip_cmn1;//1DC int32_t module_equip_cmn2;//1E0 int32_t module_equip_cmn3;//1E4 int32_t module_equip_cmn4;//1E8 int32_t module_equip_cmn5;//1EC int32_t field_1F0;//1F0 int32_t field_1F4; int32_t field_1F8; int32_t field_1FC; int32_t field_200; int32_t field_204; int32_t field_208; int32_t field_20C; int32_t field_210; int32_t field_214; int32_t field_218; int32_t field_21C; int32_t field_220; int32_t field_224; int32_t field_228; int32_t field_22C; int32_t field_230; int32_t field_234; int32_t field_238; int32_t field_23C; int32_t module_hist; //240 int32_t field_244; int32_t field_248; int32_t field_24C; int32_t field_250; int32_t field_254; int32_t field_258; int32_t field_25C; int32_t field_260; int32_t field_264; int32_t field_268; int32_t field_26C; int32_t field_270; int32_t field_274; int32_t field_278; int32_t field_27C; int32_t field_280; int32_t field_284; int32_t field_288; int32_t field_28C; int32_t field_290; int32_t field_294; int32_t field_298; int32_t field_29C; int32_t field_2A0; int32_t field_2A4; int32_t field_2A8; int32_t field_2AC; int8_t use_pv_module_equip; int8_t ch_pv_module_equip; int8_t field_2B2; int8_t field_2B3; int32_t module_filter_kind; int32_t field_2B8; int32_t field_2BC; int32_t field_2C0; int32_t field_2C4; int32_t field_2C8; int32_t field_2CC; int32_t field_2D0; int32_t field_2D4; int32_t field_2D8; int32_t field_2DC; int32_t field_2E0; int32_t field_2E4; int32_t field_2E8; int32_t field_2EC; int32_t field_2F0; int32_t field_2F4; int32_t field_2F8; int32_t field_2FC; int32_t field_300; int32_t field_304; int32_t field_308; int32_t field_30C; int32_t field_310; int32_t field_314; int32_t field_318; int32_t field_31C; int32_t field_320; int32_t field_324; int32_t field_328; int32_t field_32C; int32_t field_330; int32_t field_334; int32_t field_338; int32_t field_33C; int32_t field_340; int32_t field_344; int32_t field_348; int32_t field_34C; int32_t field_350; int32_t field_354; int32_t field_358; int32_t field_35C; int32_t field_360; int32_t field_364; int32_t field_368; int32_t field_36C; int32_t field_370; int32_t field_374; int32_t field_378; int32_t field_37C; int32_t field_380; int32_t field_384; int32_t field_388; int32_t field_38C; int32_t field_390; int32_t field_394; int32_t field_398; int32_t field_39C; int32_t field_3A0; int32_t field_3A4; int32_t field_3A8; int32_t field_3AC; int32_t field_3B0; int32_t field_3B4; int32_t field_3B8; int32_t field_3BC; int32_t field_3C0; int32_t field_3C4; int32_t field_3C8; int32_t field_3CC; int32_t field_3D0; int32_t field_3D4; int32_t field_3D8; int32_t field_3DC; int32_t field_3E0; int32_t field_3E4; int32_t field_3E8; int32_t field_3EC; int32_t field_3F0; int32_t field_3F4; int32_t field_3F8; int32_t field_3FC; int32_t field_400; int32_t field_404; int32_t field_408; int32_t field_40C; int32_t field_410; int32_t field_414; int32_t field_418; int32_t field_41C; int32_t field_420; int32_t field_424; int32_t field_428; int32_t field_42C; int32_t field_430; int32_t field_434; int32_t field_438; int32_t field_43C; int32_t field_440; int32_t field_444; int32_t field_448; int32_t field_44C; int32_t field_450; int32_t field_454; int32_t field_458; int32_t field_45C; int32_t field_460; int32_t field_464; int32_t field_468; int32_t field_46C; int32_t field_470; int32_t field_474; int32_t field_478; int32_t field_47C; int32_t field_480; int32_t field_484; int32_t field_488; int32_t field_48C; int32_t field_490; int32_t field_494; int32_t field_498; int32_t field_49C; int32_t field_4A0; int32_t field_4A4; int32_t field_4A8; int32_t field_4AC; int32_t field_4B0; int32_t field_4B4; int32_t field_4B8; int32_t field_4BC; int32_t field_4C0; int32_t field_4C4; int32_t field_4C8; int32_t field_4CC; int32_t field_4D0; int32_t field_4D4; int32_t field_4D8; int32_t field_4DC; int32_t field_4E0; int32_t field_4E4; int32_t field_4E8; int32_t field_4EC; int32_t field_4F0; int32_t field_4F4; int32_t field_4F8; int32_t field_4FC; int32_t field_500; int32_t field_504; int32_t field_508; int32_t field_50C; int32_t field_510; int32_t field_514; int32_t field_518; int32_t field_51C; int32_t field_520; int32_t field_524; int32_t field_528; int32_t field_52C; int32_t field_530; int32_t field_534; int32_t field_538; int32_t field_53C; int32_t field_540; int32_t field_544; int32_t skin_equip; int32_t skin_equip_cmn; int32_t use_pv_skin_equip; int32_t btn_se_equip; int32_t btn_se_equip_cmn; int32_t use_pv_btn_se_equip; int32_t slide_se_equip; int32_t slide_se_equip_cmn; int32_t use_pv_slide_se_equip; int32_t chainslide_se_equip; int32_t chainslide_se_equip_cmn; int32_t use_pv_chainslide_se_equip; int32_t slidertouch_se_equip; int32_t slidertouch_se_equip_cmn; int32_t use_pv_slidertouch_se_equip; int32_t field_584; int* mylistA_begin; int* mylistA_end; int32_t field_598; int32_t field_59C; int* mylistB_begin; int* mylistB_end; int32_t field_5B0; int32_t field_5B4; int* mylistC_begin; int* mylistC_end; int32_t field_5C8; int32_t field_5CC; int32_t field_5D0; int32_t field_5D4; int32_t field_5D8; int32_t field_5DC; int32_t field_5E0; int32_t field_5E4; int32_t field_5E8; int32_t field_5EC; int32_t field_5F0; int32_t field_5F4; int32_t field_5F8; int32_t field_5FC; int32_t field_600; int32_t field_604; int32_t field_608; int32_t field_60C; int32_t field_610; int32_t field_614; int32_t field_618; int32_t field_61C; int32_t field_620; int32_t field_624; int32_t field_628; int32_t field_62C; int32_t field_630; int32_t field_634; int32_t field_638; int32_t field_63C; int32_t field_640; int32_t field_644; int32_t field_648; int32_t field_64C; int32_t field_650; int32_t field_654; int32_t field_658; int32_t field_65C; int32_t field_660; int32_t field_664; int32_t field_668; int32_t field_66C; int32_t field_670; int32_t field_674; int32_t field_678; int32_t field_67C; int32_t field_680; int32_t field_684; int32_t field_688; int32_t field_68C; int32_t field_690; int32_t field_694; int32_t field_698; int32_t field_69C; int32_t field_6A0; int32_t field_6A4; int32_t field_6A8; int32_t field_6AC; int32_t field_6B0; int32_t field_6B4; int32_t field_6B8; int32_t field_6BC; int32_t field_6C0; int32_t field_6C4; int32_t field_6C8; int32_t field_6CC; int32_t field_6D0; int32_t field_6D4; int32_t field_6D8; int32_t field_6DC; int32_t field_6E0; int32_t field_6E4; int32_t field_6E8; int32_t field_6EC; int32_t field_6F0; int32_t field_6F4; int32_t field_6F8; int32_t field_6FC; int32_t field_700; int32_t field_704; int32_t field_708; int32_t field_70C; int32_t field_710; int32_t field_714; int32_t field_718; int32_t field_71C; int32_t field_720; int32_t field_724; int32_t field_728; int32_t field_72C; int32_t field_730; int32_t field_734; int32_t field_738; int32_t field_73C; int32_t field_740; int32_t field_744; int32_t field_748; int32_t field_74C; int32_t field_750; int32_t field_754; int32_t field_758; int32_t field_75C; int32_t field_760; int32_t field_764; int32_t field_768; int32_t field_76C; int32_t field_770; int32_t field_774; int32_t field_778; int32_t field_77C; int32_t field_780; int32_t field_784; int32_t field_788; int32_t field_78C; int32_t field_790; int32_t field_794; int32_t field_798; int32_t field_79C; int32_t field_7A0; int32_t field_7A4; int32_t field_7A8; int32_t field_7AC; int32_t field_7B0; int32_t field_7B4; int32_t field_7B8; int32_t field_7BC; int32_t field_7C0; int32_t field_7C4; int32_t field_7C8; int32_t field_7CC; int32_t field_7D0; int32_t field_7D4; int32_t field_7D8; int32_t field_7DC; int32_t field_7E0; int32_t field_7E4; int32_t field_7E8; int32_t field_7EC; int32_t field_7F0; int32_t field_7F4; int32_t field_7F8; int32_t field_7FC; int32_t field_800; int32_t field_804; int32_t field_808; int32_t field_80C; int32_t field_810; int32_t field_814; int32_t field_818; int32_t field_81C; int32_t field_820; int32_t field_824; int32_t field_828; int32_t field_82C; int32_t field_830; int32_t field_834; int32_t field_838; int32_t field_83C; int32_t field_840; int32_t field_844; int32_t field_848; int32_t field_84C; int32_t field_850; int32_t field_854; int32_t field_858; int32_t field_85C; int32_t field_860; int32_t field_864; int32_t field_868; int32_t field_86C; int32_t field_870; int32_t field_874; int32_t field_878; int32_t field_87C; int32_t field_880; int32_t field_884; int32_t field_888; int32_t field_88C; int32_t field_890; int32_t field_894; int32_t field_898; int32_t field_89C; int32_t field_8A0; int32_t field_8A4; int32_t field_8A8; int32_t field_8AC; int32_t field_8B0; int32_t field_8B4; int32_t field_8B8; int32_t field_8BC; int32_t field_8C0; int32_t field_8C4; int32_t field_8C8; int32_t field_8CC; int32_t field_8D0; int32_t field_8D4; int32_t field_8D8; int32_t field_8DC; int32_t field_8E0; int32_t field_8E4; int32_t field_8E8; int32_t field_8EC; int32_t field_8F0; int32_t field_8F4; int32_t field_8F8; int32_t field_8FC; int32_t field_900; int32_t field_904; int32_t field_908; int32_t field_90C; int32_t field_910; int32_t field_914; int32_t field_918; int32_t field_91C; int32_t field_920; int32_t field_924; int32_t field_928; int32_t field_92C; int32_t field_930; int32_t field_934; int32_t field_938; int32_t field_93C; int32_t field_940; int32_t field_944; int32_t field_948; int32_t field_94C; int32_t field_950; int32_t field_954; int32_t field_958; int32_t field_95C; int32_t field_960; int32_t field_964; int32_t field_968; int32_t field_96C; int32_t field_970; int32_t field_974; int32_t field_978; int32_t field_97C; int32_t field_980; int32_t field_984; int32_t field_988; int32_t field_98C; int32_t field_990; int32_t field_994; int32_t field_998; int32_t field_99C; int32_t field_9A0; int32_t field_9A4; int32_t field_9A8; int32_t field_9AC; int32_t field_9B0; int32_t field_9B4; int32_t field_9B8; int32_t field_9BC; int32_t field_9C0; int32_t field_9C4; int32_t field_9C8; int32_t field_9CC; int32_t field_9D0; int32_t field_9D4; int32_t field_9D8; int32_t field_9DC; int32_t field_9E0; int32_t field_9E4; int32_t field_9E8; int32_t field_9EC; int32_t field_9F0; int32_t field_9F4; int32_t field_9F8; int32_t field_9FC; int32_t field_A00; int32_t field_A04; int32_t field_A08; int32_t field_A0C; int32_t field_A10; int32_t field_A14; int32_t field_A18; int32_t field_A1C; int32_t field_A20; int32_t field_A24; int32_t field_A28; int32_t field_A2C; int32_t field_A30; int32_t field_A34; int32_t field_A38; int32_t field_A3C; int32_t field_A40; int32_t field_A44; int32_t field_A48; int32_t field_A4C; int32_t field_A50; int32_t field_A54; int32_t field_A58; int32_t field_A5C; int32_t field_A60; int32_t field_A64; int32_t field_A68; int32_t field_A6C; int32_t field_A70; int32_t field_A74; int32_t field_A78; int32_t field_A7C; int32_t field_A80; int32_t field_A84; int32_t field_A88; int32_t field_A8C; int32_t field_A90; int32_t field_A94; int32_t field_A98; int32_t field_A9C; int32_t field_AA0; int32_t field_AA4; int32_t field_AA8; int32_t field_AAC; int32_t field_AB0; int32_t field_AB4; int32_t field_AB8; int32_t field_ABC; int32_t field_AC0; int32_t field_AC4; int32_t field_AC8; int32_t field_ACC; int32_t field_AD0; int32_t field_AD4; int32_t field_AD8; int32_t field_ADC; int32_t field_AE0; int32_t field_AE4; int32_t field_AE8; int32_t field_AEC; int32_t field_AF0; int32_t field_AF4; int32_t field_AF8; int32_t field_AFC; int32_t field_B00; int32_t field_B04; int32_t field_B08; int32_t field_B0C; int32_t field_B10; int32_t field_B14; int32_t field_B18; int32_t field_B1C; int32_t field_B20; int32_t field_B24; int32_t field_B28; int32_t field_B2C; int32_t field_B30; int32_t field_B34; int32_t field_B38; int32_t field_B3C; int32_t field_B40; int32_t field_B44; int32_t field_B48; int32_t field_B4C; int32_t field_B50; int32_t field_B54; int32_t field_B58; int32_t field_B5C; int32_t field_B60; int32_t field_B64; int32_t field_B68; int32_t field_B6C; int32_t field_B70; int32_t field_B74; int32_t field_B78; int32_t field_B7C; int32_t field_B80; int32_t field_B84; int32_t field_B88; int32_t field_B8C; int32_t field_B90; int32_t field_B94; int32_t field_B98; int32_t field_B9C; int32_t field_BA0; int32_t field_BA4; int32_t field_BA8; int32_t field_BAC; int32_t field_BB0; int32_t field_BB4; int32_t field_BB8; int32_t field_BBC; int32_t field_BC0; int32_t field_BC4; int32_t field_BC8; int32_t field_BCC; int32_t field_BD0; int32_t field_BD4; int32_t field_BD8; int32_t field_BDC; int32_t field_BE0; int32_t field_BE4; int32_t field_BE8; int32_t field_BEC; int32_t field_BF0; int32_t field_BF4; int32_t field_BF8; int32_t field_BFC; int32_t field_C00; int32_t field_C04; int32_t field_C08; int32_t field_C0C; int32_t field_C10; int32_t field_C14; int32_t field_C18; int32_t field_C1C; int32_t field_C20; int32_t field_C24; int32_t field_C28; int32_t field_C2C; int32_t field_C30; int32_t field_C34; int32_t field_C38; int32_t field_C3C; int32_t field_C40; int32_t field_C44; int32_t field_C48; int32_t field_C4C; int32_t field_C50; int32_t field_C54; int32_t field_C58; int32_t field_C5C; int32_t field_C60; int32_t field_C64; int32_t field_C68; int32_t field_C6C; int32_t field_C70; int32_t field_C74; int32_t field_C78; int32_t field_C7C; int32_t field_C80; int32_t field_C84; int32_t field_C88; int32_t field_C8C; int32_t field_C90; int32_t field_C94; int32_t field_C98; int32_t field_C9C; int32_t field_CA0; int32_t field_CA4; int32_t field_CA8; int32_t field_CAC; int32_t field_CB0; int32_t field_CB4; int32_t field_CB8; int32_t field_CBC; int32_t field_CC0; int32_t field_CC4; int32_t field_CC8; int32_t field_CCC; int32_t field_CD0; int32_t field_CD4; int32_t field_CD8; int32_t field_CDC; int32_t field_CE0; int32_t field_CE4; int32_t field_CE8; int32_t field_CEC; int32_t field_CF0; int32_t field_CF4; int32_t field_CF8; int32_t field_CFC; int32_t field_D00; int32_t field_D04; int32_t field_D08; int32_t field_D0C; int32_t field_D10; int32_t field_D14; int32_t field_D18; int32_t field_D1C; int32_t field_D20; int32_t field_D24; int32_t field_D28; int32_t field_D2C; int32_t field_D30; int32_t field_D34; int32_t field_D38; int32_t field_D3C; int32_t field_D40; int32_t field_D44; int32_t field_D48; int32_t field_D4C; int32_t field_D50; int32_t field_D54; int32_t field_D58; int32_t field_D5C; int32_t field_D60; int32_t field_D64; int32_t field_D68; int32_t field_D6C; int32_t field_D70; int32_t field_D74; int32_t field_D78; int32_t field_D7C; int32_t field_D80; int32_t field_D84; int32_t field_D88; int32_t field_D8C; int32_t field_D90; uint8_t clear_border; uint8_t field_D95; uint8_t field_D96; uint8_t field_D97; int32_t field_D98; int32_t field_D9C; int32_t field_DA0; int32_t field_DA4; int32_t field_DA8; int32_t field_DAC; int32_t field_DB0; int32_t field_DB4; int32_t field_DB8; int32_t field_DBC; int32_t field_DC0; int32_t field_DC4; int32_t field_DC8; int32_t field_DCC; int32_t field_DD0; int32_t field_DD4; int32_t field_DD8; int32_t field_DDC; int32_t field_DE0; int32_t field_DE4; int32_t field_DE8; int32_t field_DEC; int32_t field_DF0; int32_t field_DF4; int32_t field_DF8; int32_t field_DFC; int32_t field_E00; int32_t field_E04; int32_t field_E08; int32_t field_E0C; int32_t field_E10; int32_t field_E14; int32_t field_E18; int32_t field_E1C; int32_t field_E20; int32_t field_E24; int32_t field_E28; int32_t field_E2C; int32_t field_E30; int8_t field_E34; int8_t game_opts; int8_t field_E36; int8_t field_E37; int32_t field_E38; int32_t field_E3C; int32_t field_E40; int32_t field_E44; int32_t field_E48; int32_t field_E4C; int32_t field_E50; int32_t field_E54; int32_t field_E58; int32_t field_E5C; int32_t field_E60; int32_t field_E64; int32_t field_E68; int32_t field_E6C; int32_t field_E70; int32_t field_E74; int32_t field_E78; int32_t field_E7C; int32_t field_E80; int32_t field_E84; int32_t field_E88; int32_t field_E8C; int32_t field_E90; int32_t field_E94; int32_t field_E98; int32_t field_E9C; int32_t field_EA0; int32_t field_EA4; int32_t field_EA8; int32_t field_EAC; int32_t field_EB0; int32_t field_EB4; int32_t field_EB8; int32_t field_EBC; int32_t field_EC0; int32_t field_EC4; int32_t field_EC8; int32_t field_ECC; int32_t field_ED0; int32_t field_ED4; int32_t field_ED8; int32_t field_EDC; int32_t field_EE0; int32_t field_EE4; int32_t field_EE8; int32_t field_EEC; int32_t field_EF0; int32_t field_EF4; int32_t field_EF8; int32_t field_EFC; }; ================================================ FILE: source-code/source/plugins/TLAC/Components/PlayerDataManager.cpp ================================================ #include "PlayerDataManager.h" #include #include "../framework.h" #include "../Constants.h" #include "../Input/Keyboard/Keyboard.h" #include "../FileSystem/ConfigFile.h" #include "../Utilities/Operations.h" #include #include "GameState.h" const std::string PLAYER_DATA_FILE_NAME = "playerdata.ini"; static WCHAR configPath[256]; int* headitemequip = (int*)0x0000000141804CDC; int customheaditemequip; namespace TLAC::Components { PlayerDataManager::PlayerDataManager() { } PlayerDataManager::~PlayerDataManager() { if (customPlayerData != nullptr) delete customPlayerData; } const char* PlayerDataManager::GetDisplayName() { return "player_data_manager"; } void PlayerDataManager::Initialize(ComponentsManager*) { playerData = (PlayerData*)PLAYER_DATA_ADDRESS; ApplyPatch(); LoadConfig(); ApplyCustomData(); } void PlayerDataManager::Update() { ApplyCustomData(); /*if (false && Input::Keyboard::GetInstance()->IsTapped(VK_F12)) { printf("[TLAC] PlayerDataManager::Update(): Loading config...\n"); LoadConfig(); }*/ // nas, I moved the patches back to patches because please.. at least don't apply it every frame when it's not necessary lol // and reverting was the easiest way to undo that if (moduleCardWorkaround) { int* pvId = (int*)0x00000001418054C4; int* modState = (int*)0x00000001411A9790; int* loadState = (int*)0x0000000141197E58; if (!customPlayerData->UseCard) { if (*(char*)0x000000014CC5E270 == 32) { DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BC8E6 + 0) = 0x00; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck); pvModuleLoaded = false; } else { if (!pvModuleLoaded) { pvModuleLoaded = true; DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BC8E6 + 0) = 0x01; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck); } } if ((initPvId == false) || ((lastModState == 0) && (*modState == 1))) { if ((lastModState == 0) && (*modState == 1)) { *(int*)0x00000001411A8A10 = *(int*)0x00000001411A8A28; *(int*)(0x00000001411A8A10 + 4) = *(int*)(0x00000001411A8A28 + 4); *(int*)(0x00000001411A8A10 + 8) = *(int*)(0x00000001411A8A28 + 8); *(int*)(0x00000001411A8A10 + 12) = *(int*)(0x00000001411A8A28 + 12); *(int*)(0x00000001411A8A10 + 16) = *(int*)(0x00000001411A8A28 + 16); *(int*)(0x00000001411A8A10 + 18) = *(int*)(0x00000001411A8A28 + 18); } initPvId = true; lastModState = *modState; DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405CBBA3 + 0) = 0x90; *((BYTE*)0x00000001405CBBA3 + 1) = 0x90; *((BYTE*)0x00000001405CBBA3 + 2) = 0x90; *((BYTE*)0x00000001405CBBA3 + 3) = 0x90; *((BYTE*)0x00000001405CBBA3 + 4) = 0x90; *((BYTE*)0x00000001405CBBA3 + 5) = 0x90; *((BYTE*)0x00000001405CBBA3 + 6) = 0x90; *((BYTE*)0x00000001405CBBA3 + 7) = 0x90; VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck); } if (((*modState == 0) && (*pvId != lastPvId)) || ((lastModState == 1) && (*modState == 0))) { if ((lastModState == 1) && (*modState == 0)) { *(int*)0x00000001411A8A28 = *(int*)0x00000001411A8A10; *(int*)(0x00000001411A8A28 + 4) = *(int*)(0x00000001411A8A10 + 4); *(int*)(0x00000001411A8A28 + 8) = *(int*)(0x00000001411A8A10 + 8); *(int*)(0x00000001411A8A28 + 12) = *(int*)(0x00000001411A8A10 + 12); *(int*)(0x00000001411A8A28 + 16) = *(int*)(0x00000001411A8A10 + 16); *(int*)(0x00000001411A8A28 + 18) = *(int*)(0x00000001411A8A10 + 18); } initPvId = false; lastPvId = *pvId; lastModState = *modState; DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405CBBA3 + 0) = 0x42; *((BYTE*)0x00000001405CBBA3 + 1) = 0x89; *((BYTE*)0x00000001405CBBA3 + 2) = 0x84; *((BYTE*)0x00000001405CBBA3 + 3) = 0xb6; *((BYTE*)0x00000001405CBBA3 + 4) = 0xc0; *((BYTE*)0x00000001405CBBA3 + 5) = 0x01; *((BYTE*)0x00000001405CBBA3 + 6) = 0x00; *((BYTE*)0x00000001405CBBA3 + 7) = 0x00; VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck); } } else { if (*(char*)0x000000014CC5E270 == 32) { DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BC8E6 + 0) = 0x00; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck); VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405CBBA3 + 0) = 0x42; *((BYTE*)0x00000001405CBBA3 + 1) = 0x89; *((BYTE*)0x00000001405CBBA3 + 2) = 0x84; *((BYTE*)0x00000001405CBBA3 + 3) = 0xb6; *((BYTE*)0x00000001405CBBA3 + 4) = 0xc0; *((BYTE*)0x00000001405CBBA3 + 5) = 0x01; *((BYTE*)0x00000001405CBBA3 + 6) = 0x00; *((BYTE*)0x00000001405CBBA3 + 7) = 0x00; VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck); VirtualProtect((BYTE*)0x00000001405BCBE3, 2, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BCBE3 + 0) = 0x00; VirtualProtect((BYTE*)0x00000001405BCBE3, 2, oldProtect, &bck); pvModuleLoaded = false; } else { if (!pvModuleLoaded) { pvModuleLoaded = true; DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BC8E6 + 0) = 0x00; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck); VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405CBBA3 + 0) = 0x90; *((BYTE*)0x00000001405CBBA3 + 1) = 0x90; *((BYTE*)0x00000001405CBBA3 + 2) = 0x90; *((BYTE*)0x00000001405CBBA3 + 3) = 0x90; *((BYTE*)0x00000001405CBBA3 + 4) = 0x90; *((BYTE*)0x00000001405CBBA3 + 5) = 0x90; *((BYTE*)0x00000001405CBBA3 + 6) = 0x90; *((BYTE*)0x00000001405CBBA3 + 7) = 0x90; VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck); VirtualProtect((BYTE*)0x00000001405BCBE3, 2, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BCBE3 + 0) = 0x01; VirtualProtect((BYTE*)0x00000001405BCBE3, 2, oldProtect, &bck); } } } } } void PlayerDataManager::ApplyPatch() { DWORD oldProtect; VirtualProtect((void*)SET_DEFAULT_PLAYER_DATA_ADDRESS, sizeof(uint8_t), PAGE_EXECUTE_READWRITE, &oldProtect); { // prevent the PlayerData from being reset *(uint8_t*)(SET_DEFAULT_PLAYER_DATA_ADDRESS) = RET_OPCODE; } VirtualProtect((void*)SET_DEFAULT_PLAYER_DATA_ADDRESS, sizeof(uint8_t), oldProtect, &oldProtect); // allow player to select the module and extra item VirtualProtect((void*)MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS, sizeof(byte) * 2, PAGE_EXECUTE_READWRITE, &oldProtect); { *(byte*)(MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS) = 0xB0; // xor al,al -> ld al,1 *(byte*)(MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS + 0x1) = 0x01; } VirtualProtect((void*)MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS, sizeof(byte) * 2, oldProtect, &oldProtect); // fix annoying behavior of closing after changing module or item (don't yet know the reason, maybe NW/Card checks) { VirtualProtect((void*)MODSELECTOR_CLOSE_AFTER_MODULE, sizeof(uint8_t), PAGE_EXECUTE_READWRITE, &oldProtect); { *(uint8_t*)(MODSELECTOR_CLOSE_AFTER_MODULE) = JNE_OPCODE; } VirtualProtect((void*)MODSELECTOR_CLOSE_AFTER_MODULE, sizeof(uint8_t), oldProtect, &oldProtect); VirtualProtect((void*)MODSELECTOR_CLOSE_AFTER_CUSTOMIZE, sizeof(uint8_t), PAGE_EXECUTE_READWRITE, &oldProtect); { *(uint8_t*)(MODSELECTOR_CLOSE_AFTER_CUSTOMIZE) = JNE_OPCODE; } VirtualProtect((void*)MODSELECTOR_CLOSE_AFTER_CUSTOMIZE, sizeof(uint8_t), oldProtect, &oldProtect); } } void PlayerDataManager::LoadConfig() { if (playerData == nullptr) return; FileSystem::ConfigFile config(framework::GetModuleDirectory(), PLAYER_DATA_FILE_NAME); if (!config.OpenRead()) return; if (customPlayerData != nullptr) delete customPlayerData; customPlayerData = new CustomPlayerData(); config.TryGetValue("player_name", &customPlayerData->PlayerName); config.TryGetValue("level_name", &customPlayerData->LevelName); // ScoreSaver copies & declaring non-playerdata values std::string utf8path = TLAC::framework::GetModuleDirectory() + "/playerdata.ini"; MultiByteToWideChar(CP_UTF8, 0, utf8path.c_str(), -1, configPath, 256); customPlayerData->LevelNum = config.GetIntegerValue("level"); customPlayerData->VocaloidPoints = config.GetIntegerValue("vocaloid_point"); customPlayerData->LevelPlateId = config.GetIntegerValue("level_plate_id"); customPlayerData->LevelPlateEffect = config.GetIntegerValue("level_plate_effect"); customPlayerData->SkinEquip = config.GetIntegerValue("skin_equip"); customPlayerData->BtnSeEquip = config.GetIntegerValue("btn_se_equip"); customPlayerData->SlideSeEquip = config.GetIntegerValue("slide_se_equip"); customPlayerData->ChainslideSeEquip = config.GetIntegerValue("chainslide_se_equip"); customPlayerData->SlidertouchSeEquip = config.GetIntegerValue("slidertouch_se_equip"); customPlayerData->ModuleEquipCmn0 = config.GetIntegerValue("module_equip_cmn0"); customPlayerData->ModuleEquipCmn1 = config.GetIntegerValue("module_equip_cmn1"); customPlayerData->ModuleEquipCmn2 = config.GetIntegerValue("module_equip_cmn2"); customPlayerData->ModuleEquipCmn3 = config.GetIntegerValue("module_equip_cmn3"); customPlayerData->ModuleEquipCmn4 = config.GetIntegerValue("module_equip_cmn4"); customPlayerData->ModuleEquipCmn5 = config.GetIntegerValue("module_equip_cmn5"); customPlayerData->ActionVol = config.GetIntegerValue("act_vol"); customPlayerData->ActionSlideVol = config.GetIntegerValue("act_slide_vol"); customPlayerData->UsePVSFXEquip = config.GetBooleanValue("use_pv_sfx_equip"); customPlayerData->UsePVSkinEquip = config.GetBooleanValue("use_pv_skin_equip"); customPlayerData->UsePVEquip = config.GetBooleanValue("use_pv_module_equip"); customPlayerData->ShowExcellentClearBorder = config.GetBooleanValue("border_excellent"); customPlayerData->ShowGreatClearBorder = config.GetBooleanValue("border_great"); customPlayerData->ShowRivalClearBorder = config.GetBooleanValue("border_rival"); customPlayerData->UseCard = config.GetBooleanValue("use_card"); customPlayerData->GameModifierOptions = config.GetBooleanValue("gamemode_options"); customPlayerData->ActionSE = config.GetBooleanValue("act_toggle"); moduleCardWorkaround = config.GetBooleanValue("module_card_workaround"); // don't want to overwrite the default values auto setIfNotEqual = [](int* target, int value, int comparison) { if (value != comparison) * target = value; }; // only need to run this line once on startup, otherwise cannot increase/decrease in-game (or use per-song settings!) setIfNotEqual(&playerData->vocaloid_point, customPlayerData->VocaloidPoints, 0); setIfNotEqual(&playerData->skin_equip_cmn, customPlayerData->SkinEquip, 0); setIfNotEqual(&playerData->module_equip_cmn0, customPlayerData->ModuleEquipCmn0, 0); setIfNotEqual(&playerData->module_equip_cmn1, customPlayerData->ModuleEquipCmn1, 0); setIfNotEqual(&playerData->module_equip_cmn2, customPlayerData->ModuleEquipCmn2, 0); setIfNotEqual(&playerData->module_equip_cmn3, customPlayerData->ModuleEquipCmn3, 0); setIfNotEqual(&playerData->module_equip_cmn4, customPlayerData->ModuleEquipCmn4, 0); setIfNotEqual(&playerData->module_equip_cmn5, customPlayerData->ModuleEquipCmn5, 0); setIfNotEqual(&playerData->act_vol, customPlayerData->ActionVol, 100); setIfNotEqual(&playerData->act_slide_vol, customPlayerData->ActionSlideVol, 100); setIfNotEqual(&playerData->btn_se_equip_cmn, customPlayerData->BtnSeEquip, -1); setIfNotEqual(&playerData->slide_se_equip_cmn, customPlayerData->SlideSeEquip, -1); setIfNotEqual(&playerData->chainslide_se_equip_cmn, customPlayerData->ChainslideSeEquip, -1); setIfNotEqual(&playerData->slidertouch_se_equip_cmn, customPlayerData->SlidertouchSeEquip, -1); setIfNotEqual(&playerData->act_toggle, customPlayerData->ActionSE, 1); std::string* mylistString; std::vector mylistStringVec; customPlayerData->Mylist[0].clear(); config.TryGetValue("mylist_A", &mylistString); if (mylistString != nullptr) { for (std::string &pvStr : TLAC::Utilities::Split(*mylistString, ",")) customPlayerData->Mylist[0].push_back(atoi(pvStr.c_str())); delete mylistString; } customPlayerData->Mylist[1].clear(); config.TryGetValue("mylist_B", &mylistString); if (mylistString != nullptr) { for (std::string &pvStr : TLAC::Utilities::Split(*mylistString, ",")) customPlayerData->Mylist[1].push_back(atoi(pvStr.c_str())); delete mylistString; } customPlayerData->Mylist[2].clear(); config.TryGetValue("mylist_C", &mylistString); if (mylistString != nullptr) { for (std::string &pvStr : TLAC::Utilities::Split(*mylistString, ",")) customPlayerData->Mylist[2].push_back(atoi(pvStr.c_str())); delete mylistString; } if (moduleCardWorkaround) { if (!customPlayerData->UseCard) { DWORD oldProtect, bck; VirtualProtect((BYTE*)0x000000014010523F, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x000000014010523F + 0) = 0x30; *((BYTE*)0x000000014010523F + 1) = 0xC0; *((BYTE*)0x000000014010523F + 2) = 0x90; VirtualProtect((BYTE*)0x000000014010523F, 3, oldProtect, &bck); VirtualProtect((BYTE*)0x00000001405BCC48, 6, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BCC48 + 0) = 0x90; *((BYTE*)0x00000001405BCC48 + 1) = 0x90; *((BYTE*)0x00000001405BCC48 + 2) = 0x90; *((BYTE*)0x00000001405BCC48 + 3) = 0x90; *((BYTE*)0x00000001405BCC48 + 4) = 0x90; *((BYTE*)0x00000001405BCC48 + 5) = 0x90; VirtualProtect((BYTE*)0x00000001405BCC48, 6, oldProtect, &bck); VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BC8E6 + 0) = 0x01; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck); } else { DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BC8E6 + 0) = 0x00; VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck); VirtualProtect((BYTE*)0x00000001405BCC48, 6, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405BCC48 + 0) = 0xC7; *((BYTE*)0x00000001405BCC48 + 1) = 0x03; *((BYTE*)0x00000001405BCC48 + 2) = 0x00; *((BYTE*)0x00000001405BCC48 + 3) = 0x00; *((BYTE*)0x00000001405BCC48 + 4) = 0x00; *((BYTE*)0x00000001405BCC48 + 5) = 0x00; VirtualProtect((BYTE*)0x00000001405BCC48, 6, oldProtect, &bck); VirtualProtect((BYTE*)0x000000014010523F, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x000000014010523F + 0) = 0x0F; *((BYTE*)0x000000014010523F + 1) = 0x94; *((BYTE*)0x000000014010523F + 2) = 0xC1; VirtualProtect((BYTE*)0x000000014010523F, 3, oldProtect, &bck); //just incase the player is reloading VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect); *((BYTE*)0x00000001405CBBA3 + 0) = 0x42; *((BYTE*)0x00000001405CBBA3 + 1) = 0x89; *((BYTE*)0x00000001405CBBA3 + 2) = 0x84; *((BYTE*)0x00000001405CBBA3 + 3) = 0xb6; *((BYTE*)0x00000001405CBBA3 + 4) = 0xc0; *((BYTE*)0x00000001405CBBA3 + 5) = 0x01; *((BYTE*)0x00000001405CBBA3 + 6) = 0x00; *((BYTE*)0x00000001405CBBA3 + 7) = 0x00; VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck); } } } void PlayerDataManager::ApplyCustomData() { // don't want to overwrite the default values auto setIfNotEqual = [](int *target, int value, int comparison) { if (value != comparison) *target = value; }; // check if the playerData in-game value is different from the customPlayerData value and update and save the ini if (customPlayerData->VocaloidPoints != playerData->vocaloid_point) { customPlayerData->VocaloidPoints = playerData->vocaloid_point; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->vocaloid_point); WritePrivateProfileStringW(L"playerdata", L"vocaloid_point", val, configPath); } // save module choices to module_equip_cmn[0-5] if (customPlayerData->ModuleEquipCmn0 != playerData->module_equip_cmn0) { customPlayerData->ModuleEquipCmn0 = playerData->module_equip_cmn0; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->module_equip_cmn0); WritePrivateProfileStringW(L"playerdata", L"module_equip_cmn0", val, configPath); } if (customPlayerData->ModuleEquipCmn1 != playerData->module_equip_cmn1) { customPlayerData->ModuleEquipCmn1 = playerData->module_equip_cmn1; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->module_equip_cmn1); WritePrivateProfileStringW(L"playerdata", L"module_equip_cmn1", val, configPath); } if (customPlayerData->ModuleEquipCmn2 != playerData->module_equip_cmn2) { customPlayerData->ModuleEquipCmn2 = playerData->module_equip_cmn2; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->module_equip_cmn2); WritePrivateProfileStringW(L"playerdata", L"module_equip_cmn2", val, configPath); } if (customPlayerData->ModuleEquipCmn3 != playerData->module_equip_cmn3) { customPlayerData->ModuleEquipCmn3 = playerData->module_equip_cmn3; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->module_equip_cmn3); WritePrivateProfileStringW(L"playerdata", L"module_equip_cmn3", val, configPath); } if (customPlayerData->ModuleEquipCmn4 != playerData->module_equip_cmn4) { customPlayerData->ModuleEquipCmn4 = playerData->module_equip_cmn4; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->module_equip_cmn4); WritePrivateProfileStringW(L"playerdata", L"module_equip_cmn4", val, configPath); } if (customPlayerData->ModuleEquipCmn5 != playerData->module_equip_cmn5) { customPlayerData->ModuleEquipCmn5 = playerData->module_equip_cmn5; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->module_equip_cmn5); WritePrivateProfileStringW(L"playerdata", L"module_equip_cmn5", val, configPath); } if (customPlayerData->ActionVol != playerData->act_vol) { customPlayerData->ActionVol = playerData->act_vol; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->act_vol); WritePrivateProfileStringW(L"playerdata", L"act_vol", val, configPath); } if (customPlayerData->ActionSlideVol != playerData->act_slide_vol) { customPlayerData->ActionSlideVol = playerData->act_slide_vol; WCHAR val[32]; swprintf(val, 32, L"%d", playerData->act_slide_vol); WritePrivateProfileStringW(L"playerdata", L"act_slide_vol", val, configPath); } if (customPlayerData->UsePVEquip != playerData->use_pv_module_equip) { playerData->use_pv_module_equip = 1; } if (customPlayerData->UsePVSFXEquip != playerData->use_pv_btn_se_equip) { playerData->use_pv_btn_se_equip = 1; playerData->use_pv_chainslide_se_equip = 1; playerData->use_pv_slidertouch_se_equip = 1; playerData->use_pv_slide_se_equip = 1; } if (customPlayerData->UsePVSkinEquip != playerData->use_pv_skin_equip) { playerData->use_pv_skin_equip = 1; } setIfNotEqual(&playerData->level, customPlayerData->LevelNum, 1); setIfNotEqual(&playerData->level_plate_id, customPlayerData->LevelPlateId, 0); setIfNotEqual(&playerData->level_plate_effect, customPlayerData->LevelPlateEffect, 0); // Display clear borders on the progress bar playerData->clear_border = (customPlayerData->ShowRivalClearBorder << 2) | (customPlayerData->ShowExcellentClearBorder << 1) | (customPlayerData->ShowGreatClearBorder); playerData->use_card = customPlayerData->UseCard; // required to allow for module selection playerData->game_opts = customPlayerData->GameModifierOptions; // hi-speed, etc.. memset((void*)MODULE_TABLE_START, 0xFF, 128); memset((void*)ITEM_TABLE_START, 0xFF, 128); playerData->mylistA_begin = customPlayerData->Mylist[0].begin()._Ptr; playerData->mylistA_end = customPlayerData->Mylist[0].end()._Ptr; playerData->mylistB_begin = customPlayerData->Mylist[1].begin()._Ptr; playerData->mylistB_end = customPlayerData->Mylist[1].end()._Ptr; playerData->mylistC_begin = customPlayerData->Mylist[2].begin()._Ptr; playerData->mylistC_end = customPlayerData->Mylist[2].end()._Ptr; if (customPlayerData->PlayerName != nullptr) { playerData->field_DC = 0x10; playerData->player_name = (char*)customPlayerData->PlayerName->c_str(); } if (customPlayerData->LevelName != nullptr) { playerData->level_name = (char*)customPlayerData->LevelName->c_str(); playerData->field_110 = 0xFF; playerData->field_118 = 0x1F; } } } ================================================ FILE: source-code/source/plugins/TLAC/Components/PlayerDataManager.h ================================================ #pragma once #include "EmulatorComponent.h" #include "PlayerData.h" #include "CustomPlayerData.h" #include namespace TLAC::Components { class PlayerDataManager : public EmulatorComponent { public: PlayerDataManager(); ~PlayerDataManager(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; private: PlayerData* playerData; CustomPlayerData* customPlayerData; int lastPvId = -1; bool initPvId = true; bool pvModuleLoaded = true; bool moduleCardWorkaround = true; int lastModState = 0; void ApplyPatch(); void LoadConfig(); void ApplyCustomData(); }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/ScaleComponent.cpp ================================================ #include "ScaleComponent.h" #include #include #include "../Constants.h" #include #include "../framework.h" #include #include #include #include namespace TLAC::Components { ScaleComponent::ScaleComponent() { } ScaleComponent::~ScaleComponent() { } const char* ScaleComponent::GetDisplayName() { return "scale_component"; } void ScaleComponent::Initialize(ComponentsManager*) { { DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001404ACD24, 7, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001404ACD24 + 0) = 0x44; *((byte*)0x00000001404ACD24 + 1) = 0x8B; *((byte*)0x00000001404ACD24 + 2) = 0x0D; *((byte*)0x00000001404ACD24 + 3) = 0xD1; *((byte*)0x00000001404ACD24 + 4) = 0x08; *((byte*)0x00000001404ACD24 + 5) = 0xD0; *((byte*)0x00000001404ACD24 + 6) = 0x00; VirtualProtect((BYTE*)0x00000001404ACD24, 7, oldProtect, &bck); } { DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001404ACD2B, 7, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001404ACD2B + 0) = 0x44; *((byte*)0x00000001404ACD2B + 1) = 0x8B; *((byte*)0x00000001404ACD2B + 2) = 0x05; *((byte*)0x00000001404ACD2B + 3) = 0xC6; *((byte*)0x00000001404ACD2B + 4) = 0x08; *((byte*)0x00000001404ACD2B + 5) = 0xD0; *((byte*)0x00000001404ACD2B + 6) = 0x00; VirtualProtect((BYTE*)0x00000001404ACD2B, 7, oldProtect, &bck); } { DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001405030A0, 6, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001405030A0 + 0) = 0x90; *((byte*)0x00000001405030A0 + 1) = 0x90; *((byte*)0x00000001405030A0 + 2) = 0x90; *((byte*)0x00000001405030A0 + 3) = 0x90; *((byte*)0x00000001405030A0 + 4) = 0x90; *((byte*)0x00000001405030A0 + 5) = 0x90; VirtualProtect((BYTE*)0x00000001404ACD2B, 6, oldProtect, &bck); } } void ScaleComponent::Update() { uiAspectRatio = (float*)UI_ASPECT_RATIO; uiWidth = (float*)UI_WIDTH_ADDRESS; uiHeight = (float*)UI_HEIGHT_ADDRESS; fb1Height = (int*)FB1_HEIGHT_ADDRESS; fb1Width = (int*)FB1_WIDTH_ADDRESS; //fb2Height = (int*)FB2_HEIGHT_ADDRESS; //fb2Width = (int*)FB2_WIDTH_ADDRESS; fbAspectRatio = (double*)FB_ASPECT_RATIO; RECT hWindow; GetClientRect(TLAC::framework::DivaWindowHandle, &hWindow); *uiAspectRatio = (float)(hWindow.right - hWindow.left) / (float)(hWindow.bottom - hWindow.top); *fbAspectRatio = (double)(hWindow.right - hWindow.left) / (double)(hWindow.bottom - hWindow.top); *uiWidth = hWindow.right - hWindow.left; *uiHeight = hWindow.bottom - hWindow.top; *fb1Width = hWindow.right - hWindow.left; *fb1Height = hWindow.bottom - hWindow.top; //*fb2Width = hWindow.right - hWindow.left; //*fb2Height = hWindow.bottom - hWindow.top; *((int*)0x00000001411AD608) = 0; *((int*)0x0000000140EDA8E4) = *(int*)0x0000000140EDA8BC; *((int*)0x0000000140EDA8E8) = *(int*)0x0000000140EDA8C0; *(float*)0x00000001411A1900 = 0; *(float*)0x00000001411A1904 = (float)*(int*)0x0000000140EDA8BC; *(float*)0x00000001411A1908 = (float)*(int*)0x0000000140EDA8C0; //*((int*)0x00000001411AD5F8) = hWindow.right - hWindow.left; //*((int*)0x00000001411AD5FC) = hWindow.bottom - hWindow.top; //*((int*)0x00000001411ABB48) = hWindow.right - hWindow.left; //*((int*)0x00000001411ABB4C) = hWindow.bottom - hWindow.top; //*((int*)0x00000001411ABB5C) = (int)(*((int*)0x00000001411ABB54) * ((float)8 / (float)9)); //wtf?? } void ScaleComponent::UpdateInput() { return; } } ================================================ FILE: source-code/source/plugins/TLAC/Components/ScaleComponent.h ================================================ #pragma once #include "EmulatorComponent.h" #include "GameState.h" namespace TLAC::Components { class ScaleComponent : public EmulatorComponent { public: ScaleComponent(); ~ScaleComponent(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateInput() override; const int updatesPerFrame = 39; float* uiAspectRatio; float* uiWidth; float* uiHeight; int* fb1Width; int* fb1Height; int* fb2Width; int* fb2Height; double* fbAspectRatio; private: }; } ================================================ FILE: source-code/source/plugins/TLAC/Components/ScoreSaver.cpp ================================================ #include "ScoreSaver.h" #include "GameState.h" #include "../Constants.h" #include "../framework.h" #include "../Utilities/Operations.h" #include #include #include #include #pragma comment(lib, "detours.lib") namespace TLAC::Components { WCHAR ScoreSaver::configPath[256]; WCHAR ScoreSaver::rival_configPath[256]; WCHAR ScoreSaver::modules_configPath[256]; WCHAR ScoreSaver::skins_configPath[256]; WCHAR ScoreSaver::sfx_configPath[256]; ScoreSaver::ScoreSaver() { std::string utf8path = TLAC::framework::GetModuleDirectory() + "/scores.ini"; MultiByteToWideChar(CP_UTF8, 0, utf8path.c_str(), -1, configPath, 256); utf8path = TLAC::framework::GetModuleDirectory() + "/rivalscores.ini"; MultiByteToWideChar(CP_UTF8, 0, utf8path.c_str(), -1, rival_configPath, 256); utf8path = TLAC::framework::GetModuleDirectory() + "/pv_equip/modules.ini"; MultiByteToWideChar(CP_UTF8, 0, utf8path.c_str(), -1, modules_configPath, 256); utf8path = TLAC::framework::GetModuleDirectory() + "/pv_equip/skins.ini"; MultiByteToWideChar(CP_UTF8, 0, utf8path.c_str(), -1, skins_configPath, 256); utf8path = TLAC::framework::GetModuleDirectory() + "/pv_equip/sfx.ini"; MultiByteToWideChar(CP_UTF8, 0, utf8path.c_str(), -1, sfx_configPath, 256); } ScoreSaver::~ScoreSaver() { for (int diff = 0; diff < 4; diff++) { *(DivaScore**)(PLAYER_DATA_ADDRESS + diff * 0x18 + 0x5d0) = 0; *(DivaScore**)(PLAYER_DATA_ADDRESS + diff * 0x18 + 0x5d8) = 0; } } const char* ScoreSaver::GetDisplayName() { return "score_saver"; } bool ScoreSaver::initCacheFinished = false; void ScoreSaver::initCache() { // build the score cache UpdateScoreCache(); UpdateClearCounts(); initCacheFinished = true; } bool(__stdcall* ScoreSaver::divaInitResults)(void* cls) = (bool(__stdcall*)(void* cls))RESULTS_INIT_ADDRESS; std::thread ScoreSaver::initThread; void ScoreSaver::Initialize(ComponentsManager*) { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)ScoreSaver::divaInitResults, (PVOID)(ScoreSaver::hookedInitResults)); DetourTransactionCommit(); initThread = std::thread(initCache); } bool ScoreSaver::checkExistingScoreValid(int pv, int difficulty, int isEx) { WCHAR keyBase[32]; // needs to be big enough to store pv.999.diff.3.ex WCHAR key[32]; // needs to be big enough to store pv.999.diff.3.alltimemodifiers const WCHAR section[] = L"scores"; if (isEx == 0) swprintf(keyBase, 32, L"pv.%03d.diff.%01d", pv, difficulty); else swprintf(keyBase, 32, L"pv.%03d.diff.%01d.ex", pv, difficulty); swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); int score = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"notecounts"); WCHAR countsBufW[32]; char countsBufA[32]; int cntHitTypes[2] = { 0, 0 }; GetPrivateProfileStringW(section, key, L"", countsBufW, 32, configPath); WideCharToMultiByte(CP_UTF8, 0, countsBufW, -1, countsBufA, 32, NULL, NULL); std::vector countToks = TLAC::Utilities::Split(countsBufA, ","); if (countToks.size() >= 2) { cntHitTypes[0] = atoi(countToks[0].c_str()); cntHitTypes[1] = atoi(countToks[1].c_str()); } swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); int percent = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"combo"); int combo = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); int clearRank = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); int allTimeRank = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimemodifiers"); int allTimeModifiers = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimepercent"); int allTimePercent = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); int expectedCheck = GetPrivateProfileIntW(section, key, -1, configPath); return expectedCheck == calculateCheck(score, cntHitTypes[0], cntHitTypes[1], percent, combo, clearRank, allTimeRank, allTimeModifiers, allTimePercent); } int ScoreSaver::calculateCheck(int score, int cntCools, int cntFines, int percent, int combo, int clearRank, int allTimeRank, int allTimeModifiers, int allTimePercent) { int checkField = ((short)score ^ ((short)cntCools << 16) ^ ((short)cntFines) ^ ((short)percent << 16) ^ ((short)combo)) * clearRank; checkField += (allTimeRank * clearRank); // first extension checkField ^= (allTimeModifiers * allTimePercent); return checkField; } bool ScoreSaver::hookedInitResults(void* cls) { bool result = divaInitResults(cls); int clearRank = *(int*)(RESULTS_BASE_ADDRESS + 0xe8); byte insurance = *(byte*)(GAME_INFO_ADDRESS + 0x14); if (insurance != 0) return result; // get the base for this specific set of results uint64_t resultBase = *(uint64_t*)(RESULTS_BASE_ADDRESS + 0x100); int pvNum = *(int*)(resultBase + 0x2c); int pvDifficulty = *(int*)(resultBase + 0x34); int pvDifficultyIsEx = *(int*)(resultBase + 0x44); int modifier = *(int*)(resultBase + 0x70); int* cntHitTypes = (int*)(resultBase + 0x158); int* pctHitTypes = (int*)(resultBase + 0x16c); int combo = *(int*)(resultBase + 0x180); int challengeScore = *(int*)(resultBase + 0x184); int holdScore = *(int*)(resultBase + 0x188); int score = *(int*)(resultBase + 0x18c); int percent = *(int*)(resultBase + 0x190); int slideScore = *(int*)(resultBase + 0x194); WCHAR songName[256]; //std::string utf8song = *(std::string*)(CURRENT_SONG_NAME_ADDRESS); uint64_t songnamelen = *(uint64_t*)(CURRENT_SONG_NAME_ADDRESS + 0x18); char* utf8song = songnamelen < 0x10 ? (char*)CURRENT_SONG_NAME_ADDRESS : *(char**)CURRENT_SONG_NAME_ADDRESS; MultiByteToWideChar(CP_UTF8, 0, utf8song, -1, songName, 256); WCHAR keyBase[32]; // needs to be big enough to store pv.999.diff.3.ex WCHAR key[32]; // needs to be big enough to store pv.999.diff.3.alltimemodifiers WCHAR val[32]; // needs to be big enough to store five <=four digit ints (with comma separators) const WCHAR section[] = L"scores"; if (pvDifficultyIsEx == 0) swprintf(keyBase, 32, L"pv.%03d.diff.%01d", pvNum, pvDifficulty); else swprintf(keyBase, 32, L"pv.%03d.diff.%01d.ex", pvNum, pvDifficulty); swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); int oldScore = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); int oldAlltimeRank = GetPrivateProfileIntW(section, key, -1, configPath); if (oldAlltimeRank == -1) // fallback for old scores without alltimerank { swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); oldAlltimeRank = GetPrivateProfileIntW(section, key, 0, configPath); } int allTimeRank = clearRank > oldAlltimeRank ? clearRank : oldAlltimeRank; swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimemodifiers"); int oldAlltimeModifiers = GetPrivateProfileIntW(section, key, -1, configPath); if (oldAlltimeModifiers == -1) // fallback for old scores without alltimemodifiers { swprintf(key, 32, L"%ls.%ls", keyBase, L"modifier"); oldAlltimeModifiers = GetPrivateProfileIntW(section, key, 0, configPath); oldAlltimeModifiers = oldAlltimeModifiers > 0 ? 1 << (oldAlltimeModifiers - 1) : 0; } int allTimeModifiers = oldAlltimeModifiers | ((clearRank > 1 && modifier > 0) ? (1 << (modifier - 1)) : 0); // use clearRank to not update if didn't clear swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimepercent"); int oldAlltimePercent = GetPrivateProfileIntW(section, key, -1, configPath); if (oldAlltimePercent == -1) // fallback for old scores without alltimepercent { swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); oldAlltimePercent = GetPrivateProfileIntW(section, key, 0, configPath); } int allTimePercent = percent > oldAlltimePercent ? percent : oldAlltimePercent; bool oldScoreValid = true; if (!checkExistingScoreValid(pvNum, pvDifficulty, pvDifficultyIsEx)) { oldScore = 0; // ensure new score is written allTimeRank = clearRank; // don't trust old all-time clear rank, use a new one allTimeModifiers = ((clearRank > 1 && modifier > 0) ? (1 << (modifier - 1)) : 0); // don't trust old all-time modifiers, use a new one allTimePercent = percent; // don't trust old all-time percent, use a new one oldScoreValid = false; } if (clearRank > 1 && score > oldScore) { swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimemodifiers"); swprintf(val, 32, L"%d", allTimeModifiers); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimepercent"); swprintf(val, 32, L"%d", allTimePercent); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); swprintf(val, 32, L"%d", allTimeRank); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"challengescore"); swprintf(val, 32, L"%d", challengeScore); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"combo"); swprintf(val, 32, L"%d", combo); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"holdscore"); swprintf(val, 32, L"%d", holdScore); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"modifier"); swprintf(val, 32, L"%d", modifier); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"name"); WritePrivateProfileStringW(section, key, songName, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"notecounts"); swprintf(val, 32, L"%d,%d,%d,%d,%d", cntHitTypes[0], cntHitTypes[1], cntHitTypes[2], cntHitTypes[3], cntHitTypes[4]); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"notepercents"); swprintf(val, 32, L"%d,%d,%d,%d,%d", pctHitTypes[0], pctHitTypes[1], pctHitTypes[2], pctHitTypes[3], pctHitTypes[4]); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); swprintf(val, 32, L"%d", percent); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); swprintf(val, 32, L"%d", clearRank); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); swprintf(val, 32, L"%d", score); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"slidescore"); swprintf(val, 32, L"%d", slideScore); WritePrivateProfileStringW(section, key, val, configPath); int checkField = calculateCheck(score, cntHitTypes[0], cntHitTypes[1], percent, combo, clearRank, allTimeRank, allTimeModifiers, allTimePercent); swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); swprintf(val, 32, L"%d", checkField); WritePrivateProfileStringW(section, key, val, configPath); } else // if (oldScoreValid) { if (allTimeRank != oldAlltimeRank) // first extension { swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); swprintf(val, 32, L"%d", allTimeRank); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); int oldClearRank = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); int oldCheck = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); swprintf(val, 32, L"%d", oldCheck - (oldAlltimeRank * oldClearRank) + (allTimeRank * oldClearRank)); WritePrivateProfileStringW(section, key, val, configPath); } if (allTimeModifiers != oldAlltimeModifiers || allTimePercent != oldAlltimePercent) // second extension { swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimemodifiers"); swprintf(val, 32, L"%d", allTimeModifiers); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimepercent"); swprintf(val, 32, L"%d", allTimePercent); WritePrivateProfileStringW(section, key, val, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); int oldCheck = GetPrivateProfileIntW(section, key, 0, configPath); swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); swprintf(val, 32, L"%d", oldCheck ^ (oldAlltimeModifiers * oldAlltimePercent) ^ (allTimeModifiers * allTimePercent)); WritePrivateProfileStringW(section, key, val, configPath); } } UpdateSingleScoreCacheEntry(pvNum, pvDifficulty, pvDifficultyIsEx, true); if (initCacheFinished) // don't update clear counts if they're not ready yet UpdateClearCounts(); if (didInitialAddressUpdate) // don't set the addresses if they're not ready yet FixScoreCacheAddresses(pvDifficulty); return result; } bool ScoreSaver::didInitialAddressUpdate = false; void ScoreSaver::Update() { // the below stuff is only verified for operating in menus if (*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && (*(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_SELECTOR || *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_SEL)) { if (!didInitialAddressUpdate) { if (initCacheFinished) // check for initThread to be done { // fix the addresses here instead of doing it unsafely in initThread FixScoreCacheAddresses(0); FixScoreCacheAddresses(1); FixScoreCacheAddresses(2); FixScoreCacheAddresses(3); didInitialAddressUpdate = true; } } else { // it probably doesn't really matter whether the initial address update is done first if I add some locks, // but I feel better knowing that there won't be multiple things racing to modify the vector // this does mean that with a lot of scores you can beat the loading into the game, thus not getting the new record banner etc. after a song.... int pvNum = *(int*)SELPV_CURRENT_SONG_ADDRESS; int diff = *(int*)(GAME_INFO_ADDRESS); int diffIsEx = *(int*)(GAME_INFO_ADDRESS + 0x4); byte insurance = *(byte*)(GAME_INFO_ADDRESS + 0x14); if (pvNum != currentPv || diff != currentDifficulty || diffIsEx != currentDifficultyIsEx || insurance != currentInsurance) { DivaScore* cachedScore = GetCachedScore(pvNum, diff, diffIsEx); if (cachedScore == nullptr) { // create a score cache entry if none exists for current song ScoreCache[diff].push_back(DivaScore(pvNum, diffIsEx)); // update score begin and end vars from game FixScoreCacheAddresses(diff); } else { UpdateSingleScoreCacheModulesEntry; } currentPv = pvNum; currentDifficulty = diff; currentDifficultyIsEx = diffIsEx; currentInsurance = insurance; } ModuleCheck(pvNum, diff, diffIsEx); } } } void ScoreSaver::UpdateInput() { return; } void ScoreSaver::InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } std::vector ScoreSaver::ScoreCache[4] = { // * 4 difficulties {}, {}, {}, {} }; ScoreSaver::DivaScore* ScoreSaver::GetCachedScore(int pvNum, int diff, int exDiff) { if (pvNum < 0 || diff < 0 || exDiff < 0 || pvNum > 999 || diff > 3 || exDiff > 1) return nullptr; for (DivaScore &scoreinfo : ScoreCache[diff]) { if (scoreinfo.pvNum == pvNum && scoreinfo.exDifficulty == exDiff) return &scoreinfo; } return nullptr; } void ScoreSaver::UpdateSingleScoreCacheEntry(int pvNum, int diff, int exDiff, bool doDefaultsReset) { if (pvNum < 0 || diff < 0 || exDiff < 0 || pvNum > 999 || diff > 3 || exDiff > 1) return; WCHAR keyBase[32]; // needs to be big enough to store pv.999.diff.3.ex WCHAR key[32]; // needs to be big enough to store pv.999.diff.3.alltimemodifiers const WCHAR section[] = L"scores"; if (exDiff == 0) swprintf(keyBase, 32, L"pv.%03d.diff.%01d", pvNum, diff); else swprintf(keyBase, 32, L"pv.%03d.diff.%01d.ex", pvNum, diff); if (checkExistingScoreValid(pvNum, diff, exDiff)) { swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); int score = GetPrivateProfileIntW(section, key, 0, configPath); if (score > 99999999) score = 99999999; swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimepercent"); int percent = GetPrivateProfileIntW(section, key, -1, configPath); if (percent == -1) // fallback for old scores without alltimepercent { swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); percent = GetPrivateProfileIntW(section, key, 0, configPath); } swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); int allTimeRank = GetPrivateProfileIntW(section, key, -1, configPath); if (allTimeRank == -1) // fallback for old scores without alltimerank { swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); allTimeRank = GetPrivateProfileIntW(section, key, -1, configPath); } swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimemodifiers"); int modifiers = GetPrivateProfileIntW(section, key, -1, configPath); if (modifiers == -1) // fallback for old scores without alltimemodifiers { swprintf(key, 32, L"%ls.%ls", keyBase, L"modifier"); modifiers = GetPrivateProfileIntW(section, key, 0, configPath); modifiers = modifiers > 0 ? 1 << (modifiers - 1) : 0; } DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore == nullptr) { ScoreCache[diff].push_back(DivaScore(pvNum, exDiff)); cachedScore = GetCachedScore(pvNum, diff, exDiff); } if (cachedScore != nullptr) { cachedScore->score = score; cachedScore->percent = percent; cachedScore->clearRank = allTimeRank; if (modifiers & 1) cachedScore->optionA = 1; if (modifiers & 2) cachedScore->optionB = 1; if (modifiers & 4) cachedScore->optionC = 1; } } else if (doDefaultsReset) // reset to defaults if not valid { DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore != nullptr) { cachedScore->score = 0; cachedScore->percent = 0; cachedScore->clearRank = -1; cachedScore->optionA = 0; cachedScore->optionB = 0; cachedScore->optionC = 0; } } } void ScoreSaver::UpdateSingleScoreCacheRivalEntry(int pvNum, int diff, int exDiff) { if (pvNum < 0 || diff < 0 || exDiff < 0 || pvNum > 999 || diff > 3 || exDiff > 1) return; WCHAR keyBase[32]; // needs to be big enough to store pv.999.diff.3.ex WCHAR key[32]; // needs to be big enough to store pv.999.diff.3.alltimemodifiers const WCHAR section[] = L"scores"; if (exDiff == 0) swprintf(keyBase, 32, L"pv.%03d.diff.%01d", pvNum, diff); else swprintf(keyBase, 32, L"pv.%03d.diff.%01d.ex", pvNum, diff); swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); int score = GetPrivateProfileIntW(section, key, 0, rival_configPath); if (score > 99999999) score = 99999999; swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimepercent"); int percent = GetPrivateProfileIntW(section, key, -1, rival_configPath); if (percent == -1) // fallback for old scores without alltimepercent { swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); percent = GetPrivateProfileIntW(section, key, 0, rival_configPath); } swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); int allTimeRank = GetPrivateProfileIntW(section, key, -1, rival_configPath); if (allTimeRank == -1) // fallback for old scores without alltimerank { swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); allTimeRank = GetPrivateProfileIntW(section, key, -1, rival_configPath); } if (score > 0 || percent > 0) { DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore == nullptr) { ScoreCache[diff].push_back(DivaScore(pvNum, exDiff)); cachedScore = GetCachedScore(pvNum, diff, exDiff); } if (cachedScore != nullptr) { cachedScore->rival_clearRank = allTimeRank; cachedScore->rival_score = score; cachedScore->rival_percent = percent; } } } void ScoreSaver::UpdateSingleScoreCacheModulesEntry(int pvNum, int diff, int exDiff) { if (pvNum < 0 || diff < 0 || exDiff < 0 || pvNum > 999 || diff > 3 || exDiff > 1) return; WCHAR keyBase[32]; // needs to be big enough to store pv.999 WCHAR key[32]; // needs to be big enough to store pv.999.module5 const WCHAR section[] = L"modules"; swprintf(keyBase, 32, L"pv.%03d", pvNum); for (int i = 0; i < 6; ++i) { swprintf(key, 32, L"%ls.module%d", keyBase, i); int INImodule = GetPrivateProfileIntW(section, key, 0, modules_configPath); if (INImodule > 0) { DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore == nullptr) { ScoreCache[diff].push_back(DivaScore(pvNum, exDiff)); cachedScore = GetCachedScore(pvNum, diff, exDiff); } if (cachedScore != nullptr) { cachedScore->per_module_equip[i] = INImodule; } } } } void ScoreSaver::ModuleCheck(int pvNum, int diff, int exDiff) { if (pvNum < 0 || diff < 0 || exDiff < 0 || pvNum > 999 || diff > 3 || exDiff > 1) return; WCHAR keyBase[32]; // needs to be big enough to store pv.999 WCHAR key[32]; // needs to be big enough to store pv.999.module5 const WCHAR section[] = L"modules"; swprintf(keyBase, 32, L"pv.%03d", pvNum); DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); for (int i = 0; i < 6; ++i) { swprintf(key, 32, L"%ls.module%d", keyBase, i); int INImodule = GetPrivateProfileIntW(section, key, 0, modules_configPath); if (INImodule != cachedScore->per_module_equip[i]) { INImodule = *cachedScore->per_module_equip; WCHAR val[32]; swprintf(val, 32, L"%d", cachedScore->per_module_equip[i]); WritePrivateProfileStringW(L"modules", key, val, modules_configPath); } } } void ScoreSaver::UpdateSingleScoreCacheSkinsEntry(int pvNum, int diff, int exDiff) { if (pvNum < 0 || diff < 0 || exDiff < 0 || pvNum > 999 || diff > 3 || exDiff > 1) return; WCHAR keyBase[32]; // needs to be big enough to store pv.999 WCHAR key[32]; // needs to be big enough to store pv.999.module5 const WCHAR section[] = L"skins"; swprintf(keyBase, 32, L"pv.%03d", pvNum); swprintf(key, 32, L"%ls.skin", keyBase); int INISkin = GetPrivateProfileIntW(section, key, 0, skins_configPath); if (INISkin > -1) { DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore == nullptr) { ScoreCache[diff].push_back(DivaScore(pvNum, exDiff)); cachedScore = GetCachedScore(pvNum, diff, exDiff); } if (cachedScore != nullptr) { cachedScore->per_skin_equip = INISkin; } } } void ScoreSaver::UpdateSingleScoreCacheSFXEntry(int pvNum, int diff, int exDiff) { if (pvNum < 0 || diff < 0 || exDiff < 0 || pvNum > 999 || diff > 3 || exDiff > 1) return; WCHAR keyBase[32]; // needs to be big enough to store pv.999 WCHAR key[32]; // needs to be big enough to store pv.999.module5 const WCHAR section[] = L"SFX"; swprintf(keyBase, 32, L"pv.%03d", pvNum); swprintf(key, 32, L"%ls.btn", keyBase); int INIBtn = GetPrivateProfileIntW(section, key, 0, sfx_configPath); if (INIBtn > 0) { DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore == nullptr) { ScoreCache[diff].push_back(DivaScore(pvNum, exDiff)); cachedScore = GetCachedScore(pvNum, diff, exDiff); } if (cachedScore != nullptr) { cachedScore->per_btn_se_equip = INIBtn; } } swprintf(keyBase, 32, L"pv.%03d", pvNum); swprintf(key, 32, L"%ls.chain", keyBase); int INIChain = GetPrivateProfileIntW(section, key, 0, sfx_configPath); if (INIChain > 0) { DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore == nullptr) { ScoreCache[diff].push_back(DivaScore(pvNum, exDiff)); cachedScore = GetCachedScore(pvNum, diff, exDiff); } if (cachedScore != nullptr) { cachedScore->per_chainslide_se_equip = INIChain; } } swprintf(keyBase, 32, L"pv.%03d", pvNum); swprintf(key, 32, L"%ls.slide", keyBase); int INISlide = GetPrivateProfileIntW(section, key, 0, sfx_configPath); if (INISlide > 0) { DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore == nullptr) { ScoreCache[diff].push_back(DivaScore(pvNum, exDiff)); cachedScore = GetCachedScore(pvNum, diff, exDiff); } if (cachedScore != nullptr) { cachedScore->per_slide_se_equip = INISlide; } } swprintf(keyBase, 32, L"pv.%03d", pvNum); swprintf(key, 32, L"%ls.touch", keyBase); int INITouch = GetPrivateProfileIntW(section, key, 0, sfx_configPath); if (INITouch > 0) { DivaScore* cachedScore = GetCachedScore(pvNum, diff, exDiff); if (cachedScore == nullptr) { ScoreCache[diff].push_back(DivaScore(pvNum, exDiff)); cachedScore = GetCachedScore(pvNum, diff, exDiff); } if (cachedScore != nullptr) { cachedScore->per_slidertouch_se_equip = INITouch; } } } void ScoreSaver::FixScoreCacheAddresses(int diff) { // update score begin and end vars from game *(DivaScore**)(PLAYER_DATA_ADDRESS + diff * 0x18 + 0x5d0) = ScoreCache[diff].begin()._Ptr; *(DivaScore**)(PLAYER_DATA_ADDRESS + diff * 0x18 + 0x5d8) = ScoreCache[diff].end()._Ptr; } void ScoreSaver::UpdateScoreCache() { for (int pvNum = 0; pvNum < 1000; pvNum++) { for (int diff = 0; diff < 4; diff++) { for (int exDiff = 0; exDiff < 2; exDiff++) { UpdateSingleScoreCacheEntry(pvNum, diff, exDiff, false); UpdateSingleScoreCacheRivalEntry(pvNum, diff, exDiff); UpdateSingleScoreCacheModulesEntry(pvNum, diff, exDiff); UpdateSingleScoreCacheSkinsEntry(pvNum, diff, exDiff); UpdateSingleScoreCacheSFXEntry(pvNum, diff, exDiff); } } } } void ScoreSaver::UpdateClearCounts() { int* counts = (int*)SONG_CLEAR_COUNTS_ADDRESS; for (int i = 0; i < 20; i++) { counts[i] = 0; } for (int diff = 0; diff < 4; diff++) { for (DivaScore &scoreinfo : ScoreCache[diff]) { if (scoreinfo.clearRank > 1 && scoreinfo.clearRank <= 5 && scoreinfo.exDifficulty == 0) // at least clear and no greater than perfect and not ex { counts[diff * 4 + scoreinfo.clearRank - 2] += 1; } } } // exex special case for (DivaScore &scoreinfo : ScoreCache[3]) { if (scoreinfo.clearRank > 1 && scoreinfo.clearRank <= 5 && scoreinfo.exDifficulty == 1) // at least clear and no greater than perfect and IS ex { counts[4 * 4 + scoreinfo.clearRank - 2] += 1; } } // perfects count as clears for <= excellent, etc for (int diff = 0; diff < 5; diff++) { counts[diff * 4 + 2] += counts[diff * 4 + 3]; counts[diff * 4 + 1] += counts[diff * 4 + 2]; counts[diff * 4 + 0] += counts[diff * 4 + 1]; } } } ================================================ FILE: source-code/source/plugins/TLAC/Components/ScoreSaver.h ================================================ #pragma once #include "EmulatorComponent.h" #include "../Constants.h" #include #include #include namespace TLAC::Components { class ScoreSaver : public EmulatorComponent { public: ScoreSaver(); ~ScoreSaver(); virtual const char* GetDisplayName() override; virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdateInput() override; struct DivaScore { int pvNum; int exDifficulty; int per_module_equip[6]; int other_module_shit[30]; // ??? -- seems to be 6*6 ints (0x90 bytes) for modules + 5 ints (0x14 bytes) for skin and button se int per_skin_equip; int per_btn_se_equip; int per_slide_se_equip; int per_chainslide_se_equip; int per_slidertouch_se_equip; int clearRank; // +0xac: clear rank int score; // +0xb0: score int percent; // +0xb4: best percent byte paddingB8[0x14]; // ??? -- challenge_kind, chain_challenge_flag, chain_challenge_num, chain_challenge_max, challenge_ng_flag int rival_clearRank; // +0xcc: rival clear rank? int rival_score; // +0xd0: rival score int rival_percent; // +0xd4: rival percent byte paddingD8[0x9]; // ??? -- interim_ranking int? byte optionA; // +0xe1: gamemode options byte optionB; byte optionC; inline bool operator==(const DivaScore& cmp) { return cmp.pvNum == pvNum && cmp.exDifficulty == exDifficulty; } DivaScore(int pv, int exDiff) { // this is just copied from 140113510 // no clue what most of it is pvNum = pv; exDifficulty = exDiff; *(int*)((uint64_t)this + 0x08) = 0; *(int*)((uint64_t)this + 0x0c) = 0; *(int*)((uint64_t)this + 0x10) = 0; *(int*)((uint64_t)this + 0x14) = 0; *(int*)((uint64_t)this + 0x18) = 0; *(int*)((uint64_t)this + 0x1c) = 0; *(long long*)((uint64_t)this + 0x20) = -1; *(long long*)((uint64_t)this + 0x28) = -1; *(long long*)((uint64_t)this + 0x30) = -1; *(long long*)((uint64_t)this + 0x38) = -1; *(long long*)((uint64_t)this + 0x40) = -1; *(long long*)((uint64_t)this + 0x48) = -1; *(long long*)((uint64_t)this + 0x50) = -1; *(long long*)((uint64_t)this + 0x58) = -1; *(long long*)((uint64_t)this + 0x60) = -1; *(long long*)((uint64_t)this + 0x68) = -1; *(long long*)((uint64_t)this + 0x70) = -1; *(long long*)((uint64_t)this + 0x78) = -1; *(int*)((uint64_t)this + 0x80) = 0x01010101; *(int*)((uint64_t)this + 0x84) = 0x01010101; *(int*)((uint64_t)this + 0x88) = 0x01010101; *(int*)((uint64_t)this + 0x8c) = 0x01010101; *(int*)((uint64_t)this + 0x90) = 0x01010101; *(int*)((uint64_t)this + 0x94) = 0x01010101; *(int*)((uint64_t)this + 0x98) = 0; *(long long*)((uint64_t)this + 0x9c) = -1; *(long long*)((uint64_t)this + 0xa4) = -1; *(int*)((uint64_t)this + 0xac) = -1; *(long long*)((uint64_t)this + 0xb0) = 0; *(int*)((uint64_t)this + 0xb8) = -1; *(byte*)((uint64_t)this + 0xbc) = 0; *(long long*)((uint64_t)this + 0xc0) = -1; *(byte*)((uint64_t)this + 0xc8) = 0; *(int*)((uint64_t)this + 0xcc) = -1; *(long long*)((uint64_t)this + 0xd0) = 0; *(int*)((uint64_t)this + 0xd8) = -1; *(byte*)((uint64_t)this + 0xdc) = 0; *(byte*)((uint64_t)this + 0xdd) = 0; *(byte*)((uint64_t)this + 0xde) = 0; *(byte*)((uint64_t)this + 0xdf) = 0; *(byte*)((uint64_t)this + 0xe0) = 0; *(byte*)((uint64_t)this + 0xe1) = 0; *(byte*)((uint64_t)this + 0xe2) = 0; *(byte*)((uint64_t)this + 0xe3) = 0; } DivaScore() { DivaScore(0, 0); } }; static std::vector ScoreCache[4]; // * 4 difficulties static void UpdateScoreCache(); static void UpdateSingleScoreCacheEntry(int pvNum, int diff, int exDiff, bool doDefaultsReset); static void UpdateSingleScoreCacheRivalEntry(int pvNum, int diff, int exDiff); static void UpdateSingleScoreCacheModulesEntry(int pvNum, int diff, int exDiff); static void UpdateSingleScoreCacheSkinsEntry(int pvNum, int diff, int exDiff); static void UpdateSingleScoreCacheSFXEntry(int pvNum, int diff, int exDiff); static void FixScoreCacheAddresses(int diff); // only call this from the main thread static DivaScore* GetCachedScore(int pvNum, int diff, int exDiff); static void UpdateClearCounts(); static void ModuleCheck(int pvNum, int diff, int exDiff); private: static bool(__stdcall* divaInitResults)(void* cls); static bool hookedInitResults(void* cls); static void InjectCode(void* address, const std::vector data); static void initCache(); static bool checkExistingScoreValid(int pv, int difficulty, int isEx); static int calculateCheck(int score, int cntCools, int cntFines, int percent, int combo, int clearRank, int allTimeRank, int allTimeModifiers, int allTimePercent); static WCHAR configPath[256]; static WCHAR rival_configPath[256]; static WCHAR modules_configPath[256]; static WCHAR skins_configPath[256]; static WCHAR sfx_configPath[256]; static std::thread initThread; int currentPv; int currentDifficulty; int currentDifficultyIsEx; byte currentInsurance; static bool initCacheFinished; static bool didInitialAddressUpdate; }; } ================================================ FILE: source-code/source/plugins/TLAC/Constants.h ================================================ #pragma once #include constexpr uint8_t NOP_OPCODE = 0x90; constexpr uint8_t RET_OPCODE = 0xC3; constexpr uint8_t JMP_OPCODE = 0xE9; constexpr uint8_t JNE_OPCODE = 0x85; //constexpr uint64_t ENGINE_UPDATE_HOOK_TARGET_ADDRESS = 0x000000014018CC40; constexpr uint64_t ENGINE_UPDATE_INPUT_ADDRESS = 0x000000014018CBB0; constexpr uint64_t ENGINE_STAGE_DISP_SHADOW_ADDRESS = 0x0000000140649840; constexpr uint64_t ENGINE_FINISH_DRAW_ADDRESS = 0x0000000140192730; constexpr uint64_t CURRENT_GAME_STATE_ADDRESS = 0x0000000140EDA810; constexpr uint64_t CURRENT_GAME_SUB_STATE_ADDRESS = 0x0000000140EDA82C; constexpr uint64_t RESOLUTION_WIDTH_ADDRESS = 0x0000000140EDA8BC; constexpr uint64_t RESOLUTION_HEIGHT_ADDRESS = 0x0000000140EDA8C0; constexpr uint64_t SYSTEM_WARNING_ELAPSED_ADDRESS = (0x00000001411A1430 + 0x68); constexpr uint64_t DATA_INIT_STATE_ADDRESS = 0x0000000140EDA7A8; constexpr uint64_t AET_FRAME_DURATION_ADDRESS = 0x00000001409A0A58; constexpr uint64_t PV_FRAME_RATE_ADDRESS = 0x0000000140EDA7CC; constexpr uint64_t FRAME_SPEED_ADDRESS = 0x0000000140EDA798; constexpr uint64_t FRAME_RATE_ADDRESS = 0x0000000140EDA6D0; constexpr uint64_t USE_AUTO_FRAMESPEED_ADDRESS = 0x0000000140EDA79C; constexpr uint64_t AUTO_FRAMESPEED_TARGET_FRAMERATE_ADDRESS = 0x0000000140EDA6CC; constexpr uint64_t DW_GUI_DISPLAY_INSTANCE_PTR_ADDRESS = 0x0000000141190108; constexpr uint64_t INPUT_STATE_PTR_ADDRESS = 0x0000000140EDA330; constexpr uint64_t SLIDER_CTRL_TASK_ADDRESS = 0x000000014CC5DE40; constexpr uint64_t TASK_TOUCH_ADDRESS = 0x000000014CC9EC30; constexpr uint64_t SEL_PV_TIME_ADDRESS = 0x000000014CC12498; constexpr uint64_t PLAYER_DATA_ADDRESS = 0x00000001411A8850; constexpr uint64_t SET_DEFAULT_PLAYER_DATA_ADDRESS = 0x00000001404A7370; constexpr uint64_t PLAYS_PER_SESSION_GETTER_ADDRESS = 0x000000014038AEE0; constexpr uint64_t PV_SEL_SLOTS_TO_SCROLL = 0x000000014CC12470; constexpr uint64_t PV_SEL_SLOTS_CONST = 0x000000014CC119C8; constexpr uint64_t MODULE_SEL_SLOTS_TO_SCROLL = 0x00000001418047EC; constexpr uint64_t MODULE_IS_RECOMMENDED = 0x00000001418047E0; constexpr uint64_t CAMERA_ADDRESS = 0x0000000140FBC2C0; constexpr uint64_t CAMERA_POS_SETTER_ADDRESS = 0x00000001401F9460; constexpr uint64_t CAMERA_INTR_SETTER_ADDRESS = 0x00000001401F93F0; constexpr uint64_t CAMERA_ROT_SETTER_ADDRESS = 0x00000001401F9480; constexpr uint64_t CAMERA_PERS_SETTER_ADDRESS = 0x00000001401F9430; constexpr uint64_t UPDATE_TASKS_ADDRESS = 0x000000014019B980; constexpr uint64_t GLUT_SET_CURSOR_ADDRESS = 0x00000001408B68E6; constexpr uint64_t CHANGE_MODE_ADDRESS = 0x00000001401953D0; constexpr uint64_t CHANGE_SUB_MODE_ADDRESS = 0x0000000140195260; constexpr uint64_t TGT_CLASS_ADDRESS = 0x0000000140D0B660; constexpr uint64_t TGT_STATES_FIRST_POINTER_ADDRESS = 0x0000000140D0B680; constexpr uint64_t TGT_STATES_BASE_ADDRESS = 0x0000000140D0B688; constexpr uint64_t TGT_ON_SCREEN_ADDRESS = 0x0000000140D0B678; constexpr uint64_t HOLD_STATE_ADDRESS = 0x0000000140D1E20C; constexpr uint64_t MAX_HOLD_STATE_ADDRESS = 0x0000000140D1E234; constexpr uint64_t CHECK_SOMETHING_SET_MODULE_ADDRESS = 0x0000000140581C78; constexpr uint64_t MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS = 0x00000001405869AD; constexpr uint64_t MODSELECTOR_CLOSE_AFTER_MODULE = 0x0000000140583B45; constexpr uint64_t MODSELECTOR_CLOSE_AFTER_CUSTOMIZE = 0x0000000140583C8C; constexpr uint64_t MODULE_TABLE_START = PLAYER_DATA_ADDRESS + 0x140; constexpr uint64_t MODULE_TABLE_END = MODULE_TABLE_START + 128; constexpr uint64_t ITEM_TABLE_START = PLAYER_DATA_ADDRESS + 0x2B8; constexpr uint64_t ITEM_TABLE_END = ITEM_TABLE_START + 128; constexpr uint64_t FB_WIDTH_ADDRESS = 0x00000001411ABCA8; constexpr uint64_t FB_HEIGHT_ADDRESS = 0x00000001411ABCAC; constexpr uint64_t FB1_WIDTH_ADDRESS = 0x00000001411AD5F8; constexpr uint64_t FB1_HEIGHT_ADDRESS = 0x00000001411AD5FC; constexpr uint64_t FB2_WIDTH_ADDRESS = 0x0000000140EDA8E4; constexpr uint64_t FB2_HEIGHT_ADDRESS = 0x0000000140EDA8E8; constexpr uint64_t FB_RESOLUTION_WIDTH_ADDRESS = 0x00000001411ABB50; constexpr uint64_t FB_RESOLUTION_HEIGHT_ADDRESS = 0x00000001411ABB54; constexpr uint64_t UI_WIDTH_ADDRESS = 0x000000014CC621E4; constexpr uint64_t UI_HEIGHT_ADDRESS = 0x000000014CC621E8; constexpr uint64_t FB_ASPECT_RATIO = 0x0000000140FBC2E8; constexpr uint64_t UI_ASPECT_RATIO = 0x000000014CC621D0; constexpr uint64_t GET_SLIDER_TAPPED_ADDRESS = 0x0000000140618C60; constexpr uint64_t GET_SLIDER_RELEASED_ADDRESS = 0x0000000140618C40; constexpr uint64_t GET_SLIDER_DOWN_ADDRESS = 0x0000000140618C20; constexpr uint64_t SHOULD_EXIT_BOOL_ADDRESS = 0x0000000140EDA6B0; constexpr uint64_t DOEXIT_ADDRESS = 0x000000014085B574; constexpr uint64_t RESULTS_INIT_ADDRESS = 0x000000014065BBC0; constexpr uint64_t RESULTS_BASE_ADDRESS = 0x000000014CC93830; constexpr uint64_t GAME_INFO_ADDRESS = 0x0000000141197E00; constexpr uint64_t CURRENT_SONG_NAME_ADDRESS = 0x0000000140D0A578; constexpr uint64_t CURRENT_SONG_ID_ADDRESS = 0x0000000140CDD8E0; constexpr uint64_t SELPV_CURRENT_SONG_ADDRESS = 0x000000014CC12438; constexpr uint64_t SONG_CLEAR_COUNTS_ADDRESS = 0x00000001411A95E8; constexpr uint64_t AUDIO_MAIN_CLASS_ADDRESS = 0x000000014CC61120; constexpr uint64_t DSC_TIME_ADDRESS = 0x0000000140D0B518; constexpr uint64_t DSC_START_FROM_TIME_ADDRESS = 0x0000000140D0B540; constexpr uint64_t DSC_START_SYS_TIME_ADDRESS = 0x0000000140D0B548; constexpr uint64_t DSC_TIME_ADDRESS_2 = 0x0000000140D0B520; constexpr uint64_t DSC_START_FROM_TIME_ADDRESS_2 = 0x0000000140D0B560; constexpr uint64_t DSC_START_SYS_TIME_ADDRESS_2 = 0x0000000140D0B568; constexpr uint64_t DSC_PAUSE_FUNC_ADDRESS = 0x00000001401295C0; constexpr uint64_t DSC_UNPAUSE_FUNC_ADDRESS = 0x0000000140129590; constexpr uint64_t DSC_POSITION_ADDRESS = 0x0000000140D098A4; constexpr uint64_t DSC_TIME_RESET_ADDRESS = 0x0000000140D0B538; constexpr uint64_t DSC_TIME_RESET_ADDRESS_2 = 0x0000000140D0B512; constexpr uint64_t DSC_TIME_RESET_FLAG_1 = 0x0000000140CDD7D0; constexpr uint64_t DSC_TIME_RESET_FLAG_2 = 0x0000000140CDD7D4; constexpr uint64_t PV_GAME_BASE_ADDRESS = 0x000000014CC95270; constexpr uint64_t GIVEUP_FUNC_ADDRESS = 0x000000014010EF00; constexpr uint64_t PV_STATE_ADDRESS = 0x0000000140D0B512; constexpr uint64_t PV_LOADING_STATE_ADDRESS = 0x0000000140D0B524; constexpr uint64_t PV_INNER_LOADING_STATE_ADDRESS = 0x0000000140CDD8D8; constexpr uint64_t AET_DEBUG_ARRAY_POINTER_ADDRESS = 0x0000000140EC5430 + 0x98; constexpr uint64_t AET_ARRAY_POINTER_ADDRESS = 0x0000000140EC5430 + 0xD8; #define XINPUT_A 0x00 #define XINPUT_B 0x01 #define XINPUT_X 0x02 #define XINPUT_Y 0x03 #define XINPUT_UP 0x10 #define XINPUT_DOWN 0x11 #define XINPUT_LEFT 0x12 #define XINPUT_RIGHT 0x13 #define XINPUT_LS 0x20 #define XINPUT_RS 0x21 #define XINPUT_LT 0x22 #define XINPUT_RT 0x23 #define XINPUT_LSB 0x24 #define XINPUT_RSB 0x25 #define XINPUT_START 0x30 #define XINPUT_BACK 0x31 #define XINPUT_LUP 0x40 #define XINPUT_LDOWN 0x41 #define XINPUT_LLEFT 0x42 #define XINPUT_LRIGHT 0x43 #define XINPUT_RUP 0x50 #define XINPUT_RDOWN 0x51 #define XINPUT_RLEFT 0x52 #define XINPUT_RRIGHT 0x53 ================================================ FILE: source-code/source/plugins/TLAC/FileSystem/ConfigFile.cpp ================================================ #include #include "ConfigFile.h" #include "../Utilities/Operations.h" namespace TLAC::FileSystem { ConfigFile::ConfigFile(const std::string &path) : TextFile(path) { return; } ConfigFile::ConfigFile(const std::string &directory, const std::string &file) : TextFile(directory, file) { return; } bool ConfigFile::TryGetValue(const std::string &key, std::string **value) { auto pair = ConfigMap.find(key); bool found = pair != ConfigMap.end(); *value = found ? new std::string(pair->second) : nullptr; return found; } int ConfigFile::GetIntegerValue(const std::string& key, int defaultval) { auto pair = ConfigMap.find(key); bool found = pair != ConfigMap.end(); return found ? atoi(pair->second.c_str()) : defaultval; } bool ConfigFile::GetBooleanValue(const std::string& key) { auto pair = ConfigMap.find(key); bool found = pair != ConfigMap.end(); return found ? pair->second == "true" : false; } float ConfigFile::GetFloatValue(const std::string & key) { auto pair = ConfigMap.find(key); bool found = pair != ConfigMap.end(); return found ? (float)atof(pair->second.c_str()) : 0.0f; } std::string ConfigFile::GetStringValue(const std::string& key) { auto pair = ConfigMap.find(key); bool found = pair != ConfigMap.end(); return found ? pair->second : ""; } void ConfigFile::Parse(std::ifstream &fileStream) { std::string line; // check for BOM std::getline(fileStream, line); if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0) fileStream.seekg(3); else fileStream.seekg(0); while (std::getline(fileStream, line)) { if (IsComment(line)) continue; auto splitline = Utilities::Split(line, "="); if (splitline.size() < 2) continue; for (auto &line : splitline) Utilities::Trim(line); ConfigMap.insert(std::make_pair(splitline[0], splitline[1])); } } bool ConfigFile::IsComment(const std::string &line) { return line.size() <= 0 || line[0] == '#' || line[0] == '[' || (line.size() >= 2 && line.rfind("//", 0) == 0); } } ================================================ FILE: source-code/source/plugins/TLAC/FileSystem/ConfigFile.h ================================================ #pragma once #include "TextFile.h" #include namespace TLAC::FileSystem { class ConfigFile : public TextFile { public: ConfigFile(const std::string &path); ConfigFile(const std::string &directory, const std::string &file); std::unordered_map ConfigMap; bool TryGetValue(const std::string &key, std::string **value); int GetIntegerValue(const std::string& key, int defaultval = 0); bool GetBooleanValue(const std::string& key); float GetFloatValue(const std::string& key); std::string GetStringValue(const std::string& key); protected: virtual void Parse(std::ifstream &fileStream) override; private: bool IsComment(const std::string &line); }; } ================================================ FILE: source-code/source/plugins/TLAC/FileSystem/TextFile.cpp ================================================ #include "TextFile.h" #include namespace fs = std::filesystem; namespace TLAC::FileSystem { TextFile::TextFile(const std::string &path) { FileName = path; } TextFile::TextFile(const std::string &directory, const std::string &file) { auto fullPath = directory + "/" + file; FileName = fullPath; } TextFile::~TextFile() { } bool TextFile::OpenRead() { fs::path configPath = fs::u8path(FileName); if (!fs::exists(configPath)) return false; std::ifstream fileStream(configPath.wstring().c_str()); if (!fileStream.is_open()) return false; Parse(fileStream); fileStream.close(); return true; } } ================================================ FILE: source-code/source/plugins/TLAC/FileSystem/TextFile.h ================================================ #pragma once #include #include namespace TLAC::FileSystem { class TextFile { public: std::string FileName; TextFile(const std::string &path); TextFile(const std::string &directory, const std::string &file); ~TextFile(); bool OpenRead(); protected: virtual void Parse(std::ifstream &fileStream) = 0; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/Binding.cpp ================================================ #include "Binding.h" namespace TLAC::Input { Binding::Binding() { } Binding::~Binding() { for (auto& binding : InputBindings) delete binding; } void Binding::AddBinding(IInputBinding* inputBinding) { InputBindings.push_back(inputBinding); } bool Binding::AnyDown() { int i = 0; for (const auto& binding : InputBindings) { // If an old input is still held down, don't register it, only a new input is allowed. if (binding->IsDown() && (this->lastDownId == i || binding->BypassTransferCheck())) return true; i++; } return false; } bool Binding::AnyTapped() { int i = 0; for (const auto& binding : InputBindings) { if (binding->IsTapped()) { // This saves the last button id to a variable, so that it's known as the last input registered (see AnyDown()). this->lastDownId = i; return true; } i++; } return false; } bool Binding::AnyReleased() { for (const auto& binding : InputBindings) { if (binding->IsReleased()) return true; } return false; } int Binding::GetDownCount() { int count = 0; for (const auto& binding : InputBindings) { if (binding->IsDown()) count++; } return count; } int Binding::GetTappedCount() { int count = 0; for (const auto& binding : InputBindings) { if (binding->IsTapped()) count++; } return count; } int Binding::GetReleasedCount() { int count = 0; for (const auto& binding : InputBindings) { if (binding->IsReleased()) count++; } return count; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/Binding.h ================================================ #pragma once #include #include "IInputBinding.h" namespace TLAC::Input { class Binding { // Used in down & tapped events int lastDownId = -1; public: std::vector InputBindings; Binding(); ~Binding(); void AddBinding(IInputBinding* inputBinding); bool AnyDown(); bool AnyTapped(); bool AnyReleased(); int GetDownCount(); int GetTappedCount(); int GetReleasedCount(); }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/DVLBinding.cpp ================================================ #include "DVLBinding.h" namespace TLAC::Input { #define DivallerInstanceCheckDefault(checkFunc) (Divaller::InstanceInitialized() ? Divaller::GetInstance()->checkFunc : false) DivallerBinding::DivallerBinding(DivallerButton button) : Button(button) { } DivallerBinding::~DivallerBinding() { } bool DivallerBinding::BypassTransferCheck() { return false; } bool DivallerBinding::IsDown() { return DivallerInstanceCheckDefault(IsDown(Button)); } bool DivallerBinding::IsTapped() { return DivallerInstanceCheckDefault(IsTapped(Button)); } bool DivallerBinding::IsReleased() { return DivallerInstanceCheckDefault(IsReleased(Button)); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/DVLBinding.h ================================================ #pragma once #include "IInputBinding.h" #include "../Divaller/Divaller.h" namespace TLAC::Input { class DivallerBinding : public IInputBinding { public: DivallerButton Button; DivallerBinding(DivallerButton button); ~DivallerBinding(); bool BypassTransferCheck() override; bool IsDown() override; bool IsTapped() override; bool IsReleased() override; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/Ds4Binding.cpp ================================================ #include "Ds4Binding.h" namespace TLAC::Input { #define Ds4InstanceCheckDefault(checkFunc) (DualShock4::InstanceInitialized() ? DualShock4::GetInstance()->checkFunc : false) Ds4Binding::Ds4Binding(Ds4Button button) : Button(button) { } Ds4Binding::~Ds4Binding() { } bool Ds4Binding::BypassTransferCheck() { return false; } bool Ds4Binding::IsDown() { return Ds4InstanceCheckDefault(IsDown(Button)); } bool Ds4Binding::IsTapped() { return Ds4InstanceCheckDefault(IsTapped(Button)); } bool Ds4Binding::IsReleased() { return Ds4InstanceCheckDefault(IsReleased(Button)); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/Ds4Binding.h ================================================ #pragma once #include "IInputBinding.h" #include "../DirectInput/Ds4/DualShock4.h" namespace TLAC::Input { class Ds4Binding : public IInputBinding { public: Ds4Button Button; Ds4Binding(Ds4Button button); ~Ds4Binding(); bool BypassTransferCheck() override; bool IsDown() override; bool IsTapped() override; bool IsReleased() override; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/GuBinding.cpp ================================================ #include "GuBinding.h" namespace TLAC::Input { #define GuInstanceCheckDefault(checkFunc) (GenericUsbInput::InstanceInitialized() ? GenericUsbInput::GetInstance()->checkFunc : false) GuBinding::GuBinding(GuButton button) : Button(button) { } GuBinding::~GuBinding() { } bool GuBinding::BypassTransferCheck() { return false; } bool GuBinding::IsDown() { return GuInstanceCheckDefault(IsDown(Button)); } bool GuBinding::IsTapped() { return GuInstanceCheckDefault(IsTapped(Button)); } bool GuBinding::IsReleased() { return GuInstanceCheckDefault(IsReleased(Button)); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/GuBinding.h ================================================ #pragma once #include "IInputBinding.h" #include "../DirectInput/GenericUsb/GenericUsbInput.h" namespace TLAC::Input { class GuBinding : public IInputBinding { public: GuButton Button; GuBinding(GuButton button); ~GuBinding(); bool BypassTransferCheck() override; bool IsDown() override; bool IsTapped() override; bool IsReleased() override; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/IInputBinding.h ================================================ #pragma once namespace TLAC::Input { class IInputBinding { public: virtual bool BypassTransferCheck() = 0; virtual bool IsDown() = 0; virtual bool IsTapped() = 0; virtual bool IsReleased() = 0; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/KeyboardBinding.cpp ================================================ #include "KeyboardBinding.h" namespace TLAC::Input { KeyboardBinding::KeyboardBinding(BYTE keycode, bool bypassTransferCheck) : Keycode(keycode), SetBypassTransferCheck(bypassTransferCheck) { } KeyboardBinding::~KeyboardBinding() { } bool KeyboardBinding::BypassTransferCheck() { return SetBypassTransferCheck; } bool KeyboardBinding::IsDown() { return Keyboard::GetInstance()->IsDown(Keycode); } bool KeyboardBinding::IsTapped() { return Keyboard::GetInstance()->IsTapped(Keycode); } bool KeyboardBinding::IsReleased() { return Keyboard::GetInstance()->IsReleased(Keycode); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/KeyboardBinding.h ================================================ #pragma once #include "IInputBinding.h" #include "../Keyboard/Keyboard.h" namespace TLAC::Input { class KeyboardBinding : public IInputBinding { public: BYTE Keycode; bool SetBypassTransferCheck; KeyboardBinding(BYTE keycode, bool bypassTransferCheck = false); ~KeyboardBinding(); bool BypassTransferCheck() override; bool IsDown() override; bool IsTapped() override; bool IsReleased() override; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/MouseBinding.cpp ================================================ #include "MouseBinding.h" #include "../Keyboard/Keyboard.h" namespace TLAC::Input { MouseBinding::MouseBinding(MouseAction action) : Action(action) { } MouseBinding::~MouseBinding() { } bool MouseBinding::IsDown() { switch (Action) { case MouseAction_LeftButton: return Keyboard::GetInstance()->IsDown(MK_LBUTTON); case MouseAction_RightButton: return Keyboard::GetInstance()->IsDown(MK_RBUTTON); case MouseAction_MiddleButton: return Keyboard::GetInstance()->IsDown(MK_MBUTTON); case MouseAction_ScrollUp: return Mouse::GetInstance()->GetIsScrolledUp(); case MouseAction_ScrollDown: return Mouse::GetInstance()->GetIsScrolledDown(); default: return false; } } bool MouseBinding::IsTapped() { switch (Action) { case MouseAction_LeftButton: return Keyboard::GetInstance()->IsTapped(MK_LBUTTON); case MouseAction_RightButton: return Keyboard::GetInstance()->IsTapped(MK_RBUTTON); case MouseAction_MiddleButton: return Keyboard::GetInstance()->IsTapped(MK_MBUTTON); case MouseAction_ScrollUp: return Mouse::GetInstance()->GetIsScrolledUp(); case MouseAction_ScrollDown: return Mouse::GetInstance()->GetIsScrolledDown(); default: return false; } } bool MouseBinding::IsReleased() { switch (Action) { case MouseAction_LeftButton: return Keyboard::GetInstance()->IsReleased(MK_LBUTTON); case MouseAction_RightButton: return Keyboard::GetInstance()->IsReleased(MK_RBUTTON); case MouseAction_MiddleButton: return Keyboard::GetInstance()->IsReleased(MK_MBUTTON); case MouseAction_ScrollUp: return Mouse::GetInstance()->GetWasScrolledUp(); case MouseAction_ScrollDown: return Mouse::GetInstance()->GetWasScrolledDown(); default: return false; } } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/MouseBinding.h ================================================ #pragma once #include "IInputBinding.h" #include "../Mouse/Mouse.h" namespace TLAC::Input { enum MouseAction { MouseAction_LeftButton, MouseAction_RightButton, MouseAction_MiddleButton, MouseAction_ScrollUp, MouseAction_ScrollDown, }; class MouseBinding : public IInputBinding { public: MouseAction Action; MouseBinding(MouseAction action); ~MouseBinding(); bool IsDown() override; bool IsTapped() override; bool IsReleased() override; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/XinputBinding.cpp ================================================ #include "XinputBinding.h" #include "..\Xinput\Xinput.h" namespace TLAC::Input { XinputBinding::XinputBinding(BYTE keycode) : Keycode(keycode) { } XinputBinding::~XinputBinding() { } bool XinputBinding::BypassTransferCheck() { return false; } bool XinputBinding::IsDown() { return Xinput::GetInstance()->IsDown(Keycode); } bool XinputBinding::IsTapped() { return Xinput::GetInstance()->IsTapped(Keycode); } bool XinputBinding::IsReleased() { return Xinput::GetInstance()->IsReleased(Keycode); } bool XinputBinding::IsDoubleTapped() { return Xinput::GetInstance()->IsDoubleTapped(Keycode); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Bindings/XinputBinding.h ================================================ #pragma once #include "IInputBinding.h" #include #include namespace TLAC::Input { class XinputBinding : public IInputBinding { public: BYTE Keycode; XinputBinding(BYTE keycode); ~XinputBinding(); bool BypassTransferCheck() override; bool IsDown() override; bool IsTapped() override; bool IsReleased() override; bool IsDoubleTapped(); }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/Controller.cpp ================================================ #include "Controller.h" namespace TLAC::Input { Controller::Controller() { } Controller::~Controller() { } } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/Controller.h ================================================ #pragma once #include "DirectInputDevice.h" namespace TLAC::Input { class Controller : public DirectInputDevice { protected: Controller(); ~Controller(); }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/DirectInput.cpp ================================================ #include "DirectInput.h" namespace TLAC::Input { IDirectInput8 *IDirectInputInstance = nullptr; HRESULT InitializeDirectInput(HMODULE module) { HRESULT result = DirectInput8Create(module, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&IDirectInputInstance, nullptr); return result; } bool DirectInputInitialized() { return IDirectInputInstance != nullptr; } void DisposeDirectInput() { if (IDirectInputInstance == nullptr) return; IDirectInputInstance->Release(); IDirectInputInstance = nullptr; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/DirectInput.h ================================================ #pragma once #define DIRECTINPUT_VERSION 0x0800 #include namespace TLAC::Input { extern IDirectInput8 *IDirectInputInstance; HRESULT InitializeDirectInput(HMODULE module); bool DirectInputInitialized(); void DisposeDirectInput(); } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/DirectInputDevice.cpp ================================================ #include "DirectInputDevice.h" namespace TLAC::Input { HRESULT DirectInputDevice::DI_CreateDevice(const GUID &guid) { if (!DirectInputInitialized()) return DIERR_NOTINITIALIZED; HRESULT result = IDirectInputInstance->CreateDevice(guid, &directInputdevice, NULL); return result; } HRESULT DirectInputDevice::DI_SetDataFormat(LPCDIDATAFORMAT dataFormat) { HRESULT result = directInputdevice->SetDataFormat(dataFormat); return result; } HRESULT DirectInputDevice::DI_SetCooperativeLevel(HWND windowHandle, DWORD flags) { HRESULT result = directInputdevice->SetCooperativeLevel(windowHandle, flags); return result; } HRESULT DirectInputDevice::DI_Acquire() { HRESULT result = directInputdevice->Acquire(); return result; } HRESULT DirectInputDevice::DI_Unacquire() { HRESULT result = directInputdevice->Unacquire(); return result; } HRESULT DirectInputDevice::DI_Release() { HRESULT result = directInputdevice->Release(); return result; } HRESULT DirectInputDevice::DI_Poll() { HRESULT result = directInputdevice->Poll(); return result; } HRESULT DirectInputDevice::DI_GetDeviceState(DWORD size, LPVOID data) { HRESULT result = directInputdevice->GetDeviceState(size, data); return result; } HRESULT DirectInputDevice::DI_SetRange(LONG min, LONG max) { DIPROPRANGE propData; propData.lMin = min; propData.lMax = max; propData.diph.dwSize = sizeof(DIPROPRANGE); propData.diph.dwHeaderSize = sizeof(DIPROPHEADER); propData.diph.dwHow = DIPH_DEVICE; propData.diph.dwObj = 0; HRESULT result = directInputdevice->SetProperty(DIPROP_RANGE, &propData.diph); return result; } HRESULT DirectInputDevice::DI_SetRawMode(BOOL raw) { // extra unacquire/acquire logic so this can be called on an active device BOOL wasAcquired = DI_Unacquire() == DI_OK; DIPROPDWORD propData; propData.dwData = raw ? DIPROPCALIBRATIONMODE_RAW : DIPROPCALIBRATIONMODE_COOKED; propData.diph.dwSize = sizeof(DIPROPDWORD); propData.diph.dwHeaderSize = sizeof(DIPROPHEADER); propData.diph.dwHow = DIPH_DEVICE; propData.diph.dwObj = 0; HRESULT result = NULL; if (FAILED(result = directInputdevice->SetProperty(DIPROP_CALIBRATIONMODE, &propData.diph))) return result; if (wasAcquired) result = DI_Acquire(); return result; } void DirectInputDevice::DI_Dispose() { if (directInputdevice == nullptr) return; HRESULT result = NULL; result = DI_Unacquire(); result = DI_Release(); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/DirectInputDevice.h ================================================ #pragma once #include "DirectInput.h" namespace TLAC::Input { class DirectInputDevice { protected: IDirectInputDevice8 *directInputdevice; HRESULT DI_CreateDevice(const GUID& guid); HRESULT DI_SetDataFormat(LPCDIDATAFORMAT dataFormat); HRESULT DI_SetCooperativeLevel(HWND windowHandle, DWORD flags); HRESULT DI_Acquire(); HRESULT DI_Unacquire(); HRESULT DI_Release(); HRESULT DI_Poll(); HRESULT DI_GetDeviceState(DWORD size, LPVOID data); HRESULT DI_SetRange(LONG min, LONG max); HRESULT DI_SetRawMode(BOOL raw); void DI_Dispose(); }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/DirectInputMouse.cpp ================================================ #include "DirectInputMouse.h" namespace TLAC::Input { DirectInputMouse::DirectInputMouse() { HRESULT result = NULL; result = DI_CreateDevice(GUID_SysMouse); if (FAILED(result)) return; result = DI_SetDataFormat(&c_dfDIMouse); result = DI_Acquire(); } DirectInputMouse::~DirectInputMouse() { DI_Dispose(); } bool DirectInputMouse::Poll() { if (!DirectInputInitialized()) return FALSE; HRESULT result = NULL; result = DI_Poll(); result = DI_GetDeviceState(sizeof(mouseState), &mouseState); return !FAILED(result); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/DirectInputMouse.h ================================================ #pragma once #include "DirectInputDevice.h" namespace TLAC::Input { class DirectInputMouse : public DirectInputDevice { public: DirectInputMouse(); ~DirectInputMouse(); bool Poll(); inline long GetXPosition() { return mouseState.lX; }; inline long GetYPosition() { return mouseState.lY; }; inline long GetMouseWheel() { return mouseState.lZ; }; private: DIMOUSESTATE mouseState; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/Ds4/Ds4Button.h ================================================ #pragma once namespace TLAC::Input { enum Direction { DIR_UP, DIR_RIGHT, DIR_DOWN, DIR_LEFT }; enum Ds4Button : int { DS4_SQUARE = 0, DS4_CROSS = 1, DS4_CIRCLE = 2, DS4_TRIANGLE = 3, DS4_L1 = 4, DS4_R1 = 5, DS4_L_TRIGGER = 6, DS4_R_TRIGGER = 7, DS4_SHARE = 8, DS4_OPTIONS = 9, DS4_L3 = 10, DS4_R3 = 11, DS4_PS = 12, DS4_TOUCH = 13, DS4_DPAD_UP, DS4_DPAD_RIGHT, DS4_DPAD_DOWN, DS4_DPAD_LEFT, DS4_L_STICK_UP, DS4_L_STICK_RIGHT, DS4_L_STICK_DOWN, DS4_L_STICK_LEFT, DS4_R_STICK_UP, DS4_R_STICK_RIGHT, DS4_R_STICK_DOWN, DS4_R_STICK_LEFT, DS4_BUTTON_MAX, }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/Ds4/Ds4State.cpp ================================================ #include "Ds4State.h" namespace TLAC::Input { Joystick::Joystick() : XAxis(0.0f), YAxis(0.0f) { return; }; Joystick::Joystick(float xAxis, float yAxis) : XAxis(xAxis), YAxis(yAxis) { return; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/Ds4/Ds4State.h ================================================ #pragma once #include "../DirectInput.h" #include "Ds4Button.h" namespace TLAC::Input { struct Joystick { FLOAT XAxis, YAxis; Joystick(); Joystick(float xAxis, float yAxis); }; struct Dpad { BOOL IsDown; FLOAT Angle; Joystick Stick; }; struct Trigger { FLOAT Axis; }; struct Ds4State { DIJOYSTATE2 DI_JoyState; BYTE Buttons[DS4_BUTTON_MAX]; Dpad Dpad; Joystick LeftStick; Joystick RightStick; Trigger LeftTrigger; Trigger RightTrigger; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/Ds4/DualShock4.cpp ================================================ #include "DualShock4.h" #include "../../../Utilities/Math.h" #include "../../../framework.h" #include namespace TLAC::Input { DualShock4* DualShock4::instance; bool DualShock4::rawMode = false; DualShock4::DualShock4() { } DualShock4::~DualShock4() { DI_Dispose(); } bool DualShock4::TryInitializeInstance() { if (InstanceInitialized()) return true; if (!DirectInputInitialized()) return false; DualShock4 *dualShock4 = new DualShock4(); bool success = dualShock4->Initialize(); instance = success ? dualShock4 : nullptr; if (!success) delete dualShock4; return success; } bool DualShock4::Initialize() { HRESULT result = NULL; const size_t guidCount = sizeof(GUID_Ds4) / sizeof(GUID); for (size_t i = 0; i < guidCount; i++) { result = DI_CreateDevice(GUID_Ds4[i]); if (!FAILED(result)) break; else if (i == guidCount - 1) return false; } if (FAILED(result = DI_SetDataFormat(&c_dfDIJoystick2))) return false; if (FAILED(result = DI_SetRange(0, 255))) // use 8-bit data return false; // set raw mode from previous instance if (rawMode && FAILED(result = DI_SetRawMode(true))) return false; result = DI_Acquire(); return true; } bool DualShock4::SetRawMode(bool raw) { HRESULT result = NULL; if (FAILED(result = DI_SetRawMode(raw))) return false; rawMode = raw; return true; } bool DualShock4::PollInput() { lastState = currentState; HRESULT result = NULL; result = DI_Poll(); result = DI_GetDeviceState(sizeof(DIJOYSTATE2), ¤tState.DI_JoyState); if (result != DI_OK) return false; UpdateInternalDs4State(currentState); for (int button = 0; button < DS4_BUTTON_MAX; button++) currentState.Buttons[button] = GetButtonState(currentState, (Ds4Button)button); return true; } void DualShock4::UpdateInternalDs4State(Ds4State &state) { if (state.Dpad.IsDown = state.DI_JoyState.rgdwPOV[0] != -1) { state.Dpad.Angle = (state.DI_JoyState.rgdwPOV[0] / 100.0f); auto direction = Utilities::GetDirection(state.Dpad.Angle); state.Dpad.Stick = { direction.Y, -direction.X }; } else { state.Dpad.Angle = 0; state.Dpad.Stick = Joystick(); } state.LeftStick = NormalizeStick(state.DI_JoyState.lX, state.DI_JoyState.lY); state.RightStick = NormalizeStick(state.DI_JoyState.lZ, state.DI_JoyState.lRz); state.LeftTrigger = { NormalizeTrigger(state.DI_JoyState.lRx) }; state.RightTrigger = { NormalizeTrigger(state.DI_JoyState.lRy) }; } bool DualShock4::IsDown(Ds4Button button) { return currentState.Buttons[button]; } bool DualShock4::IsUp(Ds4Button button) { return !IsDown(button); } bool DualShock4::IsTapped(Ds4Button button) { return IsDown(button) && WasUp(button); } bool DualShock4::IsReleased(Ds4Button button) { return IsUp(button) && WasDown(button); } bool DualShock4::WasDown(Ds4Button button) { return lastState.Buttons[button]; } bool DualShock4::WasUp(Ds4Button button) { return !WasDown(button); } bool DualShock4::MatchesDirection(Joystick joystick, Direction directionEnum, float threshold) { switch (directionEnum) { case TLAC::Input::DIR_UP: return joystick.YAxis <= -threshold; case TLAC::Input::DIR_RIGHT: return joystick.XAxis >= +threshold; case TLAC::Input::DIR_DOWN: return joystick.YAxis >= +threshold; case TLAC::Input::DIR_LEFT: return joystick.XAxis <= -threshold; default: return false; } } bool DualShock4::GetButtonState(Ds4State &state, Ds4Button button) { if (button >= DS4_SQUARE && button <= DS4_TOUCH) return state.DI_JoyState.rgbButtons[button]; if (button >= DS4_DPAD_UP && button <= DS4_DPAD_LEFT) return state.Dpad.IsDown ? MatchesDirection(state.Dpad.Stick, (Direction)(button - DS4_DPAD_UP), dpadThreshold) : false; if (button >= DS4_L_STICK_UP && button <= DS4_L_STICK_LEFT) return MatchesDirection(state.LeftStick, (Direction)(button - DS4_L_STICK_UP), joystickThreshold); if (button >= DS4_R_STICK_UP && button <= DS4_R_STICK_LEFT) return MatchesDirection(state.RightStick, (Direction)(button - DS4_R_STICK_UP), joystickThreshold); return false; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/Ds4/DualShock4.h ================================================ #pragma once #include "../Controller.h" #include "../../IInputDevice.h" #include "Ds4State.h" namespace TLAC::Input { // Controller GUIDs: const GUID GUID_Ds4[] = { // First Generation: {05C4054C-0000-0000-0000-504944564944} { 0x05C4054C, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, // Second Generation: {09CC054C-0000-0000-0000-504944564944} { 0x09CC054C, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, // PS5 DualSense: {0CE6054C-0000-0000-0000-504944564944} { 0x0CE6054C, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, // GAMO2 DIVALLER: {11140E8F-0000-0000-0000-504944564944} { 0x11140E8F, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, // Hori HATSUNE MIKU X: {00A50F0D-0000-0000-0000-504944564944} { 0x00A50F0D, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, // Hori F2nd Miniboard (Hatsune Miku Sho): {00490F0D-0000-0000-0000-504944564944} { 0x00490F0D, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, // Hori FT Senyou: {013C0F0D-0000-0000-0000-504944564944} { 0x013C0F0D, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }, // HORI HATSUNE MIKU 39S CONTROLLER: {00FB0F0D-0000-0000-0000-504944564944} { 0x00FB0F0D, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } } }; class DualShock4 : public Controller, public IInputDevice { public: DualShock4(); ~DualShock4(); static bool TryInitializeInstance(); bool Initialize(); bool SetRawMode(bool raw); bool PollInput() override; bool IsDown(Ds4Button button); bool IsUp(Ds4Button button); bool IsTapped(Ds4Button button); bool IsReleased(Ds4Button button); bool WasDown(Ds4Button button); bool WasUp(Ds4Button button); inline Joystick GetLeftStick() { return currentState.LeftStick; }; inline Joystick GetRightStick() { return currentState.RightStick; }; inline Joystick GetDpad() { return currentState.Dpad.Stick; }; static inline bool InstanceInitialized() { return instance != nullptr; }; static inline DualShock4* GetInstance() { return instance; }; static inline void DeleteInstance() { delete instance; instance = nullptr; }; static bool rawMode; // kinda dodgy, used to set raw mode for all instances without waiting for a single one private: static DualShock4* instance; Ds4State lastState; Ds4State currentState; const float triggerThreshold = 0.5f; const float joystickThreshold = 0.5f; const float dpadThreshold = 0.5f; inline float NormalizeTrigger(long value) { return (float)value / UCHAR_MAX; }; inline float NormalizeStick(long value) { return (float)value / UCHAR_MAX * 2.0f - 1.0f; }; inline Joystick NormalizeStick(long x, long y) { return Joystick(NormalizeStick(x), NormalizeStick(y)); }; void UpdateInternalDs4State(Ds4State &state); bool MatchesDirection(Joystick joystick, Direction directionEnum, float threshold); bool GetButtonState(Ds4State &state, Ds4Button button); }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/GenericUsb/GenericUsbInput.cpp ================================================ #include "GenericUsbInput.h" #include "../../../Utilities/Math.h" #include "../../../Utilities/Operations.h" #include "../../../framework.h" #include "../../../FileSystem/ConfigFile.h" #include const std::string GU_CONFIG_FILE_NAME = "keyconfig.ini"; namespace TLAC::Input { GenericUsbInput* GenericUsbInput::instance; GenericUsbInput::GenericUsbInput() { } GenericUsbInput::~GenericUsbInput() { DI_Dispose(); } bool GenericUsbInput::TryInitializeInstance() { if (InstanceInitialized()) return true; if (!DirectInputInitialized()) return false; GenericUsbInput *genericUsbInput = new GenericUsbInput (); bool success = genericUsbInput->Initialize(); instance = success ? genericUsbInput : nullptr; if (!success) delete genericUsbInput; return success; } bool GenericUsbInput::Initialize() { HRESULT result = NULL; FileSystem::ConfigFile configFile(framework::GetModuleDirectory(), GU_CONFIG_FILE_NAME); configFile.OpenRead(); customKeyMapping = configFile.ConfigMap; std::string stt = "0x"; std::string vid = configFile.GetStringValue("VID"); std::string pid = configFile.GetStringValue("PID"); unsigned int gid = std::strtoul((stt + pid + vid).c_str(), 0, 16); GUID GUID_GenericUsb = { gid, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; result = DI_CreateDevice(GUID_GenericUsb); if (!FAILED(result)) { if (FAILED(result = DI_SetDataFormat(&c_dfDIJoystick2))) return false; result = DI_Acquire(); return true; } else { return false; } } bool GenericUsbInput::PollInput() { lastState = currentState; HRESULT result = NULL; result = DI_Poll(); result = DI_GetDeviceState(sizeof(DIJOYSTATE2), ¤tState.DI_JoyState); if (result != DI_OK) return false; UpdateInternalGuState(currentState); for (int button = 0; button < GU_BUTTON_MAX; button++) { bool buttonState = GetButtonState(currentState, (GuButton)button); currentState.Buttons[button] = buttonState; // If custom button is pressed if (buttonState) { // Check whether this button is a custom mapped button auto customMapping = customKeyMapping.find(buttonNames[button]); if (customMapping != customKeyMapping.end()) { std::vector keys = Utilities::Split(customMapping->second, "+"); for (std::string key : keys) { Utilities::Trim(key); auto guButton = KeyConfig::Config::GuMap.find(key.c_str()); currentState.Buttons[guButton->second] = buttonState; } } } } return true; } void GenericUsbInput::UpdateInternalGuState(GuState &state) { if (state.Dpad.IsDown = state.DI_JoyState.rgdwPOV[0] != -1) { state.Dpad.Angle = (state.DI_JoyState.rgdwPOV[0] / 100.0f); auto direction = Utilities::GetDirection(state.Dpad.Angle); state.Dpad.Stick = { direction.Y, -direction.X }; } else { state.Dpad.Angle = 0; state.Dpad.Stick = GuJoystick(); } state.LeftStick = NormalizeStick(state.DI_JoyState.lX, state.DI_JoyState.lY); state.RightStick = NormalizeStick(state.DI_JoyState.lZ, state.DI_JoyState.lRz); state.LeftTrigger = { NormalizeTrigger(state.DI_JoyState.lRx) }; state.RightTrigger = { NormalizeTrigger(state.DI_JoyState.lRy) }; } bool GenericUsbInput::IsDown(GuButton button) { return currentState.Buttons[button]; } bool GenericUsbInput::IsUp(GuButton button) { return !IsDown(button); } bool GenericUsbInput::IsTapped(GuButton button) { return IsDown(button) && WasUp(button); } bool GenericUsbInput::IsReleased(GuButton button) { return IsUp(button) && WasDown(button); } bool GenericUsbInput::WasDown(GuButton button) { return lastState.Buttons[button]; } bool GenericUsbInput::WasUp(GuButton button) { return !WasDown(button); } bool GenericUsbInput::MatchesDirection(GuJoystick joystick, GuDirection directionEnum, float threshold) { switch (directionEnum) { case TLAC::Input::GU_DIR_UP: return joystick.YAxis <= -threshold; case TLAC::Input::GU_DIR_RIGHT: return joystick.XAxis >= +threshold; case TLAC::Input::GU_DIR_DOWN: return joystick.YAxis >= +threshold; case TLAC::Input::GU_DIR_LEFT: return joystick.XAxis <= -threshold; default: return false; } } bool GenericUsbInput::GetButtonState(GuState &state, GuButton button) { if (button >= GU_BUTTON1 && button <= GU_BUTTON13) return state.DI_JoyState.rgbButtons[button]; if (button >= GU_DPAD_UP && button <= GU_DPAD_LEFT) return state.Dpad.IsDown ? MatchesDirection(state.Dpad.Stick, (GuDirection)(button - GU_DPAD_UP), dpadThreshold) : false; if (button >= GU_L_STICK_UP && button <= GU_L_STICK_LEFT) return MatchesDirection(state.LeftStick, (GuDirection)(button - GU_L_STICK_UP), joystickThreshold); if (button >= GU_R_STICK_UP && button <= GU_R_STICK_LEFT) return MatchesDirection(state.RightStick, (GuDirection)(button - GU_R_STICK_UP), joystickThreshold); return false; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/GenericUsb/GenericUsbInput.h ================================================ #pragma once #include "../Controller.h" #include "../../IInputDevice.h" #include "../../../Input/KeyConfig/Config.h" #include "GuState.h" #include namespace TLAC::Input { class GenericUsbInput : public Controller, public IInputDevice { public: GenericUsbInput(); ~GenericUsbInput(); static bool TryInitializeInstance(); bool Initialize(); bool PollInput() override; bool IsDown(GuButton button); bool IsUp(GuButton button); bool IsTapped(GuButton button); bool IsReleased(GuButton button); bool WasDown(GuButton button); bool WasUp(GuButton button); inline GuJoystick GetLeftStick() { return currentState.LeftStick; }; inline GuJoystick GetRightStick() { return currentState.RightStick; }; inline GuJoystick GetDpad() { return currentState.Dpad.Stick; }; static inline bool InstanceInitialized() { return instance != nullptr; }; static inline GenericUsbInput* GetInstance() { return instance; }; static inline void DeleteInstance() { delete instance; instance = nullptr; }; private: static GenericUsbInput* instance; GuState lastState; GuState currentState; std::unordered_map customKeyMapping; std::vector buttonNames = { "GU_BUTTON1", "GU_BUTTON2", "GU_BUTTON3", "GU_BUTTON4", "GU_BUTTON5", "GU_BUTTON6", "GU_BUTTON7", "GU_BUTTON8", "GU_BUTTON9", "GU_BUTTON10", "GU_BUTTON11", "GU_BUTTON12", "GU_BUTTON13", "GU_DPAD_UP", "GU_DPAD_RIGHT", "GU_DPAD_DOWN", "GU_DPAD_LEFT", "GU_L_STICK_UP", "GU_L_STICK_RIGHT", "GU_L_STICK_DOWN", "GU_L_STICK_LEFT", "GU_R_STICK_UP", "GU_R_STICK_RIGHT", "GU_R_STICK_DOWN", "GU_R_STICK_LEFT", "GU_BUTTON_MAX" }; const float triggerThreshold = 0.5f; const float joystickThreshold = 0.5f; const float dpadThreshold = 0.5f; inline float NormalizeTrigger(long value) { return (float)value / USHRT_MAX; }; inline float NormalizeStick(long value) { return (float)value / USHRT_MAX * 2.0f - 1.0f; }; inline GuJoystick NormalizeStick(long x, long y) { return GuJoystick(NormalizeStick(x), NormalizeStick(y)); }; void UpdateInternalGuState(GuState &state); bool MatchesDirection(GuJoystick joystick, GuDirection directionEnum, float threshold); bool GetButtonState(GuState &state, GuButton button); }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/GenericUsb/GuButton.h ================================================ #pragma once namespace TLAC::Input { enum GuDirection { GU_DIR_UP, GU_DIR_RIGHT, GU_DIR_DOWN, GU_DIR_LEFT }; enum GuButton : int { GU_BUTTON1 = 0, GU_BUTTON2 = 1, GU_BUTTON3 = 2, GU_BUTTON4 = 3, GU_BUTTON5 = 4, GU_BUTTON6 = 5, GU_BUTTON7 = 6, GU_BUTTON8 = 7, GU_BUTTON9 = 8, GU_BUTTON10 = 9, GU_BUTTON11 = 10, GU_BUTTON12 = 11, GU_BUTTON13 = 12, GU_DPAD_UP = 14, GU_DPAD_RIGHT = 15, GU_DPAD_DOWN = 16, GU_DPAD_LEFT = 17, GU_L_STICK_UP = 18, GU_L_STICK_RIGHT = 19, GU_L_STICK_DOWN = 20, GU_L_STICK_LEFT = 21, GU_R_STICK_UP = 22, GU_R_STICK_RIGHT = 23, GU_R_STICK_DOWN = 24, GU_R_STICK_LEFT = 25, GU_BUTTON_MAX = 26, }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/GenericUsb/GuState.cpp ================================================ #include "GuState.h" namespace TLAC::Input { GuJoystick::GuJoystick() : XAxis(0.0f), YAxis(0.0f) { return; }; GuJoystick::GuJoystick(float xAxis, float yAxis) : XAxis(xAxis), YAxis(yAxis) { return; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/DirectInput/GenericUsb/GuState.h ================================================ #pragma once #include "../DirectInput.h" #include "GuButton.h" namespace TLAC::Input { struct GuJoystick { FLOAT XAxis, YAxis; GuJoystick(); GuJoystick(float xAxis, float yAxis); }; struct GuDpad { BOOL IsDown; FLOAT Angle; GuJoystick Stick; }; struct GuTrigger { FLOAT Axis; }; struct GuState { DIJOYSTATE2 DI_JoyState; BYTE Buttons[GU_BUTTON_MAX]; GuDpad Dpad; GuJoystick LeftStick; GuJoystick RightStick; GuTrigger LeftTrigger; GuTrigger RightTrigger; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Divaller/Divaller.cpp ================================================ #include "Divaller.h" #include "../../framework.h" #include "DivallerButton.h" #include "DivallerState.h" #include #include #include namespace TLAC::Input { Divaller *Divaller::instance; Divaller::Divaller() { memset(outputBuffer, 0, sizeof(outputBuffer)); outputBuffer[0] = 0x44; outputBuffer[1] = 0x4c; outputBuffer[2] = 0x61; } Divaller::~Divaller() { CloseHandle(hDeviceHandle); } bool Divaller::TryInitializeInstance() { if (InstanceInitialized()) return true; Divaller *divaller = new Divaller(); BOOL success = divaller->Initialize(); instance = success ? divaller : nullptr; if (!success) delete divaller; return success; } bool Divaller::Initialize() { HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == INVALID_HANDLE_VALUE) { printf("[TLAC] Divaller::Initialize(): SetupDiGetClassDevs returned INVALID_HANDLE_VALUE\n"); return false; } LPCWSTR devPath = NULL; for (size_t i = 0;; i++) { SP_DEVICE_INTERFACE_DATA device_interface_data = {0}; device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); BOOL success = SetupDiEnumDeviceInterfaces( hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, (DWORD)i, &device_interface_data); if (!success) { break; } ULONG required_length = 0; success = SetupDiGetDeviceInterfaceDetail( hDevInfo, &device_interface_data, NULL, 0, &required_length, NULL); UINT8 *interface_data = (UINT8 *)calloc(required_length, sizeof(UINT8)); PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)interface_data; device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); ULONG actual_length = required_length; success = SetupDiGetDeviceInterfaceDetail( hDevInfo, &device_interface_data, device_interface_detail_data, actual_length, &required_length, NULL); if (!success) { continue; } if ( wcsstr(device_interface_detail_data->DevicePath, L"vid_0e8f") == 0 || wcsstr(device_interface_detail_data->DevicePath, L"pid_2213") == 0) { continue; } devPath = device_interface_detail_data->DevicePath; break; } if (devPath == NULL) { SetupDiDestroyDeviceInfoList(hDevInfo); return false; } hDeviceHandle = CreateFile( devPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hDeviceHandle == INVALID_HANDLE_VALUE) { printf("[TLAC] Divaller::Initialize(): Open device failed.\n"); SetupDiDestroyDeviceInfoList(hDevInfo); return false; } if (!WinUsb_Initialize(hDeviceHandle, &hInterfaceHandle)) { printf("[TLAC] Divaller::Initialize(): WinUsb_Initialize failed.\n"); std::cout << GetLastError() << std::endl; SetupDiDestroyDeviceInfoList(hDevInfo); CloseHandle(hDeviceHandle); return false; } USB_INTERFACE_DESCRIPTOR USBInterfaceDescriptor; if (!WinUsb_QueryInterfaceSettings(hInterfaceHandle, 0, &USBInterfaceDescriptor)) { std::cout << GetLastError() << std::endl; SetupDiDestroyDeviceInfoList(hDevInfo); CloseHandle(hDeviceHandle); return false; } SetupDiDestroyDeviceInfoList(hDevInfo); return true; } bool Divaller::PollInput() { lastState = currentState; ULONG len = 0; memset(currentState.state, 0, sizeof(currentState.state)); BOOL bResult = WinUsb_ReadPipe(hInterfaceHandle, (UCHAR)132, currentState.state, _countof(currentState.state), &len, nullptr); if (!bResult || currentState.state[0] != 0x42 || currentState.state[1] != 0x56 || currentState.state[2] != 0x5a) { printf("[TLAC] Divaller::PollInput(): WinUsb_ReadPipe failed.\n"); std::cout << GetLastError() << std::endl; } SetLED(); return bResult; } bool Divaller::SetLED() { outputBuffer[3] &= 0x0F; // Reset Button LED outputBuffer[3] |= (!(*buttonLed >> 1 & 0x0001)) << 4; // SQUARE outputBuffer[3] |= (!(*buttonLed >> 3 & 0x0001)) << 5; // CIRCLE outputBuffer[3] |= (!(*buttonLed & 0x0001)) << 6; // TRIANGLE outputBuffer[3] |= (!(*buttonLed >> 2 & 0x0001)) << 7; // CROSS if (*sliderLedInit && !sliderLedData) { sliderLedData = reinterpret_cast(*(uint64_t *)(0x14cc5de40 + 0x68) + 0x189c); } if (sliderLedData) { for (int n = 0; n < 32; n++) { // LED number + 3 bytes header + color offset outputBuffer[(31 - n) * 3 + 3 + 3] = sliderLedData[n * 3 + 1]; // BLUE outputBuffer[(31 - n) * 3 + 3 + 2] = sliderLedData[n * 3 + 2]; // RED outputBuffer[(31 - n) * 3 + 3 + 1] = sliderLedData[n * 3 + 3]; // GREEN } } ULONG len = 0; BOOL bResult = WinUsb_WritePipe(hInterfaceHandle, (UCHAR)0x03, outputBuffer, 100, &len, NULL); if (!bResult) { printf("[TLAC] Divaller::SetLED(): WinUsb_WritePipe failed.\n"); std::cout << GetLastError() << std::endl; } return bResult; } bool Divaller::IsDown(DivallerButton button) { switch (button) { case DivallerButton::DVL_L1: return (currentState.state[5] >> 0) & 1; case DivallerButton::DVL_L2: return (currentState.state[4] >> 7) & 1; case DivallerButton::DVL_L3: return (currentState.state[4] >> 6) & 1; case DivallerButton::DVL_FN: return (currentState.state[3] >> 1) & 1; case DivallerButton::DVL_TRIANGLE: return (currentState.state[3] >> 4) & 1; case DivallerButton::DVL_SQUARE: return (currentState.state[3] >> 2) & 1; case DivallerButton::DVL_CROSS: return (currentState.state[3] >> 5) & 1; case DivallerButton::DVL_CIRCLE: return (currentState.state[3] >> 3) & 1; } return false; } bool Divaller::IsUp(DivallerButton button) { return !IsDown(button); } bool Divaller::IsTapped(DivallerButton button) { return IsDown(button) && WasUp(button); } bool Divaller::IsReleased(DivallerButton button) { return IsUp(button) && WasDown(button); } bool Divaller::WasDown(DivallerButton button) { switch (button) { case DivallerButton::DVL_L1: return (lastState.state[5] >> 0) & 1; case DivallerButton::DVL_L2: return (lastState.state[4] >> 7) & 1; case DivallerButton::DVL_L3: return (lastState.state[4] >> 6) & 1; case DivallerButton::DVL_FN: return (lastState.state[3] >> 1) & 1; case DivallerButton::DVL_TRIANGLE: return (lastState.state[3] >> 4) & 1; case DivallerButton::DVL_SQUARE: return (lastState.state[3] >> 2) & 1; case DivallerButton::DVL_CROSS: return (lastState.state[3] >> 5) & 1; case DivallerButton::DVL_CIRCLE: return (lastState.state[3] >> 3) & 1; } return false; } bool Divaller::WasUp(DivallerButton button) { return !WasDown(button); } uint32_t Divaller::GetSlider() { uint32_t i = 0; i |= currentState.state[5] >> 4; i |= currentState.state[6] << 4; i |= currentState.state[7] << 12; i |= currentState.state[8] << 20; i |= currentState.state[9] << 28; // Reverse the bit order of uint32 i = (i & 0xaaaaaaaa) >> 1 | (i & 0x55555555) << 1; i = (i & 0xcccccccc) >> 2 | (i & 0x33333333) << 2; i = (i & 0xf0f0f0f0) >> 4 | (i & 0x0f0f0f0f) << 4; i = (i & 0xff00ff00) >> 8 | (i & 0x00ff00ff) << 8; return i >> 16 | i << 16; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Divaller/Divaller.h ================================================ #pragma once #include "../IInputDevice.h" #include "DivallerState.h" #include "DivallerButton.h" #include #include #include #include namespace TLAC::Input { class Divaller : public IInputDevice { public: Divaller(); ~Divaller(); static bool TryInitializeInstance(); bool Initialize(); bool PollInput() override; bool SetLED(); bool IsDown(DivallerButton button); bool IsUp(DivallerButton button); bool IsTapped(DivallerButton button); bool IsReleased(DivallerButton button); bool WasDown(DivallerButton button); bool WasUp(DivallerButton button); uint32_t GetSlider(); static inline bool InstanceInitialized() { return instance != nullptr; }; static inline Divaller *GetInstance() { return instance; }; static inline void DeleteInstance() { delete instance; instance = nullptr; }; private: static Divaller *instance; DivallerState lastState; DivallerState currentState; WINUSB_INTERFACE_HANDLE hInterfaceHandle; HANDLE hDeviceHandle; UCHAR outputBuffer[100]; int *buttonLed = reinterpret_cast(0x14119b950); uint64_t *partionLed = reinterpret_cast(*(uint64_t *)0x140eda330 + 0xc9); uint64_t *sliderLedInit = reinterpret_cast((uint64_t *)0x14cc5dea8); UCHAR *sliderLedData = nullptr; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Divaller/DivallerButton.h ================================================ #pragma once namespace TLAC::Input { enum DivallerButton : int { DVL_SQUARE = 0, DVL_CROSS = 1, DVL_CIRCLE = 2, DVL_TRIANGLE = 3, DVL_FN = 4, DVL_L1 = 5, DVL_L2 = 6, DVL_L3 = 7, DVL_R1 = 8, DVL_R2 = 9, DVL_R3 = 10, DVL_UP = 11, DVL_LEFT = 12, DVL_DOWN = 13, DVL_RIGHT = 14, DVL_PAD = 11, DVL_SHARE = 12, DVL_HOME = 13, DVL_OPTION = 14 }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Divaller/DivallerState.h ================================================ #pragma once #include "../../framework.h" namespace TLAC::Input { struct DivallerState { uint8_t state[24]; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/IInputDevice.h ================================================ #pragma once namespace TLAC::Input { class IInputDevice { public: virtual bool PollInput() = 0; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/KeyConfig/Config.cpp ================================================ #include "Config.h" #include "windows.h" #include "../Bindings/KeyboardBinding.h" #include "../Bindings/Ds4Binding.h" #include "../Bindings/GuBinding.h" #include "../../Utilities/Operations.h" #include "../Bindings/XinputBinding.h" #include "../../Constants.h" namespace TLAC::Input::KeyConfig { KeycodeMap Config::Keymap = { // NumPad Keys { "NumPad0", VK_NUMPAD0 }, { "NumPad1", VK_NUMPAD1 }, { "NumPad2", VK_NUMPAD2 }, { "NumPad3", VK_NUMPAD3 }, { "NumPad4", VK_NUMPAD4 }, { "NumPad5", VK_NUMPAD5 }, { "NumPad6", VK_NUMPAD6 }, { "NumPad7", VK_NUMPAD7 }, { "NumPad8", VK_NUMPAD8 }, { "NumPad9", VK_NUMPAD9 }, { "Plus", VK_ADD }, { "Minus", VK_SUBTRACT }, { "Divide", VK_DIVIDE }, { "Multiply", VK_MULTIPLY }, // F-Keys { "F1", VK_F1 }, { "F2", VK_F2 }, { "F3", VK_F3 }, { "F4", VK_F4 }, { "F5", VK_F5 }, { "F6", VK_F6 }, { "F7", VK_F7 }, { "F8", VK_F8 }, { "F9", VK_F9 }, { "F10", VK_F10 }, { "F11", VK_F11 }, { "F12", VK_F12 }, { "F13", VK_F13 }, { "F14", VK_F14 }, { "F15", VK_F15 }, { "F16", VK_F16 }, { "F17", VK_F17 }, { "F18", VK_F18 }, { "F19", VK_F19 }, { "F20", VK_F20 }, { "F21", VK_F21 }, { "F22", VK_F22 }, { "F23", VK_F23 }, { "F24", VK_F24 }, // Shift Keys { "LeftShift", VK_LSHIFT }, { "LShift", VK_LSHIFT }, { "RightShift", VK_RSHIFT }, { "RShift", VK_RSHIFT }, // Control Keys { "LeftControl", VK_LCONTROL }, { "LControl", VK_LCONTROL }, { "LCtrl", VK_LCONTROL }, { "RightControl", VK_RCONTROL }, { "RControl", VK_RCONTROL }, { "RCtrl", VK_RCONTROL }, // Arrow Keys { "Up", VK_UP }, { "Down", VK_DOWN }, { "Left", VK_LEFT }, { "Right", VK_RIGHT }, // Special Keys { "Enter", VK_RETURN }, { "Return", VK_RETURN }, { "Tab", VK_TAB }, { "Back", VK_BACK }, { "Backspace", VK_BACK }, { "Space", VK_SPACE }, { "Spacebar", VK_SPACE }, { "Insert", VK_INSERT }, { "Ins", VK_INSERT }, { "Delete", VK_DELETE }, { "Del", VK_DELETE }, { "Home", VK_HOME }, { "End", VK_END }, { "PageUp", VK_PRIOR }, { "PageDown", VK_NEXT }, { "ESC", VK_ESCAPE }, { "Escape", VK_ESCAPE }, { "Comma", VK_OEM_COMMA }, { "Period", VK_OEM_PERIOD }, { "Colon", VK_OEM_1 }, { "Slash", VK_OEM_2 }, { "Tilde", VK_OEM_3 }, { "LeftBracket", VK_OEM_4 }, { "Backslash", VK_OEM_5 }, { "RightBracket", VK_OEM_6 }, { "SingleDoubleQuote", VK_OEM_7 }, { "OEM_8", VK_OEM_8 }, // Mouse buttons { "MouseLeft", VK_LBUTTON }, { "MouseMiddle", VK_MBUTTON }, { "MouseRight", VK_RBUTTON }, { "MouseX1", VK_XBUTTON1 }, { "MouseX2", VK_XBUTTON2 }, }; KeycodeMap Config::XinputMap = { //XINPUT { "XINPUT_A", XINPUT_A}, { "XINPUT_B", XINPUT_B}, { "XINPUT_X", XINPUT_X}, { "XINPUT_Y", XINPUT_Y}, { "XINPUT_UP", XINPUT_UP}, { "XINPUT_DOWN", XINPUT_DOWN}, { "XINPUT_LEFT", XINPUT_LEFT}, { "XINPUT_RIGHT", XINPUT_RIGHT}, { "XINPUT_START", XINPUT_START}, { "XINPUT_BACK", XINPUT_BACK}, { "XINPUT_LS", XINPUT_LS}, { "XINPUT_RS", XINPUT_RS}, { "XINPUT_LB", XINPUT_LS}, { "XINPUT_RB", XINPUT_RS}, { "XINPUT_LT", XINPUT_LT}, { "XINPUT_RT", XINPUT_RT}, { "XINPUT_LSB", XINPUT_LSB}, { "XINPUT_RSB", XINPUT_RSB}, { "XINPUT_LLEFT", XINPUT_LLEFT}, { "XINPUT_LRIGHT", XINPUT_LRIGHT}, { "XINPUT_LUP", XINPUT_LUP}, { "XINPUT_LDOWN", XINPUT_LDOWN}, { "XINPUT_RLEFT", XINPUT_RLEFT}, { "XINPUT_RRIGHT", XINPUT_RRIGHT}, { "XINPUT_RUP", XINPUT_RUP}, { "XINPUT_RDOWN", XINPUT_RDOWN}, }; Ds4ButtonMap Config::Ds4Map = { // Face Buttons { "DS4_SQUARE", DS4_SQUARE }, { "Ds4_Square", DS4_SQUARE }, { "DS4_CROSS", DS4_CROSS }, { "Ds4_Cross", DS4_CROSS }, { "DS4_CIRCLE", DS4_CIRCLE }, { "Ds4_Circle", DS4_CIRCLE }, { "DS4_TRIANGLE", DS4_TRIANGLE }, { "Ds4_Triangle", DS4_TRIANGLE }, // Standard Buttons { "DS4_SHARE", DS4_SHARE }, { "Ds4_Share", DS4_SHARE }, { "DS4_OPTIONS", DS4_OPTIONS }, { "Ds4_Options", DS4_OPTIONS }, { "DS4_PS", DS4_PS }, { "Ds4_PS", DS4_PS }, { "DS4_TOUCH", DS4_TOUCH }, { "Ds4_Touch", DS4_TOUCH }, { "DS4_L1", DS4_L1 }, { "Ds4_L1", DS4_L1 }, { "DS4_R1", DS4_R1 }, { "Ds4_R1", DS4_R1 }, // D-Pad Directions { "DS4_DPAD_UP", DS4_DPAD_UP }, { "Ds4_DPad_Up", DS4_DPAD_UP }, { "DS4_DPAD_RIGHT", DS4_DPAD_RIGHT }, { "Ds4_DPad_Right", DS4_DPAD_RIGHT }, { "DS4_DPAD_DOWN", DS4_DPAD_DOWN }, { "Ds4_DPad_Down", DS4_DPAD_DOWN }, { "DS4_DPAD_LEFT", DS4_DPAD_LEFT }, { "Ds4_DPad_Left", DS4_DPAD_LEFT }, // Trigger Buttons { "DS4_L_TRIGGER", DS4_L_TRIGGER }, { "Ds4_L_Trigger", DS4_L_TRIGGER }, { "DS4_R_TRIGGER", DS4_R_TRIGGER }, { "Ds4_R_Trigger", DS4_R_TRIGGER }, // Joystick Buttons { "DS4_L3", DS4_L3 }, { "Ds4_L3", DS4_L3 }, { "DS4_R3", DS4_R3 }, { "Ds4_R3", DS4_R3 }, // Left Joystick { "DS4_L_STICK_UP", DS4_L_STICK_UP }, { "Ds4_L_Stick_Up", DS4_L_STICK_UP }, { "DS4_L_STICK_RIGHT", DS4_L_STICK_RIGHT }, { "Ds4_L_Stick_Right", DS4_L_STICK_RIGHT }, { "DS4_L_STICK_DOWN", DS4_L_STICK_DOWN }, { "Ds4_L_Stick_Down", DS4_L_STICK_DOWN }, { "DS4_L_STICK_LEFT", DS4_L_STICK_LEFT }, { "Ds4_L_Stick_Left", DS4_L_STICK_LEFT }, // Right Joystick { "DS4_R_STICK_UP", DS4_R_STICK_UP }, { "Ds4_R_Stick_Up", DS4_R_STICK_UP }, { "DS4_R_STICK_RIGHT", DS4_R_STICK_RIGHT }, { "Ds4_R_Stick_Right", DS4_R_STICK_RIGHT }, { "DS4_R_STICK_DOWN", DS4_R_STICK_DOWN }, { "Ds4_R_Stick_Down", DS4_R_STICK_DOWN }, { "DS4_R_STICK_LEFT", DS4_R_STICK_LEFT }, { "Ds4_R_Stick_Left", DS4_R_STICK_LEFT }, }; GuButtonMap Config::GuMap = { // Face Buttons { "GU_BUTTON1", GU_BUTTON1 }, { "GU_BUTTON2", GU_BUTTON2 }, { "GU_BUTTON3", GU_BUTTON3 }, { "GU_BUTTON4", GU_BUTTON4 }, { "GU_BUTTON5", GU_BUTTON5 }, { "GU_BUTTON6", GU_BUTTON6 }, { "GU_BUTTON7", GU_BUTTON7 }, { "GU_BUTTON8", GU_BUTTON8 }, { "GU_BUTTON9", GU_BUTTON9 }, { "GU_BUTTON10", GU_BUTTON10 }, { "GU_BUTTON11", GU_BUTTON11 }, { "GU_BUTTON12", GU_BUTTON12 }, { "GU_BUTTON13", GU_BUTTON13 }, // D-Pad Directions { "GU_DPAD_UP", GU_DPAD_UP }, { "GU_DPAD_RIGHT", GU_DPAD_RIGHT }, { "GU_DPAD_DOWN", GU_DPAD_DOWN }, { "GU_DPAD_LEFT", GU_DPAD_LEFT }, // Left Joystick { "GU_L_STICK_UP", GU_L_STICK_UP }, { "GU_L_STICK_RIGHT", GU_L_STICK_RIGHT }, { "GU_L_STICK_DOWN", GU_L_STICK_DOWN }, { "GU_L_STICK_LEFT", GU_L_STICK_LEFT }, // Right Joystick { "GU_R_STICK_UP", GU_R_STICK_UP }, { "GU_R_STICK_RIGHT", GU_R_STICK_RIGHT }, { "GU_R_STICK_DOWN", GU_R_STICK_DOWN }, { "GU_R_STICK_LEFT", GU_R_STICK_LEFT }, }; void Config::BindConfigKeys(std::unordered_map &configMap, const char *configKeyName, Binding &bindObj, std::vector defaultKeys) { std::vector keys; auto configPair = configMap.find(configKeyName); // config variable was found in the ini if (configPair != configMap.end()) { keys = Utilities::Split(configPair->second, ","); } else { keys = defaultKeys; } for (std::string key : keys) { Utilities::Trim(key); // Applies only for Single-Character keys if (key.length() == 1) { bindObj.AddBinding(new KeyboardBinding(key[0])); } else // for special key names { auto keycode = Config::Keymap.find(key.c_str()); // name is known in the special keys map if (keycode != Config::Keymap.end()) { bindObj.AddBinding(new KeyboardBinding(keycode->second)); } else { auto xinputBtn = Config::XinputMap.find(key.c_str()); if (xinputBtn != Config::XinputMap.end()) { bindObj.AddBinding(new XinputBinding(xinputBtn->second)); } else { // just gonna be lazy for now and put this inside an else statement auto ds4Button = Config::Ds4Map.find(key.c_str()); if (ds4Button != Config::Ds4Map.end()) { bindObj.AddBinding(new Ds4Binding(ds4Button->second)); } else { auto guButton = Config::GuMap.find(key.c_str()); if (guButton != Config::GuMap.end()) { bindObj.AddBinding(new GuBinding(guButton->second)); } else { printf("[TLAC] Config::BindConfigKeys(): Unable to parse key: '%s'\n", key.c_str()); } } } } } } } } ================================================ FILE: source-code/source/plugins/TLAC/Input/KeyConfig/Config.h ================================================ #pragma once #include #include "KeyString.h" #include "KeyStringHash.h" #include "../Bindings/Binding.h" #include "../DirectInput/Ds4/Ds4Button.h" #include "../DirectInput/GenericUsb/GuButton.h" namespace TLAC::Input::KeyConfig { typedef std::unordered_map KeycodeMap; typedef std::unordered_map Ds4ButtonMap; typedef std::unordered_map GuButtonMap; class Config { public: static KeycodeMap Keymap; static Ds4ButtonMap Ds4Map; static KeycodeMap XinputMap; static GuButtonMap GuMap; static void BindConfigKeys(std::unordered_map &configMap, const char *configKeyName, Binding &bindObj, std::vector defaultKeys); }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/KeyConfig/KeyString.cpp ================================================ #include "KeyString.h" namespace TLAC::Input::KeyConfig { KeyString::KeyString(const char* str) : value(str) { } bool KeyString::operator==(const KeyString& rsv) const { return !_strcmpi(value.c_str(), rsv.value.c_str()); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/KeyConfig/KeyString.h ================================================ #pragma once #include namespace TLAC::Input::KeyConfig { struct KeyString { std::string value; KeyString(const char* str); bool operator==(const KeyString& rsv) const; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/KeyConfig/KeyStringHash.cpp ================================================ #include "KeyStringHash.h" #include namespace TLAC::Input::KeyConfig { size_t KeyStringHash::operator()(const KeyString& key) const { std::string ret = key.value; std::transform(ret.begin(), ret.end(), ret.begin(), [](unsigned char c) { return std::tolower(c, std::locale()); }); return std::hash()(ret); } } ================================================ FILE: source-code/source/plugins/TLAC/Input/KeyConfig/KeyStringHash.h ================================================ #pragma once #include "KeyString.h" namespace TLAC::Input::KeyConfig { struct KeyStringHash { size_t operator()(const KeyString& key) const; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Keyboard/Keyboard.cpp ================================================ #include "Keyboard.h" namespace TLAC::Input { Keyboard* Keyboard::instance; Keyboard::Keyboard() { } Keyboard* Keyboard::GetInstance() { if (instance == nullptr) instance = new Keyboard(); return instance; } bool Keyboard::PollInput() { lastState = currentState; float elapsed = keyIntervalWatch.Restart(); for (BYTE i = 0; i < KEYBOARD_KEYS; i++) { // DOWN bool isDown = GetAsyncKeyState(i) < 0; currentState.KeyStates[i] = isDown; // DOUBLE TAPPED bool isTapped = IsTapped(i); keyDoubleTapStates[i] = isTapped ? keyDoubleTapWatches[i].Restart() <= DOUBLE_TAP_THRESHOLD : false; // INTERVAL TAPPED keyIntervalTapStates[i] = isTapped; if (isTapped) { keyIntervalTapTimes[i] = 0; keyIntervalInitials[i] = true; } else if (isDown) { float threshold = keyIntervalInitials[i] ? INTERVAL_TAP_DELAY_THRESHOLD : INTERVAL_TAP_THRESHOLD; bool intervalTapped = (keyIntervalTapTimes[i] += elapsed) > threshold; keyIntervalTapStates[i] = intervalTapped; if (intervalTapped) { keyIntervalTapTimes[i] = 0; keyIntervalInitials[i] = false; } } } return true; } bool Keyboard::IsDown(BYTE keycode) { return currentState.IsDown(keycode); } bool Keyboard::IsUp(BYTE keycode) { return !IsDown(keycode); } bool Keyboard::IsTapped(BYTE keycode) { return IsDown(keycode) && WasUp(keycode); } bool Keyboard::IsDoubleTapped(BYTE keycode) { return keyDoubleTapStates[keycode]; } bool Keyboard::IsReleased(BYTE keycode) { return IsUp(keycode) && WasDown(keycode); } inline bool Keyboard::WasDown(BYTE keycode) { return lastState.IsDown(keycode); } inline bool Keyboard::WasUp(BYTE keycode) { return !WasDown(keycode); } bool Keyboard::IsIntervalTapped(BYTE keycode) { return keyIntervalTapStates[keycode]; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Keyboard/Keyboard.h ================================================ #pragma once #include "../IInputDevice.h" #include "KeyboardState.h" #include "../../Utilities/Stopwatch.h" using Stopwatch = TLAC::Utilities::Stopwatch; namespace TLAC::Input { constexpr float DOUBLE_TAP_THRESHOLD = 200.0f; constexpr float INTERVAL_TAP_DELAY_THRESHOLD = 500.0f; constexpr float INTERVAL_TAP_THRESHOLD = 75.0f; class Keyboard : public IInputDevice { public: static Keyboard* GetInstance(); bool PollInput() override; bool IsDown(BYTE keycode); bool IsUp(BYTE keycode); bool IsTapped(BYTE keycode); bool IsDoubleTapped(BYTE keycode); bool IsReleased(BYTE keycode); bool IsIntervalTapped(BYTE keycode); bool WasDown(BYTE keycode); bool WasUp(BYTE keycode); private: Keyboard(); KeyboardState lastState; KeyboardState currentState; Stopwatch keyIntervalWatch; BYTE keyDoubleTapStates[KEYBOARD_KEYS]; Stopwatch keyDoubleTapWatches[KEYBOARD_KEYS]; BOOL keyIntervalInitials[KEYBOARD_KEYS]; BYTE keyIntervalTapStates[KEYBOARD_KEYS]; FLOAT keyIntervalTapTimes[KEYBOARD_KEYS]; static Keyboard* instance; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Keyboard/KeyboardState.cpp ================================================ #include "KeyboardState.h" namespace TLAC::Input { bool KeyboardState::IsDown(BYTE keycode) { return KeyStates[keycode]; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Keyboard/KeyboardState.h ================================================ #pragma once #include namespace TLAC::Input { const int KEYBOARD_KEYS = 0xFF; struct KeyboardState { BYTE KeyStates[KEYBOARD_KEYS]; bool IsDown(BYTE keycode); }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Mouse/Mouse.cpp ================================================ #include "Mouse.h" #include "../../framework.h" #include "../../Constants.h" namespace TLAC::Input { Mouse* Mouse::instance; Mouse::Mouse() { directInputMouse = new DirectInputMouse(); } Mouse::~Mouse() { if (directInputMouse != nullptr) delete directInputMouse; } Mouse* Mouse::GetInstance() { if (instance == nullptr) instance = new Mouse(); return instance; } POINT Mouse::GetPosition() { return currentState.Position; } POINT Mouse::GetRelativePosition() { return currentState.RelativePosition; } POINT Mouse::GetDeltaPosition() { return { currentState.Position.x - lastState.Position.x, currentState.Position.y - lastState.Position.y }; } long Mouse::GetMouseWheel() { return currentState.MouseWheel; } long Mouse::GetDeltaMouseWheel() { return currentState.MouseWheel - lastState.MouseWheel; } bool Mouse::HasMoved() { POINT delta = GetDeltaPosition(); return delta.x != 0 || delta.y != 0; } bool Mouse::GetIsScrolledUp() { return currentState.ScrolledUp; } bool Mouse::GetIsScrolledDown() { return currentState.ScrolledDown; } bool Mouse::GetWasScrolledUp() { return lastState.ScrolledUp; } bool Mouse::GetWasScrolledDown() { return lastState.ScrolledDown; } void Mouse::SetPosition(int x, int y) { lastState.Position.x = x; lastState.Position.y = y; SetCursorPos(x, y); } bool Mouse::PollInput() { lastState = currentState; GetCursorPos(¤tState.Position); currentState.RelativePosition = currentState.Position; if (framework::DivaWindowHandle != NULL) ScreenToClient(framework::DivaWindowHandle, ¤tState.RelativePosition); RECT hWindow; GetClientRect(TLAC::framework::DivaWindowHandle, &hWindow); gameHeight = (int*)RESOLUTION_HEIGHT_ADDRESS; gameWidth = (int*)RESOLUTION_WIDTH_ADDRESS; fbWidth = (int*)FB_WIDTH_ADDRESS; fbHeight = (int*)FB_HEIGHT_ADDRESS; if (directInputMouse != nullptr) { if (directInputMouse->Poll()) currentState.MouseWheel += directInputMouse->GetMouseWheel(); currentState.ScrolledUp = (GetDeltaMouseWheel() > 0); currentState.ScrolledDown = (GetDeltaMouseWheel() < 0); } if ((fbWidth != gameWidth) && (fbHeight != gameHeight)) { xoffset = ((float)16 / (float)9) * (hWindow.bottom - hWindow.top); if (xoffset != (hWindow.right - hWindow.left)) { scale = xoffset / (hWindow.right - hWindow.left); xoffset = ((hWindow.right - hWindow.left) / 2) - (xoffset / 2); } else { xoffset = 0; scale = 1; } currentState.RelativePosition.x = ((currentState.RelativePosition.x - round(xoffset)) * *gameWidth / (hWindow.right - hWindow.left)) / scale; currentState.RelativePosition.y = currentState.RelativePosition.y * *gameHeight / (hWindow.bottom - hWindow.top); } return true; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Mouse/Mouse.h ================================================ #pragma once #include "../IInputDevice.h" #include "../DirectInput/DirectInputMouse.h" #include "MouseState.h" namespace TLAC::Input { class Mouse : public IInputDevice { public: ~Mouse(); static Mouse* GetInstance(); bool PollInput() override; POINT GetPosition(); POINT GetRelativePosition(); POINT GetDeltaPosition(); long GetMouseWheel(); long GetDeltaMouseWheel(); bool HasMoved(); bool GetIsScrolledUp(); bool GetIsScrolledDown(); bool GetWasScrolledUp(); bool GetWasScrolledDown(); void SetPosition(int x, int y); private: Mouse(); MouseState lastState; MouseState currentState; DirectInputMouse* directInputMouse = nullptr; int* gameWidth; int* gameHeight; int* fbWidth; int* fbHeight; float xoffset; float scale; static Mouse* instance; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Mouse/MouseState.h ================================================ #pragma once #include namespace TLAC::Input { struct MouseState { POINT Position; POINT RelativePosition; long MouseWheel; bool ScrolledUp; bool ScrolledDown; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Xinput/Xinput.cpp ================================================ #include #include "Xinput.h" #include "../../Constants.h" #include "../../FileSystem/ConfigFile.h" #include "../../framework.h" #include "../../Components/GameTargets/TargetInspector.h" #include "../../Components/Input/TouchSliderEmulator.h" namespace TLAC::Input { Xinput* Xinput::instance; Xinput::Xinput() { TLAC::FileSystem::ConfigFile config(TLAC::framework::GetModuleDirectory(), "keyconfig.ini"); config.OpenRead(); xinput_num = config.GetIntegerValue("xinput_preferred"); rumble = config.GetBooleanValue("rumble"); rumble_left = config.GetIntegerValue("xinput_rumble_intensity_left", 8000); rumble_right = config.GetIntegerValue("xinput_rumble_intensity_right", 4000); } Xinput* Xinput::GetInstance() { if (instance == nullptr) { instance = new Xinput(); } return instance; } void Xinput::SetTapStates(BYTE keycode, float elapsed) { KeyDoubleTapStates[keycode] = IsTapped(keycode) ? KeyDoubleTapWatches[keycode].Restart() <= DOUBLE_TAP_THRESHOLD : false; bool isDown = currentState.KeyStates[keycode]; bool isTapped = IsTapped(keycode); keyIntervalTapStates[keycode] = isTapped; if (isTapped) { keyIntervalTapTimes[keycode] = 0; keyIntervalInitials[keycode] = true; } else if (isDown) { float threshold = keyIntervalInitials[keycode] ? INTERVAL_TAP_DELAY_THRESHOLD : INTERVAL_TAP_THRESHOLD; bool intervalTapped = (keyIntervalTapTimes[keycode] += elapsed) > threshold; keyIntervalTapStates[keycode] = intervalTapped; if (intervalTapped) { keyIntervalTapTimes[keycode] = 0; keyIntervalInitials[keycode] = false; } } } bool Xinput::PollInput() { lastState = currentState; ZeroMemory(&state, sizeof(XINPUT_STATE)); float elapsed = keyIntervalWatch.Restart(); int xc_pref = xinput_num; if (xc_pref < 0 || xc_pref > 3) xc_pref = 0; for (int n = 0; n < 4; n++) { ZeroMemory(&state, sizeof(XINPUT_STATE)); if (XInputGetState(xc_pref, &state) == ERROR_SUCCESS) { BYTE i = XINPUT_A; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_DOWN; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_B; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_RIGHT; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_X; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_LEFT; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_Y; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_UP; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_LS; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_RS; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_LSB; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_RSB; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_START; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_BACK; { currentState.KeyStates[i] = false; if (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_LT; { currentState.KeyStates[i] = false; if (state.Gamepad.bLeftTrigger > 230) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } i = XINPUT_RT; { currentState.KeyStates[i] = false; if (state.Gamepad.bRightTrigger > 230) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } { //float normLX = fmaxf(-1, (float)state.Gamepad.sThumbLX / 32767); i = XINPUT_LRIGHT; currentState.KeyStates[i] = false; if (state.Gamepad.sThumbLX > 10000) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); i = XINPUT_LLEFT; currentState.KeyStates[i] = false; if (state.Gamepad.sThumbLX < -10000) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); i = XINPUT_LUP; currentState.KeyStates[i] = false; if (state.Gamepad.sThumbLY > 10000) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); i = XINPUT_LDOWN; currentState.KeyStates[i] = false; if (state.Gamepad.sThumbLY < -10000) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } { //float normLX = fmaxf(-1, (float)state.Gamepad.sThumbRX / 32767); i = XINPUT_RRIGHT; currentState.KeyStates[i] = false; if (state.Gamepad.sThumbRX > 10000) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); i = XINPUT_RLEFT; currentState.KeyStates[i] = false; if (state.Gamepad.sThumbRX < -10000) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); i = XINPUT_RUP; currentState.KeyStates[i] = false; if (state.Gamepad.sThumbRY > 10000) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); i = XINPUT_RDOWN; currentState.KeyStates[i] = false; if (state.Gamepad.sThumbRY < -10000) currentState.KeyStates[i] = true; SetTapStates(i, elapsed); } if (rumble && TLAC::Components::touchSliderEmulatorIsEnabled && TLAC::Components::TouchSliderEmulator::LatestInstance->isSliderTouched() && TLAC::Components::TargetInspector::ShouldVibrate) { XINPUT_VIBRATION vibration; ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); vibration.wLeftMotorSpeed = rumble_left; // use any value between 0-65535 here vibration.wRightMotorSpeed = rumble_right; // use any value between 0-65535 here XInputSetState(xc_pref, &vibration); } else { XINPUT_VIBRATION vibration; ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); vibration.wLeftMotorSpeed = 0; // use any value between 0-65535 here vibration.wRightMotorSpeed = 0; // use any value between 0-65535 here XInputSetState(xc_pref, &vibration); //printf("0"); } break; } else if (n == 3) { ZeroMemory(&state, sizeof(XINPUT_STATE)); ZeroMemory(¤tState, sizeof(currentState)); } if (xc_pref == 3) xc_pref = 0; else xc_pref++; } return TRUE; } bool Xinput::IsDown(BYTE keycode) { return currentState.IsDown(keycode); } bool Xinput::IsUp(BYTE keycode) { return !IsDown(keycode); } bool Xinput::IsTapped(BYTE keycode) { return IsDown(keycode) && WasUp(keycode); } bool Xinput::IsDoubleTapped(BYTE keycode) { return KeyDoubleTapStates[keycode]; } bool Xinput::IsReleased(BYTE keycode) { return IsUp(keycode) && WasDown(keycode); } inline bool Xinput::WasDown(BYTE keycode) { return lastState.IsDown(keycode); } inline bool Xinput::WasUp(BYTE keycode) { return !WasDown(keycode); } bool Xinput::IsIntervalTapped(BYTE keycode) { return keyIntervalTapStates[keycode]; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Xinput/Xinput.h ================================================ #pragma once #include "../IInputDevice.h" #include #include "../../Utilities/Stopwatch.h" #include "XinputState.h" using Stopwatch = TLAC::Utilities::Stopwatch; namespace TLAC::Input { class Xinput : public IInputDevice { const float DOUBLE_TAP_THRESHOLD = 200.0f; const float INTERVAL_TAP_DELAY_THRESHOLD = 500.0f; const float INTERVAL_TAP_THRESHOLD = 75.0f; public: static Xinput* GetInstance(); bool PollInput() override; bool IsDown(BYTE keycode); bool IsUp(BYTE keycode); bool IsTapped(BYTE keycode); bool IsReleased(BYTE keycode); bool IsDoubleTapped(BYTE keycode); bool IsIntervalTapped(BYTE keycode); bool WasDown(BYTE keycode); bool WasUp(BYTE keycode); private: Xinput(); XinputState lastState; XinputState currentState; XINPUT_STATE state; BYTE KeyDoubleTapStates[0xFF]; Utilities::Stopwatch KeyDoubleTapWatches[0xFF]; Stopwatch keyIntervalWatch; BOOL keyIntervalInitials[0xFF]; BYTE keyIntervalTapStates[0xFF]; FLOAT keyIntervalTapTimes[0xFF]; static Xinput* instance; void SetTapStates(BYTE keycode, float elapsed); int xinput_num, rumble_left, rumble_right; bool rumble; }; } ================================================ FILE: source-code/source/plugins/TLAC/Input/Xinput/XinputState.cpp ================================================ #include "XinputState.h" namespace TLAC::Input { bool XinputState::IsDown(BYTE keycode) { return KeyStates[keycode]; } } ================================================ FILE: source-code/source/plugins/TLAC/Input/Xinput/XinputState.h ================================================ #pragma once #include namespace TLAC::Input { struct XinputState { bool KeyStates[0x8F]; bool IsDown(BYTE keycode); }; } ================================================ FILE: source-code/source/plugins/TLAC/TLAC.vcxproj ================================================  Debug x64 Release x64 16.0 {2B5533BB-04A1-424F-9BCA-1CA963B46B7F} Win32Proj TLAC 10.0 DynamicLibrary true v142 Unicode DynamicLibrary false v142 true Unicode false $(ProjectName) .dva true $(ProjectName) .dva NotUsing Level3 MaxSpeed true true true NDEBUG;TLAC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true stdcpp17 ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\detours\include;..\..\..\dependencies\freeglut\include;%(AdditionalIncludeDirectories) MultiThreadedDLL -d2FH4- %(AdditionalOptions) Windows true true true false XINPUT9_1_0.LIB;dinput8.lib;dxguid.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Winusb.lib;Setupapi.lib;%(AdditionalDependencies) Xinput.h ..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories) -d2:-FH4- %(AdditionalOptions) NotUsing Level3 Disabled true _DEBUG;TLAC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true stdcpp17 ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\detours\include;..\..\..\dependencies\freeglut\include;%(AdditionalIncludeDirectories) -d2FH4- %(AdditionalOptions) Windows true false ..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories) XINPUT9_1_0.LIB;dinput8.lib;dxguid.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) Xinput.h -d2:-FH4- %(AdditionalOptions) ================================================ FILE: source-code/source/plugins/TLAC/TLAC.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Drawing.cpp ================================================ #pragma once #include #include #include #include "Drawing.h" #include "../Constants.h" namespace TLAC::Utilities { #pragma pack(push, 1) Drawing::FontInfo*(*Drawing::getFont)(FontInfo* fi, uint32_t id) = (FontInfo*(*)(FontInfo* fi, uint32_t id))0x140196510; void(*Drawing::fontSize)(FontInfo* fi, float width, float height) = (void(*)(FontInfo* fi, float width, float height))0x140199e60; void Drawing::drawText(DrawParams* dtParam, drawTextFlags flags, std::string str) { ((void(*)(DrawParams*, uint32_t, const char*, int64_t))0x140198500)(dtParam, flags, str.c_str(), str.length()); } void Drawing::drawTextW(DrawParams* dtParam, drawTextFlags flags, std::wstring str) { const wchar_t* ptrs[2]; ptrs[0] = str.c_str(); ptrs[1] = (wchar_t*)((uint64_t)ptrs[0] + str.length() * 2); ((void(*)(DrawParams*, uint32_t, const wchar_t**))0x140198380)(dtParam, flags, &ptrs[0]); } void Drawing::drawTextFormattedW(DrawParams* dtParam, drawTextFlags flags, std::wstring str) { const wchar_t* ptrs[2]; ptrs[0] = str.c_str(); ptrs[1] = (wchar_t*)((uint64_t)ptrs[0] + str.length() * 2); ((void(*)(uint32_t, const wchar_t**, DrawParams*))0x1404c2aa0)(flags, &ptrs[0], dtParam); } void Drawing::drawTextWithSpritesW(DrawParams* dtParam, drawTextFlags flags, std::wstring str) { const wchar_t* ptrs[2]; ptrs[0] = str.c_str(); ptrs[1] = (wchar_t*)((uint64_t)ptrs[0] + str.length() * 2); ((void(*)(uint32_t, const wchar_t**, DrawParams*))0x1404c2cf0)(flags, &ptrs[0], dtParam); } void(*Drawing::fillRectangle)(DrawParams* dtParam, const RectangleBounds &rect) = (void(*)(DrawParams* dtParam, const RectangleBounds &rect))0x140198d80; // draws only a border -- use fillRectangle to fill contained pixels void Drawing::drawRectangle(DrawParams* dtParam, const RectangleBounds &rect) { ((void(*)(DrawParams*, const RectangleBounds&))0x140198320)(dtParam, rect); } // draws only a border -- use fillRectangle to fill contained pixels void Drawing::drawRectangle(DrawParams* dtParam, const RectangleBounds &rect, float thickness) { uint32_t oldFillColour = dtParam->fillColour; dtParam->fillColour = dtParam->colour; // yes this seems pretty dodgy, but sega does it this way so... I guess it's the only way RectangleBounds tempRect = { rect.x, rect.y, thickness, rect.height }; // left side fillRectangle(dtParam, tempRect); tempRect.x = rect.x + rect.width - thickness; // right side fillRectangle(dtParam, tempRect); tempRect = { rect.x + thickness, rect.y, rect.width - (thickness * 2), thickness }; // top side fillRectangle(dtParam, tempRect); tempRect.y = rect.y + rect.height - thickness; // left side fillRectangle(dtParam, tempRect); dtParam->fillColour = oldFillColour; } void Drawing::drawLine(DrawParams* dtParam, const Point &p1, const Point &p2) { ((void(*)(DrawParams*, const RectangleBounds&))0x140198080)(dtParam, { p1.x, p1.y, p2.x, p2.y }); } // draw from the top left corner of rect to the bottom left void Drawing::drawLine(DrawParams* dtParam, const RectangleBounds &rect) { drawLine(dtParam, { rect.x, rect.y }, { rect.x + rect.width, rect.y + rect.height }); } void Drawing::drawPolyline(DrawParams* dtParam, const std::vector points) { ((void(*)(DrawParams*, const Point*, uint64_t))0x1401980e0)(dtParam, points.data(), points.size()); } /* int Drawing::findAetDebugFileId(std::string name) { AetDebugFileInfo* aetArray = *(AetDebugFileInfo**)AET_DEBUG_ARRAY_POINTER_ADDRESS; AetDebugFileInfo* aetArrayEndAddress = *(AetDebugFileInfo**)(AET_DEBUG_ARRAY_POINTER_ADDRESS + 0x08); int id = 0; while (&aetArray[id] < aetArrayEndAddress) { if (name == aetArray[id].name2.GetCharBuf()) // dwgui enum uses name2, so this should too I guess return aetArray[id].gameId; else id++; } return -1; } */ // gets a file ID for use with createAetLayer // returns -1 if the file was not found // note: names are a little different to in 2dauth test -- it seems like they have "_MAIN" appended int Drawing::findAetFileId(std::string name) { AetFileInfo* aetArray = *(AetFileInfo**)AET_ARRAY_POINTER_ADDRESS; AetFileInfo* aetArrayEndAddress = *(AetFileInfo**)(AET_ARRAY_POINTER_ADDRESS + 0x08); int id = 0; while (&aetArray[id] < aetArrayEndAddress) { if (name == aetArray[id].name.GetCharBuf()) // dwgui enum uses name2, so this should too I guess return aetArray[id].id1; else id++; } return -1; } // draw an aet layer (with all settings) // aetSpeedCallback is actually a pointer to a class or struct with the callback address at offset +0x8 int Drawing::createAetLayer(int32_t fileId, uint32_t drawLayer, createAetFlags flags, const char* name, const Point &loc, int32_t unk2, const char* animation, const char* animation2, float animationInTime, float animationOutTime, const Point &scale, const void* aetSpeedCallback) { return ((int(*)(int32_t, uint32_t, createAetFlags, const char*, const Point&, int32_t, const char*, const char*, float, float, const Point&, const void*))0x14013be60)(fileId, drawLayer, flags, name, loc, unk2, animation, animation2, animationInTime, animationOutTime, scale, aetSpeedCallback); } // draw an aet layer (with animation timing override) int Drawing::createAetLayer(int32_t fileId, uint32_t drawLayer, createAetFlags flags, const char* name, const Point &loc, float animationInTime, float animationOutTime) { return createAetLayer(fileId, drawLayer, flags, name, loc, 0, 0, 0, animationInTime, animationOutTime, *(Point*)0, 0); } // draw an aet layer (with scale) int Drawing::createAetLayer(int32_t fileId, uint32_t drawLayer, createAetFlags flags, const char* name, const Point &loc, const Point &scale) { return createAetLayer(fileId, drawLayer, flags, name, loc, 0, 0, 0, -1, -1, scale, 0); } // draw an aet layer int Drawing::createAetLayer(int32_t fileId, uint32_t drawLayer, createAetFlags flags, const char* name, const Point &loc) { return createAetLayer(fileId, drawLayer, flags, name, loc, 0, 0, 0, -1, -1, *(Point*)0, 0); } void Drawing::destroyAetLayer(int &layer) { if (layer != 0) { ((void(*)(int layer))0x14019d570)(layer); layer = 0; } } #pragma pack(pop) } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Drawing.h ================================================ #pragma once #include #include #include namespace TLAC::Utilities { class Drawing { public: #pragma pack(push, 1) struct Point { float x; float y; }; struct RectangleBounds { float x; float y; float width; float height; }; struct RawFont { uint32_t sprId; // ? uint8_t width1; // advance uint8_t height1; // advance uint8_t width2; // tex glyph box uint8_t height2; // tex glyph box uint8_t layoutParam2Num; // layout param 2 is a fraction that seems to relate to margins uint8_t layoutParam2Div; uint8_t padding0a[0x02]; int32_t fontmapId; float layoutParam2NumOverDiv; uint8_t padding14[0x04]; uint64_t texWidthChars; int64_t dataBegin; int64_t dataEnd; int64_t dataCapacityEnd; uint8_t layoutParam1; uint8_t padding39[0x7]; }; struct RawFontHolderIdk // ...SeemsPrettyPointlessTbh { RawFont* rawfont; uint16_t width1; uint16_t height1; uint16_t zero1; // ? uint16_t zero2; // ? uint8_t proportional; // game always sets this to 0 }; struct FontInfo { uint32_t fontId; uint8_t padding04[0x4]; RawFont* rawfont; uint16_t flag10; // (proportional != 0 && layoutParam1 != 0) ? 2 : (layoutParam2NumOverDiv != 1 ? 1 : 0) uint8_t padding12[0x02]; float width1; float height1; float width2; float height2; float userSizeWidth; float userSizeHeight; float userSizeWidthMultiplier; // userSizeWidth / width1 float userSizeHeightMultiplier; // userSizeHeight / width2 float spacingWidth; // ? float spacingHeight; // ? void setSize(float width, float height) { ((void(*)(FontInfo* fi, float width, float height))0x140199e60)(this, width, height); } FontInfo(uint32_t id) { ((FontInfo*(*)(FontInfo* fi, uint32_t id))0x140196510)(this, id); } }; static FontInfo*(*getFont)(FontInfo* fi, uint32_t id); static void(*fontSize)(FontInfo* fi, float width, float height); struct DrawParams { uint32_t colour; // RGBA byte array?, so set as 0xAABBGGRR uint32_t fillColour; // ?? RGBA byte array?, so set as 0xAABBGGRR uint8_t clip; uint8_t unk09[0x3]; RectangleBounds clipRect; uint32_t layer; // 8 seems similar to default but higher // 0x18 is below 0x19 but still seems to be above any game elements // 0x19 is startup screen (below dwgui) // I noticed some use different scaling uint32_t unk20; uint32_t unk24; uint32_t unk28; Point textCurrentLoc; Point lineOriginLoc; // must be set for newlines to work as expected uint8_t padding3c[0x4]; uint64_t lineLength; // in characters FontInfo* font; uint16_t unk50; DrawParams(FontInfo* fi) { colour = 0xffffffff; fillColour = 0xff808080; // except it's not? clip = 0; clipRect = { 0, 0, 0, 0 }; layer = 0x7; unk20 = 0x0; unk24 = 0xd; unk28 = 0; textCurrentLoc = { 0, 0 }; lineOriginLoc = { 0, 0 }; lineLength = 0; font = fi; unk50 = 0x25a1; } DrawParams() { DrawParams((FontInfo*)0x140eda860); } }; enum drawTextFlags : uint32_t { DRAWTEXT_ENABLE_XADVANCE = 1, DRAWTEXT_ALIGN_RIGHT = 2, DRAWTEXT_ALIGN_SCREEN_CENTRE = 4, DRAWTEXT_ALIGN_CENTRE = 8, DRAWTEXT_ENABLE_CLIP = 0x200, DRAWTEXT_SCALING_OPTIMISED = 0x400, // ? -- seems to be set if the requested font size doesn't match the original font, and the internal width/height 1 and 2 match // maybe it's just required for any scaling though DRAWTEXT_STROKE = 0x10000, }; static void drawText(DrawParams* dtParam, drawTextFlags flags, std::string str); static void drawTextW(DrawParams* dtParam, drawTextFlags flags, std::wstring str); static void drawTextFormattedW(DrawParams* dtParam, drawTextFlags flags, std::wstring str); static void drawTextWithSpritesW(DrawParams* dtParam, drawTextFlags flags, std::wstring str); static void(*fillRectangle)(DrawParams* dtParam, const RectangleBounds &rect); // draws only a border -- use fillRectangle to fill contained pixels static void drawRectangle(DrawParams* dtParam, const RectangleBounds &rect); // draws only a border -- use fillRectangle to fill contained pixels static void drawRectangle(DrawParams* dtParam, const RectangleBounds &rect, float thickness); static void drawLine(DrawParams* dtParam, const Point &p1, const Point &p2); // draw from the top left corner of rect to the bottom left static void drawLine(DrawParams* dtParam, const RectangleBounds &rect); static void drawPolyline(DrawParams* dtParam, const std::vector points); struct MsString { union { char* string_ptr; char string_buf[16]; }; uint64_t len; uint64_t bufsize; char* GetCharBuf() { if (bufsize > 0xf && string_ptr != nullptr) return string_ptr; else return string_buf; }; void SetCharBuf(char* newcontent) { len = strlen(newcontent); bufsize = len; if (len > 0xf) { string_ptr = _strdup(newcontent); } else { strcpy_s(string_buf, newcontent); } } }; /* struct MsStringW { union { wchar_t* string_ptr; wchar_t string_buf[8]; }; uint64_t len; uint64_t bufsize; wchar_t* GetCharBuf() { if (bufsize > 0x7 && string_ptr != nullptr) return string_ptr; else return string_buf; }; void SetCharBuf(wchar_t* newcontent) { len = wcslen(newcontent); bufsize = len; if (len > 0xf) { string_ptr = wcsdup(newcontent); } else { wcscpy_s(string_buf, newcontent); } } }; */ struct AetDebugFileInfo { MsString name1; int32_t gameId; char unk[4]; // seems to be some kind of mode prefix (eg. "GAM_") MsString name2; // same as name1??? MsString filename; int32_t dbId1; // not sure what the db ids are... this one might be a position int32_t dbId12; }; struct AetFileInfo { int32_t id1; char unk1[4]; // seems to be some kind of mode prefix (eg. "GAM_") int32_t id2; // same as id1??? int32_t unk2; MsString name; int32_t unk3; int32_t unk4; // might be related to sprites? }; // int findAetDebugFileId(std::string name); // gets a file ID for use with createAetLayer // returns -1 if the file was not found // note: names are a little different to in 2dauth test -- it seems like they have "_MAIN" appended static int findAetFileId(std::string name); enum createAetFlags : uint32_t { CREATEAET_20000 = 0x20000, }; // draw an aet layer (with all settings) // aetSpeedCallback is actually a pointer to a class or struct with the callback address at offset +0x8 static int createAetLayer(int32_t fileId, uint32_t drawLayer, createAetFlags flags, const char* name, const Point &loc, int32_t unk2, const char* animation, const char* animation2, float animationInTime, float animationOutTime, const Point &scale, const void* aetSpeedCallback); // draw an aet layer (with animation timing override) static int createAetLayer(int32_t fileId, uint32_t drawLayer, createAetFlags flags, const char* name, const Point &loc, float animationInTime, float animationOutTime); // draw an aet layer (with scale) static int createAetLayer(int32_t fileId, uint32_t drawLayer, createAetFlags flags, const char* name, const Point &loc, const Point &scale); // draw an aet layer static int createAetLayer(int32_t fileId, uint32_t drawLayer, createAetFlags flags, const char* name, const Point &loc); static void destroyAetLayer(int &layer); #pragma pack(pop) }; } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/EnumBitwiseOperations.h ================================================ #pragma once namespace TLAC::Utilities { template inline T operator~ (T a) { return (T)~(int)a; } template inline T operator| (T a, T b) { return (T)((int)a | (int)b); } template inline T operator& (T a, T b) { return (T)((int)a & (int)b); } template inline T operator^ (T a, T b) { return (T)((int)a ^ (int)b); } template inline T& operator|= (T& a, T b) { return (T&)((int&)a |= (int)b); } template inline T& operator&= (T& a, T b) { return (T&)((int&)a &= (int)b); } template inline T& operator^= (T& a, T b) { return (T&)((int&)a ^= (int)b); } } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Math.cpp ================================================ #define _USE_MATH_DEFINES #include "Math.h" namespace TLAC::Utilities { float ToDegrees(float radians) { return radians * (180.0f / M_PI); } float ToRadians(float degrees) { return (degrees * M_PI) / 180.0f; } Vec2 GetDirection(float degrees) { float radians = ToRadians(degrees); return Vec2(cos(radians), sin(radians)); } Vec2 PointFromAngle(float degrees, float distance) { float radians = ToRadians(degrees + 90.0f); return Vec2(-1 * std::cos(radians) * distance, -1 * std::sin(radians) * distance); } float AngleFromPoints(Vec2 p0, Vec2 p1) { return (float)(std::atan2(p1.Y - p0.Y, p1.X - p0.X) * 180.0 / M_PI) + 90.0f; } float ConvertRange(float originalStart, float originalEnd, float newStart, float newEnd, float value) { return newStart + ((value - originalStart) * (newEnd - newStart) / (originalEnd - originalStart)); } } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Math.h ================================================ #pragma once #include #include "Vec2.h" #include "Vec3.h" namespace TLAC::Utilities { float ToDegrees(float radians); float ToRadians(float degrees); Vec2 GetDirection(float degrees); Vec2 PointFromAngle(float degrees, float distance); float AngleFromPoints(Vec2 p0, Vec2 p1); float ConvertRange(float originalStart, float originalEnd, float newStart, float newEnd, float value); } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Operations.cpp ================================================ #pragma once #include "Operations.h" namespace TLAC::Utilities { std::vector Split(const std::string& str, const std::string& delim) { std::vector tokens; size_t prev = 0, pos = 0; do { pos = str.find(delim, prev); if (pos == std::string::npos) pos = str.length(); std::string token = str.substr(prev, pos - prev); if (!token.empty()) tokens.push_back(token); prev = pos + delim.length(); } while (pos < str.length() && prev < str.length()); return tokens; } void LeftTrim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); } void RightTrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); } void Trim(std::string &s) { s = trim(s); } std::string trim(const std::string& str, const std::string& whitespace) { const size_t strBegin = str.find_first_not_of(whitespace); if (strBegin == std::string::npos) return ""; const size_t strEnd = str.find_last_not_of(whitespace); const size_t strRange = strEnd - strBegin + 1; return str.substr(strBegin, strRange); } } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Operations.h ================================================ #pragma once #include #include #include #include namespace TLAC::Utilities { std::vector Split(const std::string& str, const std::string& delim); void LeftTrim(std::string &s); void RightTrim(std::string &s); void Trim(std::string &s); std::string trim(const std::string& str, const std::string& whitespace = " \t"); } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Stopwatch.cpp ================================================ #include "Stopwatch.h" namespace TLAC::Utilities { Stopwatch::Stopwatch() { } Stopwatch::~Stopwatch() { } void Stopwatch::Start() { start = high_resolution_clock::now(); } float Stopwatch::Stop() { end = high_resolution_clock::now(); return GetElapsed(); } float Stopwatch::Restart() { float elapsed = Stop(); Start(); return elapsed; } float Stopwatch::GetElapsed() { return (float)(chrono::duration_cast(end - start).count() / TIME_FACTOR); } } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Stopwatch.h ================================================ #pragma once #include namespace chrono = std::chrono; typedef chrono::time_point steady_clock; typedef chrono::high_resolution_clock high_resolution_clock; namespace TLAC::Utilities { class Stopwatch { const float TIME_FACTOR = 1000.0f; public: Stopwatch(); ~Stopwatch(); void Start(); float Stop(); float Restart(); float GetElapsed(); private: steady_clock start; steady_clock end; }; } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Vec2.cpp ================================================ #include "Vec2.h" namespace TLAC::Utilities { Vec2::Vec2() { }; Vec2::Vec2(float x, float y) : X(x), Y(y) { }; Vec2 Vec2::operator+(Vec2 value) { return Vec2(X + value.X, Y + value.Y); } void Vec2::operator+=(const Vec2 &value) { X += value.X; Y += value.Y; } Vec2 Vec2::operator-(Vec2 value) { return Vec2(X - value.X, Y - value.Y); } void Vec2::operator-=(const Vec2 &value) { X -= value.X; Y -= value.Y; } } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Vec2.h ================================================ #pragma once namespace TLAC::Utilities { struct Vec2 { float X, Y; Vec2(); Vec2(float x, float y); Vec2 operator+(Vec2 value); void operator+=(const Vec2 &value); Vec2 operator-(Vec2 value); void operator-=(const Vec2 &value); }; } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Vec3.cpp ================================================ #include "Vec3.h" namespace TLAC::Utilities { Vec3::Vec3() { }; Vec3::Vec3(float x, float y, float z) : X(x), Y(y), Z(z) { }; Vec3 Vec3::operator+(Vec2 value) { return Vec3(X + value.X, Y, Z + value.Y); } void Vec3::operator+=(const Vec2 &value) { X += value.X; Z += value.Y; } Vec3 Vec3::operator-(Vec2 value) { return Vec3(X - value.X, Y, Z - value.Y); } void Vec3::operator-=(const Vec2 &value) { X -= value.X; Z -= value.Y; } Vec3 Vec3::operator+(Vec3 value) { return Vec3(X + value.X, Y + value.Y, Z + value.Z); } void Vec3::operator+=(const Vec3 &value) { X += value.X; Y += value.Y; Z += value.Z; } Vec3 Vec3::operator-(Vec3 value) { return Vec3(X - value.X, Y - value.Y, Z - value.Z); } void Vec3::operator-=(const Vec3 &value) { X -= value.X; Y -= value.Y; Z -= value.Z; } } ================================================ FILE: source-code/source/plugins/TLAC/Utilities/Vec3.h ================================================ #pragma once #include "Vec2.h" namespace TLAC::Utilities { struct Vec3 { float X, Y, Z; Vec3(); Vec3(float x, float y, float z); // Vec2 Vec3 operator+(Vec2 value); void operator+=(const Vec2 &value); Vec3 operator-(Vec2 value); void operator-=(const Vec2 &value); // Vec3 Vec3 operator+(Vec3 value); void operator+=(const Vec3 &value); Vec3 operator-(Vec3 value); void operator-=(const Vec3 &value); }; } ================================================ FILE: source-code/source/plugins/TLAC/Utils.cpp ================================================ #include "Utils.h" #include void InjectCode(void* address, const std::vector data) { const size_t byteCount = data.size() * sizeof(uint8_t); DWORD oldProtect; VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } ================================================ FILE: source-code/source/plugins/TLAC/Utils.h ================================================ #pragma once #include void InjectCode(void* address, const std::vector data); ================================================ FILE: source-code/source/plugins/TLAC/dllmain.cpp ================================================ #include #include #include #include #include #include "Constants.h" #include "framework.h" #include "pluginconfig.h" #include "Input/Mouse/Mouse.h" #include "Input/Xinput/Xinput.h" #include "Input/Keyboard/Keyboard.h" #include "Input/DirectInput/DirectInput.h" #include "Input/DirectInput/Ds4/DualShock4.h" #include "Input/DirectInput/GenericUsb/GenericUsbInput.h" #include "Input/Divaller/Divaller.h" #include "Components/ComponentsManager.h" #include #include #include #include #pragma comment(lib, "detours.lib") void(__cdecl* divaEngineUpdate)() = (void(__cdecl*)())0x14018CC40; void(__cdecl* divaEngineStageDispShadow)() = (void(__cdecl*)())ENGINE_STAGE_DISP_SHADOW_ADDRESS; LRESULT CALLBACK MessageWindowProcessCallback(HWND, UINT, WPARAM, LPARAM); DWORD WINAPI WindowMessageDispatcher(LPVOID); VOID RegisterMessageWindowClass(); struct { DWORD ID = NULL; HANDLE Handle = NULL; } MessageThread; const wchar_t* MessageWindowClassName = TEXT("MessageWindowClass"); const wchar_t* MessageWindowName = TEXT("MessageWindowTitle"); namespace TLAC { Components::ComponentsManager ComponentsManager; bool DeviceConnected = true; bool FirstUpdateTick = true; bool HasWindowFocus, HadWindowFocus; void InitializeTick() { RegisterMessageWindowClass(); if ((MessageThread.Handle = CreateThread(0, 0, WindowMessageDispatcher, 0, 0, 0)) == NULL) printf("[TLAC] InitializeTick(): CreateThread() Error: %d\n", GetLastError()); framework::DivaWindowHandle = WindowFromDC(wglGetCurrentDC()); HRESULT diInitResult = Input::InitializeDirectInput(framework::Module); if (FAILED(diInitResult)) printf("[TLAC] InitializeTick(): Failed to initialize DirectInput. Error: 0x%08X\n", diInitResult); ComponentsManager.Initialize(); } void UpdateTick() { if (FirstUpdateTick) { FirstUpdateTick = false; InitializeTick(); } if (DeviceConnected) { DeviceConnected = false; if (!Input::DualShock4::InstanceInitialized()) { if (Input::DualShock4::TryInitializeInstance()) printf("[TLAC] UpdateTick(): DualShock4 connected and initialized\n"); } if (!Input::GenericUsbInput::InstanceInitialized()) { if (Input::GenericUsbInput::TryInitializeInstance()) printf("[TLAC] UpdateTick(): GenericUsbInput connected and initialized\n"); } if (!Input::Divaller::InstanceInitialized()) { if (Input::Divaller::TryInitializeInstance()) printf("[TLAC] UpdateTick(): Divaller connected and initialized\n"); } } ComponentsManager.Update(); HadWindowFocus = HasWindowFocus; HasWindowFocus = framework::DivaWindowHandle == NULL || GetForegroundWindow() == framework::DivaWindowHandle; if ((HasWindowFocus) && (!framework::inputDisable)) { Input::Keyboard::GetInstance()->PollInput(); Input::Mouse::GetInstance()->PollInput(); Input::Xinput::GetInstance()->PollInput(); if (Input::DualShock4::GetInstance() != nullptr) { if (!Input::DualShock4::GetInstance()->PollInput()) { Input::DualShock4::DeleteInstance(); printf("[TLAC] UpdateTick(): DualShock4 connection lost\n"); } } if (Input::GenericUsbInput::GetInstance() != nullptr) { if (!Input::GenericUsbInput::GetInstance()->PollInput()) { Input::GenericUsbInput::DeleteInstance(); printf("[TLAC] UpdateTick(): GenericUsbInput connection lost\n"); } } if (Input::Divaller::GetInstance() != nullptr) { if (!Input::Divaller::GetInstance()->PollInput()) { Input::Divaller::DeleteInstance(); printf("[TLAC] UpdateTick(): Divaller connection lost\n"); } } ComponentsManager.UpdateInput(); } ComponentsManager.UpdatePostInput(); if ((framework::inputDisable)) { Input::Keyboard::GetInstance()->PollInput(); Input::Mouse::GetInstance()->PollInput(); Input::Xinput::GetInstance()->PollInput(); if (Input::DualShock4::GetInstance() != nullptr) { if (!Input::DualShock4::GetInstance()->PollInput()) { Input::DualShock4::DeleteInstance(); printf("[TLAC] UpdateTick(): DualShock4 connection lost\n"); } } if (Input::GenericUsbInput::GetInstance() != nullptr) { if (!Input::GenericUsbInput::GetInstance()->PollInput()) { Input::GenericUsbInput::DeleteInstance(); printf("[TLAC] UpdateTick(): GenericUsbInput connection lost\n"); } } if (Input::Divaller::GetInstance() != nullptr) { if (!Input::Divaller::GetInstance()->PollInput()) { Input::Divaller::DeleteInstance(); printf("[TLAC] UpdateTick(): Divaller connection lost\n"); } } } if (HasWindowFocus && !HadWindowFocus) ComponentsManager.OnFocusGain(); if (!HasWindowFocus && HadWindowFocus) ComponentsManager.OnFocusLost(); } void UpdateDraw2D() { ComponentsManager.UpdateDraw2D(); } /*void InitializeExtraSettings() { const LPCTSTR RESOLUTION_CONFIG_FILE_NAME = _T(".\\config.ini"); auto nTAA = GetPrivateProfileIntW(L"graphics", L"taa", TRUE, RESOLUTION_CONFIG_FILE_NAME); auto nMLAA = GetPrivateProfileIntW(L"graphics", L"mlaa", TRUE, RESOLUTION_CONFIG_FILE_NAME); if (!nTAA) { { // set TAA var (shouldn't be needed but whatever) *(byte*)0x00000001411AB67C = 0; } { // make constructor/init not set TAA DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001404AB11D, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001404AB11D + 0) = 0x90; *((byte*)0x00000001404AB11D + 1) = 0x90; *((byte*)0x00000001404AB11D + 2) = 0x90; VirtualProtect((BYTE*)0x00000001404AB11D, 3, oldProtect, &bck); } { // not sure, but it's somewhere in TaskPvGame init // just make it set TAA to 0 instead of 1 to avoid possible issues DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001401063CE, 1, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001401063CE + 0) = 0x00; VirtualProtect((BYTE*)0x00000001401063CE, 1, oldProtect, &bck); } { // prevent re-enabling after taking photos DWORD oldProtect, bck; VirtualProtect((BYTE*)0x000000014048FBA9, 1, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x000000014048FBA9 + 0) = 0x00; VirtualProtect((BYTE*)0x000000014048FBA9, 1, oldProtect, &bck); } printf("[TLAC] TAA disabled\n"); } if (!nMLAA) { { // set MLAA var (shouldn't be needed but whatever) *(byte*)0x00000001411AB680 = 0; } { // make constructor/init not set MLAA DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001404AB11A, 3, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001404AB11A + 0) = 0x90; *((byte*)0x00000001404AB11A + 1) = 0x90; *((byte*)0x00000001404AB11A + 2) = 0x90; VirtualProtect((BYTE*)0x00000001404AB11A, 3, oldProtect, &bck); } printf("[TLAC] MLAA disabled\n"); } /*if (nMagFilter > -1) { { // set MAG filter var *(byte*)0x00000001411AC518 = nMagFilter; } { // make constructor/init not set MAG filter (1) DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001404AB13C, 6, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001404AB13C + 0) = 0x90; *((byte*)0x00000001404AB13C + 1) = 0x90; *((byte*)0x00000001404AB13C + 2) = 0x90; *((byte*)0x00000001404AB13C + 3) = 0x90; *((byte*)0x00000001404AB13C + 4) = 0x90; *((byte*)0x00000001404AB13C + 5) = 0x90; VirtualProtect((BYTE*)0x00000001404AB13C, 6, oldProtect, &bck); } { // make constructor/init not set MAG filter (2) DWORD oldProtect, bck; VirtualProtect((BYTE*)0x00000001404A863F, 10, PAGE_EXECUTE_READWRITE, &oldProtect); *((byte*)0x00000001404A863F + 0) = 0x90; *((byte*)0x00000001404A863F + 1) = 0x90; *((byte*)0x00000001404A863F + 2) = 0x90; *((byte*)0x00000001404A863F + 3) = 0x90; *((byte*)0x00000001404A863F + 4) = 0x90; *((byte*)0x00000001404A863F + 5) = 0x90; *((byte*)0x00000001404A863F + 6) = 0x90; *((byte*)0x00000001404A863F + 7) = 0x90; *((byte*)0x00000001404A863F + 8) = 0x90; *((byte*)0x00000001404A863F + 9) = 0x90; VirtualProtect((BYTE*)0x00000001404A863F, 10, oldProtect, &bck); } printf("[TLAC] MAG Filter set to %d\n", nMagFilter); }* }*/ void Dispose() { ComponentsManager.Dispose(); delete Input::Keyboard::GetInstance(); delete Input::Mouse::GetInstance(); delete Input::DualShock4::GetInstance(); delete Input::GenericUsbInput::GetInstance(); Input::DisposeDirectInput(); PostThreadMessage(MessageThread.ID, WM_QUIT, 0, 0); } } DWORD WINAPI WindowMessageDispatcher(LPVOID lpParam) { HWND windowHandle = CreateWindowW( MessageWindowClassName, MessageWindowName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, TLAC::framework::Module, NULL); if (!windowHandle) { printf("[TLAC] WindowMessageDispatcher(): CreateWindowW() Error: %d\n", GetLastError()); return 1; } MessageThread.ID = GetCurrentThreadId(); MSG message; DWORD returnValue; printf("[TLAC] WindowMessageDispatcher(): Entering message loop...\n"); while (1) { returnValue = GetMessage(&message, NULL, 0, 0); if (returnValue != -1) { TranslateMessage(&message); DispatchMessage(&message); } else { printf("[TLAC] WindowMessageDispatcher(): GetMessage() Error: %d\n", returnValue); } } DestroyWindow(windowHandle); return 0; } BOOL RegisterDeviceInterface(HWND hWnd, HDEVNOTIFY* hDeviceNotify) { DEV_BROADCAST_DEVICEINTERFACE NotificationFilter = {}; NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; *hDeviceNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); return *hDeviceNotify != NULL; } LRESULT CALLBACK MessageWindowProcessCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: { HDEVNOTIFY hDevNotify = NULL; if (!RegisterDeviceInterface(hWnd, &hDevNotify)) printf("[TLAC] MessageWindowProcessCallback(): RegisterDeviceInterface() Error: %d\n", GetLastError()); break; } case WM_DEVICECHANGE: { switch (wParam) { case DBT_DEVICEARRIVAL: TLAC::DeviceConnected = true; break; default: break; } } default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } VOID RegisterMessageWindowClass() { WNDCLASS windowClass = { }; windowClass.lpfnWndProc = MessageWindowProcessCallback; windowClass.hInstance = TLAC::framework::Module; windowClass.lpszClassName = MessageWindowClassName; RegisterClass(&windowClass); } void hookedEngineUpdate() { TLAC::UpdateTick(); //divaEngineUpdate(); } void hookedEngineStageDispShadow() { divaEngineStageDispShadow(); TLAC::UpdateDraw2D(); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { HWND consoleHandle = GetConsoleWindow(); switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // Are you a dev and want to debug? Want to always be able to watch the console upon game initialization? Comment this. ShowWindow(consoleHandle, SW_HIDE); printf("[TLAC] DllMain(): Installing hooks...\n"); //InstallHook((void*)ENGINE_UPDATE_HOOK_TARGET_ADDRESS, (void*)UpdateTick, 0xE); DisableThreadLibraryCalls(hModule); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaEngineUpdate, hookedEngineUpdate); DetourTransactionCommit(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaEngineStageDispShadow, hookedEngineStageDispShadow); DetourTransactionCommit(); //TLAC::InitializeExtraSettings(); TLAC::framework::Module = hModule; break; case DLL_PROCESS_DETACH: TLAC::Dispose(); break; } return TRUE; } ================================================ FILE: source-code/source/plugins/TLAC/framework.cpp ================================================ #include "framework.h" #include namespace TLAC { typedef std::filesystem::path fspath; std::string *framework::moduleDirectory; HWND framework::DivaWindowHandle; HMODULE framework::Module; bool framework::inputDisable = false; std::string framework::GetModuleDirectory() { if (moduleDirectory == nullptr) { WCHAR modulePathBuffer[MAX_PATH]; GetModuleFileNameW(framework::Module, modulePathBuffer, MAX_PATH); fspath configPath = fspath(modulePathBuffer).parent_path(); moduleDirectory = new std::string(configPath.u8string()); } return *moduleDirectory; } RECT framework::GetWindowBounds() { RECT windowRect; GetWindowRect(DivaWindowHandle, &windowRect); return windowRect; } extern "C" __declspec(dllexport) void ChangeDivaWindowHandle(HWND hwnd) { framework::DivaWindowHandle = hwnd; return; } } ================================================ FILE: source-code/source/plugins/TLAC/framework.h ================================================ #pragma once #include #include namespace TLAC { class framework { private: static std::string *moduleDirectory; public: static bool inputDisable; static HWND DivaWindowHandle; static HMODULE Module; static std::string GetModuleDirectory(); static RECT GetWindowBounds(); }; } ================================================ FILE: source-code/source/plugins/TLAC/pluginconfig.h ================================================ #include "PluginConfigApi.h" using namespace PluginConfig; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"TLAC"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"Provides keyboard/mouse/controller input, player data management, bug fixes for running on more PCs, etc.\nThis plugin is required."; }