├── .gitignore ├── LICENSE ├── README.md ├── src ├── mnvg_bitcode │ ├── ios.h │ ├── macos.h │ ├── simulator.h │ └── tvos.h ├── nanovg_mtl.h ├── nanovg_mtl.m └── nanovg_mtl_shaders.metal └── tools └── metallib /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ollix 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MetalNanoVG 2 | =========== 3 | 4 | MetalNanoVG is the native [Metal](https://developer.apple.com/metal/) port of [NanoVG](https://github.com/memononen/nanovg) that tries to get the most out of Apple's Graphics APIs. 5 | 6 | ### Donation 7 | If you found this project useful, please consider donating to show your support ❤️ 8 | 9 | [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3366Q3AVUJLTQ) 10 | 11 | Precautions 12 | =========== 13 | 14 | * Works only on [macOS 10.11+](https://support.apple.com/en-us/HT205073), tvOS 9.0+ and [iOS 8.0+](https://developer.apple.com/library/content/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/DeviceCompatibilityMatrix/DeviceCompatibilityMatrix.html#//apple_ref/doc/uid/TP40013599-CH17-SW1). 15 | * Simulator support is available since iOS 13 and requires Xcode 11+ running on macOS 10.15+. 16 | * Not all Apple hardwares are supported even if meets the OS requirement. 17 | * [ARC](https://en.wikipedia.org/wiki/Automatic_Reference_Counting) is required. 18 | 19 | Advantages 20 | ========== 21 | 22 | * Shared buffers between CPU and GPU. 23 | * Various Metal states are cached whenever possible. 24 | * Low overheads compared to OpenGL. 25 | * Pre-compiled shaders. (no need to compile shaders at runtime) 26 | * Seamless integration with powerful Metal features such as [Metal Performance Shaders](https://developer.apple.com/documentation/metalperformanceshaders). 27 | 28 | Installation 29 | ============ 30 | 31 | 1. Download both `NanoVG` and `MetalNanoVG` source codes. 32 | 2. Add both `NanoVG` and `MetalNanoVG`'s `src` directories to the header search 33 | path. 34 | 3. Add `NanoVG`'s `src/nanovg.c` and `MetalNanoVG`'s `src/nanovg_mtl.m` to 35 | the `Compile Sources` section in Xcode. 36 | 4. Link the `Metal` and `QuartzCore` frameworks. 37 | 5. For best performance, disable *GPU Frame Capture* and *Metal API Validation* as described [here](https://developer.apple.com/library/content/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Dev-Technique/Dev-Technique.html#//apple_ref/doc/uid/TP40014221-CH8-SW3). 38 | 39 | Done. 40 | 41 | Usage 42 | ===== 43 | 44 | 1. Include the headers. 45 | 46 | ```C 47 | #include "nanovg.h" 48 | #include "nanovg_mtl.h" 49 | ``` 50 | 51 | 2. Pass the `CAMetalLayer` object when creating the NanoVG context. 52 | 53 | ```C 54 | NVGcontext* ctx = nvgCreateMTL(metalLayer, NVG_ANTIALIAS | NVG_STENCIL_STROKES); 55 | ``` 56 | 57 | Benchmark 58 | ========= 59 | 60 | The following table depicts a simple CPU usage benchmark of running the 61 | NanoVG demo app on iOS devices with full Retina resolution. Both Metal and 62 | OpenGL ES2 implementations get constant 60 FPS. 63 | 64 | | | iPhone 6s+ | iPad Pro 12.7" (2015) | 65 | | ---------- | ----------- | --------------------- | 66 | | Resolution | 1080 x 1920 | 2732 * 2048 | 67 | | Metal | 20% | 20% | 68 | | OpenGL ES2 | 35% | 33% | 69 | 70 | Example 71 | ======= 72 | MetalNanoVG was originally created to improve the performance of the iOS app [Fog of World](https://fogofworld.com). 73 | 74 | ![Screenshot of Fog of World](http://media.fogofworld.com.s3.amazonaws.com/github/fogofworld_screenshot.jpg) 75 | -------------------------------------------------------------------------------- /src/mnvg_bitcode/ios.h: -------------------------------------------------------------------------------- 1 | unsigned char mnvg_bitcode_ios[] = { 2 | 0x4d, 0x54, 0x4c, 0x42, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 3 | 0x00, 0x00, 0x00, 0x00, 0x13, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 4 | 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x01, 0x00, 0x00, 5 | 0x00, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 6 | 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x00, 0x00, 7 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8 | 0x13, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 9 | 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 10 | 0x4e, 0x41, 0x4d, 0x45, 0x0d, 0x00, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 11 | 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x00, 0x54, 0x59, 0x50, 0x45, 0x01, 12 | 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x20, 0x00, 0x51, 0x0a, 0x05, 0x10, 13 | 0xc7, 0xd8, 0xab, 0x67, 0x8d, 0xb5, 0xa2, 0xdb, 0x58, 0x64, 0x12, 0x2b, 14 | 0xa0, 0xce, 0x63, 0x49, 0xcf, 0x7d, 0x28, 0xf1, 0x4d, 0x6f, 0x9e, 0xc9, 15 | 0xf5, 0x31, 0x0d, 0xb2, 0x4f, 0x46, 0x46, 0x54, 0x18, 0x00, 0x00, 0x00, 16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x45, 18 | 0x52, 0x53, 0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 19 | 0x45, 0x4e, 0x44, 0x54, 0x76, 0x00, 0x00, 0x00, 0x4e, 0x41, 0x4d, 0x45, 20 | 0x0f, 0x00, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 21 | 0x61, 0x64, 0x65, 0x72, 0x00, 0x54, 0x59, 0x50, 0x45, 0x01, 0x00, 0x01, 22 | 0x48, 0x41, 0x53, 0x48, 0x20, 0x00, 0x62, 0x6c, 0x9e, 0x92, 0xf1, 0xd7, 23 | 0xdf, 0x09, 0x18, 0x4b, 0x71, 0x00, 0x23, 0xca, 0xa6, 0x07, 0x37, 0x26, 24 | 0xe7, 0x98, 0x7b, 0x86, 0xcb, 0xeb, 0xe0, 0xae, 0x2b, 0x19, 0x17, 0x18, 25 | 0xe9, 0x49, 0x4f, 0x46, 0x46, 0x54, 0x18, 0x00, 0x29, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | 0xb0, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x45, 0x52, 0x53, 28 | 0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x4e, 29 | 0x44, 0x54, 0x78, 0x00, 0x00, 0x00, 0x4e, 0x41, 0x4d, 0x45, 0x11, 0x00, 30 | 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, 31 | 0x65, 0x72, 0x41, 0x41, 0x00, 0x54, 0x59, 0x50, 0x45, 0x01, 0x00, 0x01, 32 | 0x48, 0x41, 0x53, 0x48, 0x20, 0x00, 0xa7, 0x36, 0xad, 0xef, 0xca, 0xf7, 33 | 0x5c, 0x88, 0x26, 0xf9, 0x51, 0xdd, 0x66, 0xe2, 0xdb, 0x9a, 0x4f, 0x8b, 34 | 0xad, 0x24, 0x41, 0xc3, 0xd6, 0x25, 0x51, 0x4a, 0x79, 0x23, 0xe7, 0x2a, 35 | 0x24, 0x25, 0x4f, 0x46, 0x46, 0x54, 0x18, 0x00, 0x31, 0x00, 0x00, 0x00, 36 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x20, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x45, 0x52, 0x53, 38 | 0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x4e, 39 | 0x44, 0x54, 0x45, 0x4e, 0x44, 0x54, 0x25, 0x00, 0x00, 0x00, 0x56, 0x41, 40 | 0x54, 0x54, 0x11, 0x00, 0x02, 0x00, 0x70, 0x6f, 0x73, 0x00, 0x00, 0x80, 41 | 0x74, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x01, 0x80, 0x56, 0x41, 0x54, 42 | 0x59, 0x04, 0x00, 0x02, 0x00, 0x04, 0x04, 0x45, 0x4e, 0x44, 0x54, 0x04, 43 | 0x00, 0x00, 0x00, 0x45, 0x4e, 0x44, 0x54, 0x04, 0x00, 0x00, 0x00, 0x45, 44 | 0x4e, 0x44, 0x54, 0x04, 0x00, 0x00, 0x00, 0x45, 0x4e, 0x44, 0x54, 0x04, 45 | 0x00, 0x00, 0x00, 0x45, 0x4e, 0x44, 0x54, 0x04, 0x00, 0x00, 0x00, 0x45, 46 | 0x4e, 0x44, 0x54, 0xde, 0xc0, 0x17, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x14, 47 | 0x00, 0x00, 0x00, 0x94, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x42, 48 | 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0xa2, 0x02, 0x00, 0x00, 0x0b, 49 | 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 50 | 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 51 | 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 52 | 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 53 | 0x08, 0x18, 0x49, 0x0a, 0x32, 0x44, 0x24, 0x48, 0x0a, 0x90, 0x21, 0x23, 54 | 0xc4, 0x52, 0x80, 0x0c, 0x19, 0x21, 0x72, 0x24, 0x07, 0xc8, 0x08, 0x11, 55 | 0x62, 0xa8, 0xa0, 0xa8, 0x40, 0xc6, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x51, 56 | 0x18, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x1b, 0xc8, 0x25, 0xf8, 0xff, 57 | 0xff, 0xff, 0xff, 0x01, 0x90, 0x80, 0x8a, 0x18, 0x87, 0x77, 0x90, 0x07, 58 | 0x79, 0x28, 0x87, 0x71, 0xa0, 0x07, 0x76, 0xc8, 0x87, 0x36, 0x90, 0x87, 59 | 0x77, 0xa8, 0x07, 0x77, 0x20, 0x87, 0x72, 0x20, 0x87, 0x36, 0x20, 0x87, 60 | 0x74, 0xb0, 0x87, 0x74, 0x20, 0x87, 0x72, 0x68, 0x83, 0x79, 0x88, 0x07, 61 | 0x79, 0xa0, 0x87, 0x36, 0x30, 0x07, 0x78, 0x68, 0x83, 0x76, 0x08, 0x07, 62 | 0x7a, 0x40, 0x07, 0xc0, 0x1c, 0xc2, 0x81, 0x1d, 0xe6, 0xa1, 0x1c, 0x00, 63 | 0x82, 0x1c, 0xd2, 0x61, 0x1e, 0xc2, 0x41, 0x1c, 0xd8, 0xa1, 0x1c, 0xda, 64 | 0x80, 0x1e, 0xc2, 0x21, 0x1d, 0xd8, 0xa1, 0x0d, 0xc6, 0x21, 0x1c, 0xd8, 65 | 0x81, 0x1d, 0xe6, 0x01, 0x30, 0x87, 0x70, 0x60, 0x87, 0x79, 0x28, 0x07, 66 | 0x80, 0x60, 0x87, 0x72, 0x98, 0x87, 0x79, 0x68, 0x03, 0x78, 0x90, 0x87, 67 | 0x72, 0x18, 0x87, 0x74, 0x98, 0x87, 0x72, 0x68, 0x03, 0x73, 0x80, 0x87, 68 | 0x76, 0x08, 0x07, 0x72, 0x00, 0xcc, 0x21, 0x1c, 0xd8, 0x61, 0x1e, 0xca, 69 | 0x01, 0x20, 0xdc, 0xe1, 0x1d, 0xda, 0xc0, 0x1c, 0xe4, 0x21, 0x1c, 0xda, 70 | 0xa1, 0x1c, 0xda, 0x00, 0x1e, 0xde, 0x21, 0x1d, 0xdc, 0x81, 0x1e, 0xca, 71 | 0x41, 0x1e, 0xda, 0xa0, 0x1c, 0xd8, 0x21, 0x1d, 0xda, 0x01, 0xa0, 0x07, 72 | 0x79, 0xa8, 0x87, 0x72, 0x00, 0x06, 0x77, 0x78, 0x87, 0x36, 0x30, 0x07, 73 | 0x79, 0x08, 0x87, 0x76, 0x28, 0x87, 0x36, 0x80, 0x87, 0x77, 0x48, 0x07, 74 | 0x77, 0xa0, 0x87, 0x72, 0x90, 0x87, 0x36, 0x28, 0x07, 0x76, 0x48, 0x87, 75 | 0x76, 0x68, 0x03, 0x77, 0x78, 0x07, 0x77, 0x68, 0x03, 0x76, 0x28, 0x87, 76 | 0x70, 0x30, 0x07, 0x80, 0x70, 0x87, 0x77, 0x68, 0x83, 0x74, 0x70, 0x07, 77 | 0x73, 0x98, 0x87, 0x36, 0x30, 0x07, 0x78, 0x68, 0x83, 0x76, 0x08, 0x07, 78 | 0x7a, 0x40, 0x07, 0x80, 0x1e, 0xe4, 0xa1, 0x1e, 0xca, 0x01, 0x20, 0xdc, 79 | 0xe1, 0x1d, 0xda, 0x40, 0x1d, 0xea, 0xa1, 0x1d, 0xe0, 0xa1, 0x0d, 0xe8, 80 | 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x1e, 0x00, 0x73, 0x08, 0x07, 81 | 0x76, 0x98, 0x87, 0x72, 0x00, 0x08, 0x77, 0x78, 0x87, 0x36, 0x70, 0x87, 82 | 0x70, 0x70, 0x87, 0x79, 0x68, 0x03, 0x73, 0x80, 0x87, 0x36, 0x68, 0x87, 83 | 0x70, 0xa0, 0x07, 0x74, 0x00, 0xe8, 0x41, 0x1e, 0xea, 0xa1, 0x1c, 0x00, 84 | 0xc2, 0x1d, 0xde, 0xa1, 0x0d, 0xe6, 0x21, 0x1d, 0xce, 0xc1, 0x1d, 0xca, 85 | 0x81, 0x1c, 0xda, 0x40, 0x1f, 0xca, 0x41, 0x1e, 0xde, 0x61, 0x1e, 0xda, 86 | 0xc0, 0x1c, 0xe0, 0xa1, 0x0d, 0xda, 0x21, 0x1c, 0xe8, 0x01, 0x1d, 0x00, 87 | 0x7a, 0x90, 0x87, 0x7a, 0x28, 0x07, 0x80, 0x70, 0x87, 0x77, 0x68, 0x03, 88 | 0x7a, 0x90, 0x87, 0x70, 0x80, 0x07, 0x78, 0x48, 0x07, 0x77, 0x38, 0x87, 89 | 0x36, 0x68, 0x87, 0x70, 0xa0, 0x07, 0x74, 0x00, 0xe8, 0x41, 0x1e, 0xea, 90 | 0xa1, 0x1c, 0x00, 0x62, 0x1e, 0xe8, 0x21, 0x1c, 0xc6, 0x61, 0x1d, 0xda, 91 | 0x00, 0x1e, 0xe4, 0xe1, 0x1d, 0xe8, 0xa1, 0x1c, 0xc6, 0x81, 0x1e, 0xde, 92 | 0x41, 0x1e, 0xda, 0x40, 0x1c, 0xea, 0xc1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 93 | 0xa1, 0x0d, 0xe6, 0x21, 0x1d, 0xf4, 0xa1, 0x1c, 0x00, 0x3c, 0x00, 0x88, 94 | 0x7a, 0x70, 0x87, 0x79, 0x08, 0x07, 0x73, 0x28, 0x87, 0x36, 0x30, 0x07, 95 | 0x78, 0x68, 0x83, 0x76, 0x08, 0x07, 0x7a, 0x40, 0x07, 0x80, 0x1e, 0xe4, 96 | 0xa1, 0x1e, 0xca, 0x01, 0x20, 0xea, 0x61, 0x1e, 0xca, 0xa1, 0x0d, 0xe6, 97 | 0xe1, 0x1d, 0xcc, 0x81, 0x1e, 0xda, 0xc0, 0x1c, 0xd8, 0xe1, 0x1d, 0xc2, 98 | 0x81, 0x1e, 0x00, 0x73, 0x08, 0x07, 0x76, 0x98, 0x87, 0x72, 0x00, 0x36, 99 | 0x20, 0xc2, 0x00, 0x24, 0xc0, 0x02, 0x54, 0x00, 0x00, 0x00, 0x00, 0x49, 100 | 0x18, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x84, 0x40, 0x00, 0x89, 101 | 0x20, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 102 | 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 103 | 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 104 | 0x2c, 0x33, 0x00, 0xc3, 0x08, 0x04, 0x30, 0x8c, 0x20, 0x00, 0x57, 0x49, 105 | 0x53, 0x44, 0x09, 0x93, 0xbf, 0x02, 0xd2, 0x44, 0x44, 0x48, 0x46, 0x44, 106 | 0x1d, 0x30, 0x01, 0x68, 0x08, 0x91, 0x41, 0x04, 0x41, 0x28, 0xc4, 0x88, 107 | 0x10, 0xd5, 0x40, 0xc0, 0x1c, 0x01, 0x18, 0xa4, 0x00, 0x8e, 0x00, 0x00, 108 | 0x00, 0x00, 0x00, 0x13, 0xa8, 0x70, 0x48, 0x07, 0x79, 0xb0, 0x03, 0x3a, 109 | 0x68, 0x83, 0x70, 0x80, 0x07, 0x78, 0x60, 0x87, 0x72, 0x68, 0x83, 0x74, 110 | 0x78, 0x87, 0x79, 0xc0, 0x03, 0x37, 0x80, 0x03, 0x37, 0x80, 0x83, 0x0d, 111 | 0xb7, 0x51, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x60, 0x07, 0x74, 0xa0, 0x07, 112 | 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe9, 0x10, 0x07, 113 | 0x7a, 0x80, 0x07, 0x7a, 0x80, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 114 | 0x78, 0xa0, 0x07, 0x78, 0xd0, 0x06, 0xe9, 0x10, 0x07, 0x76, 0xa0, 0x07, 115 | 0x71, 0x60, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xd0, 0x06, 0xe9, 0x30, 0x07, 116 | 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 117 | 0xe9, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 118 | 0x74, 0xd0, 0x06, 0xe6, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 119 | 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 120 | 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xf6, 0x10, 0x07, 121 | 0x76, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xd0, 0x06, 122 | 0xf6, 0x20, 0x07, 0x74, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 123 | 0x72, 0xd0, 0x06, 0xf6, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 124 | 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xf6, 0x40, 0x07, 0x78, 0xa0, 0x07, 125 | 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xf6, 0x60, 0x07, 126 | 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 127 | 0xf6, 0x90, 0x07, 0x76, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xa0, 0x07, 128 | 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xf6, 0x10, 0x07, 0x72, 0x80, 0x07, 129 | 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 130 | 0x6d, 0x60, 0x0f, 0x71, 0x90, 0x07, 0x72, 0xa0, 0x07, 0x72, 0x50, 0x07, 131 | 0x76, 0xa0, 0x07, 0x72, 0x50, 0x07, 0x76, 0xd0, 0x06, 0xf6, 0x20, 0x07, 132 | 0x75, 0x60, 0x07, 0x7a, 0x20, 0x07, 0x75, 0x60, 0x07, 0x7a, 0x20, 0x07, 133 | 0x75, 0x60, 0x07, 0x6d, 0x60, 0x0f, 0x75, 0x10, 0x07, 0x72, 0xa0, 0x07, 134 | 0x75, 0x10, 0x07, 0x72, 0xa0, 0x07, 0x75, 0x10, 0x07, 0x72, 0xd0, 0x06, 135 | 0xf6, 0x10, 0x07, 0x70, 0x20, 0x07, 0x74, 0xa0, 0x07, 0x71, 0x00, 0x07, 136 | 0x72, 0x40, 0x07, 0x7a, 0x10, 0x07, 0x70, 0x20, 0x07, 0x74, 0xd0, 0x06, 137 | 0xee, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 138 | 0x43, 0x18, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2c, 139 | 0x10, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x10, 0x19, 140 | 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xc2, 0x62, 141 | 0x28, 0x81, 0x11, 0x80, 0x82, 0x28, 0x82, 0x42, 0x20, 0x18, 0x23, 0x00, 142 | 0x41, 0x10, 0x14, 0xc1, 0x80, 0x72, 0x2c, 0xa1, 0x11, 0x00, 0x00, 0x79, 143 | 0x18, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x10, 0x97, 144 | 0x29, 0xa2, 0x25, 0x10, 0xab, 0x32, 0xb9, 0xb9, 0xb4, 0x37, 0xb7, 0x21, 145 | 0x06, 0x52, 0x1c, 0x40, 0x82, 0x50, 0xb9, 0x1b, 0x43, 0x0b, 0x93, 0xfb, 146 | 0x9a, 0x4b, 0xd3, 0x2b, 0x1b, 0x62, 0x20, 0xc2, 0x21, 0x20, 0x06, 0xd7, 147 | 0x20, 0x08, 0x0e, 0x8e, 0xad, 0x0c, 0x84, 0x89, 0xc9, 0xaa, 0x09, 0xc4, 148 | 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x0d, 0x24, 0x07, 0x46, 0xc6, 0x25, 149 | 0x07, 0x04, 0xa5, 0xad, 0x8c, 0x2e, 0x8c, 0xcd, 0xac, 0xac, 0x25, 0x07, 150 | 0x46, 0xc6, 0x25, 0xc7, 0xc5, 0x26, 0x26, 0x65, 0x88, 0x70, 0x10, 0x43, 151 | 0x0c, 0x44, 0x40, 0x02, 0x64, 0x60, 0xd1, 0x54, 0x46, 0x17, 0xc6, 0x36, 152 | 0x04, 0x39, 0x0e, 0x44, 0x40, 0x06, 0x64, 0xe0, 0x16, 0x96, 0x26, 0xe7, 153 | 0x32, 0xf6, 0xd6, 0x06, 0x97, 0xc6, 0x56, 0xe6, 0x42, 0x56, 0xe6, 0xf6, 154 | 0x26, 0xd7, 0x36, 0xf7, 0x45, 0x96, 0x36, 0x17, 0x26, 0xc6, 0x56, 0x36, 155 | 0x44, 0x38, 0x12, 0x72, 0x61, 0x69, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 156 | 0x69, 0x6c, 0x65, 0x2e, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x74, 157 | 0x68, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x84, 0x63, 0x21, 158 | 0x19, 0x84, 0xa5, 0xc9, 0xb9, 0x8c, 0xbd, 0xb5, 0xc1, 0xa5, 0xb1, 0x95, 159 | 0xb9, 0x98, 0xc9, 0x85, 0xb5, 0x95, 0x89, 0xd5, 0x99, 0x99, 0x95, 0xc9, 160 | 0x7d, 0x99, 0x95, 0xd1, 0x8d, 0xa1, 0x7d, 0x95, 0xb9, 0x85, 0x89, 0xb1, 161 | 0x95, 0x0d, 0x11, 0x8e, 0x86, 0x61, 0x10, 0x96, 0x26, 0xe7, 0x32, 0xf6, 162 | 0xd6, 0x06, 0x97, 0xc6, 0x56, 0xe6, 0xe2, 0x16, 0x46, 0x97, 0x66, 0x57, 163 | 0xf6, 0x45, 0xf6, 0x56, 0x27, 0xc6, 0x56, 0xf6, 0x45, 0x96, 0x36, 0x17, 164 | 0x26, 0xc6, 0x56, 0x36, 0x44, 0x38, 0x1e, 0x92, 0x41, 0x58, 0x9a, 0x9c, 165 | 0xcb, 0xd8, 0x5b, 0x1b, 0x5c, 0x1a, 0x5b, 0x99, 0x8b, 0x5b, 0x18, 0x5d, 166 | 0x9a, 0x5d, 0xd9, 0x17, 0xdb, 0x9b, 0xdb, 0xd9, 0x17, 0xdb, 0x9b, 0xdb, 167 | 0xd9, 0x17, 0x59, 0xda, 0x5c, 0x98, 0x18, 0x5b, 0xd9, 0x10, 0xe1, 0x88, 168 | 0x78, 0x06, 0x61, 0x69, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 169 | 0x65, 0x2e, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x77, 0x69, 0x64, 170 | 0x65, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x64, 0x69, 171 | 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x84, 0x63, 0x22, 0x13, 0x96, 0x26, 172 | 0xe7, 0x02, 0xf7, 0x36, 0x97, 0x46, 0x97, 0xf6, 0xe6, 0xc6, 0x28, 0x2c, 173 | 0x4d, 0xce, 0x25, 0x4c, 0xee, 0xec, 0x8b, 0x2e, 0x0f, 0xae, 0xec, 0xcb, 174 | 0x2d, 0xac, 0xad, 0x8c, 0x86, 0x19, 0xdb, 0x5b, 0x18, 0x1d, 0x0d, 0x99, 175 | 0xb0, 0x34, 0x39, 0x97, 0x30, 0xb9, 0xb3, 0x2f, 0xb7, 0xb0, 0xb6, 0x32, 176 | 0x0e, 0x70, 0x6f, 0x73, 0x43, 0x94, 0xa3, 0x3a, 0xac, 0xe3, 0x3a, 0xb0, 177 | 0x23, 0x63, 0x14, 0x96, 0x26, 0xe7, 0x62, 0x57, 0x26, 0x47, 0x57, 0x86, 178 | 0xf7, 0xf5, 0x56, 0x47, 0x07, 0x57, 0x47, 0xc7, 0xea, 0xac, 0xcc, 0xad, 179 | 0x4c, 0x2e, 0x8c, 0xae, 0x8c, 0x0c, 0x85, 0xc6, 0x0c, 0xee, 0x6d, 0x8e, 180 | 0xc8, 0x4e, 0xe6, 0xcb, 0x2c, 0x85, 0x86, 0x19, 0xdb, 0x5b, 0x18, 0x9d, 181 | 0x0c, 0x09, 0x33, 0xb8, 0xb7, 0xb9, 0x21, 0xcc, 0xb1, 0x1d, 0xdc, 0x61, 182 | 0x1d, 0xdd, 0x81, 0x1d, 0x1e, 0xb1, 0xb3, 0x32, 0xb7, 0x32, 0xb9, 0x30, 183 | 0xba, 0x32, 0x32, 0x94, 0x1b, 0x33, 0xba, 0xb1, 0xb7, 0x37, 0x39, 0x32, 184 | 0x22, 0x3b, 0x99, 0x2f, 0xb3, 0x14, 0x1e, 0x66, 0x74, 0x63, 0x6f, 0x6f, 185 | 0x72, 0x64, 0x43, 0x98, 0x63, 0x3b, 0xc0, 0xe0, 0xb0, 0x8e, 0xee, 0xc0, 186 | 0x8e, 0x30, 0x18, 0x62, 0x1c, 0xda, 0xf1, 0x1d, 0x62, 0x40, 0x28, 0x2c, 187 | 0x4d, 0xce, 0xc5, 0xae, 0x4c, 0x8e, 0xae, 0x0c, 0xef, 0x2b, 0xcd, 0x0d, 188 | 0xae, 0x8e, 0x8e, 0x52, 0x58, 0x9a, 0x9c, 0x0b, 0xdb, 0xdb, 0x58, 0x18, 189 | 0x5d, 0xda, 0x9b, 0xdb, 0x57, 0x9a, 0x1b, 0x59, 0x19, 0x1e, 0xa9, 0xb3, 190 | 0x32, 0xb7, 0x32, 0xb9, 0x30, 0xba, 0x32, 0x32, 0x94, 0x19, 0xb8, 0xb7, 191 | 0x39, 0x22, 0x3b, 0x99, 0x2f, 0xb3, 0x94, 0x21, 0x14, 0x32, 0x1c, 0x64, 192 | 0x70, 0x94, 0x01, 0x32, 0x20, 0xc2, 0x61, 0x06, 0x87, 0x75, 0x74, 0x07, 193 | 0x76, 0x64, 0xbc, 0xce, 0xca, 0xdc, 0xca, 0xe4, 0xc2, 0xe8, 0xca, 0xc8, 194 | 0x50, 0x6c, 0xe8, 0xc6, 0xde, 0xde, 0xe4, 0xc8, 0x88, 0xec, 0x64, 0xbe, 195 | 0xcc, 0x52, 0x68, 0xd0, 0x8d, 0xbd, 0xbd, 0xc9, 0x91, 0x0d, 0xa1, 0x10, 196 | 0xe1, 0x20, 0x83, 0xa3, 0x0c, 0x10, 0x01, 0x11, 0x0e, 0x34, 0x38, 0xac, 197 | 0xa3, 0x3b, 0xb0, 0x23, 0x0d, 0xa8, 0x84, 0xa5, 0xc9, 0xb9, 0x88, 0xd5, 198 | 0x99, 0x99, 0x95, 0xc9, 0xf1, 0x09, 0x4b, 0x93, 0x73, 0x11, 0xab, 0x33, 199 | 0x33, 0x2b, 0x93, 0xfb, 0x9a, 0x4b, 0xd3, 0x2b, 0x23, 0x12, 0x96, 0x26, 200 | 0xe7, 0x22, 0x57, 0x16, 0x46, 0xc6, 0x28, 0x2c, 0x4d, 0xce, 0x25, 0x4c, 201 | 0xee, 0xec, 0x8b, 0x2e, 0x0f, 0xae, 0xec, 0x6b, 0x2e, 0x4d, 0xaf, 0x8c, 202 | 0x57, 0x58, 0x9a, 0x9c, 0x4b, 0x98, 0xdc, 0xd9, 0x17, 0x5d, 0x1e, 0x5c, 203 | 0xd9, 0x57, 0x18, 0x5b, 0xda, 0x99, 0xdb, 0xd7, 0x5c, 0x9a, 0x5e, 0x19, 204 | 0x11, 0xbb, 0xb4, 0xb2, 0xbb, 0xa9, 0x34, 0xbd, 0xb2, 0x21, 0x60, 0x80, 205 | 0x14, 0xc7, 0x1a, 0x1c, 0x6c, 0x80, 0x10, 0x47, 0x19, 0x20, 0x02, 0x22, 206 | 0x1c, 0x6d, 0x70, 0xb8, 0x01, 0x42, 0x1c, 0x6f, 0x80, 0x10, 0x87, 0x75, 207 | 0x74, 0x07, 0x76, 0xc0, 0xc1, 0x10, 0xe3, 0x38, 0x83, 0x43, 0x0d, 0x8e, 208 | 0x38, 0x18, 0x62, 0x18, 0xc0, 0x31, 0x06, 0x87, 0x1c, 0x0c, 0x11, 0x80, 209 | 0x63, 0x44, 0xc4, 0x0e, 0xec, 0x60, 0x0f, 0xed, 0xe0, 0x06, 0xed, 0xf0, 210 | 0x0e, 0xe4, 0x50, 0x0f, 0xec, 0x50, 0x0e, 0x6e, 0x60, 0x0e, 0xec, 0x10, 211 | 0x0e, 0xe7, 0x30, 0x0f, 0x53, 0x84, 0x60, 0x18, 0xa1, 0xb0, 0x03, 0x3b, 212 | 0xd8, 0x43, 0x3b, 0xb8, 0x41, 0x3a, 0x90, 0x43, 0x39, 0xb8, 0x03, 0x3d, 213 | 0x4c, 0x09, 0x8a, 0x11, 0x4b, 0x38, 0xa4, 0x83, 0x3c, 0xb8, 0x81, 0x3d, 214 | 0x94, 0x83, 0x3c, 0xcc, 0x43, 0x3a, 0xbc, 0x83, 0x3b, 0x4c, 0x09, 0x8c, 215 | 0x11, 0x54, 0x38, 0xa4, 0x83, 0x3c, 0xb8, 0x01, 0x3b, 0x84, 0x83, 0x3b, 216 | 0x9c, 0x43, 0x3d, 0x84, 0xc3, 0x39, 0x94, 0xc3, 0x2f, 0xd8, 0x43, 0x39, 217 | 0xc8, 0xc3, 0x3c, 0xa4, 0xc3, 0x3b, 0xb8, 0xc3, 0x94, 0x00, 0x19, 0x31, 218 | 0x85, 0x43, 0x3a, 0xc8, 0x83, 0x1b, 0x8c, 0xc3, 0x3b, 0xb4, 0x03, 0x3c, 219 | 0xa4, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x03, 0x3c, 0xd0, 0x43, 0x3a, 220 | 0xbc, 0x83, 0x3b, 0xcc, 0xc3, 0x14, 0x43, 0x61, 0x1c, 0x48, 0xa2, 0x46, 221 | 0x28, 0xe1, 0x90, 0x0e, 0xf2, 0xe0, 0x06, 0xf6, 0x50, 0x0e, 0xf2, 0x40, 222 | 0x0f, 0xe5, 0x80, 0x0f, 0x53, 0x82, 0x39, 0x00, 0x00, 0x00, 0x00, 0x79, 223 | 0x18, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 224 | 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 225 | 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 226 | 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 227 | 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 228 | 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 229 | 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 230 | 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 231 | 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 232 | 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 233 | 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 234 | 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 235 | 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 236 | 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 237 | 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 238 | 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 239 | 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 240 | 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 241 | 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 242 | 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 243 | 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 244 | 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 245 | 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc7, 0x69, 0x87, 0x70, 0x58, 0x87, 246 | 0x72, 0x70, 0x83, 0x74, 0x68, 0x07, 0x78, 0x60, 0x87, 0x74, 0x18, 0x87, 247 | 0x74, 0xa0, 0x87, 0x19, 0xce, 0x53, 0x0f, 0xee, 0x00, 0x0f, 0xf2, 0x50, 248 | 0x0e, 0xe4, 0x90, 0x0e, 0xe3, 0x40, 0x0f, 0xe1, 0x20, 0x0e, 0xec, 0x50, 249 | 0x0e, 0x33, 0x20, 0x28, 0x1d, 0xdc, 0xc1, 0x1e, 0xc2, 0x41, 0x1e, 0xd2, 250 | 0x21, 0x1c, 0xdc, 0x81, 0x1e, 0xdc, 0xe0, 0x1c, 0xe4, 0xe1, 0x1d, 0xea, 251 | 0x01, 0x1e, 0x66, 0x18, 0x51, 0x38, 0xb0, 0x43, 0x3a, 0x9c, 0x83, 0x3b, 252 | 0xcc, 0x50, 0x24, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x60, 0x87, 253 | 0x77, 0x78, 0x07, 0x78, 0x98, 0x51, 0x4c, 0xf4, 0x90, 0x0f, 0xf0, 0x50, 254 | 0x0e, 0x33, 0x1e, 0x6a, 0x1e, 0xca, 0x61, 0x1c, 0xe8, 0x21, 0x1d, 0xde, 255 | 0xc1, 0x1d, 0x7e, 0x01, 0x1e, 0xe4, 0xa1, 0x1c, 0xcc, 0x21, 0x1d, 0xf0, 256 | 0x61, 0x06, 0x54, 0x85, 0x83, 0x38, 0xcc, 0xc3, 0x3b, 0xb0, 0x43, 0x3d, 257 | 0xd0, 0x43, 0x39, 0xfc, 0xc2, 0x3c, 0xe4, 0x43, 0x3b, 0x88, 0xc3, 0x3b, 258 | 0xb0, 0xc3, 0x8c, 0xc5, 0x0a, 0x87, 0x79, 0x98, 0x87, 0x77, 0x18, 0x87, 259 | 0x74, 0x08, 0x07, 0x7a, 0x28, 0x07, 0x72, 0x00, 0x00, 0x00, 0x00, 0x71, 260 | 0x20, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x54, 0x44, 0x34, 261 | 0x11, 0x17, 0x7b, 0x00, 0x03, 0x11, 0x01, 0x61, 0x20, 0x00, 0x00, 0x21, 262 | 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x09, 263 | 0x00, 0x00, 0x00, 0x04, 0x63, 0x04, 0x20, 0x08, 0x82, 0x20, 0x18, 0x8c, 264 | 0x11, 0x80, 0x20, 0x08, 0xe2, 0xdf, 0x0c, 0xc0, 0x18, 0x01, 0x08, 0x82, 265 | 0x20, 0xfe, 0x0b, 0x23, 0x00, 0x14, 0x73, 0x10, 0x8e, 0x03, 0x35, 0x34, 266 | 0x33, 0x00, 0x00, 0x63, 0x08, 0x0a, 0x64, 0x01, 0x22, 0x1f, 0x52, 0xc8, 267 | 0x18, 0x42, 0x30, 0xd9, 0x10, 0xd0, 0xc7, 0x82, 0x04, 0x3e, 0x63, 0x08, 268 | 0xd0, 0x65, 0x81, 0x23, 0x9f, 0x31, 0x04, 0x23, 0x33, 0x21, 0xa0, 0x8f, 269 | 0x41, 0x41, 0x7c, 0xe6, 0x18, 0x1a, 0x63, 0x9b, 0x63, 0x08, 0x84, 0x6e, 270 | 0xb6, 0xc1, 0x09, 0x80, 0xd9, 0x86, 0x00, 0x0b, 0x66, 0x1b, 0x02, 0x4c, 271 | 0xc8, 0x20, 0x20, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x5b, 272 | 0x06, 0x62, 0xa0, 0x83, 0x2d, 0x43, 0x32, 0xd0, 0x01, 0x00, 0x00, 0x00, 273 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 274 | 0x00, 0x00, 0x00, 0xde, 0xc0, 0x17, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x14, 275 | 0x00, 0x00, 0x00, 0x50, 0x12, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x42, 276 | 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x91, 0x04, 0x00, 0x00, 0x0b, 277 | 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 278 | 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 279 | 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 280 | 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14, 0x38, 281 | 0x08, 0x18, 0x49, 0x0a, 0x32, 0x44, 0x24, 0x48, 0x0a, 0x90, 0x21, 0x23, 282 | 0xc4, 0x52, 0x80, 0x0c, 0x19, 0x21, 0x72, 0x24, 0x07, 0xc8, 0x88, 0x11, 283 | 0x62, 0xa8, 0xa0, 0xa8, 0x40, 0xc6, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x51, 284 | 0x18, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x1b, 0xcc, 0x25, 0xf8, 0xff, 285 | 0xff, 0xff, 0xff, 0x01, 0x60, 0x00, 0x09, 0xa8, 0x88, 0x71, 0x78, 0x07, 286 | 0x79, 0x90, 0x87, 0x72, 0x18, 0x07, 0x7a, 0x60, 0x87, 0x7c, 0x68, 0x03, 287 | 0x79, 0x78, 0x87, 0x7a, 0x70, 0x07, 0x72, 0x28, 0x07, 0x72, 0x68, 0x03, 288 | 0x72, 0x48, 0x07, 0x7b, 0x48, 0x07, 0x72, 0x28, 0x87, 0x36, 0x98, 0x87, 289 | 0x78, 0x90, 0x07, 0x7a, 0x68, 0x03, 0x73, 0x80, 0x87, 0x36, 0x68, 0x87, 290 | 0x70, 0xa0, 0x07, 0x74, 0x00, 0xcc, 0x21, 0x1c, 0xd8, 0x61, 0x1e, 0xca, 291 | 0x01, 0x20, 0xc8, 0x21, 0x1d, 0xe6, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 292 | 0xa1, 0x0d, 0xe8, 0x21, 0x1c, 0xd2, 0x81, 0x1d, 0xda, 0x60, 0x1c, 0xc2, 293 | 0x81, 0x1d, 0xd8, 0x61, 0x1e, 0x00, 0x73, 0x08, 0x07, 0x76, 0x98, 0x87, 294 | 0x72, 0x00, 0x08, 0x76, 0x28, 0x87, 0x79, 0x98, 0x87, 0x36, 0x80, 0x07, 295 | 0x79, 0x28, 0x87, 0x71, 0x48, 0x87, 0x79, 0x28, 0x87, 0x36, 0x30, 0x07, 296 | 0x78, 0x68, 0x87, 0x70, 0x20, 0x07, 0xc0, 0x1c, 0xc2, 0x81, 0x1d, 0xe6, 297 | 0xa1, 0x1c, 0x00, 0xc2, 0x1d, 0xde, 0xa1, 0x0d, 0xcc, 0x41, 0x1e, 0xc2, 298 | 0xa1, 0x1d, 0xca, 0xa1, 0x0d, 0xe0, 0xe1, 0x1d, 0xd2, 0xc1, 0x1d, 0xe8, 299 | 0xa1, 0x1c, 0xe4, 0xa1, 0x0d, 0xca, 0x81, 0x1d, 0xd2, 0xa1, 0x1d, 0x00, 300 | 0x7a, 0x90, 0x87, 0x7a, 0x28, 0x07, 0x60, 0x70, 0x87, 0x77, 0x68, 0x03, 301 | 0x73, 0x90, 0x87, 0x70, 0x68, 0x87, 0x72, 0x68, 0x03, 0x78, 0x78, 0x87, 302 | 0x74, 0x70, 0x07, 0x7a, 0x28, 0x07, 0x79, 0x68, 0x83, 0x72, 0x60, 0x87, 303 | 0x74, 0x68, 0x87, 0x36, 0x70, 0x87, 0x77, 0x70, 0x87, 0x36, 0x60, 0x87, 304 | 0x72, 0x08, 0x07, 0x73, 0x00, 0x08, 0x77, 0x78, 0x87, 0x36, 0x48, 0x07, 305 | 0x77, 0x30, 0x87, 0x79, 0x68, 0x03, 0x73, 0x80, 0x87, 0x36, 0x68, 0x87, 306 | 0x70, 0xa0, 0x07, 0x74, 0x00, 0xe8, 0x41, 0x1e, 0xea, 0xa1, 0x1c, 0x00, 307 | 0xc2, 0x1d, 0xde, 0xa1, 0x0d, 0xd4, 0xa1, 0x1e, 0xda, 0x01, 0x1e, 0xda, 308 | 0x80, 0x1e, 0xc2, 0x41, 0x1c, 0xd8, 0xa1, 0x1c, 0xe6, 0x01, 0x30, 0x87, 309 | 0x70, 0x60, 0x87, 0x79, 0x28, 0x07, 0x80, 0x70, 0x87, 0x77, 0x68, 0x03, 310 | 0x77, 0x08, 0x07, 0x77, 0x98, 0x87, 0x36, 0x30, 0x07, 0x78, 0x68, 0x83, 311 | 0x76, 0x08, 0x07, 0x7a, 0x40, 0x07, 0x80, 0x1e, 0xe4, 0xa1, 0x1e, 0xca, 312 | 0x01, 0x20, 0xdc, 0xe1, 0x1d, 0xda, 0x60, 0x1e, 0xd2, 0xe1, 0x1c, 0xdc, 313 | 0xa1, 0x1c, 0xc8, 0xa1, 0x0d, 0xf4, 0xa1, 0x1c, 0xe4, 0xe1, 0x1d, 0xe6, 314 | 0xa1, 0x0d, 0xcc, 0x01, 0x1e, 0xda, 0xa0, 0x1d, 0xc2, 0x81, 0x1e, 0xd0, 315 | 0x01, 0xa0, 0x07, 0x79, 0xa8, 0x87, 0x72, 0x00, 0x08, 0x77, 0x78, 0x87, 316 | 0x36, 0xa0, 0x07, 0x79, 0x08, 0x07, 0x78, 0x80, 0x87, 0x74, 0x70, 0x87, 317 | 0x73, 0x68, 0x83, 0x76, 0x08, 0x07, 0x7a, 0x40, 0x07, 0x80, 0x1e, 0xe4, 318 | 0xa1, 0x1e, 0xca, 0x01, 0x20, 0xe6, 0x81, 0x1e, 0xc2, 0x61, 0x1c, 0xd6, 319 | 0xa1, 0x0d, 0xe0, 0x41, 0x1e, 0xde, 0x81, 0x1e, 0xca, 0x61, 0x1c, 0xe8, 320 | 0xe1, 0x1d, 0xe4, 0xa1, 0x0d, 0xc4, 0xa1, 0x1e, 0xcc, 0xc1, 0x1c, 0xca, 321 | 0x41, 0x1e, 0xda, 0x60, 0x1e, 0xd2, 0x41, 0x1f, 0xca, 0x01, 0xc0, 0x03, 322 | 0x80, 0xa8, 0x07, 0x77, 0x98, 0x87, 0x70, 0x30, 0x87, 0x72, 0x68, 0x03, 323 | 0x73, 0x80, 0x87, 0x36, 0x68, 0x87, 0x70, 0xa0, 0x07, 0x74, 0x00, 0xe8, 324 | 0x41, 0x1e, 0xea, 0xa1, 0x1c, 0x00, 0xa2, 0x1e, 0xe6, 0xa1, 0x1c, 0xda, 325 | 0x60, 0x1e, 0xde, 0xc1, 0x1c, 0xe8, 0xa1, 0x0d, 0xcc, 0x81, 0x1d, 0xde, 326 | 0x21, 0x1c, 0xe8, 0x01, 0x30, 0x87, 0x70, 0x60, 0x87, 0x79, 0x28, 0x07, 327 | 0x60, 0x83, 0x21, 0x10, 0x40, 0x02, 0x54, 0x1b, 0x8c, 0xc1, 0x00, 0x16, 328 | 0xa0, 0xda, 0x80, 0x10, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x0c, 0x20, 329 | 0x01, 0xd5, 0x06, 0xa3, 0x08, 0x80, 0x05, 0xa8, 0x36, 0x18, 0x86, 0x00, 330 | 0x2c, 0x40, 0xb5, 0xc1, 0x38, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x24, 331 | 0x80, 0x02, 0x00, 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 332 | 0x86, 0x40, 0x18, 0x26, 0x0c, 0x44, 0x61, 0x4c, 0x08, 0x0e, 0x00, 0x89, 333 | 0x20, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x32, 0x22, 0x88, 0x09, 0x20, 334 | 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84, 0x04, 0x13, 0x23, 0xe3, 0x84, 335 | 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c, 0x0b, 0x84, 0xc4, 0x4c, 0x10, 336 | 0xb0, 0xc1, 0x0c, 0xc0, 0x30, 0x02, 0x01, 0x0c, 0x23, 0x08, 0xc0, 0x30, 337 | 0xc2, 0x00, 0xe4, 0xc0, 0x30, 0x13, 0x35, 0x0f, 0xf4, 0x20, 0x0f, 0xf5, 338 | 0x30, 0x0e, 0xf4, 0xe0, 0x06, 0xed, 0x50, 0x0e, 0xf4, 0x10, 0x0e, 0xec, 339 | 0xa0, 0x07, 0x7a, 0xd0, 0x0e, 0xe1, 0x40, 0x0f, 0xf2, 0x90, 0x0e, 0xf8, 340 | 0x80, 0x02, 0x62, 0x8e, 0x00, 0x0c, 0xee, 0x91, 0xa6, 0x88, 0x12, 0x26, 341 | 0xdf, 0x6d, 0x90, 0xc2, 0x89, 0x18, 0x09, 0x35, 0x45, 0x11, 0x04, 0x82, 342 | 0x20, 0x00, 0x00, 0x00, 0x18, 0xc6, 0x20, 0xc2, 0x21, 0x1c, 0x25, 0x4d, 343 | 0x11, 0x25, 0x4c, 0xfe, 0x3f, 0x11, 0xd7, 0x44, 0x45, 0xc4, 0x6f, 0x0f, 344 | 0xff, 0x34, 0x46, 0x00, 0x0c, 0x22, 0x24, 0xc1, 0x45, 0xd2, 0x14, 0x51, 345 | 0xc2, 0xe4, 0xff, 0x12, 0xc0, 0x3c, 0x0b, 0x11, 0xfd, 0xd3, 0x18, 0x01, 346 | 0x30, 0x88, 0xb0, 0x08, 0xe5, 0x08, 0x02, 0x41, 0x40, 0x14, 0x86, 0x9a, 347 | 0x39, 0x82, 0x60, 0x18, 0x41, 0x30, 0x0a, 0x12, 0x28, 0x8c, 0xf0, 0x40, 348 | 0x0f, 0x40, 0x51, 0x21, 0x82, 0x20, 0x08, 0x68, 0x2a, 0x02, 0x00, 0x50, 349 | 0x55, 0x06, 0x40, 0x10, 0xe8, 0x2a, 0x83, 0x20, 0x08, 0x94, 0x95, 0x01, 350 | 0x00, 0x00, 0xda, 0x8a, 0x20, 0x08, 0xd4, 0x0d, 0x04, 0xa4, 0x80, 0x31, 351 | 0x88, 0x10, 0x08, 0xc3, 0x08, 0x83, 0x31, 0x47, 0x00, 0x0a, 0x83, 0x08, 352 | 0x83, 0x30, 0x88, 0x20, 0x08, 0x53, 0x00, 0x23, 0x00, 0x83, 0x08, 0x86, 353 | 0x30, 0x88, 0x50, 0x08, 0x83, 0x08, 0x80, 0x30, 0x8c, 0x40, 0x18, 0x00, 354 | 0x00, 0x00, 0x00, 0x13, 0xa8, 0x70, 0x48, 0x07, 0x79, 0xb0, 0x03, 0x3a, 355 | 0x68, 0x83, 0x70, 0x80, 0x07, 0x78, 0x60, 0x87, 0x72, 0x68, 0x83, 0x74, 356 | 0x78, 0x87, 0x79, 0xc0, 0x03, 0x37, 0x80, 0x03, 0x37, 0x80, 0x83, 0x0d, 357 | 0xb7, 0x51, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x60, 0x07, 0x74, 0xa0, 0x07, 358 | 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe9, 0x10, 0x07, 359 | 0x7a, 0x80, 0x07, 0x7a, 0x80, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 360 | 0x78, 0xa0, 0x07, 0x78, 0xd0, 0x06, 0xe9, 0x10, 0x07, 0x76, 0xa0, 0x07, 361 | 0x71, 0x60, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xd0, 0x06, 0xe9, 0x30, 0x07, 362 | 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 363 | 0xe9, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 364 | 0x74, 0xd0, 0x06, 0xe6, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 365 | 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 366 | 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xf6, 0x10, 0x07, 367 | 0x76, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xd0, 0x06, 368 | 0xf6, 0x20, 0x07, 0x74, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 369 | 0x72, 0xd0, 0x06, 0xf6, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 370 | 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xf6, 0x40, 0x07, 0x78, 0xa0, 0x07, 371 | 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xf6, 0x60, 0x07, 372 | 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 373 | 0xf6, 0x90, 0x07, 0x76, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xa0, 0x07, 374 | 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xf6, 0x10, 0x07, 0x72, 0x80, 0x07, 375 | 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 376 | 0x6d, 0x60, 0x0f, 0x71, 0x90, 0x07, 0x72, 0xa0, 0x07, 0x72, 0x50, 0x07, 377 | 0x76, 0xa0, 0x07, 0x72, 0x50, 0x07, 0x76, 0xd0, 0x06, 0xf6, 0x20, 0x07, 378 | 0x75, 0x60, 0x07, 0x7a, 0x20, 0x07, 0x75, 0x60, 0x07, 0x7a, 0x20, 0x07, 379 | 0x75, 0x60, 0x07, 0x6d, 0x60, 0x0f, 0x75, 0x10, 0x07, 0x72, 0xa0, 0x07, 380 | 0x75, 0x10, 0x07, 0x72, 0xa0, 0x07, 0x75, 0x10, 0x07, 0x72, 0xd0, 0x06, 381 | 0xf6, 0x10, 0x07, 0x70, 0x20, 0x07, 0x74, 0xa0, 0x07, 0x71, 0x00, 0x07, 382 | 0x72, 0x40, 0x07, 0x7a, 0x10, 0x07, 0x70, 0x20, 0x07, 0x74, 0xd0, 0x06, 383 | 0xee, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 384 | 0x43, 0x18, 0x07, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 385 | 0x8c, 0x04, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x10, 0x86, 386 | 0x02, 0x02, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x08, 0x63, 0x01, 387 | 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x84, 0xb1, 0x80, 0x00, 388 | 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc2, 0x60, 0x40, 0x00, 0x0c, 389 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x61, 0x34, 0x20, 0x00, 0x06, 0x00, 390 | 0x00, 0x00, 0x00, 0x00, 0x86, 0x30, 0x1c, 0x10, 0x00, 0x03, 0x00, 0x00, 391 | 0x00, 0x00, 0x00, 0x43, 0x18, 0x0e, 0x08, 0x80, 0x01, 0x00, 0x00, 0x00, 392 | 0x00, 0x80, 0x21, 0x8c, 0x07, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 393 | 0xc0, 0x10, 0xc6, 0x03, 0x02, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 394 | 0x0b, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x18, 0x19, 395 | 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, 0x0b, 396 | 0x59, 0x80, 0x8c, 0x11, 0x80, 0x42, 0x28, 0x81, 0x02, 0x2b, 0x90, 0x82, 397 | 0x28, 0x82, 0x02, 0x17, 0x28, 0x86, 0x32, 0x28, 0xe0, 0x80, 0x02, 0x0f, 398 | 0x28, 0x40, 0x81, 0x82, 0x14, 0x28, 0x50, 0x81, 0x82, 0x15, 0x28, 0x5c, 399 | 0x81, 0x02, 0x16, 0x28, 0x64, 0x81, 0x82, 0x16, 0x28, 0x6c, 0x81, 0x52, 400 | 0xa0, 0xb1, 0x80, 0x05, 0x46, 0x00, 0x0a, 0x56, 0xa0, 0x70, 0x05, 0x0a, 401 | 0x5a, 0xa0, 0xb0, 0x05, 0x0a, 0xac, 0x80, 0x03, 0x0a, 0x3c, 0xa0, 0x00, 402 | 0x05, 0x0a, 0x52, 0xa0, 0x40, 0x05, 0x08, 0x1c, 0x4b, 0x68, 0x04, 0x02, 403 | 0xc6, 0x08, 0x40, 0x10, 0x04, 0x45, 0x30, 0x00, 0x00, 0x00, 0x00, 0x79, 404 | 0x18, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x10, 0x97, 405 | 0x29, 0xa2, 0x25, 0x10, 0xab, 0x32, 0xb9, 0xb9, 0xb4, 0x37, 0xb7, 0x21, 406 | 0x86, 0x21, 0x7d, 0x00, 0x18, 0xb8, 0x01, 0x95, 0xbb, 0x31, 0xb4, 0x30, 407 | 0xb9, 0xaf, 0xb9, 0x34, 0xbd, 0xb2, 0x21, 0x86, 0xe1, 0x7c, 0x82, 0xd1, 408 | 0x70, 0x0d, 0x82, 0xe0, 0xe0, 0xd8, 0xca, 0x40, 0x98, 0x98, 0xac, 0x9a, 409 | 0x40, 0xec, 0xca, 0xe4, 0xe6, 0xd2, 0xde, 0xdc, 0x40, 0x72, 0x60, 0x64, 410 | 0x5c, 0x72, 0x40, 0x50, 0xda, 0xca, 0xe8, 0xc2, 0xd8, 0xcc, 0xca, 0x5a, 411 | 0x72, 0x60, 0x64, 0x5c, 0x72, 0x5c, 0x6c, 0x62, 0x52, 0x86, 0x08, 0x1f, 412 | 0x31, 0xc4, 0x30, 0x1c, 0x83, 0x32, 0x18, 0x16, 0x4d, 0x65, 0x74, 0x61, 413 | 0x6c, 0x43, 0x90, 0xef, 0x30, 0x1c, 0x83, 0x31, 0x18, 0x6e, 0x61, 0x69, 414 | 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e, 0x64, 0x65, 415 | 0x6e, 0x6f, 0x72, 0x6d, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 416 | 0x65, 0x43, 0x84, 0x2f, 0x21, 0x17, 0x96, 0x26, 0xe7, 0x32, 0xf6, 0xd6, 417 | 0x06, 0x97, 0xc6, 0x56, 0xe6, 0x62, 0x16, 0x36, 0x47, 0xf7, 0xd5, 0x16, 418 | 0x46, 0x87, 0xf6, 0x55, 0xe6, 0x16, 0x26, 0xc6, 0x56, 0x36, 0x44, 0xf8, 419 | 0x16, 0x92, 0x41, 0x58, 0x9a, 0x9c, 0xcb, 0xd8, 0x5b, 0x1b, 0x5c, 0x1a, 420 | 0x5b, 0x99, 0x8b, 0x99, 0x5c, 0x58, 0x5b, 0x99, 0x58, 0x9d, 0x99, 0x59, 421 | 0x99, 0xdc, 0x97, 0x59, 0x19, 0xdd, 0x18, 0xda, 0x57, 0x99, 0x5b, 0x98, 422 | 0x18, 0x5b, 0xd9, 0x10, 0xe1, 0x6b, 0x18, 0x06, 0x61, 0x69, 0x72, 0x2e, 423 | 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e, 0x6e, 0x61, 0x74, 0x69, 424 | 0x76, 0x65, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69, 425 | 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x84, 0xef, 0x21, 0x19, 0x84, 0xa5, 426 | 0xc9, 0xb9, 0x8c, 0xbd, 0xb5, 0xc1, 0xa5, 0xb1, 0x95, 0xb9, 0xb8, 0x85, 427 | 0xd1, 0xa5, 0xd9, 0x95, 0x7d, 0xb1, 0xbd, 0xb9, 0x9d, 0x7d, 0xb1, 0xbd, 428 | 0xb9, 0x9d, 0x7d, 0x91, 0xa5, 0xcd, 0x85, 0x89, 0xb1, 0x95, 0x0d, 0x11, 429 | 0xbe, 0x88, 0x67, 0x10, 0x96, 0x26, 0xe7, 0x32, 0xf6, 0xd6, 0x06, 0x97, 430 | 0xc6, 0x56, 0xe6, 0xe2, 0x16, 0x46, 0x97, 0x66, 0x57, 0xf6, 0x75, 0x97, 431 | 0x46, 0x56, 0xf6, 0x65, 0x57, 0x36, 0x46, 0xf7, 0x26, 0x37, 0xf7, 0x45, 432 | 0x96, 0x36, 0x17, 0x26, 0xc6, 0x56, 0x36, 0x44, 0xf8, 0x26, 0x46, 0x61, 433 | 0x69, 0x72, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x74, 0x61, 434 | 0x72, 0x67, 0x65, 0x74, 0x8c, 0xc2, 0xd2, 0xe4, 0x5c, 0xc2, 0xe4, 0xce, 435 | 0xbe, 0xe8, 0xf2, 0xe0, 0xca, 0xbe, 0xdc, 0xc2, 0xda, 0xca, 0x68, 0x98, 436 | 0xb1, 0xbd, 0x85, 0xd1, 0xd1, 0x0c, 0x41, 0xbe, 0xca, 0x60, 0x3e, 0xeb, 437 | 0xbb, 0x86, 0x08, 0x1f, 0x46, 0x26, 0x2c, 0x4d, 0xce, 0x05, 0xee, 0x6d, 438 | 0x2e, 0x8d, 0x2e, 0xed, 0xcd, 0x8d, 0x4a, 0x58, 0x9a, 0x9c, 0xcb, 0x58, 439 | 0x99, 0x1b, 0x5d, 0x99, 0x1c, 0xa5, 0xb0, 0x34, 0x39, 0x17, 0xb7, 0xb7, 440 | 0x2f, 0xb8, 0x32, 0xb9, 0x39, 0xb8, 0xb2, 0x31, 0xba, 0x34, 0xbb, 0x32, 441 | 0x32, 0x61, 0x69, 0x72, 0x2e, 0x61, 0x72, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 442 | 0x65, 0x1c, 0xe0, 0xde, 0xe6, 0x86, 0x40, 0x06, 0xf3, 0x69, 0xdf, 0xf6, 443 | 0x71, 0x9f, 0xf5, 0x5d, 0x5f, 0xf7, 0x79, 0x94, 0xc2, 0xd2, 0xe4, 0x5c, 444 | 0xcc, 0xe4, 0xc2, 0xce, 0xda, 0xca, 0xdc, 0xe8, 0xbe, 0xd2, 0xdc, 0xe0, 445 | 0xea, 0xe8, 0x58, 0x9d, 0x95, 0xb9, 0x95, 0xc9, 0x85, 0xd1, 0x95, 0x91, 446 | 0xa1, 0xd0, 0x98, 0xc1, 0xbd, 0xcd, 0x11, 0xd9, 0xc9, 0x7c, 0x99, 0xa5, 447 | 0xf0, 0x09, 0x4b, 0x93, 0x73, 0x81, 0x2b, 0x93, 0x9b, 0x83, 0x2b, 0x1b, 448 | 0xa3, 0x4b, 0xb3, 0x2b, 0xa3, 0x61, 0xc6, 0xf6, 0x16, 0x46, 0x27, 0x43, 449 | 0xc2, 0x0c, 0xee, 0x6d, 0x6e, 0x88, 0x64, 0x38, 0x1f, 0x18, 0x7c, 0x61, 450 | 0xf0, 0x6d, 0x9f, 0x18, 0x7c, 0xd6, 0x37, 0x06, 0x5f, 0xf7, 0x91, 0x01, 451 | 0xb1, 0xb3, 0x32, 0xb7, 0x32, 0xb9, 0x30, 0xba, 0x32, 0x32, 0x94, 0x1b, 452 | 0x33, 0xba, 0xb1, 0xb7, 0x37, 0x39, 0x32, 0x22, 0x3b, 0x99, 0x2f, 0xb3, 453 | 0x14, 0x1e, 0x66, 0x74, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x43, 0x24, 0x43, 454 | 0xfa, 0xc0, 0xe0, 0x33, 0x83, 0x6f, 0xfb, 0xc4, 0xe0, 0xb3, 0xbe, 0x31, 455 | 0xf8, 0xba, 0xef, 0x0c, 0xa8, 0x84, 0xa5, 0xc9, 0xb9, 0x88, 0xd5, 0x99, 456 | 0x99, 0x95, 0xc9, 0xf1, 0x09, 0x4b, 0x93, 0x73, 0x11, 0xab, 0x33, 0x33, 457 | 0x2b, 0x93, 0xfb, 0x9a, 0x4b, 0xd3, 0x2b, 0xa3, 0x14, 0x96, 0x26, 0xe7, 458 | 0xc2, 0xf6, 0x36, 0x16, 0x46, 0x97, 0xf6, 0xe6, 0xf6, 0x95, 0xe6, 0x46, 459 | 0x56, 0x86, 0x47, 0x24, 0x2c, 0x4d, 0xce, 0x45, 0xae, 0x2c, 0x8c, 0x8c, 460 | 0x54, 0x58, 0x9a, 0x9c, 0xcb, 0x1c, 0x9d, 0x5c, 0xdd, 0x18, 0xdd, 0x17, 461 | 0x5d, 0x1e, 0x5c, 0xd9, 0x57, 0x9a, 0x9b, 0xd9, 0x1b, 0x11, 0x33, 0xb6, 462 | 0xb7, 0x30, 0xba, 0x19, 0xbc, 0x19, 0x2a, 0x73, 0x63, 0x69, 0x73, 0x73, 463 | 0x6f, 0x72, 0x4d, 0x61, 0x74, 0x44, 0xe0, 0xc2, 0xd2, 0xdc, 0xe8, 0x9a, 464 | 0xc2, 0xe8, 0x88, 0xa4, 0xb9, 0xb9, 0x95, 0xc9, 0x0d, 0xbd, 0xb1, 0x11, 465 | 0x79, 0xab, 0xa3, 0x2b, 0x93, 0x1b, 0x7a, 0x63, 0xa3, 0x32, 0x37, 0x96, 466 | 0x36, 0x37, 0xf7, 0x26, 0x57, 0x84, 0x47, 0x47, 0x66, 0x6e, 0x2c, 0x6d, 467 | 0x6e, 0xee, 0x4d, 0x6e, 0x6a, 0x2c, 0x8c, 0xad, 0x8c, 0x46, 0x19, 0x1e, 468 | 0x5d, 0x99, 0x1b, 0x1d, 0x0b, 0x33, 0xb6, 0xb7, 0x30, 0x3a, 0x1a, 0x72, 469 | 0x61, 0x64, 0x69, 0x75, 0x73, 0x3c, 0xcc, 0xca, 0xc2, 0xe8, 0xd0, 0xca, 470 | 0xe4, 0xa8, 0xcc, 0xd1, 0xc9, 0xbd, 0xad, 0x95, 0x35, 0xd5, 0xb1, 0xd1, 471 | 0x31, 0x99, 0xa3, 0x93, 0x7b, 0x5b, 0x2b, 0xa3, 0x42, 0x93, 0xe3, 0x90, 472 | 0xe6, 0x46, 0xc7, 0x83, 0xae, 0x0c, 0x8f, 0x2a, 0x0f, 0xae, 0x8c, 0x04, 473 | 0x5d, 0x1e, 0x5c, 0xd9, 0x10, 0x91, 0x30, 0x18, 0xe3, 0x31, 0x98, 0xcf, 474 | 0x0d, 0xbe, 0x37, 0x30, 0x1e, 0xe3, 0x31, 0x98, 0xcf, 0x0d, 0x3e, 0x38, 475 | 0x30, 0x2c, 0x03, 0x32, 0x98, 0xef, 0xfa, 0xe2, 0xc0, 0xb8, 0x0c, 0xc8, 476 | 0x60, 0xbe, 0xeb, 0x93, 0x03, 0x03, 0x33, 0x22, 0x83, 0xf9, 0xc6, 0xe0, 477 | 0x9b, 0x03, 0x23, 0x33, 0x22, 0x83, 0xf9, 0xc6, 0xe0, 0xa3, 0x03, 0x43, 478 | 0x33, 0x22, 0x83, 0xf9, 0xc6, 0xe0, 0xab, 0x03, 0x63, 0x33, 0x1a, 0x83, 479 | 0xf9, 0xec, 0xe0, 0xbb, 0x03, 0x83, 0x33, 0x1a, 0x83, 0xf9, 0xec, 0xe0, 480 | 0xc3, 0x03, 0xa3, 0x33, 0x1a, 0x83, 0xf9, 0xec, 0xe0, 0xcb, 0x03, 0xc3, 481 | 0x33, 0x1a, 0x83, 0xf9, 0xec, 0xe0, 0xd3, 0x03, 0xe3, 0x33, 0x1a, 0x83, 482 | 0xf9, 0xf6, 0xe0, 0xe3, 0x03, 0x03, 0x0c, 0x8c, 0xc6, 0x60, 0xbe, 0x3d, 483 | 0xf8, 0xfa, 0x80, 0x51, 0x58, 0x9a, 0x9c, 0x4b, 0x98, 0xdc, 0xd9, 0x17, 484 | 0x5d, 0x1e, 0x5c, 0xd9, 0xd7, 0x5c, 0x9a, 0x5e, 0x19, 0xaf, 0xb0, 0x34, 485 | 0x39, 0x97, 0x30, 0xb9, 0xb3, 0x2f, 0xba, 0x3c, 0xb8, 0xb2, 0xaf, 0x30, 486 | 0xb6, 0xb4, 0x33, 0xb7, 0xaf, 0xb9, 0x34, 0xbd, 0x32, 0x22, 0x55, 0x6e, 487 | 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x44, 0xea, 0xdc, 0xd2, 0xcc, 0xde, 488 | 0xe4, 0xda, 0xe6, 0x86, 0x90, 0x81, 0x51, 0x7d, 0x69, 0xf0, 0xa9, 0x81, 489 | 0x31, 0x7d, 0x6b, 0x60, 0x30, 0x86, 0xf3, 0xb1, 0xc1, 0xd7, 0x06, 0x9f, 490 | 0x1f, 0x7c, 0x7f, 0x60, 0x4c, 0x1f, 0x28, 0x18, 0xd0, 0x67, 0x7d, 0xa1, 491 | 0xf0, 0x75, 0x9f, 0x28, 0x70, 0x09, 0x4b, 0x93, 0x73, 0xa1, 0x2b, 0xc3, 492 | 0xa3, 0xab, 0x93, 0x2b, 0xa3, 0x12, 0x96, 0x26, 0xe7, 0x32, 0x17, 0xd6, 493 | 0x06, 0xc7, 0x56, 0x46, 0x8c, 0xae, 0x0c, 0x8f, 0xae, 0x4e, 0xae, 0x4c, 494 | 0x86, 0x8c, 0xc7, 0x8c, 0xed, 0x2d, 0x8c, 0x8e, 0x05, 0x64, 0x2e, 0xac, 495 | 0x0d, 0x8e, 0xad, 0xcc, 0x87, 0x07, 0x5d, 0x19, 0x1e, 0x5d, 0x9d, 0x5c, 496 | 0xd9, 0x10, 0xca, 0x68, 0x3e, 0x52, 0xf8, 0xd6, 0xc0, 0x60, 0x0c, 0xe7, 497 | 0x2b, 0x85, 0xcf, 0xfa, 0x4c, 0xe1, 0xeb, 0xbe, 0x53, 0xe0, 0x12, 0x96, 498 | 0x26, 0xe7, 0x32, 0x17, 0xd6, 0x06, 0xc7, 0x56, 0x26, 0xc7, 0x63, 0x2e, 499 | 0xac, 0x0d, 0x8e, 0xad, 0x4c, 0x6e, 0x88, 0x64, 0x84, 0xc1, 0x97, 0x0a, 500 | 0xdf, 0x1a, 0x18, 0x8c, 0xe1, 0x7c, 0xd6, 0xa7, 0x0a, 0x5f, 0xf7, 0xa9, 501 | 0xc2, 0x10, 0xe6, 0xfb, 0xbe, 0x32, 0xf8, 0xd0, 0xe0, 0x1b, 0x85, 0x0f, 502 | 0x15, 0xbe, 0x55, 0x18, 0x62, 0x38, 0xc0, 0x97, 0x7d, 0xac, 0xc0, 0xe7, 503 | 0xad, 0xcd, 0x2d, 0x0d, 0xee, 0x8d, 0xae, 0xcc, 0x8d, 0x0e, 0x64, 0x0c, 504 | 0x2d, 0x4c, 0x8e, 0xcf, 0x54, 0x5a, 0x1b, 0x1c, 0x5b, 0x19, 0xc8, 0xd0, 505 | 0xca, 0x0a, 0x08, 0x95, 0x50, 0x50, 0xd0, 0x10, 0xe1, 0x7b, 0x85, 0x21, 506 | 0xc6, 0xe7, 0x0a, 0x1f, 0x2c, 0x8c, 0xc1, 0x18, 0x0c, 0x31, 0xbe, 0x58, 507 | 0xf8, 0x62, 0x61, 0x0c, 0xc6, 0x80, 0xcd, 0x97, 0x16, 0xd5, 0x14, 0x4e, 508 | 0x95, 0x5b, 0x9a, 0xd9, 0x9b, 0x5c, 0xdb, 0x1c, 0xbf, 0x2f, 0x2d, 0xaa, 509 | 0x29, 0xa7, 0x9a, 0xb6, 0x32, 0xba, 0x30, 0x36, 0x9b, 0xb6, 0x30, 0x3a, 510 | 0xb9, 0x34, 0xbc, 0x24, 0x33, 0xa6, 0xb4, 0x99, 0x22, 0xa6, 0xb4, 0x99, 511 | 0x22, 0xbb, 0xa2, 0xa2, 0x21, 0xc6, 0x47, 0x0b, 0x5f, 0x2c, 0x8c, 0xc1, 512 | 0x18, 0x0c, 0x31, 0x3e, 0x3b, 0xf8, 0x62, 0x61, 0x0c, 0xc6, 0x60, 0x88, 513 | 0xf1, 0xed, 0xc1, 0x17, 0x0b, 0x63, 0x30, 0x06, 0x43, 0xec, 0xe0, 0x9b, 514 | 0x85, 0xaf, 0x16, 0xc6, 0x60, 0x0c, 0xbe, 0x5a, 0x18, 0x03, 0x34, 0xf8, 515 | 0x62, 0x61, 0x0c, 0xd2, 0xe0, 0x8b, 0x85, 0x31, 0x50, 0x83, 0x2f, 0x16, 516 | 0xc6, 0x60, 0x0d, 0xbe, 0x58, 0x18, 0x03, 0x36, 0xf8, 0x62, 0x61, 0x0c, 517 | 0xda, 0xe0, 0xb3, 0x85, 0x31, 0x20, 0x83, 0xcf, 0x16, 0xc6, 0xa0, 0x0c, 518 | 0x3e, 0x5b, 0x18, 0x03, 0x31, 0xf8, 0x6c, 0x61, 0x0c, 0x96, 0xef, 0x16, 519 | 0xc6, 0xc0, 0x0c, 0xbe, 0x5b, 0x18, 0x83, 0x33, 0x18, 0x62, 0x7c, 0xb8, 520 | 0xf0, 0xdd, 0xc2, 0x18, 0x9c, 0xc1, 0x10, 0xe3, 0xc3, 0x85, 0xcf, 0x16, 521 | 0xc6, 0xa0, 0x0c, 0x86, 0x18, 0x1f, 0x2e, 0x7c, 0xb6, 0x30, 0x06, 0x64, 522 | 0x30, 0x44, 0x00, 0xde, 0x60, 0x88, 0xf1, 0xe1, 0xc2, 0x77, 0x0b, 0x63, 523 | 0x60, 0x06, 0x23, 0x22, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 524 | 0x87, 0x77, 0x20, 0x87, 0x7a, 0x60, 0x87, 0x72, 0x70, 0x03, 0x73, 0x60, 525 | 0x87, 0x70, 0x38, 0x87, 0x79, 0x98, 0x22, 0x04, 0xc3, 0x08, 0x85, 0x1d, 526 | 0xd8, 0xc1, 0x1e, 0xda, 0xc1, 0x0d, 0xd2, 0x81, 0x1c, 0xca, 0xc1, 0x1d, 527 | 0xe8, 0x61, 0x4a, 0x50, 0x8c, 0x58, 0xc2, 0x21, 0x1d, 0xe4, 0xc1, 0x0d, 528 | 0xec, 0xa1, 0x1c, 0xe4, 0x61, 0x1e, 0xd2, 0xe1, 0x1d, 0xdc, 0x61, 0x4a, 529 | 0x60, 0x8c, 0xa0, 0xc2, 0x21, 0x1d, 0xe4, 0xc1, 0x0d, 0xd8, 0x21, 0x1c, 530 | 0xdc, 0xe1, 0x1c, 0xea, 0x21, 0x1c, 0xce, 0xa1, 0x1c, 0x7e, 0xc1, 0x1e, 531 | 0xca, 0x41, 0x1e, 0xe6, 0x21, 0x1d, 0xde, 0xc1, 0x1d, 0xa6, 0x04, 0xc8, 532 | 0x88, 0x29, 0x1c, 0xd2, 0x41, 0x1e, 0xdc, 0x60, 0x1c, 0xde, 0xa1, 0x1d, 533 | 0xe0, 0x21, 0x1d, 0xd8, 0xa1, 0x1c, 0x7e, 0xe1, 0x1d, 0xe0, 0x81, 0x1e, 534 | 0xd2, 0xe1, 0x1d, 0xdc, 0x61, 0x1e, 0xa6, 0x18, 0x0a, 0xe3, 0x40, 0x12, 535 | 0x35, 0x82, 0x09, 0x87, 0x74, 0x90, 0x07, 0x37, 0x30, 0x07, 0x79, 0x08, 536 | 0x87, 0x73, 0x68, 0x87, 0x72, 0x70, 0x07, 0x7a, 0x98, 0x12, 0xb4, 0x02, 537 | 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x33, 538 | 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 539 | 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 540 | 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 541 | 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 542 | 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 543 | 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 544 | 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 545 | 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 546 | 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 547 | 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 548 | 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 549 | 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 550 | 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 551 | 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 552 | 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 553 | 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 554 | 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 555 | 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 556 | 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 557 | 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 558 | 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 559 | 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc7, 0x69, 560 | 0x87, 0x70, 0x58, 0x87, 0x72, 0x70, 0x83, 0x74, 0x68, 0x07, 0x78, 0x60, 561 | 0x87, 0x74, 0x18, 0x87, 0x74, 0xa0, 0x87, 0x19, 0xce, 0x53, 0x0f, 0xee, 562 | 0x00, 0x0f, 0xf2, 0x50, 0x0e, 0xe4, 0x90, 0x0e, 0xe3, 0x40, 0x0f, 0xe1, 563 | 0x20, 0x0e, 0xec, 0x50, 0x0e, 0x33, 0x20, 0x28, 0x1d, 0xdc, 0xc1, 0x1e, 564 | 0xc2, 0x41, 0x1e, 0xd2, 0x21, 0x1c, 0xdc, 0x81, 0x1e, 0xdc, 0xe0, 0x1c, 565 | 0xe4, 0xe1, 0x1d, 0xea, 0x01, 0x1e, 0x66, 0x18, 0x51, 0x38, 0xb0, 0x43, 566 | 0x3a, 0x9c, 0x83, 0x3b, 0xcc, 0x50, 0x24, 0x76, 0x60, 0x07, 0x7b, 0x68, 567 | 0x07, 0x37, 0x60, 0x87, 0x77, 0x78, 0x07, 0x78, 0x98, 0x51, 0x4c, 0xf4, 568 | 0x90, 0x0f, 0xf0, 0x50, 0x0e, 0x33, 0x1e, 0x6a, 0x1e, 0xca, 0x61, 0x1c, 569 | 0xe8, 0x21, 0x1d, 0xde, 0xc1, 0x1d, 0x7e, 0x01, 0x1e, 0xe4, 0xa1, 0x1c, 570 | 0xcc, 0x21, 0x1d, 0xf0, 0x61, 0x06, 0x54, 0x85, 0x83, 0x38, 0xcc, 0xc3, 571 | 0x3b, 0xb0, 0x43, 0x3d, 0xd0, 0x43, 0x39, 0xfc, 0xc2, 0x3c, 0xe4, 0x43, 572 | 0x3b, 0x88, 0xc3, 0x3b, 0xb0, 0xc3, 0x8c, 0xc5, 0x0a, 0x87, 0x79, 0x98, 573 | 0x87, 0x77, 0x18, 0x87, 0x74, 0x08, 0x07, 0x7a, 0x28, 0x07, 0x72, 0x00, 574 | 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xa6, 575 | 0x70, 0x01, 0x48, 0xe4, 0x17, 0x80, 0x34, 0xfd, 0x12, 0x30, 0x51, 0x11, 576 | 0x30, 0x11, 0x7e, 0x65, 0x17, 0xb7, 0x6d, 0x05, 0x0d, 0x80, 0x44, 0xfe, 577 | 0xe0, 0x4c, 0x7e, 0x65, 0x17, 0xb7, 0x6d, 0x01, 0x1b, 0x80, 0x44, 0xbe, 578 | 0x04, 0x30, 0xcf, 0x42, 0xfc, 0x13, 0x71, 0x4d, 0x54, 0x44, 0xfc, 0xf6, 579 | 0xe0, 0x57, 0x78, 0x71, 0xdb, 0x66, 0x30, 0x01, 0x48, 0xe4, 0x17, 0x80, 580 | 0x34, 0xfd, 0x05, 0x03, 0x5c, 0x7e, 0x65, 0x17, 0xb7, 0x6d, 0x09, 0x13, 581 | 0x80, 0x44, 0x7e, 0x01, 0x48, 0xd3, 0x5f, 0x00, 0x81, 0xe4, 0x57, 0x76, 582 | 0x71, 0xdb, 0x36, 0x50, 0x01, 0x48, 0xe4, 0x17, 0x80, 0x34, 0xfd, 0x12, 583 | 0x30, 0x51, 0x11, 0x30, 0x11, 0x7e, 0x71, 0xdb, 0x46, 0x10, 0x01, 0x48, 584 | 0xe4, 0x17, 0x80, 0x34, 0xfd, 0x12, 0x14, 0x4d, 0x7e, 0x71, 0xdb, 0x06, 585 | 0xe0, 0x14, 0x11, 0x60, 0x30, 0x44, 0x33, 0xb1, 0x07, 0x30, 0x10, 0x91, 586 | 0x09, 0x34, 0x00, 0x12, 0xf9, 0x0c, 0x72, 0xf9, 0x15, 0x5e, 0xdc, 0xb6, 587 | 0x1d, 0x44, 0x00, 0x12, 0xf9, 0x05, 0x20, 0x4d, 0x7f, 0xc1, 0x20, 0x8d, 588 | 0x5f, 0xdc, 0xb6, 0x21, 0x44, 0x00, 0x12, 0xf9, 0x05, 0x20, 0x4d, 0x7f, 589 | 0xc1, 0x00, 0x97, 0x5f, 0xdc, 0x36, 0x00, 0x61, 0x20, 0x00, 0x00, 0xe4, 590 | 0x00, 0x00, 0x00, 0x13, 0x04, 0x4c, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x17, 591 | 0x00, 0x00, 0x00, 0xb4, 0x8e, 0x45, 0x00, 0x81, 0x70, 0xcc, 0x41, 0x30, 592 | 0x8e, 0x14, 0x0a, 0x23, 0x00, 0x34, 0x16, 0x41, 0x09, 0x90, 0x38, 0xd6, 593 | 0x10, 0x04, 0xc1, 0x08, 0xc0, 0x58, 0xc3, 0x30, 0x0c, 0x64, 0x94, 0x45, 594 | 0x61, 0x94, 0xc3, 0x0c, 0x00, 0x3d, 0x35, 0x30, 0x02, 0x40, 0xd0, 0x58, 595 | 0x02, 0x10, 0x8c, 0x00, 0x90, 0x38, 0xd6, 0x00, 0x04, 0x02, 0x0d, 0x33, 596 | 0x00, 0x24, 0x8c, 0x00, 0x8c, 0x25, 0x80, 0x20, 0x08, 0xc2, 0x1f, 0x08, 597 | 0x82, 0x20, 0xfc, 0xcd, 0x00, 0x50, 0x30, 0x02, 0x30, 0x03, 0x40, 0xc0, 598 | 0x18, 0x01, 0x08, 0x82, 0x20, 0xfc, 0x8d, 0x00, 0x00, 0x00, 0x00, 0xc7, 599 | 0x85, 0x4b, 0x41, 0x19, 0x64, 0x08, 0x8a, 0x65, 0x90, 0x21, 0x0c, 0x10, 600 | 0xcb, 0x84, 0x40, 0x3e, 0xe3, 0x15, 0x61, 0x10, 0x07, 0xa8, 0x80, 0x0a, 601 | 0xda, 0x05, 0xe1, 0x52, 0x50, 0x06, 0x19, 0x82, 0x25, 0x1a, 0x64, 0x38, 602 | 0x03, 0xa7, 0x33, 0x21, 0x90, 0x8f, 0x05, 0x07, 0x7c, 0xc6, 0x2b, 0xd0, 603 | 0x00, 0x0f, 0x5e, 0xe1, 0x15, 0xc4, 0xe0, 0x82, 0x70, 0x29, 0x28, 0x83, 604 | 0x0c, 0x81, 0x84, 0x59, 0x11, 0xc0, 0x67, 0x90, 0x21, 0xc8, 0xb8, 0x11, 605 | 0x03, 0x62, 0x08, 0x70, 0x21, 0x18, 0x6f, 0x78, 0x83, 0x3f, 0xa8, 0x05, 606 | 0x0a, 0x8a, 0x0d, 0x41, 0x7c, 0xc6, 0x1b, 0xe4, 0x40, 0x14, 0x48, 0x81, 607 | 0x02, 0x62, 0x43, 0x20, 0x1f, 0xfb, 0x82, 0xf8, 0x8c, 0x18, 0x10, 0x43, 608 | 0xf0, 0x0b, 0xc1, 0x18, 0x42, 0xe0, 0x0b, 0x63, 0x08, 0x42, 0x2f, 0x98, 609 | 0x10, 0xc8, 0x67, 0xb8, 0x21, 0xf8, 0x82, 0x59, 0x86, 0x25, 0x08, 0xc6, 610 | 0x1b, 0xf6, 0x60, 0x15, 0xde, 0x80, 0x82, 0x31, 0xcc, 0x61, 0x04, 0x07, 611 | 0x23, 0x38, 0xc3, 0x78, 0x43, 0x1f, 0xb4, 0x82, 0x38, 0x5c, 0x10, 0x2e, 612 | 0x05, 0x65, 0x90, 0x21, 0x38, 0x83, 0x36, 0xb0, 0x40, 0x0c, 0xe4, 0x33, 613 | 0x5e, 0x21, 0x0a, 0xb2, 0x70, 0x0e, 0xe9, 0xb0, 0x07, 0x17, 0x84, 0x4b, 614 | 0x41, 0x19, 0x64, 0x08, 0xd8, 0x40, 0x0e, 0x2c, 0x08, 0x03, 0xf9, 0x58, 615 | 0x60, 0xc0, 0x67, 0xbc, 0x02, 0x15, 0x70, 0xa1, 0x1d, 0xde, 0x41, 0x14, 616 | 0x2e, 0x08, 0x97, 0x82, 0x32, 0xc8, 0x10, 0xc8, 0x01, 0x1e, 0x58, 0x11, 617 | 0xc0, 0x67, 0x90, 0x21, 0xc8, 0x03, 0x3e, 0x18, 0x6f, 0x70, 0x05, 0x5f, 618 | 0x80, 0x07, 0x0a, 0x86, 0x05, 0x76, 0x20, 0x9f, 0xf1, 0x86, 0x58, 0x08, 619 | 0x07, 0x78, 0xa0, 0xa0, 0x8c, 0x37, 0xcc, 0xc2, 0x38, 0x98, 0x02, 0x05, 620 | 0x64, 0x8e, 0xc1, 0x0f, 0x02, 0x7e, 0x18, 0x64, 0x08, 0xfe, 0x80, 0x14, 621 | 0xac, 0x08, 0xe2, 0x33, 0x62, 0x40, 0x0c, 0x81, 0x48, 0x2c, 0x16, 0x08, 622 | 0xf1, 0x19, 0x43, 0x08, 0x42, 0x62, 0x0c, 0x41, 0x00, 0x89, 0x11, 0x83, 623 | 0x62, 0x08, 0x4e, 0x42, 0x08, 0x46, 0x0c, 0x8a, 0x21, 0x48, 0x89, 0x40, 624 | 0x14, 0x46, 0x0c, 0x8a, 0x21, 0x58, 0x89, 0x22, 0x15, 0x46, 0x0c, 0x8a, 625 | 0x21, 0x68, 0x89, 0x20, 0x18, 0x31, 0x20, 0x86, 0xe0, 0x25, 0x02, 0x8b, 626 | 0x9a, 0xf8, 0x58, 0x50, 0xc0, 0xc7, 0x82, 0x01, 0x3e, 0x16, 0x54, 0xf4, 627 | 0x19, 0x31, 0x20, 0x86, 0xa0, 0x26, 0x82, 0xf1, 0x06, 0x73, 0xb0, 0x87, 628 | 0x93, 0xa0, 0xa0, 0x8c, 0x37, 0xa0, 0x03, 0x3e, 0x98, 0x04, 0x05, 0x65, 629 | 0x8e, 0x21, 0x16, 0x8a, 0x98, 0x18, 0x64, 0x08, 0x64, 0xc1, 0x1c, 0x46, 630 | 0x0c, 0x8c, 0x21, 0xe8, 0x89, 0x62, 0x08, 0xe6, 0x18, 0x68, 0x81, 0x0e, 631 | 0x68, 0x62, 0x90, 0x21, 0xa8, 0x85, 0x74, 0xb0, 0x21, 0x90, 0xcf, 0x2c, 632 | 0xc1, 0x32, 0xde, 0x00, 0x0f, 0x20, 0x51, 0x13, 0x17, 0x84, 0x4b, 0x41, 633 | 0x19, 0x64, 0x08, 0x74, 0x01, 0x1c, 0x2c, 0xa8, 0x05, 0xf9, 0x8c, 0x57, 634 | 0xd4, 0x43, 0x49, 0xe8, 0x04, 0x4f, 0xb8, 0xc3, 0x05, 0xe1, 0x52, 0x50, 635 | 0x06, 0x19, 0x82, 0x5f, 0x28, 0x07, 0x0b, 0x68, 0x41, 0x3e, 0x16, 0x18, 636 | 0xf0, 0x19, 0xaf, 0xd8, 0x87, 0x95, 0x00, 0x0b, 0xb1, 0xa8, 0x87, 0x0b, 637 | 0xc2, 0xa5, 0xa0, 0x0c, 0x32, 0x04, 0xe5, 0xb0, 0x0e, 0x56, 0x04, 0xf0, 638 | 0x19, 0x64, 0x08, 0xd8, 0xe1, 0x1d, 0xc6, 0x1b, 0x42, 0x22, 0x26, 0xc0, 639 | 0x82, 0x82, 0x62, 0x43, 0x40, 0x9f, 0x11, 0x03, 0x45, 0x08, 0xec, 0x62, 640 | 0x24, 0x44, 0x22, 0xa8, 0x07, 0x79, 0xa0, 0x87, 0x74, 0x18, 0x6f, 0x28, 641 | 0x89, 0x9a, 0xd0, 0x07, 0x0a, 0xc8, 0x30, 0x87, 0x11, 0x18, 0x0e, 0x21, 642 | 0x15, 0x83, 0x0c, 0x83, 0x3b, 0xd0, 0xc3, 0x20, 0x03, 0xf1, 0x0e, 0xfe, 643 | 0x60, 0x42, 0x20, 0x9f, 0x41, 0x86, 0xc0, 0x1e, 0x4c, 0x62, 0x90, 0x21, 644 | 0x38, 0x50, 0x62, 0x96, 0xc0, 0x18, 0x64, 0x40, 0xe6, 0xe1, 0x24, 0x66, 645 | 0x09, 0x8c, 0x81, 0x8e, 0x80, 0x20, 0x84, 0x42, 0x1a, 0xe6, 0x18, 0xea, 646 | 0xa1, 0x16, 0xea, 0x62, 0x90, 0x21, 0xb0, 0x07, 0x95, 0xb0, 0x21, 0x90, 647 | 0xcf, 0x78, 0x43, 0x4c, 0x84, 0x85, 0x5c, 0x50, 0x50, 0x6c, 0x08, 0xe4, 648 | 0x33, 0x4b, 0xb0, 0x8c, 0x18, 0x28, 0x42, 0x60, 0x1a, 0x33, 0x21, 0x13, 649 | 0x35, 0x51, 0x12, 0x22, 0x41, 0x12, 0xf9, 0x30, 0xde, 0x50, 0x13, 0x65, 650 | 0xa1, 0x12, 0x14, 0x90, 0x61, 0x0e, 0x23, 0x50, 0x1c, 0x44, 0x4a, 0x06, 651 | 0x19, 0x06, 0x7f, 0x20, 0x89, 0x41, 0x06, 0xe2, 0x1f, 0x5c, 0xc2, 0x84, 652 | 0x40, 0x3e, 0x83, 0x0c, 0x81, 0x49, 0xd8, 0xc4, 0x20, 0x43, 0x70, 0xe0, 653 | 0xc4, 0x2c, 0x81, 0x32, 0xc8, 0x80, 0x8c, 0xc4, 0x4d, 0xcc, 0x12, 0x28, 654 | 0x03, 0x1d, 0x01, 0x81, 0x08, 0x89, 0x74, 0xcc, 0x31, 0x94, 0x44, 0x39, 655 | 0x94, 0xc6, 0x20, 0x43, 0x60, 0x12, 0x3a, 0x61, 0x43, 0x20, 0x9f, 0xf1, 656 | 0x86, 0xb0, 0x88, 0x0b, 0xd1, 0xa0, 0xa0, 0xd8, 0x10, 0xc8, 0x67, 0x96, 657 | 0x60, 0x19, 0x28, 0x09, 0xd4, 0x41, 0x10, 0x03, 0x43, 0x50, 0x70, 0x04, 658 | 0xc8, 0x20, 0x20, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x5b, 659 | 0x06, 0x2a, 0x90, 0x85, 0x2d, 0xc3, 0x15, 0xc8, 0xc2, 0x96, 0x21, 0x0c, 660 | 0x82, 0x5c, 0xd8, 0x32, 0xd4, 0x41, 0xa0, 0x0b, 0x5b, 0x06, 0x3c, 0x08, 661 | 0x64, 0x61, 0xcb, 0xa0, 0x07, 0xc1, 0x2e, 0x6c, 0x19, 0x54, 0x61, 0xe0, 662 | 0x85, 0x2d, 0x43, 0x2b, 0x04, 0xb2, 0xb0, 0x65, 0x78, 0x85, 0x40, 0x16, 663 | 0xb6, 0x0c, 0xe9, 0x10, 0xc8, 0xc2, 0x96, 0x41, 0x1d, 0x06, 0x5e, 0xd8, 664 | 0x32, 0xb4, 0x43, 0xd0, 0x0b, 0x5b, 0x06, 0x7e, 0x08, 0x64, 0x61, 0xcb, 665 | 0x10, 0x12, 0x41, 0x2f, 0x6c, 0x19, 0x60, 0x22, 0x90, 0x05, 0x00, 0x00, 666 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 667 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xc0, 0x17, 0x0b, 0x00, 668 | 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xcc, 0x12, 0x00, 0x00, 0xff, 669 | 0xff, 0xff, 0xff, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0xb0, 670 | 0x04, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 671 | 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 672 | 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 673 | 0x04, 0x8b, 0x62, 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 674 | 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x49, 0x0a, 0x32, 0x44, 0x24, 0x48, 675 | 0x0a, 0x90, 0x21, 0x23, 0xc4, 0x52, 0x80, 0x0c, 0x19, 0x21, 0x72, 0x24, 676 | 0x07, 0xc8, 0x88, 0x11, 0x62, 0xa8, 0xa0, 0xa8, 0x40, 0xc6, 0xf0, 0x01, 677 | 0x00, 0x00, 0x00, 0x51, 0x18, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x1b, 678 | 0xcc, 0x25, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x60, 0x00, 0x09, 0xa8, 679 | 0x88, 0x71, 0x78, 0x07, 0x79, 0x90, 0x87, 0x72, 0x18, 0x07, 0x7a, 0x60, 680 | 0x87, 0x7c, 0x68, 0x03, 0x79, 0x78, 0x87, 0x7a, 0x70, 0x07, 0x72, 0x28, 681 | 0x07, 0x72, 0x68, 0x03, 0x72, 0x48, 0x07, 0x7b, 0x48, 0x07, 0x72, 0x28, 682 | 0x87, 0x36, 0x98, 0x87, 0x78, 0x90, 0x07, 0x7a, 0x68, 0x03, 0x73, 0x80, 683 | 0x87, 0x36, 0x68, 0x87, 0x70, 0xa0, 0x07, 0x74, 0x00, 0xcc, 0x21, 0x1c, 684 | 0xd8, 0x61, 0x1e, 0xca, 0x01, 0x20, 0xc8, 0x21, 0x1d, 0xe6, 0x21, 0x1c, 685 | 0xc4, 0x81, 0x1d, 0xca, 0xa1, 0x0d, 0xe8, 0x21, 0x1c, 0xd2, 0x81, 0x1d, 686 | 0xda, 0x60, 0x1c, 0xc2, 0x81, 0x1d, 0xd8, 0x61, 0x1e, 0x00, 0x73, 0x08, 687 | 0x07, 0x76, 0x98, 0x87, 0x72, 0x00, 0x08, 0x76, 0x28, 0x87, 0x79, 0x98, 688 | 0x87, 0x36, 0x80, 0x07, 0x79, 0x28, 0x87, 0x71, 0x48, 0x87, 0x79, 0x28, 689 | 0x87, 0x36, 0x30, 0x07, 0x78, 0x68, 0x87, 0x70, 0x20, 0x07, 0xc0, 0x1c, 690 | 0xc2, 0x81, 0x1d, 0xe6, 0xa1, 0x1c, 0x00, 0xc2, 0x1d, 0xde, 0xa1, 0x0d, 691 | 0xcc, 0x41, 0x1e, 0xc2, 0xa1, 0x1d, 0xca, 0xa1, 0x0d, 0xe0, 0xe1, 0x1d, 692 | 0xd2, 0xc1, 0x1d, 0xe8, 0xa1, 0x1c, 0xe4, 0xa1, 0x0d, 0xca, 0x81, 0x1d, 693 | 0xd2, 0xa1, 0x1d, 0x00, 0x7a, 0x90, 0x87, 0x7a, 0x28, 0x07, 0x60, 0x70, 694 | 0x87, 0x77, 0x68, 0x03, 0x73, 0x90, 0x87, 0x70, 0x68, 0x87, 0x72, 0x68, 695 | 0x03, 0x78, 0x78, 0x87, 0x74, 0x70, 0x07, 0x7a, 0x28, 0x07, 0x79, 0x68, 696 | 0x83, 0x72, 0x60, 0x87, 0x74, 0x68, 0x87, 0x36, 0x70, 0x87, 0x77, 0x70, 697 | 0x87, 0x36, 0x60, 0x87, 0x72, 0x08, 0x07, 0x73, 0x00, 0x08, 0x77, 0x78, 698 | 0x87, 0x36, 0x48, 0x07, 0x77, 0x30, 0x87, 0x79, 0x68, 0x03, 0x73, 0x80, 699 | 0x87, 0x36, 0x68, 0x87, 0x70, 0xa0, 0x07, 0x74, 0x00, 0xe8, 0x41, 0x1e, 700 | 0xea, 0xa1, 0x1c, 0x00, 0xc2, 0x1d, 0xde, 0xa1, 0x0d, 0xd4, 0xa1, 0x1e, 701 | 0xda, 0x01, 0x1e, 0xda, 0x80, 0x1e, 0xc2, 0x41, 0x1c, 0xd8, 0xa1, 0x1c, 702 | 0xe6, 0x01, 0x30, 0x87, 0x70, 0x60, 0x87, 0x79, 0x28, 0x07, 0x80, 0x70, 703 | 0x87, 0x77, 0x68, 0x03, 0x77, 0x08, 0x07, 0x77, 0x98, 0x87, 0x36, 0x30, 704 | 0x07, 0x78, 0x68, 0x83, 0x76, 0x08, 0x07, 0x7a, 0x40, 0x07, 0x80, 0x1e, 705 | 0xe4, 0xa1, 0x1e, 0xca, 0x01, 0x20, 0xdc, 0xe1, 0x1d, 0xda, 0x60, 0x1e, 706 | 0xd2, 0xe1, 0x1c, 0xdc, 0xa1, 0x1c, 0xc8, 0xa1, 0x0d, 0xf4, 0xa1, 0x1c, 707 | 0xe4, 0xe1, 0x1d, 0xe6, 0xa1, 0x0d, 0xcc, 0x01, 0x1e, 0xda, 0xa0, 0x1d, 708 | 0xc2, 0x81, 0x1e, 0xd0, 0x01, 0xa0, 0x07, 0x79, 0xa8, 0x87, 0x72, 0x00, 709 | 0x08, 0x77, 0x78, 0x87, 0x36, 0xa0, 0x07, 0x79, 0x08, 0x07, 0x78, 0x80, 710 | 0x87, 0x74, 0x70, 0x87, 0x73, 0x68, 0x83, 0x76, 0x08, 0x07, 0x7a, 0x40, 711 | 0x07, 0x80, 0x1e, 0xe4, 0xa1, 0x1e, 0xca, 0x01, 0x20, 0xe6, 0x81, 0x1e, 712 | 0xc2, 0x61, 0x1c, 0xd6, 0xa1, 0x0d, 0xe0, 0x41, 0x1e, 0xde, 0x81, 0x1e, 713 | 0xca, 0x61, 0x1c, 0xe8, 0xe1, 0x1d, 0xe4, 0xa1, 0x0d, 0xc4, 0xa1, 0x1e, 714 | 0xcc, 0xc1, 0x1c, 0xca, 0x41, 0x1e, 0xda, 0x60, 0x1e, 0xd2, 0x41, 0x1f, 715 | 0xca, 0x01, 0xc0, 0x03, 0x80, 0xa8, 0x07, 0x77, 0x98, 0x87, 0x70, 0x30, 716 | 0x87, 0x72, 0x68, 0x03, 0x73, 0x80, 0x87, 0x36, 0x68, 0x87, 0x70, 0xa0, 717 | 0x07, 0x74, 0x00, 0xe8, 0x41, 0x1e, 0xea, 0xa1, 0x1c, 0x00, 0xa2, 0x1e, 718 | 0xe6, 0xa1, 0x1c, 0xda, 0x60, 0x1e, 0xde, 0xc1, 0x1c, 0xe8, 0xa1, 0x0d, 719 | 0xcc, 0x81, 0x1d, 0xde, 0x21, 0x1c, 0xe8, 0x01, 0x30, 0x87, 0x70, 0x60, 720 | 0x87, 0x79, 0x28, 0x07, 0x60, 0x83, 0x21, 0x10, 0x40, 0x02, 0x54, 0x1b, 721 | 0x8c, 0xc1, 0x00, 0x16, 0xa0, 0xda, 0x80, 0x10, 0xff, 0xff, 0xff, 0xff, 722 | 0x3f, 0x00, 0x0c, 0x20, 0x01, 0xd5, 0x06, 0xa3, 0x08, 0x80, 0x05, 0xa8, 723 | 0x36, 0x18, 0x86, 0x00, 0x2c, 0x40, 0xb5, 0xc1, 0x38, 0xfe, 0xff, 0xff, 724 | 0xff, 0x7f, 0x00, 0x24, 0x80, 0x02, 0x00, 0x49, 0x18, 0x00, 0x00, 0x03, 725 | 0x00, 0x00, 0x00, 0x13, 0x86, 0x40, 0x18, 0x26, 0x0c, 0x44, 0x61, 0x4c, 726 | 0x08, 0x0e, 0x00, 0x89, 0x20, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x32, 727 | 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84, 0x04, 728 | 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c, 0x0b, 729 | 0x84, 0xc4, 0x4c, 0x10, 0xb0, 0xc1, 0x0c, 0xc0, 0x30, 0x02, 0x01, 0x0c, 730 | 0x23, 0x08, 0xc0, 0x30, 0xc2, 0x00, 0xe4, 0xc0, 0x30, 0x13, 0x35, 0x0f, 731 | 0xf4, 0x20, 0x0f, 0xf5, 0x30, 0x0e, 0xf4, 0xe0, 0x06, 0xed, 0x50, 0x0e, 732 | 0xf4, 0x10, 0x0e, 0xec, 0xa0, 0x07, 0x7a, 0xd0, 0x0e, 0xe1, 0x40, 0x0f, 733 | 0xf2, 0x90, 0x0e, 0xf8, 0x80, 0x02, 0x62, 0x8e, 0x00, 0x0c, 0xee, 0x91, 734 | 0xa6, 0x88, 0x12, 0x26, 0xdf, 0x6d, 0x90, 0xc2, 0x89, 0x18, 0x09, 0x35, 735 | 0x45, 0x11, 0x04, 0x82, 0x20, 0x00, 0x00, 0x00, 0x18, 0xc6, 0x20, 0xc2, 736 | 0x21, 0x1c, 0x25, 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x3f, 0x11, 0xd7, 0x44, 737 | 0x45, 0xc4, 0x6f, 0x0f, 0xff, 0x34, 0x46, 0x00, 0x0c, 0x22, 0x24, 0xc1, 738 | 0x45, 0xd2, 0x14, 0x51, 0xc2, 0xe4, 0xff, 0x12, 0xc0, 0x3c, 0x0b, 0x11, 739 | 0xfd, 0xd3, 0x18, 0x01, 0x30, 0x88, 0xb0, 0x08, 0xe5, 0x08, 0x02, 0x41, 740 | 0x40, 0x14, 0x86, 0x9a, 0x39, 0x82, 0x60, 0x18, 0x41, 0x30, 0x0a, 0x12, 741 | 0x28, 0x8c, 0xf0, 0x40, 0x0f, 0x40, 0x51, 0x21, 0x82, 0x20, 0x08, 0x68, 742 | 0x2a, 0x02, 0x00, 0x50, 0x55, 0x06, 0x40, 0x10, 0xe8, 0x2a, 0x83, 0x20, 743 | 0x08, 0x94, 0x95, 0x01, 0x00, 0x00, 0xda, 0x8a, 0x20, 0x08, 0xd4, 0x0d, 744 | 0x04, 0xa4, 0x80, 0x31, 0x88, 0x10, 0x08, 0xc3, 0x08, 0x83, 0x31, 0x47, 745 | 0x00, 0x0a, 0x83, 0x08, 0x83, 0x30, 0x88, 0x20, 0x08, 0x53, 0x00, 0x23, 746 | 0x00, 0x83, 0x08, 0x86, 0x30, 0x8c, 0x40, 0x18, 0x83, 0x08, 0x80, 0x30, 747 | 0x88, 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa8, 0x70, 0x48, 0x07, 748 | 0x79, 0xb0, 0x03, 0x3a, 0x68, 0x83, 0x70, 0x80, 0x07, 0x78, 0x60, 0x87, 749 | 0x72, 0x68, 0x83, 0x74, 0x78, 0x87, 0x79, 0xc0, 0x03, 0x37, 0x80, 0x03, 750 | 0x37, 0x80, 0x83, 0x0d, 0xb7, 0x51, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x60, 751 | 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 752 | 0x06, 0xe9, 0x10, 0x07, 0x7a, 0x80, 0x07, 0x7a, 0x80, 0x07, 0x6d, 0x90, 753 | 0x0e, 0x78, 0xa0, 0x07, 0x78, 0xa0, 0x07, 0x78, 0xd0, 0x06, 0xe9, 0x10, 754 | 0x07, 0x76, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xd0, 755 | 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 756 | 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 757 | 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x30, 0x07, 0x72, 0xa0, 758 | 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 759 | 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 760 | 0x06, 0xf6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x10, 761 | 0x07, 0x76, 0xd0, 0x06, 0xf6, 0x20, 0x07, 0x74, 0xa0, 0x07, 0x73, 0x20, 762 | 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xf6, 0x30, 0x07, 0x72, 0xa0, 763 | 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xf6, 0x40, 764 | 0x07, 0x78, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 765 | 0x06, 0xf6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 766 | 0x07, 0x74, 0xd0, 0x06, 0xf6, 0x90, 0x07, 0x76, 0xa0, 0x07, 0x71, 0x20, 767 | 0x07, 0x78, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xf6, 0x10, 768 | 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10, 769 | 0x07, 0x72, 0x80, 0x07, 0x6d, 0x60, 0x0f, 0x71, 0x90, 0x07, 0x72, 0xa0, 770 | 0x07, 0x72, 0x50, 0x07, 0x76, 0xa0, 0x07, 0x72, 0x50, 0x07, 0x76, 0xd0, 771 | 0x06, 0xf6, 0x20, 0x07, 0x75, 0x60, 0x07, 0x7a, 0x20, 0x07, 0x75, 0x60, 772 | 0x07, 0x7a, 0x20, 0x07, 0x75, 0x60, 0x07, 0x6d, 0x60, 0x0f, 0x75, 0x10, 773 | 0x07, 0x72, 0xa0, 0x07, 0x75, 0x10, 0x07, 0x72, 0xa0, 0x07, 0x75, 0x10, 774 | 0x07, 0x72, 0xd0, 0x06, 0xf6, 0x10, 0x07, 0x70, 0x20, 0x07, 0x74, 0xa0, 775 | 0x07, 0x71, 0x00, 0x07, 0x72, 0x40, 0x07, 0x7a, 0x10, 0x07, 0x70, 0x20, 776 | 0x07, 0x74, 0xd0, 0x06, 0xee, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xa0, 777 | 0x07, 0x73, 0x20, 0x07, 0x43, 0x18, 0x07, 0x00, 0x80, 0x00, 0x00, 0x00, 778 | 0x00, 0x00, 0x80, 0x21, 0x8c, 0x04, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 779 | 0x00, 0xc0, 0x10, 0x86, 0x02, 0x02, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 780 | 0x60, 0x08, 0x63, 0x01, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 781 | 0x84, 0xb1, 0x80, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc2, 782 | 0x60, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x61, 0x34, 783 | 0x20, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x30, 0x1c, 0x10, 784 | 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x18, 0x0e, 0x08, 0x80, 785 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0x8c, 0x07, 0x04, 0xc0, 0x00, 786 | 0x00, 0x00, 0x00, 0x00, 0xc0, 0x10, 0xc6, 0x02, 0x02, 0x60, 0x00, 0x00, 787 | 0x00, 0x00, 0x00, 0x60, 0x08, 0xe3, 0x01, 0x01, 0x30, 0x00, 0x00, 0x00, 788 | 0x00, 0x00, 0x90, 0x05, 0x02, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x32, 789 | 0x1e, 0x98, 0x18, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 790 | 0x04, 0x43, 0x1a, 0x0b, 0x54, 0x80, 0x8c, 0x11, 0x80, 0x42, 0x28, 0x81, 791 | 0x02, 0x2b, 0x90, 0x82, 0x28, 0x82, 0x02, 0x17, 0x28, 0x86, 0x32, 0x28, 792 | 0xe0, 0x80, 0x02, 0x0f, 0x28, 0x40, 0x81, 0x82, 0x14, 0x28, 0x50, 0x81, 793 | 0x82, 0x15, 0x28, 0x5c, 0x81, 0x02, 0x16, 0x28, 0x64, 0x81, 0x82, 0x16, 794 | 0x28, 0x6c, 0x81, 0x52, 0xa0, 0xb1, 0x20, 0x05, 0x46, 0x00, 0x0a, 0x56, 795 | 0xa0, 0x70, 0x05, 0x0a, 0x58, 0xa0, 0x90, 0x05, 0x0a, 0x5a, 0xa0, 0xb0, 796 | 0x05, 0x0a, 0xac, 0x80, 0x03, 0x0a, 0x3c, 0xa0, 0x00, 0x05, 0x08, 0x1c, 797 | 0x4b, 0x68, 0x04, 0x02, 0xc6, 0x08, 0x40, 0x10, 0x04, 0x45, 0x30, 0x00, 798 | 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x93, 0x01, 0x00, 0x00, 0x1a, 799 | 0x03, 0x4c, 0x10, 0x97, 0x29, 0xa2, 0x25, 0x10, 0xab, 0x32, 0xb9, 0xb9, 800 | 0xb4, 0x37, 0xb7, 0x21, 0x86, 0x31, 0x7d, 0x00, 0x18, 0xbc, 0x01, 0x95, 801 | 0xbb, 0x31, 0xb4, 0x30, 0xb9, 0xaf, 0xb9, 0x34, 0xbd, 0xb2, 0x21, 0x86, 802 | 0xf1, 0x7c, 0x82, 0xe1, 0x70, 0x0d, 0x82, 0xe0, 0xe0, 0xd8, 0xca, 0x40, 803 | 0x98, 0x98, 0xac, 0x9a, 0x40, 0xec, 0xca, 0xe4, 0xe6, 0xd2, 0xde, 0xdc, 804 | 0x40, 0x72, 0x60, 0x64, 0x5c, 0x72, 0x40, 0x50, 0xda, 0xca, 0xe8, 0xc2, 805 | 0xd8, 0xcc, 0xca, 0x5a, 0x72, 0x60, 0x64, 0x5c, 0x72, 0x5c, 0x6c, 0x62, 806 | 0x52, 0x86, 0x08, 0x1f, 0x31, 0xc4, 0x30, 0x1e, 0xa3, 0x32, 0x1a, 0x16, 807 | 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x43, 0x90, 0xef, 0x30, 0x1e, 0xa3, 0x31, 808 | 0x1a, 0x6e, 0x61, 0x69, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 809 | 0x65, 0x2e, 0x64, 0x65, 0x6e, 0x6f, 0x72, 0x6d, 0x73, 0x5f, 0x64, 0x69, 810 | 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x84, 0x2f, 0x21, 0x17, 0x96, 0x26, 811 | 0xe7, 0x32, 0xf6, 0xd6, 0x06, 0x97, 0xc6, 0x56, 0xe6, 0x62, 0x16, 0x36, 812 | 0x47, 0xf7, 0xd5, 0x16, 0x46, 0x87, 0xf6, 0x55, 0xe6, 0x16, 0x26, 0xc6, 813 | 0x56, 0x36, 0x44, 0xf8, 0x16, 0x92, 0x41, 0x58, 0x9a, 0x9c, 0xcb, 0xd8, 814 | 0x5b, 0x1b, 0x5c, 0x1a, 0x5b, 0x99, 0x8b, 0x99, 0x5c, 0x58, 0x5b, 0x99, 815 | 0x58, 0x9d, 0x99, 0x59, 0x99, 0xdc, 0x97, 0x59, 0x19, 0xdd, 0x18, 0xda, 816 | 0x57, 0x99, 0x5b, 0x98, 0x18, 0x5b, 0xd9, 0x10, 0xe1, 0x6b, 0x18, 0x06, 817 | 0x61, 0x69, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e, 818 | 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 819 | 0x65, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x84, 0xef, 820 | 0x21, 0x19, 0x84, 0xa5, 0xc9, 0xb9, 0x8c, 0xbd, 0xb5, 0xc1, 0xa5, 0xb1, 821 | 0x95, 0xb9, 0xb8, 0x85, 0xd1, 0xa5, 0xd9, 0x95, 0x7d, 0xb1, 0xbd, 0xb9, 822 | 0x9d, 0x7d, 0xb1, 0xbd, 0xb9, 0x9d, 0x7d, 0x91, 0xa5, 0xcd, 0x85, 0x89, 823 | 0xb1, 0x95, 0x0d, 0x11, 0xbe, 0x88, 0x67, 0x10, 0x96, 0x26, 0xe7, 0x32, 824 | 0xf6, 0xd6, 0x06, 0x97, 0xc6, 0x56, 0xe6, 0xe2, 0x16, 0x46, 0x97, 0x66, 825 | 0x57, 0xf6, 0x75, 0x97, 0x46, 0x56, 0xf6, 0x65, 0x57, 0x36, 0x46, 0xf7, 826 | 0x26, 0x37, 0xf7, 0x45, 0x96, 0x36, 0x17, 0x26, 0xc6, 0x56, 0x36, 0x44, 827 | 0xf8, 0x26, 0x46, 0x61, 0x69, 0x72, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 828 | 0x72, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x8c, 0xc2, 0xd2, 0xe4, 829 | 0x5c, 0xc2, 0xe4, 0xce, 0xbe, 0xe8, 0xf2, 0xe0, 0xca, 0xbe, 0xdc, 0xc2, 830 | 0xda, 0xca, 0x68, 0x98, 0xb1, 0xbd, 0x85, 0xd1, 0xd1, 0x0c, 0x41, 0xbe, 831 | 0xca, 0x68, 0x3e, 0xeb, 0xbb, 0x86, 0x08, 0x1f, 0x46, 0x26, 0x2c, 0x4d, 832 | 0xce, 0x05, 0xee, 0x6d, 0x2e, 0x8d, 0x2e, 0xed, 0xcd, 0x8d, 0x4a, 0x58, 833 | 0x9a, 0x9c, 0xcb, 0x58, 0x99, 0x1b, 0x5d, 0x99, 0x1c, 0xa5, 0xb0, 0x34, 834 | 0x39, 0x17, 0xb7, 0xb7, 0x2f, 0xb8, 0x32, 0xb9, 0x39, 0xb8, 0xb2, 0x31, 835 | 0xba, 0x34, 0xbb, 0x32, 0x32, 0x61, 0x69, 0x72, 0x2e, 0x61, 0x72, 0x67, 836 | 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x1c, 0xe0, 0xde, 0xe6, 0x86, 0x40, 0x46, 837 | 0xf3, 0x69, 0xdf, 0xf6, 0x71, 0x9f, 0xf5, 0x5d, 0x5f, 0xf7, 0x79, 0x94, 838 | 0xc2, 0xd2, 0xe4, 0x5c, 0xcc, 0xe4, 0xc2, 0xce, 0xda, 0xca, 0xdc, 0xe8, 839 | 0xbe, 0xd2, 0xdc, 0xe0, 0xea, 0xe8, 0x58, 0x9d, 0x95, 0xb9, 0x95, 0xc9, 840 | 0x85, 0xd1, 0x95, 0x91, 0xa1, 0xd0, 0x98, 0xc1, 0xbd, 0xcd, 0x11, 0xd9, 841 | 0xc9, 0x7c, 0x99, 0xa5, 0xf0, 0x09, 0x4b, 0x93, 0x73, 0x81, 0x2b, 0x93, 842 | 0x9b, 0x83, 0x2b, 0x1b, 0xa3, 0x4b, 0xb3, 0x2b, 0xa3, 0x61, 0xc6, 0xf6, 843 | 0x16, 0x46, 0x27, 0x43, 0xc2, 0x0c, 0xee, 0x6d, 0x6e, 0x88, 0x64, 0x3c, 844 | 0x1f, 0x18, 0x7c, 0x61, 0xf0, 0x6d, 0x9f, 0x18, 0x7c, 0xd6, 0x37, 0x06, 845 | 0x5f, 0xf7, 0x91, 0x01, 0xb1, 0xb3, 0x32, 0xb7, 0x32, 0xb9, 0x30, 0xba, 846 | 0x32, 0x32, 0x94, 0x1b, 0x33, 0xba, 0xb1, 0xb7, 0x37, 0x39, 0x32, 0x22, 847 | 0x3b, 0x99, 0x2f, 0xb3, 0x14, 0x1e, 0x66, 0x74, 0x63, 0x6f, 0x6f, 0x72, 848 | 0x64, 0x43, 0x24, 0x63, 0xfa, 0xc0, 0xe0, 0x33, 0x83, 0x6f, 0xfb, 0xc4, 849 | 0xe0, 0xb3, 0xbe, 0x31, 0xf8, 0xba, 0xef, 0x0c, 0xa8, 0x84, 0xa5, 0xc9, 850 | 0xb9, 0x88, 0xd5, 0x99, 0x99, 0x95, 0xc9, 0xf1, 0x09, 0x4b, 0x93, 0x73, 851 | 0x11, 0xab, 0x33, 0x33, 0x2b, 0x93, 0xfb, 0x9a, 0x4b, 0xd3, 0x2b, 0xa3, 852 | 0x14, 0x96, 0x26, 0xe7, 0xc2, 0xf6, 0x36, 0x16, 0x46, 0x97, 0xf6, 0xe6, 853 | 0xf6, 0x95, 0xe6, 0x46, 0x56, 0x86, 0x47, 0x24, 0x2c, 0x4d, 0xce, 0x45, 854 | 0xae, 0x2c, 0x8c, 0x8c, 0x54, 0x58, 0x9a, 0x9c, 0xcb, 0x1c, 0x9d, 0x5c, 855 | 0xdd, 0x18, 0xdd, 0x17, 0x5d, 0x1e, 0x5c, 0xd9, 0x57, 0x9a, 0x9b, 0xd9, 856 | 0x1b, 0x11, 0x33, 0xb6, 0xb7, 0x30, 0xba, 0x19, 0xbc, 0x19, 0x2a, 0x73, 857 | 0x63, 0x69, 0x73, 0x73, 0x6f, 0x72, 0x4d, 0x61, 0x74, 0x44, 0xe0, 0xc2, 858 | 0xd2, 0xdc, 0xe8, 0x9a, 0xc2, 0xe8, 0x88, 0xa4, 0xb9, 0xb9, 0x95, 0xc9, 859 | 0x0d, 0xbd, 0xb1, 0x11, 0x79, 0xab, 0xa3, 0x2b, 0x93, 0x1b, 0x7a, 0x63, 860 | 0xa3, 0x32, 0x37, 0x96, 0x36, 0x37, 0xf7, 0x26, 0x57, 0x84, 0x47, 0x47, 861 | 0x66, 0x6e, 0x2c, 0x6d, 0x6e, 0xee, 0x4d, 0x6e, 0x6a, 0x2c, 0x8c, 0xad, 862 | 0x8c, 0x46, 0x19, 0x1e, 0x5d, 0x99, 0x1b, 0x1d, 0x0b, 0x33, 0xb6, 0xb7, 863 | 0x30, 0x3a, 0x1a, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3c, 0xcc, 0xca, 864 | 0xc2, 0xe8, 0xd0, 0xca, 0xe4, 0xa8, 0xcc, 0xd1, 0xc9, 0xbd, 0xad, 0x95, 865 | 0x35, 0xd5, 0xb1, 0xd1, 0x31, 0x99, 0xa3, 0x93, 0x7b, 0x5b, 0x2b, 0xa3, 866 | 0x42, 0x93, 0xe3, 0x90, 0xe6, 0x46, 0xc7, 0x83, 0xae, 0x0c, 0x8f, 0x2a, 867 | 0x0f, 0xae, 0x8c, 0x04, 0x5d, 0x1e, 0x5c, 0xd9, 0x10, 0x91, 0x30, 0x1a, 868 | 0x03, 0x32, 0x9a, 0xcf, 0x0d, 0xbe, 0x37, 0x30, 0x20, 0x03, 0x32, 0x9a, 869 | 0xcf, 0x0d, 0x3e, 0x38, 0x30, 0x2e, 0x23, 0x32, 0x9a, 0xef, 0xfa, 0xe2, 870 | 0xc0, 0xc0, 0x8c, 0xc8, 0x68, 0xbe, 0xeb, 0x93, 0x03, 0x23, 0x33, 0x24, 871 | 0xa3, 0xf9, 0xc6, 0xe0, 0x9b, 0x03, 0x43, 0x33, 0x24, 0xa3, 0xf9, 0xc6, 872 | 0xe0, 0xa3, 0x03, 0x63, 0x33, 0x24, 0xa3, 0xf9, 0xc6, 0xe0, 0xab, 0x03, 873 | 0x83, 0x33, 0x1c, 0xa3, 0xf9, 0xec, 0xe0, 0xbb, 0x03, 0xa3, 0x33, 0x1c, 874 | 0xa3, 0xf9, 0xec, 0xe0, 0xc3, 0x03, 0xc3, 0x33, 0x1c, 0xa3, 0xf9, 0xec, 875 | 0xe0, 0xcb, 0x03, 0xe3, 0x33, 0x1c, 0xa3, 0xf9, 0xec, 0xe0, 0xd3, 0x03, 876 | 0x03, 0x0c, 0x0c, 0xc7, 0x68, 0xbe, 0x3d, 0xf8, 0xf8, 0xc0, 0x08, 0x03, 877 | 0xc3, 0x31, 0x9a, 0x6f, 0x0f, 0xbe, 0x3e, 0x60, 0x14, 0x96, 0x26, 0xe7, 878 | 0x12, 0x26, 0x77, 0xf6, 0x45, 0x97, 0x07, 0x57, 0xf6, 0x35, 0x97, 0xa6, 879 | 0x57, 0xc6, 0x2b, 0x2c, 0x4d, 0xce, 0x25, 0x4c, 0xee, 0xec, 0x8b, 0x2e, 880 | 0x0f, 0xae, 0xec, 0x2b, 0x8c, 0x2d, 0xed, 0xcc, 0xed, 0x6b, 0x2e, 0x4d, 881 | 0xaf, 0x8c, 0x48, 0x95, 0x5b, 0x9a, 0xd9, 0x9b, 0x5c, 0xdb, 0x1c, 0x91, 882 | 0x3a, 0xb7, 0x34, 0xb3, 0x37, 0xb9, 0xb6, 0xb9, 0x21, 0x64, 0x60, 0x58, 883 | 0x5f, 0x1a, 0x7c, 0x6a, 0x60, 0x50, 0xdf, 0x1a, 0x18, 0x8d, 0xf1, 0x7c, 884 | 0x6c, 0xf0, 0xb5, 0xc1, 0xe7, 0x07, 0xdf, 0x1f, 0x18, 0xd4, 0x07, 0x0a, 885 | 0x46, 0xf4, 0x59, 0x5f, 0x28, 0x7c, 0xdd, 0x27, 0x0a, 0x5c, 0xc2, 0xd2, 886 | 0xe4, 0x5c, 0xe8, 0xca, 0xf0, 0xe8, 0xea, 0xe4, 0xca, 0xa8, 0x84, 0xa5, 887 | 0xc9, 0xb9, 0xcc, 0x85, 0xb5, 0xc1, 0xb1, 0x95, 0x11, 0xa3, 0x2b, 0xc3, 888 | 0xa3, 0xab, 0x93, 0x2b, 0x93, 0x21, 0xe3, 0x31, 0x63, 0x7b, 0x0b, 0xa3, 889 | 0x63, 0x01, 0x99, 0x0b, 0x6b, 0x83, 0x63, 0x2b, 0xf3, 0xe1, 0x41, 0x57, 890 | 0x86, 0x47, 0x57, 0x27, 0x57, 0x36, 0x84, 0x32, 0x9c, 0x8f, 0x14, 0xbe, 891 | 0x35, 0x30, 0x1a, 0xe3, 0xf9, 0x4a, 0xe1, 0xb3, 0x3e, 0x53, 0xf8, 0xba, 892 | 0xef, 0x14, 0xb8, 0x84, 0xa5, 0xc9, 0xb9, 0xcc, 0x85, 0xb5, 0xc1, 0xb1, 893 | 0x95, 0xc9, 0xf1, 0x98, 0x0b, 0x6b, 0x83, 0x63, 0x2b, 0x93, 0x1b, 0x22, 894 | 0x19, 0x62, 0xf0, 0xa5, 0xc2, 0xb7, 0x06, 0x46, 0x63, 0x3c, 0x9f, 0xf5, 895 | 0xa9, 0xc2, 0xd7, 0x7d, 0xaa, 0x30, 0x84, 0xf9, 0xbe, 0xaf, 0x0c, 0x3e, 896 | 0x34, 0xf8, 0x46, 0xe1, 0x43, 0x85, 0x6f, 0x15, 0x86, 0x18, 0x0e, 0xf0, 897 | 0x65, 0x1f, 0x2b, 0xf0, 0x79, 0x6b, 0x73, 0x4b, 0x83, 0x7b, 0xa3, 0x2b, 898 | 0x73, 0xa3, 0x03, 0x19, 0x43, 0x0b, 0x93, 0xe3, 0x33, 0x95, 0xd6, 0x06, 899 | 0xc7, 0x56, 0x06, 0x32, 0xb4, 0xb2, 0x02, 0x42, 0x25, 0x14, 0x14, 0x34, 900 | 0x44, 0xf8, 0x5e, 0x61, 0x88, 0xf1, 0xb9, 0xc2, 0x07, 0x0b, 0x63, 0x40, 901 | 0x06, 0x43, 0x8c, 0x2f, 0x16, 0xbe, 0x58, 0x18, 0x03, 0x32, 0x60, 0xf3, 902 | 0xa5, 0x45, 0x35, 0x85, 0x53, 0xe5, 0x96, 0x66, 0xf6, 0x26, 0xd7, 0x36, 903 | 0xc7, 0xef, 0x4b, 0x8b, 0x6a, 0xca, 0xa9, 0xa6, 0xad, 0x8c, 0x2e, 0x8c, 904 | 0xcd, 0xa6, 0x2d, 0x8c, 0x4e, 0x2e, 0x0d, 0x2f, 0xc9, 0x8c, 0x29, 0x6d, 905 | 0xa6, 0x88, 0x29, 0x6d, 0xa6, 0xc8, 0xae, 0xa8, 0x68, 0x88, 0xf1, 0xd1, 906 | 0xc2, 0x17, 0x0b, 0x63, 0x40, 0x06, 0x43, 0x8c, 0xcf, 0x0e, 0xbe, 0x58, 907 | 0x18, 0x03, 0x32, 0x18, 0x62, 0x7c, 0x7b, 0xf0, 0xc5, 0xc2, 0x18, 0x90, 908 | 0xc1, 0x10, 0x3b, 0xf8, 0x66, 0xe1, 0xab, 0x85, 0x31, 0x20, 0x83, 0xaf, 909 | 0x16, 0xc6, 0x60, 0x0d, 0xbe, 0x58, 0x18, 0x03, 0x36, 0xf8, 0x62, 0x61, 910 | 0x0c, 0xda, 0xe0, 0x8b, 0x85, 0x31, 0x70, 0x83, 0x2f, 0x16, 0xc6, 0x60, 911 | 0x0c, 0xbe, 0x58, 0x18, 0x03, 0xe6, 0xb3, 0x85, 0x31, 0x28, 0x83, 0xcf, 912 | 0x16, 0xc6, 0xc0, 0x0c, 0x3e, 0x5b, 0x18, 0x83, 0x33, 0xf8, 0x6c, 0x61, 913 | 0x0c, 0xd0, 0xe0, 0xbb, 0x85, 0x31, 0x48, 0x83, 0xef, 0x16, 0xc6, 0x40, 914 | 0x0d, 0x86, 0x18, 0x1f, 0x2e, 0x7c, 0xb7, 0x30, 0x06, 0x6a, 0x30, 0xc4, 915 | 0xf8, 0x70, 0xe1, 0xbb, 0x85, 0x31, 0x48, 0x83, 0x21, 0xc6, 0x87, 0x0b, 916 | 0x9f, 0x2d, 0x8c, 0xc1, 0x19, 0x0c, 0x31, 0x3e, 0x5c, 0xf8, 0x6c, 0x61, 917 | 0x0c, 0xd0, 0x60, 0x88, 0xf1, 0xe1, 0xc2, 0x67, 0x0b, 0x63, 0x60, 0x06, 918 | 0x43, 0x8c, 0x0f, 0x17, 0x3e, 0x5b, 0x18, 0x83, 0x32, 0x18, 0x22, 0x00, 919 | 0x70, 0x30, 0x22, 0x62, 0x07, 0x76, 0xb0, 0x87, 0x76, 0x70, 0x83, 0x76, 920 | 0x78, 0x07, 0x72, 0xa8, 0x07, 0x76, 0x28, 0x07, 0x37, 0x30, 0x07, 0x76, 921 | 0x08, 0x87, 0x73, 0x98, 0x87, 0x29, 0x42, 0x30, 0x8c, 0x50, 0xd8, 0x81, 922 | 0x1d, 0xec, 0xa1, 0x1d, 0xdc, 0x20, 0x1d, 0xc8, 0xa1, 0x1c, 0xdc, 0x81, 923 | 0x1e, 0xa6, 0x04, 0xc5, 0x88, 0x25, 0x1c, 0xd2, 0x41, 0x1e, 0xdc, 0xc0, 924 | 0x1e, 0xca, 0x41, 0x1e, 0xe6, 0x21, 0x1d, 0xde, 0xc1, 0x1d, 0xa6, 0x04, 925 | 0xc6, 0x08, 0x2a, 0x1c, 0xd2, 0x41, 0x1e, 0xdc, 0x80, 0x1d, 0xc2, 0xc1, 926 | 0x1d, 0xce, 0xa1, 0x1e, 0xc2, 0xe1, 0x1c, 0xca, 0xe1, 0x17, 0xec, 0xa1, 927 | 0x1c, 0xe4, 0x61, 0x1e, 0xd2, 0xe1, 0x1d, 0xdc, 0x61, 0x4a, 0x80, 0x8c, 928 | 0x98, 0xc2, 0x21, 0x1d, 0xe4, 0xc1, 0x0d, 0xc6, 0xe1, 0x1d, 0xda, 0x01, 929 | 0x1e, 0xd2, 0x81, 0x1d, 0xca, 0xe1, 0x17, 0xde, 0x01, 0x1e, 0xe8, 0x21, 930 | 0x1d, 0xde, 0xc1, 0x1d, 0xe6, 0x61, 0x8a, 0xa1, 0x30, 0x0e, 0x24, 0x51, 931 | 0x23, 0x98, 0x70, 0x48, 0x07, 0x79, 0x70, 0x03, 0x73, 0x90, 0x87, 0x70, 932 | 0x38, 0x87, 0x76, 0x28, 0x07, 0x77, 0xa0, 0x87, 0x29, 0x41, 0x2b, 0x00, 933 | 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x33, 934 | 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 935 | 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 936 | 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 937 | 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 938 | 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 939 | 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 940 | 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 941 | 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 942 | 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 943 | 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 944 | 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 945 | 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 946 | 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 947 | 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 948 | 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 949 | 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 950 | 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 951 | 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 952 | 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 953 | 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 954 | 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 955 | 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc7, 0x69, 956 | 0x87, 0x70, 0x58, 0x87, 0x72, 0x70, 0x83, 0x74, 0x68, 0x07, 0x78, 0x60, 957 | 0x87, 0x74, 0x18, 0x87, 0x74, 0xa0, 0x87, 0x19, 0xce, 0x53, 0x0f, 0xee, 958 | 0x00, 0x0f, 0xf2, 0x50, 0x0e, 0xe4, 0x90, 0x0e, 0xe3, 0x40, 0x0f, 0xe1, 959 | 0x20, 0x0e, 0xec, 0x50, 0x0e, 0x33, 0x20, 0x28, 0x1d, 0xdc, 0xc1, 0x1e, 960 | 0xc2, 0x41, 0x1e, 0xd2, 0x21, 0x1c, 0xdc, 0x81, 0x1e, 0xdc, 0xe0, 0x1c, 961 | 0xe4, 0xe1, 0x1d, 0xea, 0x01, 0x1e, 0x66, 0x18, 0x51, 0x38, 0xb0, 0x43, 962 | 0x3a, 0x9c, 0x83, 0x3b, 0xcc, 0x50, 0x24, 0x76, 0x60, 0x07, 0x7b, 0x68, 963 | 0x07, 0x37, 0x60, 0x87, 0x77, 0x78, 0x07, 0x78, 0x98, 0x51, 0x4c, 0xf4, 964 | 0x90, 0x0f, 0xf0, 0x50, 0x0e, 0x33, 0x1e, 0x6a, 0x1e, 0xca, 0x61, 0x1c, 965 | 0xe8, 0x21, 0x1d, 0xde, 0xc1, 0x1d, 0x7e, 0x01, 0x1e, 0xe4, 0xa1, 0x1c, 966 | 0xcc, 0x21, 0x1d, 0xf0, 0x61, 0x06, 0x54, 0x85, 0x83, 0x38, 0xcc, 0xc3, 967 | 0x3b, 0xb0, 0x43, 0x3d, 0xd0, 0x43, 0x39, 0xfc, 0xc2, 0x3c, 0xe4, 0x43, 968 | 0x3b, 0x88, 0xc3, 0x3b, 0xb0, 0xc3, 0x8c, 0xc5, 0x0a, 0x87, 0x79, 0x98, 969 | 0x87, 0x77, 0x18, 0x87, 0x74, 0x08, 0x07, 0x7a, 0x28, 0x07, 0x72, 0x00, 970 | 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x76, 971 | 0x10, 0x01, 0x48, 0xe4, 0x17, 0x80, 0x34, 0xfd, 0x05, 0x83, 0x34, 0x7e, 972 | 0x71, 0xdb, 0xb6, 0x70, 0x01, 0x48, 0xe4, 0x17, 0x80, 0x34, 0xfd, 0x12, 973 | 0x30, 0x51, 0x11, 0x30, 0x11, 0x7e, 0x65, 0x17, 0xb7, 0x6d, 0x05, 0x0d, 974 | 0x80, 0x44, 0xfe, 0xe0, 0x4c, 0x7e, 0x65, 0x17, 0xb7, 0x6d, 0x01, 0x1b, 975 | 0x80, 0x44, 0xbe, 0x04, 0x30, 0xcf, 0x42, 0xfc, 0x13, 0x71, 0x4d, 0x54, 976 | 0x44, 0xfc, 0xf6, 0xe0, 0x57, 0x78, 0x71, 0xdb, 0x66, 0x30, 0x01, 0x48, 977 | 0xe4, 0x17, 0x80, 0x34, 0xfd, 0x05, 0x03, 0x5c, 0x7e, 0x65, 0x17, 0xb7, 978 | 0x6d, 0x09, 0x13, 0x80, 0x44, 0x7e, 0x01, 0x48, 0xd3, 0x5f, 0x00, 0x81, 979 | 0xe4, 0x57, 0x76, 0x71, 0xdb, 0x36, 0x50, 0x01, 0x48, 0xe4, 0x17, 0x80, 980 | 0x34, 0xfd, 0x12, 0x30, 0x51, 0x11, 0x30, 0x11, 0x7e, 0x71, 0xdb, 0x46, 981 | 0x10, 0x01, 0x48, 0xe4, 0x17, 0x80, 0x34, 0xfd, 0x12, 0x14, 0x4d, 0x7e, 982 | 0x71, 0xdb, 0x26, 0xd0, 0x00, 0x48, 0xe4, 0x33, 0xc8, 0xe5, 0x57, 0x78, 983 | 0x71, 0xdb, 0x86, 0x10, 0x01, 0x48, 0xe4, 0x17, 0x80, 0x34, 0xfd, 0x05, 984 | 0x03, 0x5c, 0x7e, 0x71, 0xdb, 0x06, 0x00, 0x15, 0x11, 0x60, 0x30, 0x44, 985 | 0x33, 0xb1, 0x07, 0x30, 0x10, 0x91, 0xa6, 0x99, 0x42, 0x04, 0x20, 0x91, 986 | 0x5f, 0x00, 0xd2, 0xf4, 0x17, 0x40, 0x20, 0xf9, 0xc5, 0x6d, 0x03, 0x61, 987 | 0x20, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x13, 0x04, 0x4e, 0x2c, 0x10, 988 | 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x94, 0x8e, 0x45, 0x00, 0x81, 989 | 0x70, 0xcc, 0x41, 0x34, 0xcf, 0x44, 0x0a, 0x23, 0x00, 0x34, 0x16, 0x41, 990 | 0x09, 0x90, 0x38, 0xd6, 0x10, 0x04, 0xc1, 0x08, 0xc0, 0x58, 0xc3, 0x30, 991 | 0x0c, 0x63, 0x0d, 0x40, 0x20, 0x10, 0x34, 0x96, 0x00, 0x04, 0x23, 0x00, 992 | 0x64, 0x94, 0x45, 0x61, 0xcc, 0x00, 0x94, 0x44, 0x51, 0x94, 0x03, 0x3d, 993 | 0x35, 0x30, 0x02, 0x40, 0xc3, 0x0c, 0x00, 0x09, 0x23, 0x00, 0x63, 0x09, 994 | 0x20, 0x08, 0x82, 0xf0, 0x07, 0x82, 0x20, 0x08, 0x7f, 0x33, 0x00, 0x14, 995 | 0x8c, 0x00, 0xcc, 0x00, 0x10, 0x30, 0x46, 0x00, 0x82, 0x20, 0x08, 0x7f, 996 | 0x63, 0x04, 0x20, 0x08, 0x82, 0xf8, 0x2f, 0x8c, 0x11, 0x80, 0x20, 0x08, 997 | 0x82, 0x60, 0x30, 0x46, 0x00, 0x82, 0x20, 0x88, 0x7f, 0x23, 0x00, 0x00, 998 | 0x00, 0x00, 0x00, 0x17, 0x06, 0xe1, 0x52, 0x50, 0x06, 0x19, 0x02, 0x04, 999 | 0x1b, 0x64, 0x30, 0x83, 0x65, 0x33, 0x21, 0x90, 0xcf, 0x78, 0x85, 0x19, 1000 | 0xd8, 0x41, 0x2b, 0xb4, 0xc2, 0x77, 0x41, 0xb8, 0x14, 0x94, 0x41, 0x86, 1001 | 0xc0, 0xf1, 0x06, 0x19, 0xd8, 0x20, 0x12, 0x03, 0x13, 0x02, 0xf9, 0x58, 1002 | 0x70, 0xc0, 0x67, 0xbc, 0xa2, 0x0d, 0xfa, 0x80, 0x16, 0x68, 0xe1, 0x0c, 1003 | 0x2e, 0x08, 0x97, 0x82, 0x32, 0xc8, 0x10, 0x54, 0x65, 0x60, 0x45, 0x00, 1004 | 0x9f, 0x41, 0x86, 0x80, 0x33, 0x83, 0x11, 0x03, 0x62, 0x08, 0x7c, 0x21, 1005 | 0x18, 0x6f, 0xa0, 0x03, 0x52, 0xd0, 0x05, 0x0a, 0x8a, 0x0d, 0x41, 0x7c, 1006 | 0xc6, 0x1b, 0xee, 0xe0, 0x14, 0x52, 0x81, 0x02, 0x62, 0x43, 0x20, 0x1f, 1007 | 0x13, 0x83, 0x20, 0x3e, 0x23, 0x06, 0xc4, 0x10, 0x90, 0x43, 0x30, 0x86, 1008 | 0x10, 0x8c, 0xc3, 0x18, 0x82, 0x20, 0x0e, 0x26, 0x04, 0xf2, 0x19, 0x6e, 1009 | 0x08, 0xbe, 0x60, 0x96, 0xa1, 0x09, 0x82, 0xf1, 0x06, 0x50, 0x80, 0x85, 1010 | 0x38, 0xa0, 0x60, 0x0c, 0x37, 0x04, 0xe3, 0x00, 0x06, 0xb3, 0x0c, 0x82, 1011 | 0x11, 0x8c, 0x18, 0x28, 0x42, 0x60, 0x0f, 0xa2, 0x10, 0x0a, 0xa4, 0xf0, 1012 | 0x06, 0x76, 0xe0, 0x06, 0x63, 0x30, 0xde, 0x40, 0x0a, 0xb4, 0x60, 0x07, 1013 | 0x14, 0x90, 0x61, 0x0e, 0x23, 0x28, 0x9e, 0x61, 0x22, 0x06, 0x19, 0x86, 1014 | 0x35, 0xd8, 0x83, 0x41, 0x06, 0x82, 0x0d, 0xfa, 0xc0, 0x84, 0x40, 0x3e, 1015 | 0x83, 0x0c, 0xc1, 0x1c, 0x94, 0xc2, 0x20, 0x43, 0x70, 0x9c, 0xc2, 0x2c, 1016 | 0x41, 0x31, 0xc8, 0x80, 0xc0, 0x81, 0x29, 0xcc, 0x12, 0x14, 0x03, 0x1d, 1017 | 0x01, 0x31, 0x08, 0x84, 0x24, 0xcc, 0x31, 0xc8, 0xc1, 0x43, 0x0f, 0x83, 1018 | 0x0c, 0xc1, 0x1c, 0xa4, 0x82, 0x0d, 0x81, 0x7c, 0xc6, 0x1b, 0x60, 0x01, 1019 | 0x1c, 0xe2, 0x81, 0x82, 0x62, 0x43, 0x20, 0x9f, 0x59, 0x82, 0x66, 0x0c, 1020 | 0x81, 0x16, 0xf4, 0xc1, 0x02, 0x3b, 0x90, 0x8f, 0x05, 0x78, 0x00, 0x9f, 1021 | 0x11, 0x03, 0x62, 0x08, 0x40, 0x22, 0x30, 0x3c, 0x08, 0xe2, 0x33, 0xde, 1022 | 0x80, 0x0b, 0xe8, 0x70, 0x0a, 0x14, 0x14, 0x1b, 0x02, 0xf9, 0x8c, 0x18, 1023 | 0x14, 0x43, 0x80, 0x12, 0x7c, 0x10, 0x8c, 0x21, 0xf4, 0x42, 0x48, 0x8c, 1024 | 0x18, 0x14, 0x43, 0xa0, 0x12, 0x7e, 0x10, 0x58, 0x30, 0xc8, 0x67, 0xbc, 1025 | 0xe1, 0x17, 0xde, 0xa1, 0x15, 0x28, 0x18, 0xc3, 0x0d, 0x43, 0x40, 0xcc, 1026 | 0x32, 0x34, 0x47, 0x30, 0xdc, 0x10, 0x06, 0x29, 0x01, 0x06, 0xe3, 0x0d, 1027 | 0xe3, 0x30, 0x0f, 0x28, 0x71, 0x41, 0xb8, 0x14, 0x94, 0x41, 0x86, 0x60, 1028 | 0x15, 0x76, 0xc1, 0x82, 0x51, 0x90, 0xcf, 0x78, 0x05, 0x3a, 0xe0, 0x43, 1029 | 0x4b, 0xbc, 0x44, 0x38, 0x5c, 0x10, 0x2e, 0x05, 0x65, 0x90, 0x21, 0x80, 1030 | 0x05, 0x70, 0xb0, 0x40, 0x14, 0xe4, 0x63, 0x81, 0x01, 0x9f, 0xf1, 0x0a, 1031 | 0x77, 0xf0, 0x87, 0x99, 0xa8, 0x09, 0x74, 0xb8, 0x20, 0x5c, 0x0a, 0xca, 1032 | 0x20, 0x43, 0x60, 0x0b, 0xe6, 0x60, 0x45, 0x00, 0x9f, 0x41, 0x86, 0xa0, 1033 | 0x17, 0xce, 0x61, 0x96, 0x01, 0x49, 0xa4, 0xf1, 0x06, 0x7a, 0x20, 0x09, 1034 | 0x9b, 0xa0, 0x60, 0x58, 0xa0, 0x0b, 0xf2, 0x19, 0x6f, 0xb8, 0x87, 0x93, 1035 | 0xb0, 0x09, 0x0a, 0xca, 0x78, 0x43, 0x3e, 0xa4, 0x84, 0x39, 0x50, 0x40, 1036 | 0xe6, 0x18, 0xc4, 0x21, 0x10, 0x8b, 0x41, 0x86, 0x60, 0x1c, 0xde, 0xc1, 1037 | 0x8a, 0x20, 0x3e, 0x23, 0x06, 0xc4, 0x10, 0xa4, 0xc5, 0x62, 0x81, 0x10, 1038 | 0x9f, 0x31, 0x84, 0xe0, 0x2c, 0xc6, 0x10, 0x04, 0xb3, 0x18, 0x31, 0x28, 1039 | 0x86, 0xc0, 0x2d, 0x84, 0x60, 0xc4, 0xa0, 0x18, 0x02, 0xb8, 0x08, 0xc6, 1040 | 0x61, 0xc4, 0xa0, 0x18, 0x02, 0xb9, 0x28, 0xda, 0x61, 0xc4, 0xa0, 0x18, 1041 | 0x02, 0xba, 0x08, 0x82, 0x11, 0x03, 0x62, 0x08, 0xec, 0x22, 0xb0, 0xa8, 1042 | 0x89, 0x8f, 0x05, 0x05, 0x7c, 0x2c, 0x18, 0xe0, 0x63, 0x41, 0x45, 0x9f, 1043 | 0x11, 0x03, 0x62, 0x08, 0xf8, 0x22, 0x18, 0x6f, 0x60, 0x09, 0x9e, 0x68, 1044 | 0x0b, 0x0a, 0xca, 0x78, 0x83, 0x4b, 0xf8, 0x04, 0x5b, 0x50, 0x50, 0xe6, 1045 | 0x18, 0xea, 0xa1, 0xb8, 0x8b, 0x41, 0x86, 0xc0, 0x1e, 0x58, 0x62, 0xc4, 1046 | 0xc0, 0x18, 0x02, 0xd2, 0x28, 0x86, 0x60, 0x8e, 0x01, 0x1f, 0x6a, 0x41, 1047 | 0x2f, 0xe6, 0x18, 0xf2, 0xc1, 0x0e, 0xf6, 0xc2, 0x02, 0x41, 0x3e, 0x83, 1048 | 0x0c, 0xc1, 0x3e, 0xc4, 0x84, 0x05, 0x85, 0x7c, 0x66, 0x09, 0x9a, 0xf1, 1049 | 0x06, 0x9c, 0x40, 0x8b, 0xbb, 0xa0, 0xa0, 0xd8, 0x19, 0x04, 0xf4, 0x19, 1050 | 0x31, 0x50, 0x84, 0xc0, 0x35, 0x74, 0x22, 0x27, 0x82, 0x93, 0x70, 0x09, 1051 | 0x93, 0xd8, 0x87, 0xf1, 0x06, 0x9e, 0x60, 0x0b, 0x97, 0xa0, 0x80, 0x0c, 1052 | 0x73, 0x18, 0x01, 0xf3, 0x28, 0xd3, 0x32, 0xc8, 0x30, 0x8c, 0xc4, 0x4c, 1053 | 0x0c, 0x32, 0x10, 0x24, 0x51, 0x13, 0x26, 0x04, 0xf2, 0x19, 0x64, 0x08, 1054 | 0x56, 0xa2, 0x27, 0x06, 0x19, 0x82, 0xe3, 0x27, 0x66, 0x09, 0x98, 0x41, 1055 | 0x06, 0x04, 0x25, 0x7c, 0x62, 0x96, 0x80, 0x19, 0xe8, 0x08, 0x08, 0x45, 1056 | 0x58, 0xa4, 0x64, 0x8e, 0x41, 0x25, 0xce, 0x81, 0x35, 0xe6, 0x18, 0x56, 1057 | 0x02, 0x15, 0x5a, 0x63, 0xbc, 0xe1, 0x2c, 0xee, 0x02, 0x35, 0x28, 0x28, 1058 | 0x36, 0x10, 0xf2, 0x19, 0x64, 0x08, 0x5e, 0xa2, 0x2c, 0x2c, 0x38, 0xe4, 1059 | 0x63, 0x01, 0x21, 0x9f, 0x59, 0x82, 0x66, 0xa0, 0x25, 0xb0, 0x8b, 0xc2, 1060 | 0x4c, 0x00, 0x36, 0x40, 0x04, 0xc6, 0x4c, 0x8c, 0x0c, 0x02, 0x62, 0x00, 1061 | 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x5b, 0x06, 0x2a, 0x90, 0x85, 1062 | 0x2d, 0xc3, 0x15, 0xc8, 0xc2, 0x96, 0x21, 0x0c, 0x82, 0x5c, 0xd8, 0x32, 1063 | 0x98, 0x41, 0xa0, 0x0b, 0x5b, 0x86, 0x3a, 0x08, 0x64, 0x61, 0xcb, 0xe0, 1064 | 0x07, 0xc1, 0x2e, 0x6c, 0x19, 0x4a, 0x21, 0xe0, 0x85, 0x2d, 0x03, 0x2f, 1065 | 0x04, 0xbd, 0xb0, 0x65, 0xf8, 0x85, 0x40, 0x16, 0xb6, 0x0c, 0xe1, 0x10, 1066 | 0xf8, 0xc2, 0x96, 0x21, 0x1e, 0x86, 0x5f, 0xd8, 0x32, 0xd0, 0x43, 0x20, 1067 | 0x0b, 0x5b, 0x06, 0x7b, 0x08, 0x64, 0x61, 0xcb, 0x10, 0x12, 0x81, 0x2c, 1068 | 0x6c, 0x19, 0x44, 0x62, 0xf8, 0x85, 0x2d, 0x43, 0x49, 0x04, 0xba, 0xb0, 1069 | 0x65, 0x98, 0x89, 0x40, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1070 | 0x00, 0x00, 0x00 1071 | }; 1072 | unsigned int mnvg_bitcode_ios_len = 12819; 1073 | -------------------------------------------------------------------------------- /src/nanovg_mtl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Ollix 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | // --- 22 | // Author: olliwang@ollix.com (Olli Wang) 23 | 24 | #ifndef NANOVG_MTL_H_ 25 | #define NANOVG_MTL_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include "nanovg.h" 32 | 33 | // Create flags 34 | enum NVGcreateFlags { 35 | // Flag indicating if geometry based anti-aliasing is used (may not be 36 | // needed when using MSAA). 37 | NVG_ANTIALIAS = 1 << 0, 38 | // Flag indicating if strokes should be drawn using stencil buffer. 39 | // The rendering will be a little slower, but path overlaps 40 | // (i.e. self-intersecting or sharp turns) will be drawn just once. 41 | NVG_STENCIL_STROKES = 1 << 1, 42 | // Flag indicating if double buffering scheme is used. 43 | NVG_DOUBLE_BUFFER = 1 << 12, 44 | // Flag indicating if triple buffering scheme is used. 45 | NVG_TRIPLE_BUFFER = 1 << 13, 46 | // Flag indicating that additional debug checks are done. 47 | NVG_DEBUG = 1 << 2, 48 | }; 49 | 50 | // These are additional flags on top of NVGimageFlags. 51 | enum NVGimageFlagsMetal { 52 | NVG_IMAGE_NODELETE = 1 << 16, // Do not delete Metal texture handle. 53 | }; 54 | 55 | // The possible OS targets. 56 | enum MNVGTarget { 57 | MNVG_IOS, 58 | MNVG_MACOS, 59 | MNVG_SIMULATOR, 60 | MNVG_TVOS, 61 | MNVG_UNKNOWN, 62 | }; 63 | 64 | struct MNVGframebuffer { 65 | NVGcontext* ctx; 66 | int image; 67 | }; 68 | typedef struct MNVGframebuffer MNVGframebuffer; 69 | 70 | // Creates a new NanoVG context. The `metalLayer` parameter should be a 71 | // `CAMetalLayer` object, and the `flags` should be combination of 72 | // `NVGcreateFlags` above. 73 | NVGcontext* nvgCreateMTL(void* metalLayer, int flags); 74 | 75 | // Deletes the specified NanoVG context. 76 | void nvgDeleteMTL(NVGcontext* ctx); 77 | 78 | // 79 | // Framebuffer 80 | // 81 | 82 | // Binds the specified framebuffer as the current render pass. 83 | void mnvgBindFramebuffer(MNVGframebuffer* framebuffer); 84 | 85 | // Creates a new framebuffer. 86 | MNVGframebuffer* mnvgCreateFramebuffer(NVGcontext* ctx, int width, 87 | int height, int imageFlags); 88 | 89 | // Deletes the specified framebuffer. 90 | void mnvgDeleteFramebuffer(MNVGframebuffer* framebuffer); 91 | 92 | // 93 | // Metal bridging functions 94 | // 95 | 96 | // Clear context on next frame, must be called before nvgEndFrame 97 | void mnvgClearWithColor(NVGcontext* ctx, NVGcolor color); 98 | 99 | // Returns a pointer to the corresponded `id` object. 100 | void* mnvgCommandQueue(NVGcontext* ctx); 101 | 102 | // Creates an image id from a `id` object pointer. 103 | int mnvgCreateImageFromHandle(NVGcontext* ctx, void* textureId, int imageFlags); 104 | 105 | // Returns a pointer to the corresponded `id` object. 106 | void* mnvgDevice(NVGcontext* ctx); 107 | 108 | // Returns a pointer to the `id` object of the specified image. 109 | void* mnvgImageHandle(NVGcontext* ctx, int image); 110 | 111 | // Copies the pixels from the specified image into the specified `data`. 112 | void mnvgReadPixels(NVGcontext* ctx, int image, int x, int y, int width, 113 | int height, void* data); 114 | 115 | // Returns the current OS target. 116 | enum MNVGTarget mnvgTarget(); 117 | 118 | #ifdef __cplusplus 119 | } 120 | #endif 121 | 122 | #endif // NANOVG_MTL_H_ 123 | -------------------------------------------------------------------------------- /src/nanovg_mtl.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Ollix 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | // --- 22 | // Author: olliwang@ollix.com (Olli Wang) 23 | 24 | #include "nanovg_mtl.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #import 33 | #import 34 | #import 35 | #include 36 | 37 | #include "nanovg.h" 38 | 39 | #if TARGET_OS_SIMULATOR 40 | # include "mnvg_bitcode/simulator.h" 41 | #elif TARGET_OS_IOS 42 | # include "mnvg_bitcode/ios.h" 43 | #elif TARGET_OS_OSX 44 | # include "mnvg_bitcode/macos.h" 45 | #elif TARGET_OS_TV 46 | # include "mnvg_bitcode/tvos.h" 47 | #else 48 | # define MNVG_INVALID_TARGET 49 | #endif 50 | 51 | typedef enum MNVGvertexInputIndex { 52 | MNVG_VERTEX_INPUT_INDEX_VERTICES = 0, 53 | MNVG_VERTEX_INPUT_INDEX_VIEW_SIZE = 1, 54 | } MNVGvertexInputIndex; 55 | 56 | typedef enum MNVGshaderType { 57 | MNVG_SHADER_FILLGRAD, 58 | MNVG_SHADER_FILLIMG, 59 | MNVG_SHADER_IMG, 60 | } MNVGshaderType; 61 | 62 | enum MNVGcallType { 63 | MNVG_NONE = 0, 64 | MNVG_FILL, 65 | MNVG_CONVEXFILL, 66 | MNVG_STROKE, 67 | MNVG_TRIANGLES, 68 | }; 69 | 70 | struct MNVGblend { 71 | MTLBlendFactor srcRGB; 72 | MTLBlendFactor dstRGB; 73 | MTLBlendFactor srcAlpha; 74 | MTLBlendFactor dstAlpha; 75 | }; 76 | typedef struct MNVGblend MNVGblend; 77 | 78 | struct MNVGcall { 79 | int type; 80 | int image; 81 | int pathOffset; 82 | int pathCount; 83 | int triangleOffset; 84 | int triangleCount; 85 | int indexOffset; 86 | int indexCount; 87 | int strokeOffset; 88 | int strokeCount; 89 | int uniformOffset; 90 | MNVGblend blendFunc; 91 | }; 92 | typedef struct MNVGcall MNVGcall; 93 | 94 | struct MNVGfragUniforms { 95 | matrix_float3x3 scissorMat; 96 | matrix_float3x3 paintMat; 97 | vector_float4 innerCol; 98 | vector_float4 outerCol; 99 | vector_float2 scissorExt; 100 | vector_float2 scissorScale; 101 | vector_float2 extent; 102 | float radius; 103 | float feather; 104 | float strokeMult; 105 | float strokeThr; 106 | int texType; 107 | MNVGshaderType type; 108 | }; 109 | typedef struct MNVGfragUniforms MNVGfragUniforms; 110 | 111 | @interface MNVGtexture : NSObject { 112 | @public 113 | int id; 114 | int type; 115 | int flags; 116 | id tex; 117 | id sampler; 118 | } 119 | @end 120 | 121 | @interface MNVGbuffers : NSObject 122 | 123 | @property (nonatomic, strong) id commandBuffer; 124 | @property (nonatomic, assign) BOOL isBusy; 125 | @property (nonatomic, assign) int image; 126 | @property (nonatomic, strong) id viewSizeBuffer; 127 | @property (nonatomic, strong) id stencilTexture; 128 | @property (nonatomic, assign) MNVGcall* calls; 129 | @property (nonatomic, assign) int ccalls; 130 | @property (nonatomic, assign) int ncalls; 131 | @property (nonatomic, strong) id indexBuffer; 132 | @property (nonatomic, assign) uint32_t* indexes; 133 | @property (nonatomic, assign) int cindexes; 134 | @property (nonatomic, assign) int nindexes; 135 | @property (nonatomic, strong) id vertBuffer; 136 | @property (nonatomic, assign) struct NVGvertex* verts; 137 | @property (nonatomic, assign) int cverts; 138 | @property (nonatomic, assign) int nverts; 139 | @property (nonatomic, strong) id uniformBuffer; 140 | @property (nonatomic, assign) unsigned char* uniforms; 141 | @property (nonatomic, assign) int cuniforms; 142 | @property (nonatomic, assign) int nuniforms; 143 | 144 | @end 145 | 146 | @interface MNVGcontext : NSObject 147 | 148 | @property (nonatomic, strong) id commandQueue; 149 | @property (nonatomic, strong) CAMetalLayer* metalLayer; 150 | @property (nonatomic, strong) id renderEncoder; 151 | 152 | @property (nonatomic, assign) int fragSize; 153 | @property (nonatomic, assign) int indexSize; 154 | @property (nonatomic, assign) int flags; 155 | @property (nonatomic, assign) vector_uint2 viewPortSize; 156 | @property (nonatomic, assign) MTLClearColor clearColor; 157 | @property (nonatomic, assign) BOOL clearBufferOnFlush; 158 | 159 | // Textures 160 | @property (nonatomic, strong) NSMutableArray* textures; 161 | @property int textureId; 162 | 163 | // Per frame buffers 164 | @property (nonatomic, assign) MNVGbuffers* buffers; 165 | @property (nonatomic, strong) NSMutableArray* cbuffers; 166 | @property (nonatomic, assign) int maxBuffers; 167 | @property (nonatomic, strong) dispatch_semaphore_t semaphore; 168 | 169 | // Cached states. 170 | @property (nonatomic, assign) MNVGblend* blendFunc; 171 | @property (nonatomic, strong) id defaultStencilState; 172 | @property (nonatomic, strong) id fillShapeStencilState; 173 | @property (nonatomic, strong) id 174 | fillAntiAliasStencilState; 175 | @property (nonatomic, strong) id fillStencilState; 176 | @property (nonatomic, strong) id strokeShapeStencilState; 177 | @property (nonatomic, strong) id 178 | strokeAntiAliasStencilState; 179 | @property (nonatomic, strong) id strokeClearStencilState; 180 | @property (nonatomic, strong) id fragmentFunction; 181 | @property (nonatomic, strong) id vertexFunction; 182 | @property MTLPixelFormat piplelinePixelFormat; 183 | @property (nonatomic, strong) id pipelineState; 184 | @property (nonatomic, strong) id 185 | stencilOnlyPipelineState; 186 | @property (nonatomic, strong) id pseudoSampler; 187 | @property (nonatomic, strong) id pseudoTexture; 188 | @property (nonatomic, strong) MTLVertexDescriptor* vertexDescriptor; 189 | 190 | - (MNVGtexture*)allocTexture; 191 | 192 | - (void)convexFill:(MNVGcall*)call; 193 | 194 | -(void)fill:(MNVGcall*)call; 195 | 196 | - (MNVGtexture*)findTexture:(int)id; 197 | 198 | - (void)renderCancel; 199 | 200 | - (int)renderCreate; 201 | 202 | - (void)renderDelete; 203 | 204 | - (int)renderDeleteTexture:(int)image; 205 | 206 | - (int)renderCreateTextureWithType:(int)type 207 | width:(int)width 208 | height:(int)height 209 | imageFlags:(int)imageFlags 210 | data:(const unsigned char*)data; 211 | 212 | - (void)renderFillWithPaint:(NVGpaint*)paint 213 | compositeOperation:(NVGcompositeOperationState)compositeOperation 214 | scissor:(NVGscissor*)scissor 215 | fringe:(float)fringe 216 | bounds:(const float*)bounds 217 | paths:(const NVGpath*)paths 218 | npaths:(int)npaths; 219 | 220 | - (void)renderFlush; 221 | 222 | - (int)renderGetTextureSizeForImage:(int)image 223 | width:(int*)width 224 | height:(int*)height; 225 | 226 | - (void)renderStrokeWithPaint:(NVGpaint*)paint 227 | compositeOperation:(NVGcompositeOperationState)compositeOperation 228 | scissor:(NVGscissor*)scissor 229 | fringe:(float)fringe 230 | strokeWidth:(float)strokeWidth 231 | paths:(const NVGpath*)paths 232 | npaths:(int)npaths; 233 | 234 | - (void)renderTrianglesWithPaint:(NVGpaint*) paint 235 | compositeOperation:(NVGcompositeOperationState)compositeOperation 236 | scissor:(NVGscissor*)scissor 237 | verts:(const NVGvertex*)verts 238 | nverts:(int)nverts 239 | fringe:(float)fringe; 240 | 241 | - (int)renderUpdateTextureWithImage:(int)image 242 | x:(int)x 243 | y:(int)y 244 | width:(int)width 245 | height:(int)height 246 | data:(const unsigned char*)data; 247 | 248 | - (void)renderViewportWithWidth:(float)width 249 | height:(float)height 250 | devicePixelRatio:(float)devicePixelRatio; 251 | 252 | - (void)stroke:(MNVGcall*)call; 253 | 254 | - (void)triangles:(MNVGcall*)call; 255 | 256 | - (void)updateRenderPipelineStatesForBlend:(MNVGblend*)blend 257 | pixelFormat:(MTLPixelFormat)pixelFormat; 258 | 259 | @end 260 | 261 | // Keeps the weak reference to the currently binded framebuffer. 262 | MNVGframebuffer* s_framebuffer = NULL; 263 | 264 | const MTLResourceOptions kMetalBufferOptions = \ 265 | (MTLResourceCPUCacheModeWriteCombined | MTLResourceStorageModeShared); 266 | 267 | #if TARGET_OS_SIMULATOR 268 | const MTLPixelFormat kStencilFormat = MTLPixelFormatDepth32Float_Stencil8; 269 | #else 270 | const MTLPixelFormat kStencilFormat = MTLPixelFormatStencil8; 271 | #endif // TARGET_OS_SIMULATOR 272 | 273 | static BOOL mtlnvg_convertBlendFuncFactor(int factor, MTLBlendFactor* result) { 274 | if (factor == NVG_ZERO) 275 | *result = MTLBlendFactorZero; 276 | else if (factor == NVG_ONE) 277 | *result = MTLBlendFactorOne; 278 | else if (factor == NVG_SRC_COLOR) 279 | *result = MTLBlendFactorSourceColor; 280 | else if (factor == NVG_ONE_MINUS_SRC_COLOR) 281 | *result = MTLBlendFactorOneMinusSourceColor; 282 | else if (factor == NVG_DST_COLOR) 283 | *result = MTLBlendFactorDestinationColor; 284 | else if (factor == NVG_ONE_MINUS_DST_COLOR) 285 | *result = MTLBlendFactorOneMinusDestinationColor; 286 | else if (factor == NVG_SRC_ALPHA) 287 | *result = MTLBlendFactorSourceAlpha; 288 | else if (factor == NVG_ONE_MINUS_SRC_ALPHA) 289 | *result = MTLBlendFactorOneMinusSourceAlpha; 290 | else if (factor == NVG_DST_ALPHA) 291 | *result = MTLBlendFactorDestinationAlpha; 292 | else if (factor == NVG_ONE_MINUS_DST_ALPHA) 293 | *result = MTLBlendFactorOneMinusDestinationAlpha; 294 | else if (factor == NVG_SRC_ALPHA_SATURATE) 295 | *result = MTLBlendFactorSourceAlphaSaturated; 296 | else 297 | return NO; 298 | return YES; 299 | } 300 | 301 | static int mtlnvg__maxi(int a, int b) { return a > b ? a : b; } 302 | 303 | static int mtlnvg__maxVertCount(const NVGpath* paths, int npaths, 304 | int* indexCount, int* strokeCount) { 305 | int count = 0; 306 | if (indexCount != NULL) *indexCount = 0; 307 | if (strokeCount != NULL) *strokeCount = 0; 308 | NVGpath* path = (NVGpath*)&paths[0]; 309 | for (int i = npaths; i--; ++path) { 310 | const int nfill = path->nfill; 311 | if (nfill > 2) { 312 | count += nfill; 313 | if (indexCount != NULL) 314 | *indexCount += (nfill - 2) * 3; 315 | } 316 | if (path->nstroke > 0) { 317 | const int nstroke = path->nstroke + 2; 318 | count += nstroke; 319 | if (strokeCount != NULL) *strokeCount += nstroke; 320 | } 321 | } 322 | return count; 323 | } 324 | 325 | static vector_float4 mtlnvg__premulColor(NVGcolor c) { 326 | c.r *= c.a; 327 | c.g *= c.a; 328 | c.b *= c.a; 329 | return (vector_float4){c.r, c.g, c.b, c.a}; 330 | } 331 | 332 | static void mtlnvg__renderCancel(void* uptr) { 333 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 334 | [mtl renderCancel]; 335 | } 336 | 337 | static int mtlnvg__renderCreateTexture(void* uptr, int type, int width, 338 | int height, int imageFlags, 339 | const unsigned char* data) { 340 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 341 | return [mtl renderCreateTextureWithType:type 342 | width:width 343 | height:height 344 | imageFlags:imageFlags 345 | data:data]; 346 | } 347 | 348 | static int mtlnvg__renderCreate(void* uptr) { 349 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 350 | return [mtl renderCreate]; 351 | } 352 | 353 | static void mtlnvg__renderDelete(void* uptr) { 354 | MNVGcontext* mtl = (__bridge_transfer MNVGcontext*)uptr; 355 | [mtl renderDelete]; 356 | } 357 | 358 | static int mtlnvg__renderDeleteTexture(void* uptr, int image) { 359 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 360 | return [mtl renderDeleteTexture:image]; 361 | } 362 | 363 | static void mtlnvg__renderFill(void* uptr, NVGpaint* paint, 364 | NVGcompositeOperationState compositeOperation, 365 | NVGscissor* scissor, float fringe, 366 | const float* bounds, const NVGpath* paths, 367 | int npaths) { 368 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 369 | [mtl renderFillWithPaint:paint 370 | compositeOperation:compositeOperation 371 | scissor:scissor 372 | fringe:fringe 373 | bounds:bounds 374 | paths:paths 375 | npaths:npaths]; 376 | } 377 | 378 | static void mtlnvg__renderFlush(void* uptr) { 379 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 380 | [mtl renderFlush]; 381 | } 382 | 383 | static int mtlnvg__renderGetTextureSize(void* uptr, int image, int* w, int* h) { 384 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 385 | return [mtl renderGetTextureSizeForImage:image width:w height:h]; 386 | } 387 | 388 | static void mtlnvg__renderStroke(void* uptr, NVGpaint* paint, 389 | NVGcompositeOperationState compositeOperation, 390 | NVGscissor* scissor, float fringe, 391 | float strokeWidth, const NVGpath* paths, 392 | int npaths) { 393 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 394 | [mtl renderStrokeWithPaint:paint 395 | compositeOperation:compositeOperation 396 | scissor:scissor 397 | fringe:fringe 398 | strokeWidth:strokeWidth 399 | paths:paths 400 | npaths:npaths]; 401 | } 402 | 403 | static void mtlnvg__renderTriangles( 404 | void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, 405 | NVGscissor* scissor, const NVGvertex* verts, int nverts, float fringe) { 406 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 407 | [mtl renderTrianglesWithPaint:paint 408 | compositeOperation:compositeOperation 409 | scissor:scissor 410 | verts:verts 411 | nverts:nverts 412 | fringe:fringe]; 413 | } 414 | 415 | static int mtlnvg__renderUpdateTexture(void* uptr, int image, int x, int y, 416 | int w, int h, 417 | const unsigned char* data) { 418 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 419 | return [mtl renderUpdateTextureWithImage:image 420 | x:x 421 | y:y 422 | width:w 423 | height:h 424 | data:data]; 425 | } 426 | 427 | static void mtlnvg__renderViewport(void* uptr, float width, float height, 428 | float devicePixelRatio) { 429 | MNVGcontext* mtl = (__bridge MNVGcontext*)uptr; 430 | [mtl renderViewportWithWidth:width 431 | height:height 432 | devicePixelRatio:devicePixelRatio]; 433 | } 434 | 435 | static void mtlnvg__xformToMat3x3(matrix_float3x3* m3, float* t) { 436 | *m3 = matrix_from_columns((vector_float3){t[0], t[1], 0.0f}, 437 | (vector_float3){t[2], t[3], 0.0f}, 438 | (vector_float3){t[4], t[5], 1.0f}); 439 | } 440 | 441 | NVGcontext* nvgCreateMTL(void* metalLayer, int flags) { 442 | #ifdef MNVG_INVALID_TARGET 443 | printf("Metal is only supported on iOS, macOS, and tvOS.\n"); 444 | return NULL; 445 | #endif // MNVG_INVALID_TARGET 446 | 447 | NVGparams params; 448 | NVGcontext* ctx = NULL; 449 | MNVGcontext* mtl = [MNVGcontext new]; 450 | 451 | memset(¶ms, 0, sizeof(params)); 452 | params.renderCreate = mtlnvg__renderCreate; 453 | params.renderCreateTexture = mtlnvg__renderCreateTexture; 454 | params.renderDeleteTexture = mtlnvg__renderDeleteTexture; 455 | params.renderUpdateTexture = mtlnvg__renderUpdateTexture; 456 | params.renderGetTextureSize = mtlnvg__renderGetTextureSize; 457 | params.renderViewport = mtlnvg__renderViewport; 458 | params.renderCancel = mtlnvg__renderCancel; 459 | params.renderFlush = mtlnvg__renderFlush; 460 | params.renderFill = mtlnvg__renderFill; 461 | params.renderStroke = mtlnvg__renderStroke; 462 | params.renderTriangles = mtlnvg__renderTriangles; 463 | params.renderDelete = mtlnvg__renderDelete; 464 | params.userPtr = (__bridge_retained void*)mtl; 465 | params.edgeAntiAlias = flags & NVG_ANTIALIAS ? 1 : 0; 466 | 467 | mtl.flags = flags; 468 | #if TARGET_OS_OSX || TARGET_OS_SIMULATOR 469 | mtl.fragSize = 256; 470 | #else 471 | mtl.fragSize = sizeof(MNVGfragUniforms); 472 | #endif // TARGET_OS_OSX 473 | mtl.indexSize = 4; // MTLIndexTypeUInt32 474 | mtl.metalLayer = (__bridge CAMetalLayer*)metalLayer; 475 | 476 | ctx = nvgCreateInternal(¶ms); 477 | if (ctx == NULL) goto error; 478 | return ctx; 479 | 480 | error: 481 | // 'mtl' is freed by nvgDeleteInternal. 482 | if (ctx != NULL) nvgDeleteInternal(ctx); 483 | return NULL; 484 | } 485 | 486 | static void mtlnvg__vset(NVGvertex* vtx, float x, float y, float u, float v) { 487 | vtx->x = x; 488 | vtx->y = y; 489 | vtx->u = u; 490 | vtx->v = v; 491 | } 492 | 493 | void nvgDeleteMTL(NVGcontext* ctx) { 494 | nvgDeleteInternal(ctx); 495 | } 496 | 497 | void mnvgBindFramebuffer(MNVGframebuffer* framebuffer) { 498 | s_framebuffer = framebuffer; 499 | } 500 | 501 | MNVGframebuffer* mnvgCreateFramebuffer(NVGcontext* ctx, int width, 502 | int height, int imageFlags) { 503 | MNVGframebuffer* framebuffer = \ 504 | (MNVGframebuffer*)malloc(sizeof(MNVGframebuffer)); 505 | if (framebuffer == NULL) 506 | return NULL; 507 | 508 | memset(framebuffer, 0, sizeof(MNVGframebuffer)); 509 | framebuffer->image = nvgCreateImageRGBA(ctx, width, height, 510 | imageFlags | NVG_IMAGE_PREMULTIPLIED, 511 | NULL); 512 | framebuffer->ctx = ctx; 513 | return framebuffer; 514 | } 515 | 516 | void mnvgDeleteFramebuffer(MNVGframebuffer* framebuffer) { 517 | if (framebuffer == NULL) return; 518 | if (framebuffer->image > 0) { 519 | nvgDeleteImage(framebuffer->ctx, framebuffer->image); 520 | } 521 | free(framebuffer); 522 | } 523 | 524 | void mnvgClearWithColor(NVGcontext* ctx, NVGcolor color) { 525 | MNVGcontext* mtl = (__bridge MNVGcontext*)nvgInternalParams(ctx)->userPtr; 526 | float alpha = (float)color.a; 527 | mtl.clearColor = MTLClearColorMake((float)color.r * alpha, 528 | (float)color.g * alpha, 529 | (float)color.b * alpha, 530 | (float)color.a); 531 | mtl.clearBufferOnFlush = YES; 532 | } 533 | 534 | void* mnvgCommandQueue(NVGcontext* ctx) { 535 | MNVGcontext* mtl = (__bridge MNVGcontext*)nvgInternalParams(ctx)->userPtr; 536 | return (__bridge void*)mtl.commandQueue; 537 | } 538 | 539 | int mnvgCreateImageFromHandle(NVGcontext* ctx, void* textureId, int imageFlags) { 540 | MNVGcontext* mtl = (__bridge MNVGcontext*)nvgInternalParams(ctx)->userPtr; 541 | MNVGtexture* tex = [mtl allocTexture]; 542 | 543 | if (tex == NULL) return 0; 544 | 545 | tex->type = NVG_TEXTURE_RGBA; 546 | tex->tex = (__bridge id)textureId; 547 | tex->flags = imageFlags; 548 | 549 | return tex->id; 550 | } 551 | 552 | void* mnvgDevice(NVGcontext* ctx) { 553 | MNVGcontext* mtl = (__bridge MNVGcontext*)nvgInternalParams(ctx)->userPtr; 554 | return (__bridge void*)mtl.metalLayer.device; 555 | } 556 | 557 | void* mnvgImageHandle(NVGcontext* ctx, int image) { 558 | MNVGcontext* mtl = (__bridge MNVGcontext*)nvgInternalParams(ctx)->userPtr; 559 | MNVGtexture* tex = [mtl findTexture:image]; 560 | if (tex == nil) return NULL; 561 | 562 | // Makes sure the command execution for the image has been done. 563 | for (MNVGbuffers* buffers in mtl.cbuffers) { 564 | if (buffers.isBusy && buffers.image == image && buffers.commandBuffer) { 565 | id commandBuffer = buffers.commandBuffer; 566 | [commandBuffer waitUntilCompleted]; 567 | break; 568 | } 569 | } 570 | 571 | return (__bridge void*)tex->tex; 572 | } 573 | 574 | void mnvgReadPixels(NVGcontext* ctx, int image, int x, int y, int width, 575 | int height, void* data) { 576 | MNVGcontext* mtl = (__bridge MNVGcontext*)nvgInternalParams(ctx)->userPtr; 577 | MNVGtexture* tex = [mtl findTexture:image]; 578 | if (tex == nil) return; 579 | 580 | NSUInteger bytesPerRow; 581 | if (tex->type == NVG_TEXTURE_RGBA) { 582 | bytesPerRow = tex->tex.width * 4; 583 | } else { 584 | bytesPerRow = tex->tex.width; 585 | } 586 | 587 | // Makes sure the command execution for the image has been done. 588 | for (MNVGbuffers* buffers in mtl.cbuffers) { 589 | if (buffers.isBusy && buffers.image == image && buffers.commandBuffer) { 590 | id commandBuffer = buffers.commandBuffer; 591 | [commandBuffer waitUntilCompleted]; 592 | break; 593 | } 594 | } 595 | 596 | #if TARGET_OS_SIMULATOR 597 | CAMetalLayer* metalLayer = mtl.metalLayer; 598 | const NSUInteger kBufferSize = bytesPerRow * height; 599 | id buffer = [metalLayer.device 600 | newBufferWithLength:kBufferSize 601 | options:MTLResourceStorageModeShared]; 602 | 603 | id commandBuffer = [mtl.commandQueue commandBuffer]; 604 | id blitCommandEncoder = [commandBuffer 605 | blitCommandEncoder]; 606 | [blitCommandEncoder copyFromTexture:tex->tex 607 | sourceSlice:0 608 | sourceLevel:0 609 | sourceOrigin:MTLOriginMake(x, y, 0) 610 | sourceSize:MTLSizeMake(width, height, 1) 611 | toBuffer:buffer 612 | destinationOffset:0 613 | destinationBytesPerRow:bytesPerRow 614 | destinationBytesPerImage:kBufferSize]; 615 | 616 | [blitCommandEncoder endEncoding]; 617 | [commandBuffer commit]; 618 | [commandBuffer waitUntilCompleted]; 619 | memcpy(data, [buffer contents], kBufferSize); 620 | #else 621 | [tex->tex getBytes:data 622 | bytesPerRow:bytesPerRow 623 | fromRegion:MTLRegionMake2D(x, y, width, height) 624 | mipmapLevel:0]; 625 | #endif // TARGET_OS_SIMULATOR 626 | } 627 | 628 | enum MNVGTarget mnvgTarget() { 629 | #if TARGET_OS_SIMULATOR 630 | return MNVG_SIMULATOR; 631 | #elif TARGET_OS_IOS 632 | return MNVG_IOS; 633 | #elif TARGET_OS_OSX 634 | return MNVG_MACOS; 635 | #elif TARGET_OS_TV 636 | return MNVG_TVOS; 637 | #else 638 | return MNVG_UNKNOWN; 639 | #endif 640 | } 641 | 642 | @implementation MNVGbuffers 643 | @end 644 | 645 | @implementation MNVGcontext 646 | 647 | - (MNVGcall*)allocCall { 648 | MNVGcall* ret = NULL; 649 | if (_buffers.ncalls + 1 > _buffers.ccalls) { 650 | MNVGcall* calls; 651 | int ccalls = mtlnvg__maxi(_buffers.ncalls + 1, 128) + _buffers.ccalls / 2; 652 | calls = (MNVGcall*)realloc(_buffers.calls, sizeof(MNVGcall) * ccalls); 653 | if (calls == NULL) return NULL; 654 | _buffers.calls = calls; 655 | _buffers.ccalls = ccalls; 656 | } 657 | ret = &_buffers.calls[_buffers.ncalls++]; 658 | memset(ret, 0, sizeof(MNVGcall)); 659 | return ret; 660 | } 661 | 662 | - (int)allocFragUniforms:(int)n { 663 | int ret = 0; 664 | if (_buffers.nuniforms + n > _buffers.cuniforms) { 665 | int cuniforms = mtlnvg__maxi(_buffers.nuniforms + n, 128) \ 666 | + _buffers.cuniforms / 2; 667 | id buffer = [_metalLayer.device 668 | newBufferWithLength:(_fragSize * cuniforms) 669 | options:kMetalBufferOptions]; 670 | unsigned char* uniforms = [buffer contents]; 671 | if (_buffers.uniformBuffer != nil) { 672 | memcpy(uniforms, _buffers.uniforms, 673 | _fragSize * _buffers.nuniforms); 674 | } 675 | _buffers.uniformBuffer = buffer; 676 | _buffers.uniforms = uniforms; 677 | _buffers.cuniforms = cuniforms; 678 | } 679 | ret = _buffers.nuniforms * _fragSize; 680 | _buffers.nuniforms += n; 681 | return ret; 682 | } 683 | 684 | - (int)allocIndexes:(int)n { 685 | int ret = 0; 686 | if (_buffers.nindexes + n > _buffers.cindexes) { 687 | int cindexes = mtlnvg__maxi(_buffers.nindexes + n, 4096) \ 688 | + _buffers.cindexes / 2; 689 | id buffer = [_metalLayer.device 690 | newBufferWithLength:(_indexSize * cindexes) 691 | options:kMetalBufferOptions]; 692 | uint32_t* indexes = [buffer contents]; 693 | if (_buffers.indexBuffer != nil) { 694 | memcpy(indexes, _buffers.indexes, _indexSize * _buffers.nindexes); 695 | } 696 | _buffers.indexBuffer = buffer; 697 | _buffers.indexes = indexes; 698 | _buffers.cindexes = cindexes; 699 | } 700 | ret = _buffers.nindexes; 701 | _buffers.nindexes += n; 702 | return ret; 703 | } 704 | 705 | - (MNVGtexture*)allocTexture { 706 | MNVGtexture* tex = nil; 707 | 708 | for (MNVGtexture* texture in _textures) { 709 | if (texture->id == 0) { 710 | tex = texture; 711 | break; 712 | } 713 | } 714 | if (tex == nil) { 715 | tex = [MNVGtexture new]; 716 | [_textures addObject:tex]; 717 | } 718 | tex->id = ++_textureId; 719 | return tex; 720 | } 721 | 722 | - (int)allocVerts:(int)n { 723 | int ret = 0; 724 | if (_buffers.nverts + n > _buffers.cverts) { 725 | int cverts = mtlnvg__maxi(_buffers.nverts + n, 4096) + _buffers.cverts / 2; 726 | id buffer = [_metalLayer.device 727 | newBufferWithLength:(sizeof(NVGvertex) * cverts) 728 | options:kMetalBufferOptions]; 729 | NVGvertex* verts = [buffer contents]; 730 | if (_buffers.vertBuffer != nil) { 731 | memcpy(verts, _buffers.verts, sizeof(NVGvertex) * _buffers.nverts); 732 | } 733 | _buffers.vertBuffer = buffer; 734 | _buffers.verts = verts; 735 | _buffers.cverts = cverts; 736 | } 737 | ret = _buffers.nverts; 738 | _buffers.nverts += n; 739 | return ret; 740 | } 741 | 742 | - (MNVGblend)blendCompositeOperation:(NVGcompositeOperationState)op { 743 | MNVGblend blend; 744 | if (!mtlnvg_convertBlendFuncFactor(op.srcRGB, &blend.srcRGB) || 745 | !mtlnvg_convertBlendFuncFactor(op.dstRGB, &blend.dstRGB) || 746 | !mtlnvg_convertBlendFuncFactor(op.srcAlpha, &blend.srcAlpha) || 747 | !mtlnvg_convertBlendFuncFactor(op.dstAlpha, &blend.dstAlpha)) { 748 | blend.srcRGB = MTLBlendFactorOne; 749 | blend.dstRGB = MTLBlendFactorOneMinusSourceAlpha; 750 | blend.srcAlpha = MTLBlendFactorOne; 751 | blend.dstAlpha = MTLBlendFactorOneMinusSourceAlpha; 752 | } 753 | return blend; 754 | } 755 | 756 | - (void)checkError:(NSError*)error withMessage:(const char*)message { 757 | if ((_flags & NVG_DEBUG) == 0) return; 758 | if (error) { 759 | printf("Error occurs after %s: %s\n", 760 | message, [[error localizedDescription] UTF8String]); 761 | } 762 | } 763 | 764 | - (int)convertPaintForFrag:(MNVGfragUniforms*)frag 765 | paint:(NVGpaint*)paint 766 | scissor:(NVGscissor*)scissor 767 | width:(float)width 768 | fringe:(float)fringe 769 | strokeThr:(float)strokeThr { 770 | MNVGtexture* tex = nil; 771 | float invxform[6]; 772 | 773 | memset(frag, 0, sizeof(*frag)); 774 | 775 | frag->innerCol = mtlnvg__premulColor(paint->innerColor); 776 | frag->outerCol = mtlnvg__premulColor(paint->outerColor); 777 | 778 | if (scissor->extent[0] < -0.5f || scissor->extent[1] < -0.5f) { 779 | frag->scissorMat = matrix_from_rows((vector_float3){0, 0, 0}, 780 | (vector_float3){0, 0, 0}, 781 | (vector_float3){0, 0, 0}); 782 | frag->scissorExt.x = 1.0f; 783 | frag->scissorExt.y = 1.0f; 784 | frag->scissorScale.x = 1.0f; 785 | frag->scissorScale.y = 1.0f; 786 | } else { 787 | nvgTransformInverse(invxform, scissor->xform); 788 | mtlnvg__xformToMat3x3(&frag->scissorMat, invxform); 789 | frag->scissorExt.x = scissor->extent[0]; 790 | frag->scissorExt.y = scissor->extent[1]; 791 | frag->scissorScale.x = sqrtf(scissor->xform[0] * scissor->xform[0] + scissor->xform[2] * scissor->xform[2]) / fringe; 792 | frag->scissorScale.y = sqrtf(scissor->xform[1] * scissor->xform[1] + scissor->xform[3] * scissor->xform[3]) / fringe; 793 | } 794 | 795 | frag->extent = (vector_float2){paint->extent[0], paint->extent[1]}; 796 | frag->strokeMult = (width * 0.5f + fringe * 0.5f) / fringe; 797 | frag->strokeThr = strokeThr; 798 | 799 | if (paint->image != 0) { 800 | tex = [self findTexture:paint->image]; 801 | if (tex == nil) return 0; 802 | if (tex->flags & NVG_IMAGE_FLIPY) { 803 | float m1[6], m2[6]; 804 | nvgTransformTranslate(m1, 0.0f, frag->extent.y * 0.5f); 805 | nvgTransformMultiply(m1, paint->xform); 806 | nvgTransformScale(m2, 1.0f, -1.0f); 807 | nvgTransformMultiply(m2, m1); 808 | nvgTransformTranslate(m1, 0.0f, -frag->extent.y * 0.5f); 809 | nvgTransformMultiply(m1, m2); 810 | nvgTransformInverse(invxform, m1); 811 | } else { 812 | nvgTransformInverse(invxform, paint->xform); 813 | } 814 | frag->type = MNVG_SHADER_FILLIMG; 815 | 816 | if (tex->type == NVG_TEXTURE_RGBA) 817 | frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1; 818 | else 819 | frag->texType = 2; 820 | } else { 821 | frag->type = MNVG_SHADER_FILLGRAD; 822 | frag->radius = paint->radius; 823 | frag->feather = paint->feather; 824 | nvgTransformInverse(invxform, paint->xform); 825 | } 826 | 827 | mtlnvg__xformToMat3x3(&frag->paintMat, invxform); 828 | 829 | return 1; 830 | } 831 | 832 | - (void)convexFill:(MNVGcall*)call { 833 | const int kIndexBufferOffset = call->indexOffset * _indexSize; 834 | [self setUniforms:call->uniformOffset image:call->image]; 835 | [_renderEncoder setRenderPipelineState:_pipelineState]; 836 | if (call->indexCount > 0) { 837 | [_renderEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle 838 | indexCount:call->indexCount 839 | indexType:MTLIndexTypeUInt32 840 | indexBuffer:_buffers.indexBuffer 841 | indexBufferOffset:kIndexBufferOffset]; 842 | } 843 | 844 | // Draw fringes 845 | if (call->strokeCount > 0) { 846 | [_renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip 847 | vertexStart:call->strokeOffset 848 | vertexCount:call->strokeCount]; 849 | } 850 | } 851 | 852 | -(void)fill:(MNVGcall*)call { 853 | // Draws shapes. 854 | const int kIndexBufferOffset = call->indexOffset * _indexSize; 855 | [_renderEncoder setCullMode:MTLCullModeNone]; 856 | [_renderEncoder setDepthStencilState:_fillShapeStencilState]; 857 | [_renderEncoder setRenderPipelineState:_stencilOnlyPipelineState]; 858 | if (call->indexCount > 0) { 859 | [_renderEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle 860 | indexCount:call->indexCount 861 | indexType:MTLIndexTypeUInt32 862 | indexBuffer:_buffers.indexBuffer 863 | indexBufferOffset:kIndexBufferOffset]; 864 | } 865 | 866 | // Restores states. 867 | [_renderEncoder setCullMode:MTLCullModeBack]; 868 | [_renderEncoder setRenderPipelineState:_pipelineState]; 869 | 870 | // Draws anti-aliased fragments. 871 | [self setUniforms:call->uniformOffset image:call->image]; 872 | if (_flags & NVG_ANTIALIAS && call->strokeCount > 0) { 873 | [_renderEncoder setDepthStencilState:_fillAntiAliasStencilState]; 874 | [_renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip 875 | vertexStart:call->strokeOffset 876 | vertexCount:call->strokeCount]; 877 | } 878 | 879 | // Draws fill. 880 | [_renderEncoder setDepthStencilState:_fillStencilState]; 881 | [_renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip 882 | vertexStart:call->triangleOffset 883 | vertexCount:call->triangleCount]; 884 | [_renderEncoder setDepthStencilState:_defaultStencilState]; 885 | } 886 | 887 | - (MNVGtexture*)findTexture:(int)id { 888 | for (MNVGtexture* texture in _textures) { 889 | if (texture->id == id) 890 | return texture; 891 | } 892 | return nil; 893 | } 894 | 895 | - (MNVGfragUniforms*)fragUniformAtIndex:(int)index { 896 | return (MNVGfragUniforms*)&_buffers.uniforms[index]; 897 | } 898 | 899 | - (void)renderCancel { 900 | _buffers.image = 0; 901 | _buffers.isBusy = NO; 902 | _buffers.nindexes = 0; 903 | _buffers.nverts = 0; 904 | _buffers.ncalls = 0; 905 | _buffers.nuniforms = 0; 906 | dispatch_semaphore_signal(_semaphore); 907 | } 908 | 909 | - (id)renderCommandEncoderWithColorTexture: 910 | (id)colorTexture { 911 | MTLRenderPassDescriptor *descriptor = \ 912 | [MTLRenderPassDescriptor renderPassDescriptor]; 913 | if (descriptor == nil) { 914 | return nil; 915 | } 916 | 917 | descriptor.colorAttachments[0].clearColor = _clearColor; 918 | descriptor.colorAttachments[0].loadAction = \ 919 | _clearBufferOnFlush ? MTLLoadActionClear : MTLLoadActionLoad; 920 | descriptor.colorAttachments[0].storeAction = MTLStoreActionStore; 921 | descriptor.colorAttachments[0].texture = colorTexture; 922 | _clearBufferOnFlush = NO; 923 | 924 | descriptor.stencilAttachment.clearStencil = 0; 925 | descriptor.stencilAttachment.loadAction = MTLLoadActionClear; 926 | descriptor.stencilAttachment.storeAction = MTLStoreActionDontCare; 927 | descriptor.stencilAttachment.texture = _buffers.stencilTexture; 928 | 929 | id commandBuffer = _buffers.commandBuffer; 930 | id encoder = [commandBuffer 931 | renderCommandEncoderWithDescriptor:descriptor]; 932 | 933 | [encoder setCullMode:MTLCullModeBack]; 934 | [encoder setFrontFacingWinding:MTLWindingCounterClockwise]; 935 | [encoder setStencilReferenceValue:0]; 936 | [encoder setViewport:(MTLViewport) 937 | {0.0, 0.0, _viewPortSize.x, _viewPortSize.y, 0.0, 1.0}]; 938 | 939 | [encoder setVertexBuffer:_buffers.vertBuffer 940 | offset:0 941 | atIndex:MNVG_VERTEX_INPUT_INDEX_VERTICES]; 942 | 943 | [encoder setVertexBuffer:_buffers.viewSizeBuffer 944 | offset:0 945 | atIndex:MNVG_VERTEX_INPUT_INDEX_VIEW_SIZE]; 946 | 947 | [encoder setFragmentBuffer:_buffers.uniformBuffer offset:0 atIndex:0]; 948 | return encoder; 949 | } 950 | 951 | - (int)renderCreate { 952 | if (_metalLayer.device == nil) { 953 | id device = MTLCreateSystemDefaultDevice(); 954 | _metalLayer.device = device; 955 | } 956 | #if TARGET_OS_OSX 957 | _metalLayer.opaque = NO; 958 | #endif // TARGET_OS_OSX 959 | 960 | // Loads shaders from pre-compiled metal library.. 961 | NSError* error; 962 | id device = _metalLayer.device; 963 | #ifdef MNVG_INVALID_TARGET 964 | id library = nil; 965 | return 0; 966 | #endif 967 | 968 | bool creates_pseudo_texture = false; 969 | unsigned char* metal_library_bitcode; 970 | unsigned int metal_library_bitcode_len; 971 | #if TARGET_OS_SIMULATOR 972 | metal_library_bitcode = mnvg_bitcode_simulator; 973 | metal_library_bitcode_len = mnvg_bitcode_simulator_len; 974 | #elif TARGET_OS_IOS 975 | if (@available(iOS 10, *)) { 976 | } else if (@available(iOS 8, *)) { 977 | creates_pseudo_texture = true; 978 | } else { 979 | return 0; 980 | } 981 | metal_library_bitcode = mnvg_bitcode_ios; 982 | metal_library_bitcode_len = mnvg_bitcode_ios_len; 983 | #elif TARGET_OS_OSX 984 | if (@available(macOS 10.11, *)) { 985 | metal_library_bitcode = mnvg_bitcode_macos; 986 | metal_library_bitcode_len = mnvg_bitcode_macos_len; 987 | } else { 988 | return 0; 989 | } 990 | #elif TARGET_OS_TV 991 | metal_library_bitcode = mnvg_bitcode_tvos; 992 | metal_library_bitcode_len = mnvg_bitcode_tvos_len; 993 | #endif 994 | 995 | dispatch_data_t data = dispatch_data_create(metal_library_bitcode, 996 | metal_library_bitcode_len, 997 | NULL, 998 | DISPATCH_DATA_DESTRUCTOR_DEFAULT); 999 | id library = [device newLibraryWithData:data error:&error]; 1000 | 1001 | [self checkError:error withMessage:"init library"]; 1002 | if (library == nil) { 1003 | return 0; 1004 | } 1005 | 1006 | _vertexFunction = [library newFunctionWithName:@"vertexShader"]; 1007 | if (_flags & NVG_ANTIALIAS) { 1008 | _fragmentFunction = [library newFunctionWithName:@"fragmentShaderAA"]; 1009 | } else { 1010 | _fragmentFunction = [library newFunctionWithName:@"fragmentShader"]; 1011 | } 1012 | 1013 | _commandQueue = [device newCommandQueue]; 1014 | 1015 | // Initializes the number of available buffers. 1016 | if (_flags & NVG_TRIPLE_BUFFER) { 1017 | _maxBuffers = 3; 1018 | } else if (_flags & NVG_DOUBLE_BUFFER) { 1019 | _maxBuffers = 2; 1020 | } else { 1021 | _maxBuffers = 1; 1022 | } 1023 | _cbuffers = [NSMutableArray arrayWithCapacity:_maxBuffers]; 1024 | for (int i = _maxBuffers; i--;) { 1025 | [_cbuffers addObject:[MNVGbuffers new]]; 1026 | } 1027 | _clearBufferOnFlush = NO; 1028 | _semaphore = dispatch_semaphore_create(_maxBuffers); 1029 | 1030 | // Initializes vertex descriptor. 1031 | _vertexDescriptor = [MTLVertexDescriptor vertexDescriptor]; 1032 | _vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; 1033 | _vertexDescriptor.attributes[0].bufferIndex = 0; 1034 | _vertexDescriptor.attributes[0].offset = offsetof(NVGvertex, x); 1035 | 1036 | _vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; 1037 | _vertexDescriptor.attributes[1].bufferIndex = 0; 1038 | _vertexDescriptor.attributes[1].offset = offsetof(NVGvertex, u); 1039 | 1040 | _vertexDescriptor.layouts[0].stride = sizeof(NVGvertex); 1041 | _vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; 1042 | 1043 | // Initialzes textures. 1044 | _textureId = 0; 1045 | _textures = [NSMutableArray array]; 1046 | 1047 | // Initializes default sampler descriptor. 1048 | MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; 1049 | _pseudoSampler = [_metalLayer.device 1050 | newSamplerStateWithDescriptor:samplerDescriptor]; 1051 | 1052 | // Initializes pseudo texture for macOS. 1053 | if (creates_pseudo_texture) { 1054 | const int kPseudoTextureImage = [self 1055 | renderCreateTextureWithType:NVG_TEXTURE_ALPHA 1056 | width:1 1057 | height:1 1058 | imageFlags:0 1059 | data:NULL]; 1060 | MNVGtexture* tex = [self findTexture:kPseudoTextureImage]; 1061 | _pseudoTexture = tex->tex; 1062 | } 1063 | 1064 | // Initializes default blend states. 1065 | _blendFunc = malloc(sizeof(MNVGblend)); 1066 | _blendFunc->srcRGB = MTLBlendFactorOne; 1067 | _blendFunc->dstRGB = MTLBlendFactorOneMinusSourceAlpha; 1068 | _blendFunc->srcAlpha = MTLBlendFactorOne; 1069 | _blendFunc->dstAlpha = MTLBlendFactorOneMinusSourceAlpha; 1070 | 1071 | // Initializes stencil states. 1072 | MTLDepthStencilDescriptor* stencilDescriptor = \ 1073 | [MTLDepthStencilDescriptor new]; 1074 | 1075 | // Default stencil state. 1076 | _defaultStencilState = [device 1077 | newDepthStencilStateWithDescriptor:stencilDescriptor]; 1078 | 1079 | // Fill shape stencil. 1080 | MTLStencilDescriptor* frontFaceStencilDescriptor = [MTLStencilDescriptor new]; 1081 | frontFaceStencilDescriptor.stencilCompareFunction = MTLCompareFunctionAlways; 1082 | frontFaceStencilDescriptor.depthStencilPassOperation = \ 1083 | MTLStencilOperationIncrementWrap; 1084 | 1085 | MTLStencilDescriptor* backFaceStencilDescriptor = [MTLStencilDescriptor new]; 1086 | backFaceStencilDescriptor.stencilCompareFunction = MTLCompareFunctionAlways; 1087 | backFaceStencilDescriptor.depthStencilPassOperation = \ 1088 | MTLStencilOperationDecrementWrap; 1089 | 1090 | stencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways; 1091 | stencilDescriptor.backFaceStencil = backFaceStencilDescriptor; 1092 | stencilDescriptor.frontFaceStencil = frontFaceStencilDescriptor; 1093 | _fillShapeStencilState = [device 1094 | newDepthStencilStateWithDescriptor:stencilDescriptor]; 1095 | 1096 | // Fill anti-aliased stencil. 1097 | frontFaceStencilDescriptor.stencilCompareFunction = MTLCompareFunctionEqual; 1098 | frontFaceStencilDescriptor.stencilFailureOperation = MTLStencilOperationKeep; 1099 | frontFaceStencilDescriptor.depthFailureOperation = MTLStencilOperationKeep; 1100 | frontFaceStencilDescriptor.depthStencilPassOperation = \ 1101 | MTLStencilOperationZero; 1102 | 1103 | stencilDescriptor.backFaceStencil = nil; 1104 | stencilDescriptor.frontFaceStencil = frontFaceStencilDescriptor; 1105 | _fillAntiAliasStencilState = [device 1106 | newDepthStencilStateWithDescriptor:stencilDescriptor]; 1107 | 1108 | // Fill stencil. 1109 | frontFaceStencilDescriptor.stencilCompareFunction = \ 1110 | MTLCompareFunctionNotEqual; 1111 | frontFaceStencilDescriptor.stencilFailureOperation = MTLStencilOperationZero; 1112 | frontFaceStencilDescriptor.depthFailureOperation = MTLStencilOperationZero; 1113 | frontFaceStencilDescriptor.depthStencilPassOperation = \ 1114 | MTLStencilOperationZero; 1115 | 1116 | stencilDescriptor.backFaceStencil = nil; 1117 | stencilDescriptor.frontFaceStencil = frontFaceStencilDescriptor; 1118 | _fillStencilState = [device 1119 | newDepthStencilStateWithDescriptor:stencilDescriptor]; 1120 | 1121 | // Stroke shape stencil. 1122 | frontFaceStencilDescriptor.stencilCompareFunction = MTLCompareFunctionEqual; 1123 | frontFaceStencilDescriptor.stencilFailureOperation = MTLStencilOperationKeep; 1124 | frontFaceStencilDescriptor.depthFailureOperation = MTLStencilOperationKeep; 1125 | frontFaceStencilDescriptor.depthStencilPassOperation = \ 1126 | MTLStencilOperationIncrementClamp; 1127 | 1128 | stencilDescriptor.backFaceStencil = nil; 1129 | stencilDescriptor.frontFaceStencil = frontFaceStencilDescriptor; 1130 | _strokeShapeStencilState = [device 1131 | newDepthStencilStateWithDescriptor:stencilDescriptor]; 1132 | 1133 | // Stroke anti-aliased stencil. 1134 | frontFaceStencilDescriptor.depthStencilPassOperation = \ 1135 | MTLStencilOperationKeep; 1136 | 1137 | stencilDescriptor.backFaceStencil = nil; 1138 | stencilDescriptor.frontFaceStencil = frontFaceStencilDescriptor; 1139 | _strokeAntiAliasStencilState = [device 1140 | newDepthStencilStateWithDescriptor:stencilDescriptor]; 1141 | 1142 | // Stroke clear stencil. 1143 | frontFaceStencilDescriptor.stencilCompareFunction = MTLCompareFunctionAlways; 1144 | frontFaceStencilDescriptor.stencilFailureOperation = MTLStencilOperationZero; 1145 | frontFaceStencilDescriptor.depthFailureOperation = MTLStencilOperationZero; 1146 | frontFaceStencilDescriptor.depthStencilPassOperation = \ 1147 | MTLStencilOperationZero; 1148 | 1149 | stencilDescriptor.backFaceStencil = nil; 1150 | stencilDescriptor.frontFaceStencil = frontFaceStencilDescriptor; 1151 | _strokeClearStencilState = [device 1152 | newDepthStencilStateWithDescriptor:stencilDescriptor]; 1153 | 1154 | return 1; 1155 | } 1156 | 1157 | - (int)renderCreateTextureWithType:(int)type 1158 | width:(int)width 1159 | height:(int)height 1160 | imageFlags:(int)imageFlags 1161 | data:(const unsigned char*)data { 1162 | MNVGtexture* tex = [self allocTexture]; 1163 | 1164 | if (tex == nil) return 0; 1165 | 1166 | MTLPixelFormat pixelFormat = MTLPixelFormatRGBA8Unorm; 1167 | if (type == NVG_TEXTURE_ALPHA) { 1168 | pixelFormat = MTLPixelFormatR8Unorm; 1169 | } 1170 | 1171 | tex->type = type; 1172 | tex->flags = imageFlags; 1173 | 1174 | MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor 1175 | texture2DDescriptorWithPixelFormat:pixelFormat 1176 | width:width 1177 | height:height 1178 | mipmapped:(imageFlags & NVG_IMAGE_GENERATE_MIPMAPS ? YES : NO)]; 1179 | textureDescriptor.usage = MTLTextureUsageShaderRead 1180 | | MTLTextureUsageRenderTarget 1181 | | MTLTextureUsageShaderWrite; 1182 | #if TARGET_OS_SIMULATOR 1183 | textureDescriptor.storageMode = MTLStorageModePrivate; 1184 | #endif // TARGET_OS_SIMULATOR 1185 | tex->tex = [_metalLayer.device newTextureWithDescriptor:textureDescriptor]; 1186 | 1187 | if (data != NULL) { 1188 | NSUInteger bytesPerRow; 1189 | if (tex->type == NVG_TEXTURE_RGBA) { 1190 | bytesPerRow = width * 4; 1191 | } else { 1192 | bytesPerRow = width; 1193 | } 1194 | 1195 | if (textureDescriptor.storageMode == MTLStorageModePrivate) { 1196 | const NSUInteger kBufferSize = bytesPerRow * height; 1197 | id buffer = [_metalLayer.device 1198 | newBufferWithLength:kBufferSize 1199 | options:MTLResourceStorageModeShared]; 1200 | memcpy([buffer contents], data, kBufferSize); 1201 | 1202 | id commandBuffer = [_commandQueue commandBuffer]; 1203 | id blitCommandEncoder = [commandBuffer 1204 | blitCommandEncoder]; 1205 | [blitCommandEncoder copyFromBuffer:buffer 1206 | sourceOffset:0 1207 | sourceBytesPerRow:bytesPerRow 1208 | sourceBytesPerImage:kBufferSize 1209 | sourceSize:MTLSizeMake(width, height, 1) 1210 | toTexture:tex->tex 1211 | destinationSlice:0 1212 | destinationLevel:0 1213 | destinationOrigin:MTLOriginMake(0, 0, 0)]; 1214 | 1215 | [blitCommandEncoder endEncoding]; 1216 | [commandBuffer commit]; 1217 | [commandBuffer waitUntilCompleted]; 1218 | } else { 1219 | [tex->tex replaceRegion:MTLRegionMake2D(0, 0, width, height) 1220 | mipmapLevel:0 1221 | withBytes:data 1222 | bytesPerRow:bytesPerRow]; 1223 | } 1224 | 1225 | if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { 1226 | id commandBuffer = [_commandQueue commandBuffer]; 1227 | id encoder = [commandBuffer blitCommandEncoder]; 1228 | [encoder generateMipmapsForTexture:tex->tex]; 1229 | [encoder endEncoding]; 1230 | [commandBuffer commit]; 1231 | [commandBuffer waitUntilCompleted]; 1232 | } 1233 | } 1234 | 1235 | MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; 1236 | if (imageFlags & NVG_IMAGE_NEAREST) { 1237 | samplerDescriptor.minFilter = MTLSamplerMinMagFilterNearest; 1238 | samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest; 1239 | if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) 1240 | samplerDescriptor.mipFilter = MTLSamplerMipFilterNearest; 1241 | } else { 1242 | samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear; 1243 | samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear; 1244 | if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) 1245 | samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear; 1246 | } 1247 | 1248 | if (imageFlags & NVG_IMAGE_REPEATX) { 1249 | samplerDescriptor.sAddressMode = MTLSamplerAddressModeRepeat; 1250 | } else { 1251 | samplerDescriptor.sAddressMode = MTLSamplerAddressModeClampToEdge; 1252 | } 1253 | 1254 | if (imageFlags & NVG_IMAGE_REPEATY) { 1255 | samplerDescriptor.tAddressMode = MTLSamplerAddressModeRepeat; 1256 | } else { 1257 | samplerDescriptor.tAddressMode = MTLSamplerAddressModeClampToEdge; 1258 | } 1259 | 1260 | tex->sampler = [_metalLayer.device 1261 | newSamplerStateWithDescriptor:samplerDescriptor]; 1262 | 1263 | return tex->id; 1264 | } 1265 | 1266 | - (void)renderDelete { 1267 | for (MNVGbuffers* buffers in _cbuffers) { 1268 | buffers.commandBuffer = nil; 1269 | buffers.viewSizeBuffer = nil; 1270 | buffers.stencilTexture = nil; 1271 | buffers.indexBuffer = nil; 1272 | buffers.vertBuffer = nil; 1273 | buffers.uniformBuffer = nil; 1274 | free(buffers.calls); 1275 | } 1276 | 1277 | for (MNVGtexture* texture in _textures) { 1278 | texture->tex = nil; 1279 | texture->sampler = nil; 1280 | } 1281 | 1282 | free(_blendFunc); 1283 | _commandQueue = nil; 1284 | _renderEncoder = nil; 1285 | _textures = nil; 1286 | _cbuffers = nil; 1287 | _defaultStencilState = nil; 1288 | _fillShapeStencilState = nil; 1289 | _fillAntiAliasStencilState = nil; 1290 | _strokeShapeStencilState = nil; 1291 | _strokeAntiAliasStencilState = nil; 1292 | _strokeClearStencilState = nil; 1293 | _fragmentFunction = nil; 1294 | _vertexFunction = nil; 1295 | _pipelineState = nil; 1296 | _stencilOnlyPipelineState = nil; 1297 | _pseudoSampler = nil; 1298 | _pseudoTexture = nil; 1299 | _vertexDescriptor = nil; 1300 | _metalLayer.device = nil; 1301 | _metalLayer = nil; 1302 | } 1303 | 1304 | - (int)renderDeleteTexture:(int)image { 1305 | for (MNVGtexture* texture in _textures) { 1306 | if (texture->id == image) { 1307 | if (texture->tex != nil && 1308 | (texture->flags & NVG_IMAGE_NODELETE) == 0) { 1309 | texture->tex = nil; 1310 | texture->sampler = nil; 1311 | } 1312 | texture->id = 0; 1313 | texture->flags = 0; 1314 | return 1; 1315 | } 1316 | } 1317 | return 0; 1318 | } 1319 | 1320 | - (void)renderFillWithPaint:(NVGpaint*)paint 1321 | compositeOperation:(NVGcompositeOperationState)compositeOperation 1322 | scissor:(NVGscissor*)scissor 1323 | fringe:(float)fringe 1324 | bounds:(const float*)bounds 1325 | paths:(const NVGpath*)paths 1326 | npaths:(int)npaths { 1327 | MNVGcall* call = [self allocCall]; 1328 | NVGvertex* quad; 1329 | 1330 | if (call == NULL) return; 1331 | 1332 | call->type = MNVG_FILL; 1333 | call->triangleCount = 4; 1334 | call->image = paint->image; 1335 | call->blendFunc = [self blendCompositeOperation:compositeOperation]; 1336 | 1337 | if (npaths == 1 && paths[0].convex) { 1338 | call->type = MNVG_CONVEXFILL; 1339 | call->triangleCount = 0; // Bounding box fill quad not needed for convex fill 1340 | } 1341 | 1342 | // Allocate vertices for all the paths. 1343 | int indexCount, strokeCount = 0; 1344 | int maxverts = mtlnvg__maxVertCount(paths, npaths, &indexCount, &strokeCount) 1345 | + call->triangleCount; 1346 | int vertOffset = [self allocVerts:maxverts]; 1347 | if (vertOffset == -1) goto error; 1348 | 1349 | int indexOffset = [self allocIndexes:indexCount]; 1350 | if (indexOffset == -1) goto error; 1351 | call->indexOffset = indexOffset; 1352 | call->indexCount = indexCount; 1353 | uint32_t* index = &_buffers.indexes[indexOffset]; 1354 | 1355 | int strokeVertOffset = vertOffset + (maxverts - strokeCount); 1356 | call->strokeOffset = strokeVertOffset + 1; 1357 | call->strokeCount = strokeCount - 2; 1358 | NVGvertex* strokeVert = _buffers.verts + strokeVertOffset; 1359 | 1360 | NVGpath* path = (NVGpath*)&paths[0]; 1361 | for (int i = npaths; i--; ++path) { 1362 | if (path->nfill > 2) { 1363 | memcpy(&_buffers.verts[vertOffset], path->fill, 1364 | sizeof(NVGvertex) * path->nfill); 1365 | 1366 | int hubVertOffset = vertOffset++; 1367 | for (int j = 2; j < path->nfill; j++) { 1368 | *index++ = hubVertOffset; 1369 | *index++ = vertOffset++; 1370 | *index++ = vertOffset; 1371 | } 1372 | vertOffset++; 1373 | } 1374 | if (path->nstroke > 0) { 1375 | memcpy(strokeVert, path->stroke, sizeof(NVGvertex)); 1376 | ++strokeVert; 1377 | memcpy(strokeVert, path->stroke, sizeof(NVGvertex) * path->nstroke); 1378 | strokeVert += path->nstroke; 1379 | memcpy(strokeVert, path->stroke + path->nstroke - 1, sizeof(NVGvertex)); 1380 | ++strokeVert; 1381 | } 1382 | } 1383 | 1384 | // Setup uniforms for draw calls 1385 | if (call->type == MNVG_FILL) { 1386 | // Quad 1387 | call->triangleOffset = vertOffset; 1388 | quad = &_buffers.verts[call->triangleOffset]; 1389 | mtlnvg__vset(&quad[0], bounds[2], bounds[3], 0.5f, 1.0f); 1390 | mtlnvg__vset(&quad[1], bounds[2], bounds[1], 0.5f, 1.0f); 1391 | mtlnvg__vset(&quad[2], bounds[0], bounds[3], 0.5f, 1.0f); 1392 | mtlnvg__vset(&quad[3], bounds[0], bounds[1], 0.5f, 1.0f); 1393 | } 1394 | 1395 | // Fill shader 1396 | call->uniformOffset = [self allocFragUniforms:1]; 1397 | if (call->uniformOffset == -1) goto error; 1398 | [self convertPaintForFrag:[self fragUniformAtIndex:call->uniformOffset] 1399 | paint:paint 1400 | scissor:scissor 1401 | width:fringe 1402 | fringe:fringe 1403 | strokeThr:-1.0f]; 1404 | return; 1405 | 1406 | error: 1407 | // We get here if call alloc was ok, but something else is not. 1408 | // Roll back the last call to prevent drawing it. 1409 | if (_buffers.ncalls > 0) _buffers.ncalls--; 1410 | } 1411 | 1412 | - (void)renderFlush { 1413 | // Cancelled if the drawable is invisible. 1414 | if (_viewPortSize.x == 0 || _viewPortSize.y == 0) { 1415 | [self renderCancel]; 1416 | return; 1417 | } 1418 | 1419 | id commandBuffer = [_commandQueue commandBuffer]; 1420 | id colorTexture = nil;; 1421 | vector_uint2 textureSize; 1422 | 1423 | _buffers.commandBuffer = commandBuffer; 1424 | __block MNVGbuffers* buffers = _buffers; 1425 | [commandBuffer enqueue]; 1426 | [commandBuffer addCompletedHandler:^(id buffer) { 1427 | buffers.isBusy = NO; 1428 | buffers.commandBuffer = nil; 1429 | buffers.image = 0; 1430 | buffers.nindexes = 0; 1431 | buffers.nverts = 0; 1432 | buffers.ncalls = 0; 1433 | buffers.nuniforms = 0; 1434 | dispatch_semaphore_signal(self.semaphore); 1435 | }]; 1436 | 1437 | if (s_framebuffer == NULL || 1438 | nvgInternalParams(s_framebuffer->ctx)->userPtr != (__bridge void*)self) { 1439 | textureSize = _viewPortSize; 1440 | } else { // renders in framebuffer 1441 | buffers.image = s_framebuffer->image; 1442 | MNVGtexture* tex = [self findTexture:s_framebuffer->image]; 1443 | colorTexture = tex->tex; 1444 | textureSize = (vector_uint2){(uint)colorTexture.width, 1445 | (uint)colorTexture.height}; 1446 | } 1447 | if (textureSize.x == 0 || textureSize.y == 0) return; 1448 | [self updateStencilTextureToSize:&textureSize]; 1449 | 1450 | id drawable = nil; 1451 | if (colorTexture == nil) { 1452 | drawable = _metalLayer.nextDrawable; 1453 | colorTexture = drawable.texture; 1454 | } 1455 | _renderEncoder = [self renderCommandEncoderWithColorTexture:colorTexture]; 1456 | if (_renderEncoder == nil) { 1457 | return; 1458 | } 1459 | MNVGcall* call = &buffers.calls[0]; 1460 | for (int i = buffers.ncalls; i--; ++call) { 1461 | MNVGblend* blend = &call->blendFunc; 1462 | [self updateRenderPipelineStatesForBlend:blend 1463 | pixelFormat:colorTexture.pixelFormat]; 1464 | 1465 | if (call->type == MNVG_FILL) 1466 | [self fill:call]; 1467 | else if (call->type == MNVG_CONVEXFILL) 1468 | [self convexFill:call]; 1469 | else if (call->type == MNVG_STROKE) 1470 | [self stroke:call]; 1471 | else if (call->type == MNVG_TRIANGLES) 1472 | [self triangles:call]; 1473 | } 1474 | 1475 | [_renderEncoder endEncoding]; 1476 | _renderEncoder = nil; 1477 | 1478 | if (drawable && !_metalLayer.presentsWithTransaction) { 1479 | [_buffers.commandBuffer presentDrawable:drawable]; 1480 | } 1481 | 1482 | #if TARGET_OS_OSX 1483 | // Makes mnvgReadPixels() work as expected on Mac. 1484 | if (s_framebuffer != NULL) { 1485 | id blitCommandEncoder = [_buffers.commandBuffer 1486 | blitCommandEncoder]; 1487 | [blitCommandEncoder synchronizeResource:colorTexture]; 1488 | [blitCommandEncoder endEncoding]; 1489 | } 1490 | #endif // TARGET_OS_OSX 1491 | 1492 | [_buffers.commandBuffer commit]; 1493 | 1494 | if (drawable && _metalLayer.presentsWithTransaction) { 1495 | [_buffers.commandBuffer waitUntilScheduled]; 1496 | [drawable present]; 1497 | } 1498 | } 1499 | 1500 | - (int)renderGetTextureSizeForImage:(int)image 1501 | width:(int*)width 1502 | height:(int*)height { 1503 | MNVGtexture* tex = [self findTexture:image]; 1504 | if (tex == nil) return 0; 1505 | *width = (int)tex->tex.width; 1506 | *height = (int)tex->tex.height; 1507 | return 1; 1508 | } 1509 | 1510 | - (void)renderStrokeWithPaint:(NVGpaint*)paint 1511 | compositeOperation:(NVGcompositeOperationState)compositeOperation 1512 | scissor:(NVGscissor*)scissor 1513 | fringe:(float)fringe 1514 | strokeWidth:(float)strokeWidth 1515 | paths:(const NVGpath*)paths 1516 | npaths:(int)npaths { 1517 | MNVGcall* call = [self allocCall]; 1518 | 1519 | if (call == NULL) return; 1520 | 1521 | call->type = MNVG_STROKE; 1522 | call->image = paint->image; 1523 | call->blendFunc = [self blendCompositeOperation:compositeOperation]; 1524 | 1525 | // Allocate vertices for all the paths. 1526 | int strokeCount = 0; 1527 | int maxverts = mtlnvg__maxVertCount(paths, npaths, NULL, &strokeCount); 1528 | int offset = [self allocVerts:maxverts]; 1529 | if (offset == -1) goto error; 1530 | 1531 | call->strokeOffset = offset + 1; 1532 | call->strokeCount = strokeCount - 2; 1533 | NVGvertex* strokeVert = _buffers.verts + offset; 1534 | 1535 | NVGpath* path = (NVGpath*)&paths[0]; 1536 | for (int i = npaths; i--; ++path) { 1537 | if (path->nstroke > 0) { 1538 | memcpy(strokeVert, path->stroke, sizeof(NVGvertex)); 1539 | ++strokeVert; 1540 | memcpy(strokeVert, path->stroke, sizeof(NVGvertex) * path->nstroke); 1541 | strokeVert += path->nstroke; 1542 | memcpy(strokeVert, path->stroke + path->nstroke - 1, sizeof(NVGvertex)); 1543 | ++strokeVert; 1544 | } 1545 | } 1546 | 1547 | if (_flags & NVG_STENCIL_STROKES) { 1548 | // Fill shader 1549 | call->uniformOffset = [self allocFragUniforms:2]; 1550 | if (call->uniformOffset == -1) goto error; 1551 | [self convertPaintForFrag:[self fragUniformAtIndex:call->uniformOffset] 1552 | paint:paint 1553 | scissor:scissor 1554 | width:strokeWidth 1555 | fringe:fringe 1556 | strokeThr:-1.0f]; 1557 | MNVGfragUniforms* frag = [self 1558 | fragUniformAtIndex:call->uniformOffset + _fragSize]; 1559 | [self convertPaintForFrag:frag 1560 | paint:paint 1561 | scissor:scissor 1562 | width:strokeWidth 1563 | fringe:fringe 1564 | strokeThr:(1.0f - 0.5f / 255.0f)]; 1565 | } else { 1566 | // Fill shader 1567 | call->uniformOffset = [self allocFragUniforms:1]; 1568 | if (call->uniformOffset == -1) goto error; 1569 | [self convertPaintForFrag:[self fragUniformAtIndex:call->uniformOffset] 1570 | paint:paint 1571 | scissor:scissor 1572 | width:strokeWidth 1573 | fringe:fringe 1574 | strokeThr:-1.0f]; 1575 | } 1576 | 1577 | return; 1578 | 1579 | error: 1580 | // We get here if call alloc was ok, but something else is not. 1581 | // Roll back the last call to prevent drawing it. 1582 | if (_buffers.ncalls > 0) _buffers.ncalls--; 1583 | } 1584 | 1585 | - (void)renderTrianglesWithPaint:(NVGpaint*) paint 1586 | compositeOperation:(NVGcompositeOperationState)compositeOperation 1587 | scissor:(NVGscissor*)scissor 1588 | verts:(const NVGvertex*)verts 1589 | nverts:(int)nverts 1590 | fringe:(float)fringe { 1591 | MNVGcall* call = [self allocCall]; 1592 | MNVGfragUniforms* frag; 1593 | 1594 | if (call == NULL) return; 1595 | 1596 | call->type = MNVG_TRIANGLES; 1597 | call->image = paint->image; 1598 | call->blendFunc = [self blendCompositeOperation:compositeOperation]; 1599 | 1600 | // Allocate vertices for all the paths. 1601 | call->triangleOffset = [self allocVerts:nverts]; 1602 | if (call->triangleOffset == -1) goto error; 1603 | call->triangleCount = nverts; 1604 | 1605 | memcpy(&_buffers.verts[call->triangleOffset], verts, 1606 | sizeof(NVGvertex) * nverts); 1607 | 1608 | // Fill shader 1609 | call->uniformOffset = [self allocFragUniforms:1]; 1610 | if (call->uniformOffset == -1) goto error; 1611 | frag = [self fragUniformAtIndex:call->uniformOffset]; 1612 | [self convertPaintForFrag:frag 1613 | paint:paint 1614 | scissor:scissor 1615 | width:1.0f 1616 | fringe:fringe 1617 | strokeThr:-1.0f]; 1618 | frag->type = MNVG_SHADER_IMG; 1619 | 1620 | return; 1621 | 1622 | error: 1623 | // We get here if call alloc was ok, but something else is not. 1624 | // Roll back the last call to prevent drawing it. 1625 | if (_buffers.ncalls > 0) _buffers.ncalls--; 1626 | } 1627 | 1628 | - (int)renderUpdateTextureWithImage:(int)image 1629 | x:(int)x 1630 | y:(int)y 1631 | width:(int)width 1632 | height:(int)height 1633 | data:(const unsigned char*)data { 1634 | MNVGtexture* tex = [self findTexture:image]; 1635 | 1636 | if (tex == nil) return 0; 1637 | 1638 | unsigned char* bytes; 1639 | NSUInteger bytesPerRow; 1640 | if (tex->type == NVG_TEXTURE_RGBA) { 1641 | bytesPerRow = tex->tex.width * 4; 1642 | bytes = (unsigned char*)data + y * bytesPerRow + x * 4; 1643 | } else { 1644 | bytesPerRow = tex->tex.width; 1645 | bytes = (unsigned char*)data + y * bytesPerRow + x; 1646 | } 1647 | 1648 | #if TARGET_OS_SIMULATOR 1649 | const NSUInteger kBufferSize = bytesPerRow * height; 1650 | id buffer = [_metalLayer.device 1651 | newBufferWithLength:kBufferSize 1652 | options:MTLResourceStorageModeShared]; 1653 | memcpy([buffer contents], bytes, kBufferSize); 1654 | 1655 | id commandBuffer = [_commandQueue commandBuffer]; 1656 | id blitCommandEncoder = [commandBuffer 1657 | blitCommandEncoder]; 1658 | [blitCommandEncoder copyFromBuffer:buffer 1659 | sourceOffset:0 1660 | sourceBytesPerRow:bytesPerRow 1661 | sourceBytesPerImage:kBufferSize 1662 | sourceSize:MTLSizeMake(width, height, 1) 1663 | toTexture:tex->tex 1664 | destinationSlice:0 1665 | destinationLevel:0 1666 | destinationOrigin:MTLOriginMake(x, y, 0)]; 1667 | 1668 | [blitCommandEncoder endEncoding]; 1669 | [commandBuffer commit]; 1670 | [commandBuffer waitUntilCompleted]; 1671 | #else 1672 | id texture = tex->tex; 1673 | [texture replaceRegion:MTLRegionMake2D(x, y, width, height) 1674 | mipmapLevel:0 1675 | withBytes:bytes 1676 | bytesPerRow:bytesPerRow]; 1677 | #endif 1678 | 1679 | return 1; 1680 | } 1681 | 1682 | - (void)renderViewportWithWidth:(float)width 1683 | height:(float)height 1684 | devicePixelRatio:(float)devicePixelRatio { 1685 | _viewPortSize = (vector_uint2){width * devicePixelRatio, 1686 | height * devicePixelRatio}; 1687 | 1688 | dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER); 1689 | for (MNVGbuffers* buffers in _cbuffers) { 1690 | if (!buffers.isBusy) { 1691 | buffers.isBusy = YES; 1692 | _buffers = buffers; 1693 | break; 1694 | } 1695 | } 1696 | 1697 | // Initializes view size buffer for vertex function. 1698 | if (_buffers.viewSizeBuffer == nil) { 1699 | _buffers.viewSizeBuffer = [_metalLayer.device 1700 | newBufferWithLength:sizeof(vector_float2) 1701 | options:kMetalBufferOptions]; 1702 | } 1703 | float* viewSize = (float*)[_buffers.viewSizeBuffer contents]; 1704 | viewSize[0] = width; 1705 | viewSize[1] = height; 1706 | } 1707 | 1708 | - (void)setUniforms:(int)uniformOffset image:(int)image { 1709 | [_renderEncoder setFragmentBufferOffset:uniformOffset atIndex:0]; 1710 | 1711 | MNVGtexture* tex = (image == 0 ? nil : [self findTexture:image]); 1712 | if (tex != nil) { 1713 | [_renderEncoder setFragmentTexture:tex->tex atIndex:0]; 1714 | [_renderEncoder setFragmentSamplerState:tex->sampler atIndex:0]; 1715 | } else { 1716 | [_renderEncoder setFragmentTexture:_pseudoTexture atIndex:0]; 1717 | [_renderEncoder setFragmentSamplerState:_pseudoSampler atIndex:0]; 1718 | } 1719 | } 1720 | 1721 | - (void)stroke:(MNVGcall*)call { 1722 | if (call->strokeCount <= 0) { 1723 | return; 1724 | } 1725 | 1726 | if (_flags & NVG_STENCIL_STROKES) { 1727 | // Fills the stroke base without overlap. 1728 | [self setUniforms:(call->uniformOffset + _fragSize) image:call->image]; 1729 | [_renderEncoder setDepthStencilState:_strokeShapeStencilState]; 1730 | [_renderEncoder setRenderPipelineState:_pipelineState]; 1731 | [_renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip 1732 | vertexStart:call->strokeOffset 1733 | vertexCount:call->strokeCount]; 1734 | 1735 | // Draws anti-aliased fragments. 1736 | [self setUniforms:call->uniformOffset image:call->image]; 1737 | [_renderEncoder setDepthStencilState:_strokeAntiAliasStencilState]; 1738 | [_renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip 1739 | vertexStart:call->strokeOffset 1740 | vertexCount:call->strokeCount]; 1741 | 1742 | // Clears stencil buffer. 1743 | [_renderEncoder setDepthStencilState:_strokeClearStencilState]; 1744 | [_renderEncoder setRenderPipelineState:_stencilOnlyPipelineState]; 1745 | [_renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip 1746 | vertexStart:call->strokeOffset 1747 | vertexCount:call->strokeCount]; 1748 | [_renderEncoder setDepthStencilState:_defaultStencilState]; 1749 | } else { 1750 | // Draws strokes. 1751 | [self setUniforms:call->uniformOffset image:call->image]; 1752 | [_renderEncoder setRenderPipelineState:_pipelineState]; 1753 | [_renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip 1754 | vertexStart:call->strokeOffset 1755 | vertexCount:call->strokeCount]; 1756 | } 1757 | } 1758 | 1759 | - (void)triangles:(MNVGcall*)call { 1760 | [self setUniforms:call->uniformOffset image:call->image]; 1761 | [_renderEncoder setRenderPipelineState:_pipelineState]; 1762 | [_renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle 1763 | vertexStart:call->triangleOffset 1764 | vertexCount:call->triangleCount]; 1765 | } 1766 | 1767 | - (void)updateRenderPipelineStatesForBlend:(MNVGblend*)blend 1768 | pixelFormat:(MTLPixelFormat)pixelFormat { 1769 | if (_pipelineState != nil && 1770 | _stencilOnlyPipelineState != nil && 1771 | _piplelinePixelFormat == pixelFormat && 1772 | _blendFunc->srcRGB == blend->srcRGB && 1773 | _blendFunc->dstRGB == blend->dstRGB && 1774 | _blendFunc->srcAlpha == blend->srcAlpha && 1775 | _blendFunc->dstAlpha == blend->dstAlpha) { 1776 | return; 1777 | } 1778 | 1779 | MTLRenderPipelineDescriptor* pipelineStateDescriptor = \ 1780 | [MTLRenderPipelineDescriptor new]; 1781 | 1782 | MTLRenderPipelineColorAttachmentDescriptor* colorAttachmentDescriptor = \ 1783 | pipelineStateDescriptor.colorAttachments[0]; 1784 | colorAttachmentDescriptor.pixelFormat = pixelFormat; 1785 | pipelineStateDescriptor.stencilAttachmentPixelFormat = kStencilFormat; 1786 | pipelineStateDescriptor.fragmentFunction = _fragmentFunction; 1787 | pipelineStateDescriptor.vertexFunction = _vertexFunction; 1788 | pipelineStateDescriptor.vertexDescriptor = _vertexDescriptor; 1789 | 1790 | // Sets blending states. 1791 | colorAttachmentDescriptor.blendingEnabled = YES; 1792 | colorAttachmentDescriptor.sourceRGBBlendFactor = blend->srcRGB; 1793 | colorAttachmentDescriptor.sourceAlphaBlendFactor = blend->srcAlpha; 1794 | colorAttachmentDescriptor.destinationRGBBlendFactor = blend->dstRGB; 1795 | colorAttachmentDescriptor.destinationAlphaBlendFactor = blend->dstAlpha; 1796 | _blendFunc->srcRGB = blend->srcRGB; 1797 | _blendFunc->dstRGB = blend->dstRGB; 1798 | _blendFunc->srcAlpha = blend->srcAlpha; 1799 | _blendFunc->dstAlpha = blend->dstAlpha; 1800 | 1801 | NSError* error; 1802 | _pipelineState = [_metalLayer.device 1803 | newRenderPipelineStateWithDescriptor:pipelineStateDescriptor 1804 | error:&error]; 1805 | [self checkError:error withMessage:"init pipeline state"]; 1806 | 1807 | pipelineStateDescriptor.fragmentFunction = nil; 1808 | colorAttachmentDescriptor.writeMask = MTLColorWriteMaskNone; 1809 | _stencilOnlyPipelineState = [_metalLayer.device 1810 | newRenderPipelineStateWithDescriptor:pipelineStateDescriptor 1811 | error:&error]; 1812 | [self checkError:error withMessage:"init pipeline stencil only state"]; 1813 | 1814 | _piplelinePixelFormat = pixelFormat; 1815 | } 1816 | 1817 | // Re-creates stencil texture whenever the specified size is bigger. 1818 | - (void)updateStencilTextureToSize:(vector_uint2*)size { 1819 | if (_buffers.stencilTexture != nil && 1820 | (_buffers.stencilTexture.width < size->x || 1821 | _buffers.stencilTexture.height < size->y)) { 1822 | _buffers.stencilTexture = nil; 1823 | } 1824 | if (_buffers.stencilTexture == nil) { 1825 | MTLTextureDescriptor* stencilTextureDescriptor = [MTLTextureDescriptor 1826 | texture2DDescriptorWithPixelFormat:kStencilFormat 1827 | width:size->x 1828 | height:size->y 1829 | mipmapped:NO]; 1830 | stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget; 1831 | #if TARGET_OS_OSX || TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST 1832 | stencilTextureDescriptor.storageMode = MTLStorageModePrivate; 1833 | #endif // TARGET_OS_OSX || TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST 1834 | _buffers.stencilTexture = [_metalLayer.device 1835 | newTextureWithDescriptor:stencilTextureDescriptor]; 1836 | } 1837 | } 1838 | 1839 | @end 1840 | 1841 | @implementation MNVGtexture 1842 | @end 1843 | -------------------------------------------------------------------------------- /src/nanovg_mtl_shaders.metal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Ollix 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | // --- 22 | // Author: olliwang@ollix.com (Olli Wang) 23 | 24 | #include 25 | #include 26 | 27 | using namespace metal; 28 | 29 | typedef struct { 30 | float2 pos [[attribute(0)]]; 31 | float2 tcoord [[attribute(1)]]; 32 | } Vertex; 33 | 34 | typedef struct { 35 | float4 pos [[position]]; 36 | float2 fpos; 37 | float2 ftcoord; 38 | } RasterizerData; 39 | 40 | typedef struct { 41 | float3x3 scissorMat; 42 | float3x3 paintMat; 43 | float4 innerCol; 44 | float4 outerCol; 45 | float2 scissorExt; 46 | float2 scissorScale; 47 | float2 extent; 48 | float radius; 49 | float feather; 50 | float strokeMult; 51 | float strokeThr; 52 | int texType; 53 | int type; 54 | } Uniforms; 55 | 56 | float scissorMask(constant Uniforms& uniforms, float2 p); 57 | float sdroundrect(constant Uniforms& uniforms, float2 pt); 58 | float strokeMask(constant Uniforms& uniforms, float2 ftcoord); 59 | 60 | float scissorMask(constant Uniforms& uniforms, float2 p) { 61 | float2 sc = (abs((uniforms.scissorMat * float3(p, 1.0f)).xy) 62 | - uniforms.scissorExt) \ 63 | * uniforms.scissorScale; 64 | sc = saturate(float2(0.5f) - sc); 65 | return sc.x * sc.y; 66 | } 67 | 68 | float sdroundrect(constant Uniforms& uniforms, float2 pt) { 69 | float2 ext2 = uniforms.extent - float2(uniforms.radius); 70 | float2 d = abs(pt) - ext2; 71 | return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - uniforms.radius; 72 | } 73 | 74 | float strokeMask(constant Uniforms& uniforms, float2 ftcoord) { 75 | return min(1.0, (1.0 - abs(ftcoord.x * 2.0 - 1.0)) * uniforms.strokeMult) \ 76 | * min(1.0, ftcoord.y); 77 | } 78 | 79 | // Vertex Function 80 | vertex RasterizerData vertexShader(Vertex vert [[stage_in]], 81 | constant float2& viewSize [[buffer(1)]]) { 82 | RasterizerData out; 83 | out.ftcoord = vert.tcoord; 84 | out.fpos = vert.pos; 85 | out.pos = float4(2.0 * vert.pos.x / viewSize.x - 1.0, 86 | 1.0 - 2.0 * vert.pos.y / viewSize.y, 87 | 0, 1); 88 | return out; 89 | } 90 | 91 | // Fragment function (No AA) 92 | fragment float4 fragmentShader(RasterizerData in [[stage_in]], 93 | constant Uniforms& uniforms [[buffer(0)]], 94 | texture2d texture [[texture(0)]], 95 | sampler sampler [[sampler(0)]]) { 96 | float scissor = scissorMask(uniforms, in.fpos); 97 | if (scissor == 0) 98 | return float4(0); 99 | 100 | if (uniforms.type == 0) { // MNVG_SHADER_FILLGRAD 101 | float2 pt = (uniforms.paintMat * float3(in.fpos, 1.0)).xy; 102 | float d = saturate((uniforms.feather * 0.5 + sdroundrect(uniforms, pt)) 103 | / uniforms.feather); 104 | float4 color = mix(uniforms.innerCol, uniforms.outerCol, d); 105 | return color * scissor; 106 | } else if (uniforms.type == 1) { // MNVG_SHADER_FILLIMG 107 | float2 pt = (uniforms.paintMat * float3(in.fpos, 1.0)).xy / uniforms.extent; 108 | float4 color = texture.sample(sampler, pt); 109 | if (uniforms.texType == 1) 110 | color = float4(color.xyz * color.w, color.w); 111 | else if (uniforms.texType == 2) 112 | color = float4(color.x); 113 | color *= scissor; 114 | return color * uniforms.innerCol; 115 | } else { // MNVG_SHADER_IMG 116 | float4 color = texture.sample(sampler, in.ftcoord); 117 | if (uniforms.texType == 1) 118 | color = float4(color.xyz * color.w, color.w); 119 | else if (uniforms.texType == 2) 120 | color = float4(color.x); 121 | color *= scissor; 122 | return color * uniforms.innerCol; 123 | } 124 | } 125 | 126 | // Fragment function (AA) 127 | fragment float4 fragmentShaderAA(RasterizerData in [[stage_in]], 128 | constant Uniforms& uniforms [[buffer(0)]], 129 | texture2d texture [[texture(0)]], 130 | sampler sampler [[sampler(0)]]) { 131 | float scissor = scissorMask(uniforms, in.fpos); 132 | if (scissor == 0) 133 | return float4(0); 134 | 135 | if (uniforms.type == 2) { // MNVG_SHADER_IMG 136 | float4 color = texture.sample(sampler, in.ftcoord); 137 | if (uniforms.texType == 1) 138 | color = float4(color.xyz * color.w, color.w); 139 | else if (uniforms.texType == 2) 140 | color = float4(color.x); 141 | color *= scissor; 142 | return color * uniforms.innerCol; 143 | } 144 | 145 | float strokeAlpha = strokeMask(uniforms, in.ftcoord); 146 | if (strokeAlpha < uniforms.strokeThr) { 147 | return float4(0); 148 | } 149 | 150 | if (uniforms.type == 0) { // MNVG_SHADER_FILLGRAD 151 | float2 pt = (uniforms.paintMat * float3(in.fpos, 1.0)).xy; 152 | float d = saturate((uniforms.feather * 0.5 + sdroundrect(uniforms, pt)) 153 | / uniforms.feather); 154 | float4 color = mix(uniforms.innerCol, uniforms.outerCol, d); 155 | color *= scissor; 156 | color *= strokeAlpha; 157 | return color; 158 | } else { // MNVG_SHADER_FILLIMG 159 | float2 pt = (uniforms.paintMat * float3(in.fpos, 1.0)).xy / uniforms.extent; 160 | float4 color = texture.sample(sampler, pt); 161 | if (uniforms.texType == 1) 162 | color = float4(color.xyz * color.w, color.w); 163 | else if (uniforms.texType == 2) 164 | color = float4(color.x); 165 | color *= scissor; 166 | color *= strokeAlpha; 167 | return color * uniforms.innerCol; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /tools/metallib: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2017 Ollix 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | # --- 24 | # Author: olliwang@ollix.com (Olli Wang) 25 | # 26 | # This script compiles the metal source file "nanovg_mtl_shaders.metal" 27 | # into metallib binary data as defined in "nanovg_mtl_metallib_*.h" headers. 28 | 29 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 30 | cd $DIR/../src 31 | 32 | result=true 33 | 34 | PREFIX="mnvg_bitcode" 35 | 36 | mkdir $PREFIX 37 | 38 | execute_cmd() { 39 | SDK=$1 40 | TARGET=$2 41 | 42 | SUFFIX="" 43 | CMD="xcrun -sdk $SDK metal -c nanovg_mtl_shaders.metal" 44 | 45 | AIR_FILE_NAME="$PREFIX/$TARGET$SUFFIX.air" 46 | HEADER_NAME="$PREFIX/$TARGET$SUFFIX.h" 47 | VARIABLE_NAME="$PREFIX/$TARGET$SUFFIX" 48 | 49 | if [ $SDK = "iphoneos" ]; then 50 | CMD="$CMD -mios-version-min=8.0" 51 | elif [ $SDK = "macosx" ]; then 52 | CMD="$CMD -mmacosx-version-min=10.11" 53 | fi 54 | 55 | CMD="$CMD -o $AIR_FILE_NAME" 56 | eval $CMD 57 | 58 | if [ $? -ne 0 ]; then 59 | return 1 60 | fi 61 | xcrun -sdk $SDK metallib $AIR_FILE_NAME -o $VARIABLE_NAME \ 62 | > /dev/null 2>&1 63 | xxd -i $VARIABLE_NAME > $HEADER_NAME 64 | rm $AIR_FILE_NAME $VARIABLE_NAME 65 | return 0 66 | } 67 | 68 | for SDK in "iphoneos" "iphonesimulator" "macosx" "appletvos"; do 69 | if [ $SDK = "appletvos" ]; then 70 | echo "* Compiling for tvOS..." 71 | TARGET="tvos" 72 | execute_cmd $SDK $TARGET 73 | if [ $? -ne 0 ]; then 74 | result=false 75 | break 76 | fi 77 | else 78 | if [ $SDK = "iphoneos" ]; then 79 | echo "* Compiling for iOS..." 80 | TARGET="ios" 81 | elif [ $SDK = "iphonesimulator" ]; then 82 | echo "* Compiling for Simulator..." 83 | TARGET="simulator" 84 | elif [ $SDK = "macosx" ]; then 85 | echo "* Compiling for macOS..." 86 | TARGET="macos" 87 | fi 88 | 89 | execute_cmd $SDK $TARGET 90 | if [ $? -ne 0 ]; then 91 | result=false 92 | break 93 | fi 94 | fi 95 | done 96 | 97 | if $result; then 98 | echo "Done" 99 | fi 100 | --------------------------------------------------------------------------------