[
  {
    "path": ".gitignore",
    "content": ".config\n*.o\n*.pyc\n*.a\n*.d\n\n# gtags\nGTAGS\nGRTAGS\nGPATH\n\n# emacs\n.dir-locals.el\n\n# emacs temp file suffixes\n*~\n.#*\n\\#*#\n\nsdkconfig\nsdkconfig.old\nsdkconfig.lobo\n.cproject\n.project\n.settings\nBUILD\nbuild/\ntemp/\nlocal/\n*.dis\n*.elf\n*.map\n**/.DS_Store\n"
  },
  {
    "path": "Makefile",
    "content": "#\n# This is a project Makefile. It is assumed the directory this Makefile resides in is a\n# project subdirectory.\n#\n\nPROJECT_NAME := ePaper\n\n#EXTRA_CFLAGS += --save-temps\n\ninclude $(IDF_PATH)/make/project.mk\n\n"
  },
  {
    "path": "README.md",
    "content": "\n### ePaper library for ESP32\n\n---\n\n\n#### Features\n\n* Support for **GDEH029A1** / **SSD1608** based ePaper modules in 4-wire SPI mode. Support for other controllers will be added later\n* **emulated** 4-bit gray scale mode\n* **SPI displays oriented SPI driver library** based on *spi-master* driver\n* Combined **DMA SPI** transfer mode and **direct SPI** for maximal speed\n* **4-bit Grayscale mode** or **1-bit b/w mode** can be selected during runtime\n* SPI speeds up to **20 MHz** are tested and works without problems\n* **Demo application** included which demonstrates most of the library features\n\n\n* **Graphics drawing functions**:\n  * **EPD_drawPixel**  Draw pixel at given x,y coordinates\n  * **EPD_drawLine**  Draw line between two points\n  * **EPD_drawFastVLine**, **EPD_drawFastHLine**  Draw vertical or horizontal line of given lenght\n  * **EPD_drawLineByAngle**  Draw line on screen from (x,y) point at given angle\n  * **EPD_drawRect**, **EPD_fillRect**  Draw rectangle on screen or fill given rectangular screen region with color\n  * **EPD_drawRoundRect**, **EPD_fillRoundRect**  Draw rectangle on screen or fill given rectangular screen region with color with rounded corners\n  * **EPD_drawCircle**, **EPD_fillCircle**  Draw or fill circle on screen\n  * **EPD_drawEllipse**, **EPD_fillEllipse**  Draw or fill ellipse on screen\n  * **EPD_drawTriangel**, **EPD_fillTriangle**  Draw or fill triangle on screen\n  * **EPD_drawArc**  Draw circle arc on screen, from ~ to given angles, with given thickness. Can be outlined with different color\n  * **EPD_drawPolygon**  Draw poligon on screen with given number of sides (3~60). Can be outlined with different color and rotated by given angle.\n* **Fonts**:\n  * **fixed** width and proportional fonts are supported; 8 fonts embeded\n  * unlimited number of **fonts from file**\n  * **7-segment vector font** with variable width/height is included (only numbers and few characters)\n  * Proportional fonts can be used in fixed width mode.\n  * Related functions:\n    * **EPD_setFont**  Set current font from one of embeded fonts or font file\n    * **EPD_getfontsize**  Returns current font height & width in pixels.\n    * **EPD_getfontheight**  Returns current font height in pixels.\n    * **set_7seg_font_atrib**  Set atributes for 7 segment vector font\n    * **getFontCharacters**  Get all font's characters to buffer\n* **String write function**:\n  * **EPD_print**  Write text to display.\n    * Strings can be printed at **any angle**. Rotation of the displayed text depends on *font_ratate* variable (0~360)\n    * if *font_transparent* variable is set to 1, no background pixels will be printed\n    * If the text does not fit the screen/window width it will be clipped ( if *text_wrap=0* ), or continued on next line ( if *text_wrap=1* )\n    * Two special characters are allowed in strings: *\\r* CR (0x0D), clears the display to EOL, *\\n* LF (ox0A), continues to the new line, x=0\n    * Special values can be entered for X position:\n      * *CENTER*  centers the text\n      * *RIGHT*   right justifies the text horizontaly\n      * *LASTX*   continues from last X position; offset can be used: *LASTX+n*\n    * Special values can be entered for Y:\n      * *CENTER*  centers the text verticaly\n      * *BOTTOM*  bottom justifies the text\n      * *LASTY*   continues from last Y position; offset can be used: *LASTY+n*\n  * **EPD_getStringWidth** Returns the string width in pixels based on current font characteristics. Useful for positioning strings on the screen.\n  * **EPD_clearStringRect** Fills the rectangle occupied by string with current background color\n* **Images**:\n  * **EPD_jpg_image**  Decodes and displays JPG images\n    * Limits:\n      * Baseline only. Progressive and Lossless JPEG format are not supported.\n      * Image size: Up to 65520 x 65520 pixels\n      * Color space: YCbCr three components only. Gray scale image is not supported.\n      * Sampling factor: 4:4:4, 4:2:2 or 4:2:0.\n    * Can display the image **from file** or **memory buffer**\n    * Image can be **scaled** by factor 0 ~ 3  (1/1, 1/2, 1/4 or 1/8)\n    * Image is displayed from X,Y position on screen/window:\n      * X: image left position; constants CENTER & RIGHT can be used; *negative* value is accepted\n      * Y: image top position;  constants CENTER & BOTTOM can be used; *negative* value is accepted\n    * Image is converted to **4-bit Gray Scale mode**\n* **Other display functions**:\n  * **EPD_fillScreen**  Fill the whole screen with black, white or gray scale\n* **compile_font_file**  Function which compiles font c source file to font file which can be used in *EPD_setFont()* function to select external font. Created file have the same name as source file and extension *.fnt*\n\n\n* **Global wariables**\n  * **orientation**  current screen orientation\n  * **font_ratate**  current font rotate angle (0~395)\n  * **font_transparent**  if not 0 draw fonts transparent\n  * **font_forceFixed**  if not zero force drawing proportional fonts with fixed width\n  * **text_wrap**  if not 0 wrap long text to the new line, else clip\n  * **_fg**  current foreground color for fonts\n  * **_bg**  current background for non transparent fonts\n  * **_angleOffset**  angle offset for arc, polygon and line by angle functions\n  * **image_debug**  print debug messages during image decode if set to 1\n  * **cfont**  Currently used font structure\n  * **EPD_X**  X position of the next character after EPD_print() function\n  * **EPD_Y**  Y position of the next character after EPD_print() function\n  * **_gs**  use 4-bit Gray scale if set to 1\n  * **_width** screen width (larger dimension) in pixels\n  * **_height** screen height (smaller dimension) in pixels\n\n---\n\nFull functions **syntax and descriptions** can be found in *EPD.h* and *EPDspi.h* files.\n\nFull **demo application**, well documented, is included, please **analyze it** to learn how to use the library functions.\n\n---\n\n#### Connecting the display\n\nTo run the demo, attach display module to ESP32. Default pins used are:\n* mosi: 23\n*  sck: 18\n*   CS:  5 (display CS)\n*   DC: 26 (display DC)\n*  RST: 27 (display RESET)\n* BUSY: 32 (display BUSY output)\n\nThe display can be powered from 3.3V or from **GPIO pin**. See *EPDspi.h* for configuration options.\n\n**If you want to use different pins, change them in** *EPDspi.h*\n\nUsing *make menuconfig* **select tick rate 1000** ( → Component config → FreeRTOS → Tick rate (Hz) ) to get more accurate timings\n\n---\n\n#### How to build\n\nConfigure your esp32 build environment as for **esp-idf examples**\n\nClone the repository\n\n`git clone https://github.com/loboris/ESP32_ePaper_example.git`\n\nExecute menuconfig and configure your Serial flash config and other settings. Included *sdkconfig.defaults* sets some defaults to be used.\n\nNavigate to **ePaper Display DEMO Configuration** and set **SPIFFS** options.\n\nSelect if you want to use **wifi** (recommended) to get the time from **NTP** server and set your WiFi SSID and password.\n\n`make menuconfig`\n\nMake and flash the example.\n\n`make all && make flash`\n\n---\n\n#### Prepare **SPIFFS** image\n\n*The demo uses some image and font files and it is necessary to flash the spiffs image*\n\n**To flash already prepared image** *components/spiffs_image/spiffs_image.img* execute:\n\n`make copyfs`\n\n---\n\nYou can also prepare different SFPIFFS **image** and flash it to ESP32.\n\nFiles to be included on spiffs are already in **components/spiffs_image/image/** directory. You can add or remove the files you want to include.\n\nThen execute:\n\n`make makefs`\n\nto create **spiffs image** in *build* directory **without flashing** to ESP32\n\nOr execute:\n\n`make flashfs`\n\nto create **spiffs image** in *build* directory and **flash** it to ESP32\n\n---\n\nTested on Waveshare 2.9\" ePaper module connected to SparkFun ESP32 Thing board.\n![Tested on](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/2.9inch-e-paper-module-4.jpg)\n\n---\n\n![Fonts](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD-fonts.jpg)\n![Rotated](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD-Rotated.jpg)\n![7-segFont](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD-7sef_font.jpg)\n![Grayscale](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD_Grayscale.jpg)\n![No power](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD-No_power.jpg)\n"
  },
  {
    "path": "components/epaper/DefaultFont.c",
    "content": "// Default font\r\n\r\n// ========================================================================\r\n// This comes with no warranty, implied or otherwise\r\n\r\n// This data structure was designed to support Proportional fonts\r\n// fonts. Individual characters do not have to be multiples of 8 bits wide.\r\n// Any width is fine and does not need to be fixed.\r\n\r\n// The data bits are packed to minimize data requirements, but the tradeoff\r\n// is that a header is required per character.\r\n\r\n// Header Format:\r\n// ------------------------------------------------\r\n// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)\r\n// Character Height\r\n// First Character (Reserved. 0x00)\r\n// Number Of Characters (Reserved. 0x00)\r\n\r\n// Individual Character Format:\r\n// ----------------------------\r\n// Character Code\r\n// Adjusted Y Offset\t(start Y of visible pixels)\r\n// Width\t\t\t\t(width of the visible pixels)\r\n// Height\t\t\t\t(height of the visible pixels)\r\n// xOffset\t\t\t\t(start X of visible pixels)\r\n// xDelta\t\t\t\t(the distance to move the cursor. Effective width of the character.)\r\n// Data[n]\r\n\r\n// NOTE: You can remove any of these characters if they are not needed in\r\n// your application. The first character number in each Glyph indicates\r\n// the ASCII character code. Therefore, these do not have to be sequential.\r\n// Just remove all the content for a particular character to save space.\r\n// ========================================================================\r\n\r\n// dejavu\r\n// Point Size   : 12\r\n// Memory usage : 1158 bytes\r\n// # characters : 95\r\n\r\nconst unsigned char tft_DefaultFont[] =\r\n{\r\n0x00, 0x0B, 0x86, 0x04,\r\n\r\n// ' '\r\n0x20,0x0A,0x00,0x00,0x00,0x04,\r\n\r\n// '!'\r\n0x21,0x01,0x01,0x09,0x02,0x05,\r\n0xFD,0x80,\r\n// '\"'\r\n0x22,0x01,0x03,0x03,0x01,0x05,\r\n0xB6,0x80,\r\n// '#'\r\n0x23,0x02,0x08,0x08,0x01,0x0A,\r\n0x12,0x14,0x7F,0x24,0x24,0xFE,0x28,0x48,\r\n// '$'\r\n0x24,0x01,0x06,0x0B,0x02,0x08,\r\n0x21,0xCA,0xA8,0xE0,0xE2,0xAA,0x70,0x82,0x00,\r\n// '%'\r\n0x25,0x01,0x0A,0x09,0x00,0x0B,\r\n0x61,0x24,0x89,0x22,0x50,0x6D,0x82,0x91,0x24,0x49,0x21,0x80,\r\n// '&'\r\n0x26,0x01,0x09,0x09,0x01,0x0A,\r\n0x30,0x24,0x10,0x0C,0x05,0x14,0x4A,0x19,0x8C,0x7B,0x00,\r\n// '''\r\n0x27,0x01,0x01,0x03,0x01,0x03,\r\n0xE0,\r\n// '('\r\n0x28,0x00,0x03,0x0B,0x01,0x05,\r\n0x69,0x49,0x24,0x48,0x80,\r\n// ')'\r\n0x29,0x00,0x03,0x0B,0x01,0x05,\r\n0x89,0x12,0x49,0x4A,0x00,\r\n// '*'\r\n0x2A,0x01,0x05,0x06,0x01,0x06,\r\n0x25,0x5C,0xEA,0x90,\r\n// '+'\r\n0x2B,0x03,0x07,0x07,0x01,0x0A,\r\n0x10,0x20,0x47,0xF1,0x02,0x04,0x00,\r\n// ','\r\n0x2C,0x08,0x01,0x03,0x01,0x04,\r\n0xE0,\r\n// '-'\r\n0x2D,0x06,0x03,0x01,0x01,0x04,\r\n0xE0,\r\n// '.'\r\n0x2E,0x08,0x01,0x02,0x01,0x04,\r\n0xC0,\r\n// '/'\r\n0x2F,0x01,0x04,0x0A,0x00,0x04,\r\n0x11,0x22,0x24,0x44,0x88,\r\n// '0'\r\n0x30,0x01,0x06,0x09,0x01,0x08,\r\n0x79,0x28,0x61,0x86,0x18,0x52,0x78,\r\n// '1'\r\n0x31,0x01,0x05,0x09,0x01,0x08,\r\n0xE1,0x08,0x42,0x10,0x84,0xF8,\r\n// '2'\r\n0x32,0x01,0x07,0x09,0x01,0x08,\r\n0x79,0x18,0x10,0x20,0x82,0x08,0x20,0xFC,\r\n// '3'\r\n0x33,0x01,0x06,0x09,0x01,0x08,\r\n0x7A,0x10,0x41,0x38,0x30,0x63,0x78,\r\n// '4'\r\n0x34,0x01,0x06,0x09,0x01,0x08,\r\n0x18,0x62,0x92,0x4A,0x2F,0xC2,0x08,\r\n// '5'\r\n0x35,0x01,0x06,0x09,0x01,0x08,\r\n0xFA,0x08,0x3C,0x0C,0x10,0x63,0x78,\r\n// '6'\r\n0x36,0x01,0x06,0x09,0x01,0x08,\r\n0x39,0x18,0x3E,0xCE,0x18,0x53,0x78,\r\n// '7'\r\n0x37,0x01,0x06,0x09,0x01,0x08,\r\n0xFC,0x10,0x82,0x10,0x42,0x08,0x40,\r\n// '8'\r\n0x38,0x01,0x06,0x09,0x01,0x08,\r\n0x7B,0x38,0x73,0x7B,0x38,0x73,0x78,\r\n// '9'\r\n0x39,0x01,0x06,0x09,0x01,0x08,\r\n0x7B,0x28,0x61,0xCD,0xD0,0x62,0x70,\r\n// ':'\r\n0x3A,0x04,0x01,0x06,0x01,0x04,\r\n0xCC,\r\n// ';'\r\n0x3B,0x04,0x01,0x07,0x01,0x04,\r\n0xCE,\r\n// '<'\r\n0x3C,0x03,0x08,0x06,0x01,0x0A,\r\n0x03,0x1E,0xE0,0xE0,0x1E,0x03,\r\n// '='\r\n0x3D,0x05,0x08,0x03,0x01,0x0A,\r\n0xFF,0x00,0xFF,\r\n// '>'\r\n0x3E,0x03,0x08,0x06,0x01,0x0A,\r\n0xC0,0x78,0x07,0x07,0x78,0xC0,\r\n// '?'\r\n0x3F,0x01,0x05,0x09,0x00,0x06,\r\n0x74,0x42,0x22,0x10,0x04,0x20,\r\n// '@'\r\n0x40,0x01,0x0B,0x0B,0x01,0x0D,\r\n0x1F,0x06,0x19,0x01,0x46,0x99,0x13,0x22,0x64,0x54,0x6C,0x40,0x04,0x10,0x7C,0x00,\r\n// 'A'\r\n0x41,0x01,0x08,0x09,0x00,0x08,\r\n0x18,0x18,0x24,0x24,0x24,0x42,0x7E,0x42,0x81,\r\n// 'B'\r\n0x42,0x01,0x06,0x09,0x01,0x08,\r\n0xFA,0x18,0x61,0xFA,0x18,0x61,0xF8,\r\n// 'C'\r\n0x43,0x01,0x06,0x09,0x01,0x08,\r\n0x39,0x18,0x20,0x82,0x08,0x11,0x38,\r\n// 'D'\r\n0x44,0x01,0x07,0x09,0x01,0x09,\r\n0xF9,0x0A,0x0C,0x18,0x30,0x60,0xC2,0xF8,\r\n// 'E'\r\n0x45,0x01,0x06,0x09,0x01,0x08,\r\n0xFE,0x08,0x20,0xFE,0x08,0x20,0xFC,\r\n// 'F'\r\n0x46,0x01,0x05,0x09,0x01,0x07,\r\n0xFC,0x21,0x0F,0xC2,0x10,0x80,\r\n// 'G'\r\n0x47,0x01,0x07,0x09,0x01,0x09,\r\n0x3C,0x86,0x04,0x08,0xF0,0x60,0xA1,0x3C,\r\n// 'H'\r\n0x48,0x01,0x07,0x09,0x01,0x09,\r\n0x83,0x06,0x0C,0x1F,0xF0,0x60,0xC1,0x82,\r\n// 'I'\r\n0x49,0x01,0x01,0x09,0x01,0x03,\r\n0xFF,0x80,\r\n// 'J'\r\n0x4A,0x01,0x03,0x0B,0xFF,0x03,\r\n0x24,0x92,0x49,0x27,0x00,\r\n// 'K'\r\n0x4B,0x01,0x07,0x09,0x01,0x07,\r\n0x85,0x12,0x45,0x0C,0x14,0x24,0x44,0x84,\r\n// 'L'\r\n0x4C,0x01,0x05,0x09,0x01,0x06,\r\n0x84,0x21,0x08,0x42,0x10,0xF8,\r\n// 'M'\r\n0x4D,0x01,0x08,0x09,0x01,0x0A,\r\n0x81,0xC3,0xC3,0xA5,0xA5,0x99,0x99,0x81,0x81,\r\n// 'N'\r\n0x4E,0x01,0x07,0x09,0x01,0x09,\r\n0xC3,0x86,0x8D,0x19,0x31,0x62,0xC3,0x86,\r\n// 'O'\r\n0x4F,0x01,0x07,0x09,0x01,0x09,\r\n0x38,0x8A,0x0C,0x18,0x30,0x60,0xA2,0x38,\r\n// 'P'\r\n0x50,0x01,0x06,0x09,0x01,0x08,\r\n0xFA,0x38,0x63,0xFA,0x08,0x20,0x80,\r\n// 'Q'\r\n0x51,0x01,0x07,0x0B,0x01,0x09,\r\n0x38,0x8A,0x0C,0x18,0x30,0x60,0xA2,0x38,0x10,0x10,\r\n// 'R'\r\n0x52,0x01,0x07,0x09,0x01,0x08,\r\n0xF9,0x1A,0x14,0x6F,0x91,0x21,0x42,0x82,\r\n// 'S'\r\n0x53,0x01,0x06,0x09,0x01,0x08,\r\n0x7B,0x18,0x30,0x78,0x30,0x63,0x78,\r\n// 'T'\r\n0x54,0x01,0x07,0x09,0x00,0x07,\r\n0xFE,0x20,0x40,0x81,0x02,0x04,0x08,0x10,\r\n// 'U'\r\n0x55,0x01,0x07,0x09,0x01,0x09,\r\n0x83,0x06,0x0C,0x18,0x30,0x60,0xA2,0x38,\r\n// 'V'\r\n0x56,0x01,0x0A,0x09,0xFF,0x08,\r\n0x40,0x90,0x22,0x10,0x84,0x21,0x04,0x81,0x20,0x30,0x0C,0x00,\r\n// 'W'\r\n0x57,0x01,0x0B,0x09,0x00,0x0B,\r\n0x84,0x28,0x89,0x11,0x27,0x22,0xA8,0x55,0x0E,0xE0,0x88,0x11,0x00,\r\n// 'X'\r\n0x58,0x01,0x07,0x09,0x00,0x07,\r\n0xC6,0x88,0xA1,0xC1,0x07,0x0A,0x22,0x82,\r\n// 'Y'\r\n0x59,0x01,0x07,0x09,0x00,0x07,\r\n0x82,0x89,0x11,0x43,0x82,0x04,0x08,0x10,\r\n// 'Z'\r\n0x5A,0x01,0x07,0x09,0x01,0x09,\r\n0xFE,0x04,0x10,0x41,0x04,0x10,0x40,0xFE,\r\n// '['\r\n0x5B,0x01,0x02,0x0B,0x02,0x05,\r\n0xEA,0xAA,0xAC,\r\n// '\\'\r\n0x5C,0x01,0x04,0x0A,0x00,0x04,\r\n0x88,0x44,0x42,0x22,0x11,\r\n// ']'\r\n0x5D,0x01,0x02,0x0B,0x01,0x05,\r\n0xD5,0x55,0x5C,\r\n// '^'\r\n0x5E,0x01,0x08,0x03,0x01,0x0A,\r\n0x18,0x24,0x42,\r\n// '_'\r\n0x5F,0x0C,0x06,0x01,0x00,0x06,\r\n0xFC,\r\n// '`'\r\n0x60,0x00,0x03,0x02,0x01,0x06,\r\n0x44,\r\n// 'a'\r\n0x61,0x03,0x06,0x07,0x01,0x08,\r\n0x7A,0x30,0x5F,0x86,0x37,0x40,\r\n// 'b'\r\n0x62,0x00,0x06,0x0A,0x01,0x08,\r\n0x82,0x08,0x2E,0xCA,0x18,0x61,0xCE,0xE0,\r\n// 'c'\r\n0x63,0x03,0x05,0x07,0x01,0x07,\r\n0x72,0x61,0x08,0x25,0xC0,\r\n// 'd'\r\n0x64,0x00,0x06,0x0A,0x01,0x08,\r\n0x04,0x10,0x5D,0xCE,0x18,0x61,0xCD,0xD0,\r\n// 'e'\r\n0x65,0x03,0x06,0x07,0x01,0x08,\r\n0x39,0x38,0x7F,0x81,0x13,0x80,\r\n// 'f'\r\n0x66,0x00,0x04,0x0A,0x00,0x04,\r\n0x34,0x4F,0x44,0x44,0x44,\r\n// 'g'\r\n0x67,0x03,0x06,0x0A,0x01,0x08,\r\n0x77,0x38,0x61,0x87,0x37,0x41,0x4C,0xE0,\r\n// 'h'\r\n0x68,0x00,0x06,0x0A,0x01,0x08,\r\n0x82,0x08,0x2E,0xC6,0x18,0x61,0x86,0x10,\r\n// 'i'\r\n0x69,0x01,0x01,0x09,0x01,0x03,\r\n0xBF,0x80,\r\n// 'j'\r\n0x6A,0x01,0x02,0x0C,0x00,0x03,\r\n0x45,0x55,0x56,\r\n// 'k'\r\n0x6B,0x00,0x06,0x0A,0x01,0x07,\r\n0x82,0x08,0x22,0x92,0x8E,0x28,0x92,0x20,\r\n// 'l'\r\n0x6C,0x00,0x01,0x0A,0x01,0x03,\r\n0xFF,0xC0,\r\n// 'm'\r\n0x6D,0x03,0x09,0x07,0x01,0x0B,\r\n0xB3,0x66,0x62,0x31,0x18,0x8C,0x46,0x22,\r\n// 'n'\r\n0x6E,0x03,0x06,0x07,0x01,0x08,\r\n0xBB,0x18,0x61,0x86,0x18,0x40,\r\n// 'o'\r\n0x6F,0x03,0x06,0x07,0x01,0x08,\r\n0x7B,0x38,0x61,0x87,0x37,0x80,\r\n// 'p'\r\n0x70,0x03,0x06,0x0A,0x01,0x08,\r\n0xBB,0x28,0x61,0x87,0x3B,0xA0,0x82,0x00,\r\n// 'q'\r\n0x71,0x03,0x06,0x0A,0x01,0x08,\r\n0x77,0x38,0x61,0x87,0x37,0x41,0x04,0x10,\r\n// 'r'\r\n0x72,0x03,0x04,0x07,0x01,0x05,\r\n0xBC,0x88,0x88,0x80,\r\n// 's'\r\n0x73,0x03,0x06,0x07,0x01,0x07,\r\n0x72,0x28,0x1C,0x0A,0x27,0x00,\r\n// 't'\r\n0x74,0x01,0x04,0x09,0x00,0x05,\r\n0x44,0xF4,0x44,0x44,0x30,\r\n// 'u'\r\n0x75,0x03,0x06,0x07,0x01,0x08,\r\n0x86,0x18,0x61,0x86,0x37,0x40,\r\n// 'v'\r\n0x76,0x03,0x08,0x07,0xFF,0x06,\r\n0x42,0x42,0x24,0x24,0x24,0x18,0x18,\r\n// 'w'\r\n0x77,0x03,0x09,0x07,0x00,0x09,\r\n0x88,0xC4,0x57,0x4A,0xA5,0x51,0x10,0x88,\r\n// 'x'\r\n0x78,0x03,0x06,0x07,0x00,0x06,\r\n0x85,0x24,0x8C,0x49,0x28,0x40,\r\n// 'y'\r\n0x79,0x03,0x08,0x0A,0xFF,0x06,\r\n0x42,0x42,0x24,0x24,0x14,0x18,0x08,0x08,0x10,0x60,\r\n// 'z'\r\n0x7A,0x03,0x05,0x07,0x00,0x05,\r\n0xF8,0x44,0x44,0x43,0xE0,\r\n// '{'\r\n0x7B,0x01,0x05,0x0B,0x02,0x08,\r\n0x19,0x08,0x42,0x60,0x84,0x21,0x06,\r\n// '|'\r\n0x7C,0x01,0x01,0x0C,0x02,0x04,\r\n0xFF,0xF0,\r\n// '}'\r\n0x7D,0x01,0x05,0x0B,0x01,0x08,\r\n0xC1,0x08,0x42,0x0C,0x84,0x21,0x30,\r\n// '~'\r\n0x7E,0x04,0x08,0x03,0x01,0x0A,\r\n0x00,0x71,0x8E,\r\n\r\n// Terminator\r\n0xFF\r\n};\r\n"
  },
  {
    "path": "components/epaper/DejaVuSans18.c",
    "content": "// ============================================================================\r\n// Proportional font Header Format:\r\n// ------------------------------------------------\r\n// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)\r\n// Character Height\r\n// First Character (Reserved. 0x00)\r\n// Number Of Characters (Reserved. 0x00)\r\n\r\n// Individual Character Format:\r\n// ----------------------------\r\n// Character Code\r\n// Adjusted Y Offset\r\n// Width\r\n// Height\r\n// xOffset\r\n// xDelta (the distance to move the cursor. Effective width of the character.)\r\n// Data[n]\r\n\r\n// NOTE: You can remove any of these characters if they are not needed in\r\n// your application. The first character number in each Glyph indicates\r\n// the ASCII character code. Therefore, these do not have to be sequential.\r\n// Just remove all the content for a particular character to save space.\r\n// ============================================================================\r\n\r\n// DejaVuSans\r\n// Point Size   : 18\r\n// Memory usage : 1828 bytes\r\n// # characters : 95\r\n\r\nconst unsigned char tft_Dejavu18x[] =\r\n{\r\n0x00, 0x12, 0x00, 0x00,\r\n\r\n// ' '\r\n0x20,0x0E,0x00,0x00,0x00,0x06,\r\n\r\n// '!'\r\n0x21,0x01,0x02,0x0D,0x03,0x07,\r\n0xFF,0xFF,0xC3,0xC0,\r\n// '\"'\r\n0x22,0x01,0x06,0x05,0x01,0x08,\r\n0xCF,0x3C,0xF3,0xCC,\r\n// '#'\r\n0x23,0x00,0x0C,0x0E,0x01,0x0F,\r\n0x04,0x40,0x44,0x0C,0xC0,0xC8,0x7F,0xF7,0xFF,0x09,0x81,0x90,0xFF,0xEF,0xFE,0x13,0x03,0x30,0x32,0x02,0x20,\r\n// '$'\r\n0x24,0x00,0x0A,0x11,0x01,0x0B,\r\n0x08,0x02,0x03,0xE1,0xFC,0xE9,0x32,0x0F,0x81,0xF8,0x0F,0x02,0x60,0x9A,0x2E,0xFF,0x1F,0x80,0x80,0x20,0x08,0x00,\r\n// '%'\r\n0x25,0x01,0x0F,0x0D,0x01,0x11,\r\n0x78,0x10,0x90,0x43,0x31,0x86,0x62,0x0C,0xC8,0x19,0x10,0x1E,0x4F,0x01,0x12,0x02,0x66,0x08,0xCC,0x31,0x98,0x41,0x21,0x03,0xC0,\r\n// '&'\r\n0x26,0x01,0x0C,0x0D,0x01,0x0D,\r\n0x0F,0x01,0xF8,0x30,0x83,0x00,0x38,0x03,0xC0,0x7E,0x6C,0x76,0xC3,0xCC,0x18,0xE1,0xC7,0xFE,0x3E,0x70,\r\n// '''\r\n0x27,0x01,0x02,0x05,0x01,0x04,\r\n0xFF,0xC0,\r\n// '('\r\n0x28,0x00,0x04,0x10,0x02,0x07,\r\n0x32,0x66,0x4C,0xCC,0xCC,0xC4,0x66,0x23,\r\n// ')'\r\n0x29,0x00,0x04,0x10,0x01,0x07,\r\n0xC4,0x66,0x23,0x33,0x33,0x32,0x66,0x4C,\r\n// '*'\r\n0x2A,0x01,0x07,0x08,0x01,0x09,\r\n0x11,0x25,0x51,0xC3,0x8A,0xA4,0x88,\r\n// '+'\r\n0x2B,0x02,0x0C,0x0C,0x02,0x0F,\r\n0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x0F,0xFF,0xFF,0xF0,0x60,0x06,0x00,0x60,0x06,0x00,0x60,\r\n// ','\r\n0x2C,0x0C,0x03,0x04,0x01,0x06,\r\n0x6D,0x40,\r\n// '-'\r\n0x2D,0x08,0x05,0x02,0x01,0x07,\r\n0xFF,0xC0,\r\n// '.'\r\n0x2E,0x0C,0x02,0x02,0x02,0x06,\r\n0xF0,\r\n// '/'\r\n0x2F,0x01,0x06,0x0F,0x00,0x06,\r\n0x0C,0x31,0x86,0x18,0xE3,0x0C,0x31,0xC6,0x18,0x63,0x0C,0x00,\r\n// '0'\r\n0x30,0x01,0x09,0x0D,0x01,0x0B,\r\n0x3E,0x3F,0x98,0xD8,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xD8,0xCF,0xE3,0xE0,\r\n// '1'\r\n0x31,0x01,0x08,0x0D,0x02,0x0B,\r\n0x38,0xF8,0xD8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0xFF,\r\n// '2'\r\n0x32,0x01,0x09,0x0D,0x01,0x0B,\r\n0x7C,0x7F,0x21,0xC0,0x60,0x30,0x30,0x18,0x18,0x18,0x18,0x18,0x1F,0xEF,0xF0,\r\n// '3'\r\n0x33,0x01,0x09,0x0D,0x01,0x0B,\r\n0x7E,0x7F,0xA0,0xE0,0x30,0x39,0xF0,0xFC,0x07,0x01,0x80,0xE0,0xFF,0xE7,0xE0,\r\n// '4'\r\n0x34,0x01,0x0A,0x0D,0x01,0x0B,\r\n0x07,0x01,0xC0,0xB0,0x6C,0x13,0x08,0xC6,0x31,0x0C,0xFF,0xFF,0xF0,0x30,0x0C,0x03,0x00,\r\n// '5'\r\n0x35,0x01,0x08,0x0D,0x01,0x0B,\r\n0x7E,0x7E,0x60,0x60,0x7C,0x7E,0x47,0x03,0x03,0x03,0x87,0xFE,0x7C,\r\n// '6'\r\n0x36,0x01,0x09,0x0D,0x01,0x0B,\r\n0x1E,0x1F,0x9C,0x5C,0x0C,0x06,0xF3,0xFD,0xC7,0xC1,0xE0,0xD8,0xEF,0xE1,0xE0,\r\n// '7'\r\n0x37,0x01,0x08,0x0D,0x01,0x0B,\r\n0xFF,0xFF,0x06,0x06,0x06,0x0E,0x0C,0x0C,0x1C,0x18,0x18,0x38,0x30,\r\n// '8'\r\n0x38,0x01,0x09,0x0D,0x01,0x0B,\r\n0x3E,0x3F,0xB8,0xF8,0x3E,0x39,0xF1,0xFD,0xC7,0xC1,0xE0,0xF8,0xEF,0xE3,0xE0,\r\n// '9'\r\n0x39,0x01,0x09,0x0D,0x01,0x0B,\r\n0x3C,0x3F,0xB8,0xD8,0x3C,0x1F,0x1D,0xFE,0x7B,0x01,0x81,0xD1,0xCF,0xC3,0xC0,\r\n// ':'\r\n0x3A,0x05,0x02,0x09,0x02,0x06,\r\n0xF0,0x03,0xC0,\r\n// ';'\r\n0x3B,0x05,0x03,0x0B,0x01,0x06,\r\n0x6C,0x00,0x03,0x6A,0x00,\r\n// '<'\r\n0x3C,0x04,0x0B,0x0A,0x02,0x0F,\r\n0x00,0x20,0x3C,0x1F,0x1F,0x0F,0x81,0xF0,0x0F,0x80,0x3E,0x01,0xE0,0x04,\r\n// '='\r\n0x3D,0x05,0x0B,0x06,0x02,0x0F,\r\n0xFF,0xFF,0xFC,0x00,0x00,0x0F,0xFF,0xFF,0xC0,\r\n// '>'\r\n0x3E,0x04,0x0B,0x0A,0x02,0x0F,\r\n0x80,0x1E,0x01,0xF0,0x07,0xC0,0x3E,0x07,0xC3,0xE3,0xE0,0xF0,0x10,0x00,\r\n// '?'\r\n0x3F,0x01,0x07,0x0D,0x01,0x0A,\r\n0x79,0xFA,0x38,0x30,0x61,0x86,0x18,0x30,0x60,0x01,0x83,0x00,\r\n// '@'\r\n0x40,0x01,0x10,0x10,0x01,0x12,\r\n0x07,0xE0,0x1F,0xF8,0x3C,0x1C,0x70,0x06,0x60,0x07,0xE3,0x63,0xC7,0xE3,0xC6,0x63,0xC6,0x66,0xC7,0xFC,0xE3,0x70,0x60,0x00,0x70,0x00,0x3C,0x30,0x1F,0xF0,0x07,0xC0,\r\n// 'A'\r\n0x41,0x01,0x0C,0x0D,0x00,0x0C,\r\n0x06,0x00,0x60,0x0F,0x00,0xF0,0x19,0x81,0x98,0x19,0x83,0x0C,0x3F,0xC7,0xFE,0x60,0x66,0x06,0xC0,0x30,\r\n// 'B'\r\n0x42,0x01,0x09,0x0D,0x02,0x0C,\r\n0xFC,0x7F,0xB0,0xD8,0x6C,0x37,0xF3,0xF9,0x86,0xC1,0xE0,0xF0,0xFF,0xEF,0xE0,\r\n// 'C'\r\n0x43,0x01,0x0B,0x0D,0x01,0x0D,\r\n0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x9F,0xF0,0xFC,\r\n// 'D'\r\n0x44,0x01,0x0B,0x0D,0x02,0x0E,\r\n0xFE,0x1F,0xF3,0x07,0x60,0x6C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1B,0x07,0x7F,0xCF,0xE0,\r\n// 'E'\r\n0x45,0x01,0x08,0x0D,0x02,0x0B,\r\n0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,\r\n// 'F'\r\n0x46,0x01,0x08,0x0D,0x02,0x0A,\r\n0xFF,0xFF,0xC0,0xC0,0xC0,0xFE,0xFE,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,\r\n// 'G'\r\n0x47,0x01,0x0B,0x0D,0x01,0x0E,\r\n0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x87,0xF0,0xFE,0x03,0xC0,0x6C,0x0D,0xC1,0x9F,0xE0,0xF8,\r\n// 'H'\r\n0x48,0x01,0x0A,0x0D,0x02,0x0E,\r\n0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xFF,0xFF,0xFF,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xC0,\r\n// 'I'\r\n0x49,0x01,0x02,0x0D,0x02,0x06,\r\n0xFF,0xFF,0xFF,0xC0,\r\n// 'J'\r\n0x4A,0x01,0x05,0x11,0xFF,0x06,\r\n0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0xFE,0xE0,\r\n// 'K'\r\n0x4B,0x01,0x0B,0x0D,0x02,0x0C,\r\n0xC1,0x98,0x63,0x18,0x66,0x0D,0x81,0xE0,0x3C,0x06,0xC0,0xCC,0x18,0xC3,0x0C,0x60,0xCC,0x0C,\r\n// 'L'\r\n0x4C,0x01,0x08,0x0D,0x02,0x0A,\r\n0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,\r\n// 'M'\r\n0x4D,0x01,0x0C,0x0D,0x02,0x10,\r\n0xE0,0x7F,0x0F,0xF0,0xFD,0x8B,0xD9,0xBD,0x9B,0xCF,0x3C,0xF3,0xC6,0x3C,0x63,0xC0,0x3C,0x03,0xC0,0x30,\r\n// 'N'\r\n0x4E,0x01,0x0A,0x0D,0x02,0x0E,\r\n0xE0,0xF8,0x3F,0x0F,0xC3,0xD8,0xF6,0x3C,0xCF,0x1B,0xC6,0xF0,0xFC,0x3F,0x07,0xC1,0xC0,\r\n// 'O'\r\n0x4F,0x01,0x0C,0x0D,0x01,0x0E,\r\n0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,\r\n// 'P'\r\n0x50,0x01,0x08,0x0D,0x02,0x0B,\r\n0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0,\r\n// 'Q'\r\n0x51,0x01,0x0C,0x0F,0x01,0x0E,\r\n0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,0x18,0x00,0xC0,\r\n// 'R'\r\n0x52,0x01,0x0A,0x0D,0x02,0x0D,\r\n0xFC,0x3F,0x8C,0x73,0x0C,0xC3,0x31,0xCF,0xE3,0xF0,0xC6,0x30,0xCC,0x33,0x06,0xC1,0xC0,\r\n// 'S'\r\n0x53,0x01,0x0A,0x0D,0x01,0x0B,\r\n0x3E,0x1F,0xCE,0x13,0x00,0xC0,0x1F,0x03,0xF0,0x0E,0x01,0x80,0x68,0x3B,0xFC,0x7E,0x00,\r\n// 'T'\r\n0x54,0x01,0x0C,0x0D,0x00,0x0C,\r\n0xFF,0xFF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,\r\n// 'U'\r\n0x55,0x01,0x0A,0x0D,0x02,0x0E,\r\n0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x36,0x19,0xFE,0x1E,0x00,\r\n// 'V'\r\n0x56,0x01,0x0C,0x0D,0x00,0x0C,\r\n0xC0,0x36,0x06,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,0x06,0x00,\r\n// 'W'\r\n0x57,0x01,0x11,0x0D,0x01,0x13,\r\n0xC1,0xC1,0xE0,0xE0,0xD8,0xF8,0xCC,0x6C,0x66,0x36,0x33,0x1B,0x18,0xD8,0xD8,0x6C,0x6C,0x36,0x36,0x1F,0x1F,0x07,0x07,0x03,0x83,0x81,0xC1,0xC0,\r\n// 'X'\r\n0x58,0x01,0x0B,0x0D,0x01,0x0D,\r\n0x70,0xE6,0x18,0xE6,0x0D,0xC0,0xF0,0x1C,0x03,0x80,0x78,0x1B,0x07,0x30,0xC7,0x30,0x6E,0x0E,\r\n// 'Y'\r\n0x59,0x01,0x0C,0x0D,0x00,0x0C,\r\n0xE0,0x76,0x06,0x30,0xC1,0x98,0x19,0x80,0xF0,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,\r\n// 'Z'\r\n0x5A,0x01,0x0B,0x0D,0x01,0x0D,\r\n0xFF,0xFF,0xFC,0x07,0x01,0xC0,0x30,0x0E,0x03,0x80,0xE0,0x18,0x06,0x01,0xC0,0x7F,0xFF,0xFE,\r\n// '['\r\n0x5B,0x00,0x04,0x10,0x01,0x07,\r\n0xFF,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFF,\r\n// '\\'\r\n0x5C,0x01,0x06,0x0F,0x00,0x06,\r\n0xC3,0x06,0x18,0x61,0xC3,0x0C,0x30,0xE1,0x86,0x18,0x30,0xC0,\r\n// ']'\r\n0x5D,0x00,0x04,0x10,0x02,0x07,\r\n0xFF,0x33,0x33,0x33,0x33,0x33,0x33,0xFF,\r\n// '^'\r\n0x5E,0x01,0x0B,0x05,0x02,0x0F,\r\n0x0E,0x03,0xE0,0xC6,0x30,0x6C,0x06,\r\n// '_'\r\n0x5F,0x10,0x09,0x02,0x00,0x09,\r\n0xFF,0xFF,0xC0,\r\n// '`'\r\n0x60,0x00,0x04,0x03,0x02,0x09,\r\n0xC6,0x30,\r\n// 'a'\r\n0x61,0x04,0x08,0x0A,0x01,0x0A,\r\n0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,\r\n// 'b'\r\n0x62,0x00,0x09,0x0E,0x02,0x0B,\r\n0xC0,0x60,0x30,0x18,0x0D,0xE7,0xFB,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x7F,0xF6,0xF0,\r\n// 'c'\r\n0x63,0x04,0x08,0x0A,0x01,0x09,\r\n0x1E,0x7F,0x61,0xC0,0xC0,0xC0,0xC0,0x61,0x7F,0x1E,\r\n// 'd'\r\n0x64,0x00,0x09,0x0E,0x01,0x0B,\r\n0x01,0x80,0xC0,0x60,0x33,0xDB,0xFF,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x77,0xF9,0xEC,\r\n// 'e'\r\n0x65,0x04,0x0A,0x0A,0x01,0x0B,\r\n0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,\r\n// 'f'\r\n0x66,0x00,0x07,0x0E,0x00,0x06,\r\n0x1E,0x7C,0xC1,0x8F,0xFF,0xCC,0x18,0x30,0x60,0xC1,0x83,0x06,0x00,\r\n// 'g'\r\n0x67,0x04,0x09,0x0E,0x01,0x0B,\r\n0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x68,0x67,0xF1,0xF0,\r\n// 'h'\r\n0x68,0x00,0x08,0x0E,0x02,0x0B,\r\n0xC0,0xC0,0xC0,0xC0,0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,\r\n// 'i'\r\n0x69,0x00,0x02,0x0E,0x02,0x05,\r\n0xF0,0xFF,0xFF,0xF0,\r\n// 'j'\r\n0x6A,0x00,0x04,0x12,0x00,0x05,\r\n0x33,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0xEC,\r\n// 'k'\r\n0x6B,0x00,0x09,0x0E,0x02,0x0A,\r\n0xC0,0x60,0x30,0x18,0x0C,0x36,0x33,0x31,0xB0,0xF0,0x78,0x36,0x19,0x8C,0x66,0x18,\r\n// 'l'\r\n0x6C,0x00,0x02,0x0E,0x02,0x05,\r\n0xFF,0xFF,0xFF,0xF0,\r\n// 'm'\r\n0x6D,0x04,0x0E,0x0A,0x02,0x11,\r\n0xDC,0x7B,0xFB,0xEE,0x79,0xF0,0xC3,0xC3,0x0F,0x0C,0x3C,0x30,0xF0,0xC3,0xC3,0x0F,0x0C,0x30,\r\n// 'n'\r\n0x6E,0x04,0x08,0x0A,0x02,0x0B,\r\n0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,\r\n// 'o'\r\n0x6F,0x04,0x0A,0x0A,0x01,0x0B,\r\n0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,\r\n// 'p'\r\n0x70,0x04,0x09,0x0E,0x02,0x0B,\r\n0xDE,0x7F,0xB8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0xFF,0x6F,0x30,0x18,0x0C,0x06,0x00,\r\n// 'q'\r\n0x71,0x04,0x09,0x0E,0x01,0x0B,\r\n0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x60,0x30,0x18,0x0C,\r\n// 'r'\r\n0x72,0x04,0x06,0x0A,0x02,0x08,\r\n0xDF,0xFE,0x30,0xC3,0x0C,0x30,0xC3,0x00,\r\n// 's'\r\n0x73,0x04,0x08,0x0A,0x01,0x08,\r\n0x7C,0xFE,0xC2,0xE0,0x7C,0x1E,0x06,0x86,0xFE,0x78,\r\n// 't'\r\n0x74,0x01,0x06,0x0D,0x01,0x07,\r\n0x61,0x86,0x3F,0xFD,0x86,0x18,0x61,0x86,0x1F,0x3C,\r\n// 'u'\r\n0x75,0x04,0x08,0x0A,0x02,0x0B,\r\n0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,\r\n// 'v'\r\n0x76,0x04,0x0C,0x0A,0x00,0x0B,\r\n0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,\r\n// 'w'\r\n0x77,0x04,0x0F,0x0A,0x01,0x10,\r\n0x63,0x8C,0xC7,0x19,0x8E,0x31,0xB6,0xC3,0x6D,0x86,0xDB,0x0F,0x1E,0x0E,0x38,0x1C,0x70,0x38,0xE0,\r\n// 'x'\r\n0x78,0x04,0x0A,0x0A,0x01,0x0B,\r\n0xE1,0xD8,0x63,0x30,0xCC,0x1E,0x07,0x83,0x30,0xCC,0x61,0xB8,0x70,\r\n// 'y'\r\n0x79,0x04,0x0C,0x0E,0x00,0x0B,\r\n0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80,\r\n// 'z'\r\n0x7A,0x04,0x08,0x0A,0x01,0x09,\r\n0xFF,0xFF,0x06,0x0C,0x1C,0x38,0x30,0x70,0xFF,0xFF,\r\n// '{'\r\n0x7B,0x00,0x08,0x11,0x02,0x0B,\r\n0x0F,0x1F,0x18,0x18,0x18,0x18,0x38,0xF0,0xF0,0x38,0x18,0x18,0x18,0x18,0x18,0x1F,0x0F,\r\n// '|'\r\n0x7C,0x00,0x02,0x12,0x02,0x06,\r\n0xFF,0xFF,0xFF,0xFF,0xF0,\r\n// '}'\r\n0x7D,0x00,0x08,0x11,0x02,0x0B,\r\n0xF0,0xF8,0x18,0x18,0x18,0x18,0x1C,0x0F,0x0F,0x1C,0x18,0x18,0x18,0x18,0x18,0xF8,0xF0,\r\n// '~'\r\n0x7E,0x05,0x0B,0x05,0x02,0x0F,\r\n0x00,0x0F,0x87,0xFF,0xC3,0xE0,0x00,\r\n\r\n// Terminator\r\n0xFF\r\n};\r\n"
  },
  {
    "path": "components/epaper/DejaVuSans24.c",
    "content": "// ========================================================================\r\n// This comes with no warranty, implied or otherwise\r\n\r\n// This data structure was designed to support Proportional fonts\r\n// fonts. Individual characters do not have to be multiples of 8 bits wide. \r\n// Any width is fine and does not need to be fixed.\r\n\r\n// The data bits are packed to minimize data requirements, but the tradeoff\r\n// is that a header is required per character.\r\n\r\n// Header Format:\r\n// ------------------------------------------------\r\n// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)\r\n// Character Height\r\n// First Character (Reserved. 0x00)\r\n// Number Of Characters (Reserved. 0x00)\r\n\r\n// Individual Character Format:\r\n// ----------------------------\r\n// Character Code\r\n// Adjusted Y Offset\r\n// Width\r\n// Height\r\n// xOffset\r\n// xDelta (the distance to move the cursor. Effective width of the character.)\r\n// Data[n]\r\n\r\n// NOTE: You can remove any of these characters if they are not needed in\r\n// your application. The first character number in each Glyph indicates\r\n// the ASCII character code. Therefore, these do not have to be sequential.\r\n// Just remove all the content for a particular character to save space.\r\n// ========================================================================\r\n\r\n// dejavu\r\n// Point Size   : 24\r\n// Memory usage : 2724 bytes\r\n// # characters : 95\r\n\r\nconst unsigned char tft_Dejavu24[] =\r\n{\r\n0x00, 0x17, 0x00, 0x00,\r\n\r\n// ' '\r\n0x20,0x13,0x00,0x00,0x00,0x08,\r\n\r\n// '!'\r\n0x21,0x01,0x02,0x12,0x04,0x0A,\r\n0xFF,0xFF,0xFF,0x03,0xF0,\r\n// '\"'\r\n0x22,0x01,0x06,0x07,0x02,0x0B,\r\n0xCF,0x3C,0xF3,0xCF,0x3C,0xC0,\r\n// '#'\r\n0x23,0x01,0x10,0x12,0x02,0x14,\r\n0x03,0x08,0x03,0x18,0x03,0x18,0x03,0x18,0x02,0x18,0x7F,0xFF,0x7F,0xFF,0x06,0x30,0x04,0x30,0x0C,0x20,0x0C,0x60,0xFF,0xFE,0xFF,0xFE,0x18,0x40,0x18,0xC0,0x18,0xC0,0x18,0xC0,0x10,0xC0,\r\n// '$'\r\n0x24,0x01,0x0B,0x16,0x02,0x0F,\r\n0x04,0x00,0x80,0x10,0x0F,0xC7,0xFD,0xC8,0xB1,0x06,0x20,0xE4,0x0F,0x80,0xFE,0x03,0xE0,0x4E,0x08,0xC1,0x1E,0x27,0xFF,0xC7,0xE0,0x10,0x02,0x00,0x40,0x08,0x00,\r\n// '%'\r\n0x25,0x01,0x14,0x12,0x01,0x17,\r\n0x3C,0x03,0x06,0x60,0x60,0xC3,0x06,0x0C,0x30,0xC0,0xC3,0x1C,0x0C,0x31,0x80,0xC3,0x38,0x0C,0x33,0x00,0x66,0x63,0xC3,0xC6,0x66,0x00,0xCC,0x30,0x1C,0xC3,0x01,0x8C,0x30,0x38,0xC3,0x03,0x0C,0x30,0x60,0xC3,0x06,0x06,0x60,0xC0,0x3C,\r\n// '&'\r\n0x26,0x01,0x10,0x12,0x01,0x13,\r\n0x07,0xC0,0x1F,0xE0,0x38,0x20,0x30,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x1C,0x00,0x3E,0x00,0x77,0x06,0xE3,0x86,0xC1,0xCC,0xC0,0xFC,0xC0,0x78,0xE0,0x78,0x70,0xFC,0x3F,0xCE,0x0F,0x87,\r\n// '''\r\n0x27,0x01,0x02,0x07,0x02,0x07,\r\n0xFF,0xFC,\r\n// '('\r\n0x28,0x01,0x05,0x15,0x02,0x09,\r\n0x19,0x8C,0xC6,0x31,0x18,0xC6,0x31,0x8C,0x61,0x0C,0x63,0x0C,0x61,0x80,\r\n// ')'\r\n0x29,0x01,0x05,0x15,0x02,0x09,\r\n0xC3,0x18,0x63,0x18,0x43,0x18,0xC6,0x31,0x8C,0x46,0x31,0x98,0xCC,0x00,\r\n// '*'\r\n0x2A,0x01,0x0B,0x0A,0x00,0x0C,\r\n0x04,0x00,0x83,0x11,0xBA,0xE1,0xF0,0x3E,0x1D,0x76,0x23,0x04,0x00,0x80,\r\n// '+'\r\n0x2B,0x03,0x10,0x10,0x03,0x14,\r\n0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0xFF,0xFF,0xFF,0xFF,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,\r\n// ','\r\n0x2C,0x10,0x03,0x06,0x02,0x08,\r\n0x6D,0xBD,0x80,\r\n// '-'\r\n0x2D,0x0B,0x06,0x02,0x01,0x09,\r\n0xFF,0xF0,\r\n// '.'\r\n0x2E,0x10,0x02,0x03,0x03,0x08,\r\n0xFC,\r\n// '/'\r\n0x2F,0x01,0x08,0x14,0x00,0x08,\r\n0x03,0x07,0x06,0x06,0x06,0x0C,0x0C,0x0C,0x18,0x18,0x18,0x18,0x30,0x30,0x30,0x60,0x60,0x60,0xE0,0xC0,\r\n// '0'\r\n0x30,0x01,0x0C,0x12,0x02,0x0F,\r\n0x0F,0x03,0xFC,0x70,0xE6,0x06,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x60,0x67,0x0E,0x3F,0xC0,0xF0,\r\n// '1'\r\n0x31,0x01,0x0A,0x12,0x03,0x0F,\r\n0x3C,0x3F,0x0C,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,\r\n// '2'\r\n0x32,0x01,0x0C,0x12,0x02,0x0F,\r\n0x3F,0x0F,0xF8,0xC1,0xC0,0x0E,0x00,0x60,0x06,0x00,0x60,0x0C,0x01,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xEF,0xFE,\r\n// '3'\r\n0x33,0x01,0x0C,0x12,0x02,0x0F,\r\n0x3F,0x07,0xFC,0x41,0xC0,0x06,0x00,0x60,0x06,0x00,0x60,0x0C,0x1F,0x81,0xFC,0x00,0xE0,0x07,0x00,0x30,0x03,0x00,0x78,0x0E,0xFF,0xC3,0xF0,\r\n// '4'\r\n0x34,0x01,0x0D,0x12,0x01,0x0F,\r\n0x01,0xC0,0x1E,0x00,0xB0,0x0D,0x80,0xCC,0x06,0x60,0x63,0x03,0x18,0x30,0xC3,0x06,0x18,0x31,0x81,0x8F,0xFF,0xFF,0xFC,0x03,0x00,0x18,0x00,0xC0,0x06,0x00,\r\n// '5'\r\n0x35,0x01,0x0B,0x12,0x02,0x0F,\r\n0x7F,0xCF,0xF9,0x80,0x30,0x06,0x00,0xC0,0x1F,0xC3,0xFC,0x41,0xC0,0x1C,0x01,0x80,0x30,0x06,0x00,0xC0,0x3C,0x0E,0xFF,0x8F,0xC0,\r\n// '6'\r\n0x36,0x01,0x0C,0x12,0x02,0x0F,\r\n0x07,0xC1,0xFE,0x38,0x27,0x00,0x60,0x0C,0x00,0xCF,0x8D,0xFC,0xF8,0xEF,0x07,0xE0,0x3E,0x03,0xE0,0x36,0x03,0x70,0x77,0x8E,0x3F,0xC0,0xF8,\r\n// '7'\r\n0x37,0x01,0x0B,0x12,0x02,0x0F,\r\n0xFF,0xFF,0xFC,0x03,0x00,0x60,0x1C,0x03,0x00,0x60,0x18,0x03,0x00,0xE0,0x18,0x03,0x00,0xC0,0x18,0x07,0x00,0xC0,0x18,0x06,0x00,\r\n// '8'\r\n0x38,0x01,0x0C,0x12,0x02,0x0F,\r\n0x1F,0x87,0xFE,0x70,0xEC,0x03,0xC0,0x3C,0x03,0xC0,0x37,0x0E,0x3F,0xC3,0xFC,0x70,0xEC,0x03,0xC0,0x3C,0x03,0xC0,0x37,0x0E,0x7F,0xE1,0xF8,\r\n// '9'\r\n0x39,0x01,0x0C,0x12,0x02,0x0F,\r\n0x1F,0x03,0xFC,0x71,0xCE,0x0E,0xC0,0x6C,0x07,0xC0,0x7C,0x07,0xE0,0xF7,0x1F,0x3F,0xB1,0xF3,0x00,0x30,0x06,0x00,0xE4,0x1C,0x7F,0x83,0xE0,\r\n// ':'\r\n0x3A,0x07,0x02,0x0C,0x03,0x08,\r\n0xFC,0x00,0x3F,\r\n// ';'\r\n0x3B,0x07,0x03,0x0F,0x02,0x08,\r\n0x6D,0x80,0x00,0x0D,0xB7,0xB0,\r\n// '<'\r\n0x3C,0x05,0x0F,0x0D,0x03,0x14,\r\n0x00,0x02,0x00,0x3C,0x03,0xF0,0x3F,0x01,0xF8,0x1F,0x80,0x3C,0x00,0x7E,0x00,0x1F,0x80,0x0F,0xC0,0x03,0xF0,0x00,0xF0,0x00,0x20,\r\n// '='\r\n0x3D,0x08,0x0F,0x07,0x03,0x14,\r\n0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0x80,\r\n// '>'\r\n0x3E,0x05,0x0F,0x0D,0x03,0x14,\r\n0x80,0x01,0xE0,0x01,0xF8,0x00,0x7E,0x00,0x3F,0x00,0x0F,0xC0,0x07,0x80,0x3F,0x03,0xF0,0x1F,0x81,0xF8,0x07,0x80,0x08,0x00,0x00,\r\n// '?'\r\n0x3F,0x01,0x09,0x12,0x02,0x0D,\r\n0x3E,0x3F,0xB0,0xF0,0x30,0x18,0x0C,0x0C,0x0E,0x0E,0x0E,0x06,0x03,0x01,0x80,0x00,0x00,0x30,0x18,0x0C,0x00,\r\n// '@'\r\n0x40,0x02,0x15,0x15,0x02,0x18,\r\n0x00,0xFC,0x00,0x3F,0xF8,0x03,0xC0,0xF0,0x38,0x01,0xC3,0x80,0x07,0x38,0x79,0x99,0x8F,0xEC,0xFC,0x71,0xE3,0xC7,0x07,0x1E,0x30,0x18,0xF1,0x80,0xC7,0x8C,0x06,0x3C,0x70,0x73,0x71,0xC7,0xB9,0x8F,0xEF,0x8E,0x1E,0x70,0x38,0x00,0x00,0xE0,0x04,0x03,0xC0,0xE0,0x0F,0xFE,0x00,0x0F,0x80,0x00,\r\n// 'A'\r\n0x41,0x01,0x10,0x12,0x00,0x10,\r\n0x03,0xC0,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x06,0x60,0x06,0x60,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x18,0x18,0x18,0x18,0x38,0x1C,0x3F,0xFC,0x3F,0xFC,0x60,0x06,0x60,0x06,0x60,0x06,0xC0,0x03,\r\n// 'B'\r\n0x42,0x01,0x0C,0x12,0x02,0x10,\r\n0xFF,0x0F,0xFC,0xC0,0xEC,0x06,0xC0,0x6C,0x06,0xC0,0x6C,0x0C,0xFF,0x8F,0xFC,0xC0,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x06,0xFF,0xEF,0xF8,\r\n// 'C'\r\n0x43,0x01,0x0E,0x12,0x01,0x11,\r\n0x07,0xE0,0x7F,0xE3,0xC1,0xDC,0x01,0x60,0x01,0x80,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x60,0x01,0x80,0x07,0x00,0x4F,0x07,0x1F,0xF8,0x1F,0x80,\r\n// 'D'\r\n0x44,0x01,0x0F,0x12,0x02,0x12,\r\n0xFF,0x81,0xFF,0xE3,0x01,0xE6,0x00,0xEC,0x00,0xD8,0x01,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80,0x0F,0x00,0x1E,0x00,0x3C,0x00,0xF8,0x01,0xB0,0x07,0x60,0x3C,0xFF,0xF1,0xFF,0x00,\r\n// 'E'\r\n0x45,0x01,0x0B,0x12,0x02,0x0F,\r\n0xFF,0xFF,0xFF,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xDF,0xFB,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xFF,0xFC,\r\n// 'F'\r\n0x46,0x01,0x0A,0x12,0x02,0x0E,\r\n0xFF,0xFF,0xFC,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xFF,0xBF,0xEC,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x00,\r\n// 'G'\r\n0x47,0x01,0x0F,0x12,0x01,0x13,\r\n0x07,0xE0,0x3F,0xF0,0xE0,0x73,0x80,0x26,0x00,0x1C,0x00,0x30,0x00,0x60,0x00,0xC0,0x7F,0x80,0xFF,0x00,0x1E,0x00,0x36,0x00,0x6C,0x00,0xDC,0x01,0x9E,0x07,0x1F,0xFC,0x0F,0xE0,\r\n// 'H'\r\n0x48,0x01,0x0D,0x12,0x02,0x12,\r\n0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xFF,0xFF,0xFF,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xC0,\r\n// 'I'\r\n0x49,0x01,0x02,0x12,0x02,0x07,\r\n0xFF,0xFF,0xFF,0xFF,0xF0,\r\n// 'J'\r\n0x4A,0x01,0x06,0x17,0xFE,0x07,\r\n0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x1B,0xEF,0x00,\r\n// 'K'\r\n0x4B,0x01,0x0F,0x12,0x02,0x10,\r\n0xC0,0x71,0x81,0xC3,0x07,0x06,0x1C,0x0C,0x70,0x19,0xC0,0x37,0x00,0x7C,0x00,0xF8,0x01,0xB0,0x03,0x38,0x06,0x38,0x0C,0x38,0x18,0x38,0x30,0x38,0x60,0x38,0xC0,0x39,0x80,0x38,\r\n// 'L'\r\n0x4C,0x01,0x0B,0x12,0x02,0x0D,\r\n0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xFF,0xFC,\r\n// 'M'\r\n0x4D,0x01,0x10,0x12,0x02,0x15,\r\n0xE0,0x07,0xF0,0x0F,0xF0,0x0F,0xF8,0x1F,0xD8,0x1B,0xD8,0x1B,0xCC,0x33,0xCC,0x33,0xCC,0x33,0xC6,0x63,0xC6,0x63,0xC7,0xE3,0xC3,0xC3,0xC3,0xC3,0xC1,0x83,0xC0,0x03,0xC0,0x03,0xC0,0x03,\r\n// 'N'\r\n0x4E,0x01,0x0D,0x12,0x02,0x12,\r\n0xE0,0x1F,0x80,0xFC,0x07,0xF0,0x3D,0x81,0xE6,0x0F,0x30,0x78,0xC3,0xC6,0x1E,0x18,0xF0,0xC7,0x83,0x3C,0x19,0xE0,0x6F,0x03,0x78,0x0F,0xC0,0x7E,0x01,0xC0,\r\n// 'O'\r\n0x4F,0x01,0x10,0x12,0x01,0x13,\r\n0x07,0xE0,0x1F,0xF8,0x3C,0x3C,0x70,0x0E,0x60,0x06,0x60,0x06,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x60,0x06,0x60,0x06,0x70,0x0E,0x3C,0x3C,0x1F,0xF8,0x07,0xE0,\r\n// 'P'\r\n0x50,0x01,0x0B,0x12,0x02,0x0E,\r\n0xFF,0x1F,0xFB,0x07,0x60,0x3C,0x07,0x80,0xF0,0x1E,0x0E,0xFF,0xDF,0xE3,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x00,\r\n// 'Q'\r\n0x51,0x01,0x10,0x15,0x01,0x13,\r\n0x07,0xE0,0x1F,0xF8,0x3C,0x3C,0x70,0x0E,0x60,0x06,0x60,0x06,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x60,0x07,0x60,0x06,0x70,0x0E,0x3C,0x3C,0x1F,0xF8,0x07,0xF0,0x00,0x38,0x00,0x18,0x00,0x0C,\r\n// 'R'\r\n0x52,0x01,0x0D,0x12,0x02,0x11,\r\n0xFF,0x07,0xFE,0x30,0x31,0x80,0xCC,0x06,0x60,0x33,0x01,0x98,0x18,0xFF,0xC7,0xFC,0x30,0x71,0x81,0x8C,0x06,0x60,0x33,0x01,0xD8,0x06,0xC0,0x36,0x00,0xC0,\r\n// 'S'\r\n0x53,0x01,0x0C,0x12,0x02,0x0F,\r\n0x1F,0x87,0xFE,0x70,0x6C,0x00,0xC0,0x0C,0x00,0xC0,0x07,0x00,0x7F,0x01,0xFC,0x00,0xE0,0x07,0x00,0x30,0x03,0x00,0x3C,0x0E,0xFF,0xE3,0xF8,\r\n// 'T'\r\n0x54,0x01,0x0E,0x12,0x00,0x0F,\r\n0xFF,0xFF,0xFF,0xF0,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,\r\n// 'U'\r\n0x55,0x01,0x0D,0x12,0x02,0x12,\r\n0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0D,0x80,0xCE,0x0E,0x3F,0xE0,0x7C,0x00,\r\n// 'V'\r\n0x56,0x01,0x10,0x12,0x00,0x10,\r\n0xC0,0x03,0x60,0x06,0x60,0x06,0x60,0x06,0x30,0x0C,0x30,0x0C,0x38,0x1C,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x06,0x60,0x06,0x60,0x07,0x60,0x03,0xC0,0x03,0xC0,0x03,0xC0,\r\n// 'W'\r\n0x57,0x01,0x16,0x12,0x01,0x18,\r\n0xC0,0x78,0x0F,0x01,0xE0,0x36,0x07,0x81,0x98,0x1E,0x06,0x60,0xEC,0x19,0x83,0x30,0x63,0x0C,0xC3,0x0C,0x33,0x0C,0x30,0xCE,0x30,0xC6,0x18,0xC1,0x98,0x66,0x06,0x61,0x98,0x19,0x86,0x60,0x6C,0x0D,0x80,0xF0,0x3C,0x03,0xC0,0xF0,0x0F,0x03,0xC0,0x38,0x07,0x00,\r\n// 'X'\r\n0x58,0x01,0x0F,0x12,0x01,0x11,\r\n0x70,0x0E,0x60,0x18,0x60,0x60,0xE1,0xC0,0xC7,0x00,0xCC,0x01,0xF0,0x01,0xE0,0x03,0x80,0x07,0x80,0x1F,0x00,0x37,0x00,0xC6,0x03,0x86,0x0E,0x0E,0x18,0x0C,0x60,0x0D,0xC0,0x1C,\r\n// 'Y'\r\n0x59,0x01,0x0E,0x12,0x00,0x0F,\r\n0xE0,0x1D,0x80,0x63,0x03,0x0E,0x1C,0x18,0x60,0x33,0x00,0xFC,0x01,0xE0,0x07,0x80,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,\r\n// 'Z'\r\n0x5A,0x01,0x0E,0x12,0x01,0x10,\r\n0xFF,0xFF,0xFF,0xF0,0x01,0x80,0x0E,0x00,0x70,0x01,0x80,0x0C,0x00,0x60,0x03,0x80,0x1C,0x00,0x60,0x03,0x00,0x18,0x00,0xE0,0x07,0x00,0x18,0x00,0xFF,0xFF,0xFF,0xF0,\r\n// '['\r\n0x5B,0x01,0x05,0x15,0x02,0x09,\r\n0xFF,0xF1,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0xFF,0x80,\r\n// '\\'\r\n0x5C,0x01,0x08,0x14,0x00,0x08,\r\n0xC0,0xE0,0x60,0x60,0x60,0x30,0x30,0x30,0x18,0x18,0x18,0x18,0x0C,0x0C,0x0C,0x06,0x06,0x06,0x07,0x03,\r\n// ']'\r\n0x5D,0x01,0x05,0x15,0x02,0x09,\r\n0xFF,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC7,0xFF,0x80,\r\n// '^'\r\n0x5E,0x01,0x0F,0x07,0x03,0x14,\r\n0x03,0x80,0x0F,0x80,0x3B,0x80,0xE3,0x83,0x83,0x8E,0x03,0xB8,0x03,0x80,\r\n// '_'\r\n0x5F,0x17,0x0C,0x02,0x00,0x0C,\r\n0xFF,0xFF,0xFF,\r\n// '`'\r\n0x60,0x00,0x06,0x04,0x02,0x0C,\r\n0x60,0xC1,0x83,\r\n// 'a'\r\n0x61,0x06,0x0B,0x0D,0x01,0x0E,\r\n0x3F,0x0F,0xF9,0x03,0x00,0x30,0x06,0x3F,0xDF,0xFF,0x03,0xC0,0x78,0x1F,0x87,0xBF,0xF3,0xE6,\r\n// 'b'\r\n0x62,0x01,0x0C,0x12,0x02,0x0F,\r\n0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0xF8,0xFF,0xCF,0x0E,0xE0,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xE0,0x6F,0x0E,0xFF,0xCC,0xF8,\r\n// 'c'\r\n0x63,0x06,0x0A,0x0D,0x01,0x0D,\r\n0x0F,0x8F,0xF7,0x05,0x80,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x18,0x07,0x04,0xFF,0x0F,0x80,\r\n// 'd'\r\n0x64,0x01,0x0C,0x12,0x01,0x0F,\r\n0x00,0x30,0x03,0x00,0x30,0x03,0x00,0x31,0xF3,0x3F,0xF7,0x0F,0x60,0x7C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x77,0x0F,0x3F,0xF1,0xF3,\r\n// 'e'\r\n0x65,0x06,0x0C,0x0D,0x01,0x0E,\r\n0x0F,0x83,0xFC,0x70,0xE6,0x07,0xC0,0x3F,0xFF,0xFF,0xFC,0x00,0xC0,0x06,0x00,0x70,0x23,0xFE,0x0F,0xC0,\r\n// 'f'\r\n0x66,0x01,0x08,0x12,0x01,0x08,\r\n0x0F,0x1F,0x38,0x30,0x30,0xFF,0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,\r\n// 'g'\r\n0x67,0x06,0x0C,0x12,0x01,0x0F,\r\n0x1F,0x33,0xFF,0x70,0xF6,0x07,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x07,0x70,0xF3,0xFF,0x1F,0x30,0x03,0x00,0x72,0x0E,0x3F,0xC1,0xF8,\r\n// 'h'\r\n0x68,0x01,0x0B,0x12,0x02,0x0F,\r\n0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x9F,0x3F,0xF7,0x87,0xE0,0x78,0x0F,0x01,0xE0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x0C,\r\n// 'i'\r\n0x69,0x01,0x02,0x12,0x02,0x07,\r\n0xFC,0x3F,0xFF,0xFF,0xF0,\r\n// 'j'\r\n0x6A,0x01,0x05,0x17,0xFF,0x07,\r\n0x18,0xC6,0x00,0x0C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x33,0xFB,0x80,\r\n// 'k'\r\n0x6B,0x01,0x0C,0x12,0x02,0x0E,\r\n0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x1C,0xC3,0x8C,0x70,0xCE,0x0D,0xC0,0xF8,0x0F,0x80,0xDC,0x0C,0xE0,0xC7,0x0C,0x38,0xC1,0xCC,0x0E,\r\n// 'l'\r\n0x6C,0x01,0x02,0x12,0x02,0x06,\r\n0xFF,0xFF,0xFF,0xFF,0xF0,\r\n// 'm'\r\n0x6D,0x06,0x14,0x0D,0x02,0x18,\r\n0xCF,0x87,0xCF,0xFC,0xFE,0xF0,0xF8,0x7E,0x07,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x30,\r\n// 'n'\r\n0x6E,0x06,0x0B,0x0D,0x02,0x0F,\r\n0xCF,0x9F,0xFB,0xC3,0xF0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x0F,0x01,0xE0,0x3C,0x06,\r\n// 'o'\r\n0x6F,0x06,0x0C,0x0D,0x01,0x0E,\r\n0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,\r\n// 'p'\r\n0x70,0x06,0x0C,0x12,0x02,0x0F,\r\n0xCF,0x8F,0xFC,0xF0,0xEE,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x3E,0x06,0xF0,0xEF,0xFC,0xCF,0x8C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,\r\n// 'q'\r\n0x71,0x06,0x0C,0x12,0x01,0x0F,\r\n0x1F,0x33,0xFF,0x70,0xF6,0x07,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x07,0x70,0xF3,0xFF,0x1F,0x30,0x03,0x00,0x30,0x03,0x00,0x30,0x03,\r\n// 'r'\r\n0x72,0x06,0x08,0x0D,0x02,0x0A,\r\n0xCF,0xFF,0xF0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,\r\n// 's'\r\n0x73,0x06,0x0B,0x0D,0x01,0x0C,\r\n0x3F,0x0F,0xF3,0x82,0x60,0x0C,0x00,0xF0,0x0F,0xC0,0x3C,0x00,0xC0,0x1A,0x07,0x7F,0xC7,0xF0,\r\n// 't'\r\n0x74,0x02,0x08,0x11,0x00,0x09,\r\n0x30,0x30,0x30,0x30,0xFF,0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x1F,0x0F,\r\n// 'u'\r\n0x75,0x06,0x0B,0x0D,0x02,0x0F,\r\n0xC0,0x78,0x0F,0x01,0xE0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1F,0x87,0xBF,0xF3,0xE6,\r\n// 'v'\r\n0x76,0x06,0x0D,0x0D,0x01,0x0F,\r\n0xC0,0x1B,0x01,0x98,0x0C,0xC0,0x63,0x06,0x18,0x30,0x63,0x03,0x18,0x18,0xC0,0x6C,0x03,0x60,0x1F,0x00,0x70,0x00,\r\n// 'w'\r\n0x77,0x06,0x12,0x0D,0x01,0x14,\r\n0xC1,0xE0,0xF0,0x78,0x36,0x1E,0x19,0x87,0x86,0x63,0x31,0x9C,0xCC,0xE3,0x33,0x30,0xCC,0xCC,0x36,0x1B,0x07,0x87,0x81,0xE1,0xE0,0x78,0x78,0x1C,0x0E,0x00,\r\n// 'x'\r\n0x78,0x06,0x0D,0x0D,0x01,0x0F,\r\n0xE0,0x3B,0x83,0x8E,0x38,0x31,0x80,0xD8,0x07,0xC0,0x1C,0x01,0xF0,0x1D,0xC0,0xC6,0x0C,0x18,0xE0,0xEE,0x03,0x80,\r\n// 'y'\r\n0x79,0x06,0x0D,0x12,0x01,0x0F,\r\n0xC0,0x1B,0x01,0x98,0x0C,0xE0,0xE3,0x06,0x18,0x70,0x63,0x03,0x18,0x0D,0x80,0x6C,0x03,0xE0,0x0E,0x00,0x70,0x03,0x00,0x18,0x01,0x80,0x7C,0x03,0xC0,0x00,\r\n// 'z'\r\n0x7A,0x06,0x0B,0x0D,0x01,0x0D,\r\n0xFF,0xFF,0xFC,0x03,0x00,0xE0,0x38,0x0E,0x03,0x80,0xE0,0x38,0x0E,0x01,0x80,0x7F,0xFF,0xFE,\r\n// '{'\r\n0x7B,0x01,0x09,0x16,0x03,0x0F,\r\n0x03,0x83,0xC3,0x81,0x80,0xC0,0x60,0x30,0x18,0x0C,0x0E,0x3E,0x1F,0x01,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0xC0,0x78,0x1C,\r\n// '|'\r\n0x7C,0x01,0x02,0x18,0x03,0x08,\r\n0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\r\n// '}'\r\n0x7D,0x01,0x09,0x16,0x03,0x0F,\r\n0xE0,0x78,0x0E,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0E,0x03,0xE1,0xF1,0xC0,0xC0,0x60,0x30,0x18,0x0C,0x06,0x07,0x0F,0x07,0x00,\r\n// '~'\r\n0x7E,0x09,0x0F,0x05,0x03,0x14,\r\n0x00,0x00,0x7C,0x05,0xFE,0x1E,0x1F,0xE0,0x0F,0x80,\r\n\r\n// Terminator\r\n0xFF\r\n};\r\n"
  },
  {
    "path": "components/epaper/EPD.c",
    "content": "/* EPD library\n *\n *  Author: LoBo (loboris@gmail.com, loboris.github)\n *\n *  Module supporting SPI ePaper displays\n*/\n\n#include <stdio.h>\n#include <errno.h>\n#include <sys/stat.h>\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_system.h\"\n#include \"time.h\"\n#include <math.h>\n#include \"rom/tjpgd.h\"\n#include \"esp_heap_alloc_caps.h\"\n#include \"EPD.h\"\n#include \"EPDspi.h\"\n#include \"rom/tjpgd.h\"\n\n\n#define DEG_TO_RAD 0.01745329252\n#define RAD_TO_DEG 57.295779513\n#define deg_to_rad 0.01745329252 + 3.14159265359\n#define swap(a, b) { int16_t t = a; a = b; b = t; }\n#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))\n\n#if !defined(max)\n#define max(A,B) ( (A) > (B) ? (A):(B))\n#endif\n\n#if !defined(min)\n#define min(A,B) ( (A) < (B) ? (A):(B))\n#endif\n\n// Embedded fonts\nextern uint8_t tft_SmallFont[];\nextern uint8_t tft_DefaultFont[];\nextern uint8_t tft_Dejavu18[];\nextern uint8_t tft_Dejavu24[];\nextern uint8_t tft_Ubuntu16[];\nextern uint8_t tft_Comic24[];\nextern uint8_t tft_minya24[];\nextern uint8_t tft_tooney32[];\n\n// ==============================================================\n// ==== Set default values of global variables ==================\n\nuint8_t orientation = LANDSCAPE_0;\t// screen orientation\nuint16_t font_rotate = 0;\t\t\t// font rotation\nuint8_t\tfont_transparent = 0;\nuint8_t\tfont_forceFixed = 0;\nuint8_t\ttext_wrap = 0;\t\t\t\t// character wrapping to new line\ncolor_t\t_fg = EPD_BLACK;\ncolor_t _bg = EPD_WHITE;\n\nfloat _angleOffset = DEFAULT_ANGLE_OFFSET;\n\nint\tEPD_X = 0;\nint\tEPD_Y = 0;\n\ndispWin_t dispWin = {\n  .x1 = 0,\n  .y1 = 0,\n  .x2 = EPD_DISPLAY_WIDTH-1,\n  .y2 = EPD_DISPLAY_HEIGHT-1,\n};\n\nFont_t cfont = {\n\t.font = tft_DefaultFont,\n\t.x_size = 0,\n\t.y_size = 0x0B,\n\t.offset = 0,\n\t.numchars = 95,\n\t.bitmap = 1,\n};\n\nuint8_t font_line_space = 0;\nuint8_t image_debug = 0;\n\n// ==============================================================\n\n\ntypedef struct {\n      uint8_t charCode;\n      int adjYOffset;\n      int width;\n      int height;\n      int xOffset;\n      int xDelta;\n      uint16_t dataPtr;\n} propFont;\n\nstatic dispWin_t dispWinTemp;\n\nstatic uint8_t *userfont = NULL;\nstatic int EPD_OFFSET = 0;\nstatic propFont\tfontChar;\nstatic float _arcAngleMax = DEFAULT_ARC_ANGLE_MAX;\n\n\n\n// ==============================================================================================================\n//----------------------------------------------\nstatic void drawPixel(int x, int y, uint8_t val)\n{\n\tif (orientation == LANDSCAPE_180) {\n\t\tx = _width - x - 1;\n\t\ty = _height - y - 1;\n\t}\n\tif (_gs) {\n\t\tval &= 0x0F;\n\t\t//if (gs_drawBuff[(y * _width) + x] != val) {\n\t\t\tgs_drawBuff[(y * _width) + x] = val;\n\t\t\tgs_used_shades |= (1<<val);\n\t\t//}\n\t}\n\telse {\n\t\tval &= 0x01;\n\t\tuint8_t buf_val = drawBuff[(x * (_height >> 3)) + (y>>3)];\n\t\tuint8_t new_val = buf_val;\n\t\tif (val) new_val &= (0x80 >> (y % 8)) ^ 0xFF;\n\t\telse new_val |= (0x80 >> (y % 8));\n\t\t//if (new_val != buf_val) drawBuff[(x * (_height>>3)) + (y>>3)] = new_val;\n\t\tdrawBuff[(x * (_height>>3)) + (y>>3)] = new_val;\n\t}\n}\n\n//-------------------------------------------------------------------------\nstatic void EPD_pushColorRep(int x1, int y1, int x2, int y2, color_t color)\n{\n\tif (_gs == 0) color &= 0x01;\n\telse color &= 0x0F;\n\tfor (int y=y1; y<=y2; y++) {\n\t\tfor (int x = x1; x<=x2; x++){\n\t\t\tdrawPixel(x, y, color);\n\t\t}\n\t}\n}\n\n/*\n//---------------------------------------------------------------------------------------\nstatic void copyBuff(int x1, int y1, int x2, int y2, uint8_t *src_buf, uint8_t *dest_buf)\n{\n\tif\n\tuint8_t buf_val1 = (src_buf[(x1 * (EPD_DISPLAY_HEIGHT>>3)) + (y1>>3)]) ;\n\tuint8_t val = 0x80 >> (y1 % 8);\n\tif (val) buf_val &= (0x80 >> (y % 8)) ^ 0xFF;\n\telse buf_val |= (0x80 >> (y % 8));\n\n\tdrawBuff[(x * (EPD_DISPLAY_HEIGHT>>3)) + (y>>3)] = buf_val;\n}\n*/\n\n// ==============================================================================================================\n\n// =========================================================================\n// ** All drawings are clipped to 'dispWin' **\n// ** All x,y coordinates in public functions are relative to clip window **\n// =========== : Public functions\n// ----------- : Local functions\n// =========================================================================\n\n\n// Compare two colors; return 0 if equal\n//============================================\nint EPD_compare_colors(color_t c1, color_t c2)\n{\n\tif (c1 != c2) return 1;\n\n\treturn 0;\n}\n\n// draw color pixel on screen\n//-----------------------------------------------------------\nstatic void _drawPixel(int16_t x, int16_t y, color_t color) {\n\n\tif ((x < dispWin.x1) || (y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return;\n\tdrawPixel(x, y, color);\n}\n\n//=======================================================\nvoid EPD_drawPixel(int16_t x, int16_t y, color_t color) {\n\n\t_drawPixel(x+dispWin.x1, y+dispWin.y1, color);\n}\n\n//--------------------------------------------------------------------------\nstatic void _drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) {\n\t// clipping\n\tif ((x < dispWin.x1) || (x > dispWin.x2) || (y > dispWin.y2)) return;\n\tif (y < dispWin.y1) {\n\t\th -= (dispWin.y1 - y);\n\t\ty = dispWin.y1;\n\t}\n\tif (h < 0) h = 0;\n\tif ((y + h) > (dispWin.y2+1)) h = dispWin.y2 - y + 1;\n\tif (h == 0) h = 1;\n\tEPD_pushColorRep(x, y, x, y+h-1, color);\n}\n\n//--------------------------------------------------------------------------\nstatic void _drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) {\n\t// clipping\n\tif ((y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return;\n\tif (x < dispWin.x1) {\n\t\tw -= (dispWin.x1 - x);\n\t\tx = dispWin.x1;\n\t}\n\tif (w < 0) w = 0;\n\tif ((x + w) > (dispWin.x2+1)) w = dispWin.x2 - x + 1;\n\tif (w == 0) w = 1;\n\n\tEPD_pushColorRep(x, y, x+w-1, y, color);\n}\n\n//======================================================================\nvoid EPD_drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) {\n\t_drawFastVLine(x+dispWin.x1, y+dispWin.y1, h, color);\n}\n\n//======================================================================\nvoid EPD_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) {\n\t_drawFastHLine(x+dispWin.x1, y+dispWin.y1, w, color);\n}\n\n// Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer this uses\n// the eficient FastH/V Line draw routine for segments of 2 pixels or more\n//----------------------------------------------------------------------------------\nstatic void _drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color)\n{\n  if (x0 == x1) {\n\t  if (y0 <= y1) _drawFastVLine(x0, y0, y1-y0, color);\n\t  else _drawFastVLine(x0, y1, y0-y1, color);\n\t  return;\n  }\n  if (y0 == y1) {\n\t  if (x0 <= x1) _drawFastHLine(x0, y0, x1-x0, color);\n\t  else _drawFastHLine(x1, y0, x0-x1, color);\n\t  return;\n  }\n\n  int steep = 0;\n  if (abs(y1 - y0) > abs(x1 - x0)) steep = 1;\n  if (steep) {\n    swap(x0, y0);\n    swap(x1, y1);\n  }\n  if (x0 > x1) {\n    swap(x0, x1);\n    swap(y0, y1);\n  }\n\n  int16_t dx = x1 - x0, dy = abs(y1 - y0);;\n  int16_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0;\n\n  if (y0 < y1) ystep = 1;\n\n  // Split into steep and not steep for FastH/V separation\n  if (steep) {\n    for (; x0 <= x1; x0++) {\n      dlen++;\n      err -= dy;\n      if (err < 0) {\n        err += dx;\n        if (dlen == 1) _drawPixel(y0, xs, color);\n        else _drawFastVLine(y0, xs, dlen, color);\n        dlen = 0; y0 += ystep; xs = x0 + 1;\n      }\n    }\n    if (dlen) _drawFastVLine(y0, xs, dlen, color);\n  }\n  else\n  {\n    for (; x0 <= x1; x0++) {\n      dlen++;\n      err -= dy;\n      if (err < 0) {\n        err += dx;\n        if (dlen == 1) _drawPixel(xs, y0, color);\n        else _drawFastHLine(xs, y0, dlen, color);\n        dlen = 0; y0 += ystep; xs = x0 + 1;\n      }\n    }\n    if (dlen) _drawFastHLine(xs, y0, dlen, color);\n  }\n}\n\n//==============================================================================\nvoid EPD_drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color)\n{\n\t_drawLine(x0+dispWin.x1, y0+dispWin.y1, x1+dispWin.x1, y1+dispWin.y1, color);\n}\n\n// fill a rectangle\n//--------------------------------------------------------------------------------\nstatic void _fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) {\n\t// clipping\n\tif ((x >= dispWin.x2) || (y > dispWin.y2)) return;\n\n\tif (x < dispWin.x1) {\n\t\tw -= (dispWin.x1 - x);\n\t\tx = dispWin.x1;\n\t}\n\tif (y < dispWin.y1) {\n\t\th -= (dispWin.y1 - y);\n\t\ty = dispWin.y1;\n\t}\n\tif (w < 0) w = 0;\n\tif (h < 0) h = 0;\n\n\tif ((x + w) > (dispWin.x2+1)) w = dispWin.x2 - x + 1;\n\tif ((y + h) > (dispWin.y2+1)) h = dispWin.y2 - y + 1;\n\tif (w == 0) w = 1;\n\tif (h == 0) h = 1;\n\tEPD_pushColorRep(x, y, x+w-1, y+h-1, color);\n}\n\n//============================================================================\nvoid EPD_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) {\n\t_fillRect(x+dispWin.x1, y+dispWin.y1, w, h, color);\n}\n\n//==================================\nvoid EPD_fillScreen(color_t color) {\n\tcolor &= 0x0F;\n\tmemset(disp_buffer, ((color&1) ? 0 : 0xFF), _width * (_height/8));\n\tmemset(gs_disp_buffer, color, _width * _height);\n\tgs_used_shades = 0;\n}\n\n//==================================\nvoid EPD_fillWindow(color_t color) {\n\tEPD_pushColorRep(dispWin.x1, dispWin.y1, dispWin.x2, dispWin.y2, 0xFF);\n}\n\n// ^^^============= Basics drawing functions ================================^^^\n\n\n// ================ Graphics drawing functions ==================================\n\n//-----------------------------------------------------------------------------------\nstatic void _drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color) {\n  _drawFastHLine(x1,y1,w, color);\n  _drawFastVLine(x1+w-1,y1,h, color);\n  _drawFastHLine(x1,y1+h-1,w, color);\n  _drawFastVLine(x1,y1,h, color);\n}\n\n//===============================================================================\nvoid EPD_drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color) {\n\t_drawRect(x1+dispWin.x1, y1+dispWin.y1, w, h, color);\n}\n\n//-------------------------------------------------------------------------------------------------\nstatic void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, color_t color)\n{\n\tint16_t f = 1 - r;\n\tint16_t ddF_x = 1;\n\tint16_t ddF_y = -2 * r;\n\tint16_t x = 0;\n\tint16_t y = r;\n\n\twhile (x < y) {\n\t\tif (f >= 0) {\n\t\t\ty--;\n\t\t\tddF_y += 2;\n\t\t\tf += ddF_y;\n\t\t}\n\t\tx++;\n\t\tddF_x += 2;\n\t\tf += ddF_x;\n\t\tif (cornername & 0x4) {\n\t\t\t_drawPixel(x0 + x, y0 + y, color);\n\t\t\t_drawPixel(x0 + y, y0 + x, color);\n\t\t}\n\t\tif (cornername & 0x2) {\n\t\t\t_drawPixel(x0 + x, y0 - y, color);\n\t\t\t_drawPixel(x0 + y, y0 - x, color);\n\t\t}\n\t\tif (cornername & 0x8) {\n\t\t\t_drawPixel(x0 - y, y0 + x, color);\n\t\t\t_drawPixel(x0 - x, y0 + y, color);\n\t\t}\n\t\tif (cornername & 0x1) {\n\t\t\t_drawPixel(x0 - y, y0 - x, color);\n\t\t\t_drawPixel(x0 - x, y0 - y, color);\n\t\t}\n\t}\n}\n\n// Used to do circles and roundrects\n//----------------------------------------------------------------------------------------------------------------\nstatic void fillCircleHelper(int16_t x0, int16_t y0, int16_t r,\tuint8_t cornername, int16_t delta, color_t color)\n{\n\tint16_t f = 1 - r;\n\tint16_t ddF_x = 1;\n\tint16_t ddF_y = -2 * r;\n\tint16_t x = 0;\n\tint16_t y = r;\n\tint16_t ylm = x0 - r;\n\n\twhile (x < y) {\n\t\tif (f >= 0) {\n\t\t\tif (cornername & 0x1) _drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color);\n\t\t\tif (cornername & 0x2) _drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color);\n\t\t\tylm = x0 - y;\n\t\t\ty--;\n\t\t\tddF_y += 2;\n\t\t\tf += ddF_y;\n\t\t}\n\t\tx++;\n\t\tddF_x += 2;\n\t\tf += ddF_x;\n\n\t\tif ((x0 - x) > ylm) {\n\t\t\tif (cornername & 0x1) _drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color);\n\t\t\tif (cornername & 0x2) _drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color);\n\t\t}\n\t}\n}\n\n// Draw a rounded rectangle\n//=============================================================================================\nvoid EPD_drawRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color)\n{\n\tx += dispWin.x1;\n\ty += dispWin.y1;\n\n\t// smarter version\n\t_drawFastHLine(x + r, y, w - 2 * r, color);\t\t\t// Top\n\t_drawFastHLine(x + r, y + h - 1, w - 2 * r, color);\t// Bottom\n\t_drawFastVLine(x, y + r, h - 2 * r, color);\t\t\t// Left\n\t_drawFastVLine(x + w - 1, y + r, h - 2 * r, color);\t// Right\n\n\t// draw four corners\n\tdrawCircleHelper(x + r, y + r, r, 1, color);\n\tdrawCircleHelper(x + w - r - 1, y + r, r, 2, color);\n\tdrawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);\n\tdrawCircleHelper(x + r, y + h - r - 1, r, 8, color);\n}\n\n// Fill a rounded rectangle\n//=============================================================================================\nvoid EPD_fillRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color)\n{\n\tx += dispWin.x1;\n\ty += dispWin.y1;\n\n\t// smarter version\n\t_fillRect(x + r, y, w - 2 * r, h, color);\n\n\t// draw four corners\n\tfillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);\n\tfillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color);\n}\n\n\n\n\n//-----------------------------------------------------------------------------------------------\nstatic void _drawLineByAngle(int16_t x, int16_t y, int16_t angle, uint16_t length, color_t color)\n{\n\t_drawLine(\n\t\tx,\n\t\ty,\n\t\tx + length * cos((angle + _angleOffset) * DEG_TO_RAD),\n\t\ty + length * sin((angle + _angleOffset) * DEG_TO_RAD), color);\n}\n\n//---------------------------------------------------------------------------------------------------------------\nstatic void _DrawLineByAngle(int16_t x, int16_t y, int16_t angle, uint16_t start, uint16_t length, color_t color)\n{\n\t_drawLine(\n\t\tx + start * cos((angle + _angleOffset) * DEG_TO_RAD),\n\t\ty + start * sin((angle + _angleOffset) * DEG_TO_RAD),\n\t\tx + (start + length) * cos((angle + _angleOffset) * DEG_TO_RAD),\n\t\ty + (start + length) * sin((angle + _angleOffset) * DEG_TO_RAD), color);\n}\n\n//===========================================================================================================\nvoid EPD_drawLineByAngle(uint16_t x, uint16_t y, uint16_t start, uint16_t len, uint16_t angle, color_t color)\n{\n\tx += dispWin.x1;\n\ty += dispWin.y1;\n\n\tif (start == 0) _drawLineByAngle(x, y, angle, len, color);\n\telse _DrawLineByAngle(x, y, angle, start, len, color);\n}\n\n\n// Draw a triangle\n//--------------------------------------------------------------------------------------------------------------------\nstatic void _drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color)\n{\n\t_drawLine(x0, y0, x1, y1, color);\n\t_drawLine(x1, y1, x2, y2, color);\n\t_drawLine(x2, y2, x0, y0, color);\n}\n\n//================================================================================================================\nvoid EPD_drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color)\n{\n\tx0 += dispWin.x1;\n\ty0 += dispWin.y1;\n\tx1 += dispWin.x1;\n\ty1 += dispWin.y1;\n\tx2 += dispWin.x1;\n\ty2 += dispWin.y1;\n\n\t_drawLine(x0, y0, x1, y1, color);\n\t_drawLine(x1, y1, x2, y2, color);\n\t_drawLine(x2, y2, x0, y0, color);\n}\n\n// Fill a triangle\n//--------------------------------------------------------------------------------------------------------------------\nstatic void _fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color)\n{\n  int16_t a, b, y, last;\n\n  // Sort coordinates by Y order (y2 >= y1 >= y0)\n  if (y0 > y1) {\n    swap(y0, y1); swap(x0, x1);\n  }\n  if (y1 > y2) {\n    swap(y2, y1); swap(x2, x1);\n  }\n  if (y0 > y1) {\n    swap(y0, y1); swap(x0, x1);\n  }\n\n  if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing\n    a = b = x0;\n    if(x1 < a)      a = x1;\n    else if(x1 > b) b = x1;\n    if(x2 < a)      a = x2;\n    else if(x2 > b) b = x2;\n    _drawFastHLine(a, y0, b-a+1, color);\n    return;\n  }\n\n  int16_t\n    dx01 = x1 - x0,\n    dy01 = y1 - y0,\n    dx02 = x2 - x0,\n    dy02 = y2 - y0,\n    dx12 = x2 - x1,\n    dy12 = y2 - y1;\n  int32_t\n    sa   = 0,\n    sb   = 0;\n\n  // For upper part of triangle, find scanline crossings for segments\n  // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1\n  // is included here (and second loop will be skipped, avoiding a /0\n  // error there), otherwise scanline y1 is skipped here and handled\n  // in the second loop...which also avoids a /0 error here if y0=y1\n  // (flat-topped triangle).\n  if(y1 == y2) last = y1;   // Include y1 scanline\n  else         last = y1-1; // Skip it\n\n  for(y=y0; y<=last; y++) {\n    a   = x0 + sa / dy01;\n    b   = x0 + sb / dy02;\n    sa += dx01;\n    sb += dx02;\n    /* longhand:\n    a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);\n    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);\n    */\n    if(a > b) swap(a,b);\n    _drawFastHLine(a, y, b-a+1, color);\n  }\n\n  // For lower part of triangle, find scanline crossings for segments\n  // 0-2 and 1-2.  This loop is skipped if y1=y2.\n  sa = dx12 * (y - y1);\n  sb = dx02 * (y - y0);\n  for(; y<=y2; y++) {\n    a   = x1 + sa / dy12;\n    b   = x0 + sb / dy02;\n    sa += dx12;\n    sb += dx02;\n    /* longhand:\n    a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);\n    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);\n    */\n    if(a > b) swap(a,b);\n    _drawFastHLine(a, y, b-a+1, color);\n  }\n}\n\n//================================================================================================================\nvoid EPD_fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color)\n{\n\t_fillTriangle(\n\t\t\tx0 + dispWin.x1, y0 + dispWin.y1,\n\t\t\tx1 + dispWin.x1, y1 + dispWin.y1,\n\t\t\tx2 + dispWin.x1, y2 + dispWin.y1,\n\t\t\tcolor);\n}\n\n//====================================================================\nvoid EPD_drawCircle(int16_t x, int16_t y, int radius, color_t color) {\n\tx += dispWin.x1;\n\ty += dispWin.y1;\n\tint f = 1 - radius;\n\tint ddF_x = 1;\n\tint ddF_y = -2 * radius;\n\tint x1 = 0;\n\tint y1 = radius;\n\n\t_drawPixel(x, y + radius, color);\n\t_drawPixel(x, y - radius, color);\n\t_drawPixel(x + radius, y, color);\n\t_drawPixel(x - radius, y, color);\n\twhile(x1 < y1) {\n\t\tif (f >= 0) {\n\t\t\ty1--;\n\t\t\tddF_y += 2;\n\t\t\tf += ddF_y;\n\t\t}\n\t\tx1++;\n\t\tddF_x += 2;\n\t\tf += ddF_x;\n\t\t_drawPixel(x + x1, y + y1, color);\n\t\t_drawPixel(x - x1, y + y1, color);\n\t\t_drawPixel(x + x1, y - y1, color);\n\t\t_drawPixel(x - x1, y - y1, color);\n\t\t_drawPixel(x + y1, y + x1, color);\n\t\t_drawPixel(x - y1, y + x1, color);\n\t\t_drawPixel(x + y1, y - x1, color);\n\t\t_drawPixel(x - y1, y - x1, color);\n\t}\n}\n\n//====================================================================\nvoid EPD_fillCircle(int16_t x, int16_t y, int radius, color_t color) {\n\tx += dispWin.x1;\n\ty += dispWin.y1;\n\n\t_drawFastVLine(x, y-radius, 2*radius+1, color);\n\tfillCircleHelper(x, y, radius, 3, 0, color);\n}\n\n//----------------------------------------------------------------------------------------------------------------\nstatic void _draw_ellipse_section(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, color_t color, uint8_t option)\n{\n    // upper right\n    if ( option & EPD_ELLIPSE_UPPER_RIGHT ) _drawPixel(x0 + x, y0 - y, color);\n    // upper left\n    if ( option & EPD_ELLIPSE_UPPER_LEFT ) _drawPixel(x0 - x, y0 - y, color);\n    // lower right\n    if ( option & EPD_ELLIPSE_LOWER_RIGHT ) _drawPixel(x0 + x, y0 + y, color);\n    // lower left\n    if ( option & EPD_ELLIPSE_LOWER_LEFT ) _drawPixel(x0 - x, y0 + y, color);\n}\n\n//=====================================================================================================\nvoid EPD_drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option)\n{\n\tx0 += dispWin.x1;\n\ty0 += dispWin.y1;\n\n\tuint16_t x, y;\n\tint32_t xchg, ychg;\n\tint32_t err;\n\tint32_t rxrx2;\n\tint32_t ryry2;\n\tint32_t stopx, stopy;\n\n\trxrx2 = rx;\n\trxrx2 *= rx;\n\trxrx2 *= 2;\n\n\tryry2 = ry;\n\tryry2 *= ry;\n\tryry2 *= 2;\n\n\tx = rx;\n\ty = 0;\n\n\txchg = 1;\n\txchg -= rx;\n\txchg -= rx;\n\txchg *= ry;\n\txchg *= ry;\n\n\tychg = rx;\n\tychg *= rx;\n\n\terr = 0;\n\n\tstopx = ryry2;\n\tstopx *= rx;\n\tstopy = 0;\n\n\twhile( stopx >= stopy ) {\n\t\t_draw_ellipse_section(x, y, x0, y0, color, option);\n\t\ty++;\n\t\tstopy += rxrx2;\n\t\terr += ychg;\n\t\tychg += rxrx2;\n\t\tif ( 2*err+xchg > 0 ) {\n\t\t\tx--;\n\t\t\tstopx -= ryry2;\n\t\t\terr += xchg;\n\t\t\txchg += ryry2;\n\t\t}\n\t}\n\n\tx = 0;\n\ty = ry;\n\n\txchg = ry;\n\txchg *= ry;\n\n\tychg = 1;\n\tychg -= ry;\n\tychg -= ry;\n\tychg *= rx;\n\tychg *= rx;\n\n\terr = 0;\n\n\tstopx = 0;\n\n\tstopy = rxrx2;\n\tstopy *= ry;\n\n\twhile( stopx <= stopy ) {\n\t\t_draw_ellipse_section(x, y, x0, y0, color, option);\n\t\tx++;\n\t\tstopx += ryry2;\n\t\terr += xchg;\n\t\txchg += ryry2;\n\t\tif ( 2*err+ychg > 0 ) {\n\t\t\ty--;\n\t\t\tstopy -= rxrx2;\n\t\t\terr += ychg;\n\t\t\tychg += rxrx2;\n\t\t}\n\t}\n}\n\n//-----------------------------------------------------------------------------------------------------------------------\nstatic void _draw_filled_ellipse_section(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, color_t color, uint8_t option)\n{\n    // upper right\n    if ( option & EPD_ELLIPSE_UPPER_RIGHT ) _drawFastVLine(x0+x, y0-y, y+1, color);\n    // upper left\n    if ( option & EPD_ELLIPSE_UPPER_LEFT ) _drawFastVLine(x0-x, y0-y, y+1, color);\n    // lower right\n    if ( option & EPD_ELLIPSE_LOWER_RIGHT ) _drawFastVLine(x0+x, y0, y+1, color);\n    // lower left\n    if ( option & EPD_ELLIPSE_LOWER_LEFT ) _drawFastVLine(x0-x, y0, y+1, color);\n}\n\n//=====================================================================================================\nvoid EPD_fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option)\n{\n\tx0 += dispWin.x1;\n\ty0 += dispWin.y1;\n\n\tuint16_t x, y;\n\tint32_t xchg, ychg;\n\tint32_t err;\n\tint32_t rxrx2;\n\tint32_t ryry2;\n\tint32_t stopx, stopy;\n\n\trxrx2 = rx;\n\trxrx2 *= rx;\n\trxrx2 *= 2;\n\n\tryry2 = ry;\n\tryry2 *= ry;\n\tryry2 *= 2;\n\n\tx = rx;\n\ty = 0;\n\n\txchg = 1;\n\txchg -= rx;\n\txchg -= rx;\n\txchg *= ry;\n\txchg *= ry;\n\n\tychg = rx;\n\tychg *= rx;\n\n\terr = 0;\n\n\tstopx = ryry2;\n\tstopx *= rx;\n\tstopy = 0;\n\n\twhile( stopx >= stopy ) {\n\t\t_draw_filled_ellipse_section(x, y, x0, y0, color, option);\n\t\ty++;\n\t\tstopy += rxrx2;\n\t\terr += ychg;\n\t\tychg += rxrx2;\n\t\tif ( 2*err+xchg > 0 ) {\n\t\t\tx--;\n\t\t\tstopx -= ryry2;\n\t\t\terr += xchg;\n\t\t\txchg += ryry2;\n\t\t}\n\t}\n\n\tx = 0;\n\ty = ry;\n\n\txchg = ry;\n\txchg *= ry;\n\n\tychg = 1;\n\tychg -= ry;\n\tychg -= ry;\n\tychg *= rx;\n\tychg *= rx;\n\n\terr = 0;\n\n\tstopx = 0;\n\n\tstopy = rxrx2;\n\tstopy *= ry;\n\n\twhile( stopx <= stopy ) {\n\t\t_draw_filled_ellipse_section(x, y, x0, y0, color, option);\n\t\tx++;\n\t\tstopx += ryry2;\n\t\terr += xchg;\n\t\txchg += ryry2;\n\t\tif ( 2*err+ychg > 0 ) {\n\t\t\ty--;\n\t\t\tstopy -= rxrx2;\n\t\t\terr += ychg;\n\t\t\tychg += rxrx2;\n\t\t}\n\t}\n}\n\n\n// ==== ARC DRAWING ===================================================================\n\n//---------------------------------------------------------------------------------------------------------------------------------\nstatic void _fillArcOffsetted(uint16_t cx, uint16_t cy, uint16_t radius, uint16_t thickness, float start, float end, color_t color)\n{\n\t//float sslope = (float)cos_lookup(start) / (float)sin_lookup(start);\n\t//float eslope = (float)cos_lookup(end) / (float)sin_lookup(end);\n\tfloat sslope = (cos(start/_arcAngleMax * 2 * PI) * _arcAngleMax) / (sin(start/_arcAngleMax * 2 * PI) * _arcAngleMax) ;\n\tfloat eslope = (cos(end/_arcAngleMax * 2 * PI) * _arcAngleMax) / (sin(end/_arcAngleMax * 2 * PI) * _arcAngleMax);\n\n\tif (end == 360) eslope = -1000000;\n\n\tint ir2 = (radius - thickness) * (radius - thickness);\n\tint or2 = radius * radius;\n\n\tfor (int x = -radius; x <= radius; x++) {\n\t\tfor (int y = -radius; y <= radius; y++) {\n\t\t\tint x2 = x * x;\n\t\t\tint y2 = y * y;\n\n\t\t\tif (\n\t\t\t\t(x2 + y2 < or2 && x2 + y2 >= ir2) &&\n\t\t\t\t(\n\t\t\t\t(y > 0 && start < 180 && x <= y * sslope) ||\n\t\t\t\t(y < 0 && start > 180 && x >= y * sslope) ||\n\t\t\t\t(y < 0 && start <= 180) ||\n\t\t\t\t(y == 0 && start <= 180 && x < 0) ||\n\t\t\t\t(y == 0 && start == 0 && x > 0)\n\t\t\t\t) &&\n\t\t\t\t(\n\t\t\t\t(y > 0 && end < 180 && x >= y * eslope) ||\n\t\t\t\t(y < 0 && end > 180 && x <= y * eslope) ||\n\t\t\t\t(y > 0 && end >= 180) ||\n\t\t\t\t(y == 0 && end >= 180 && x < 0) ||\n\t\t\t\t(y == 0 && start == 0 && x > 0)\n\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t_drawPixel(cx+x, cy+y, color);\n\t\t}\n\t}\n}\n\n\n//===========================================================================================================================\nvoid EPD_drawArc(uint16_t cx, uint16_t cy, uint16_t r, uint16_t th, float start, float end, color_t color, color_t fillcolor)\n{\n\tcx += dispWin.x1;\n\tcy += dispWin.y1;\n\n\tif (th < 1) th = 1;\n\tif (th > r) th = r;\n\n\tint f = EPD_compare_colors(fillcolor, color);\n\n\tfloat astart = fmodf(start, _arcAngleMax);\n\tfloat aend = fmodf(end, _arcAngleMax);\n\n\tastart += _angleOffset;\n\taend += _angleOffset;\n\n\tif (astart < 0) astart += (float)360;\n\tif (aend < 0) aend += (float)360;\n\n\tif (aend == 0) aend = (float)360;\n\n\tif (astart > aend) {\n\t\t_fillArcOffsetted(cx, cy, r, th, astart, _arcAngleMax, fillcolor);\n\t\t_fillArcOffsetted(cx, cy, r, th, 0, aend, fillcolor);\n\t\tif (f) {\n\t\t\t_fillArcOffsetted(cx, cy, r, 1, astart, _arcAngleMax, color);\n\t\t\t_fillArcOffsetted(cx, cy, r, 1, 0, aend, color);\n\t\t\t_fillArcOffsetted(cx, cy, r-th, 1, astart, _arcAngleMax, color);\n\t\t\t_fillArcOffsetted(cx, cy, r-th, 1, 0, aend, color);\n\t\t}\n\t}\n\telse {\n\t\t_fillArcOffsetted(cx, cy, r, th, astart, aend, fillcolor);\n\t\tif (f) {\n\t\t\t_fillArcOffsetted(cx, cy, r, 1, astart, aend, color);\n\t\t\t_fillArcOffsetted(cx, cy, r-th, 1, astart, aend, color);\n\t\t}\n\t}\n\tif (f) {\n\t\t_drawLine(cx + (r-th) * cos(astart * DEG_TO_RAD), cy + (r-th) * sin(astart * DEG_TO_RAD),\n\t\t\tcx + (r-1) * cos(astart * DEG_TO_RAD), cy + (r-1) * sin(astart * DEG_TO_RAD), color);\n\t\t_drawLine(cx + (r-th) * cos(aend * DEG_TO_RAD), cy + (r-th) * sin(aend * DEG_TO_RAD),\n\t\t\tcx + (r-1) * cos(aend * DEG_TO_RAD), cy + (r-1) * sin(aend * DEG_TO_RAD), color);\n\t}\n}\n\n//=============================================================================================================\nvoid EPD_drawPolygon(int cx, int cy, int sides, int diameter, color_t color, color_t fill, int rot, uint8_t th)\n{\n\tcx += dispWin.x1;\n\tcy += dispWin.y1;\n\n\tint deg = rot - _angleOffset;\n\tint f = EPD_compare_colors(fill, color);\n\n\tif (sides < MIN_POLIGON_SIDES) sides = MIN_POLIGON_SIDES;\t// This ensures the minimum side number\n\tif (sides > MAX_POLIGON_SIDES) sides = MAX_POLIGON_SIDES;\t// This ensures the maximum side number\n\n\tint Xpoints[sides], Ypoints[sides];\t\t\t\t\t\t\t// Set the arrays based on the number of sides entered\n\tint rads = 360 / sides;\t\t\t\t\t\t\t\t\t\t// This equally spaces the points.\n\n\tfor (int idx = 0; idx < sides; idx++) {\n\t\tXpoints[idx] = cx + sin((float)(idx*rads + deg) * deg_to_rad) * diameter;\n\t\tYpoints[idx] = cy + cos((float)(idx*rads + deg) * deg_to_rad) * diameter;\n\t}\n\n\t// Draw the polygon on the screen.\n\tif (f) {\n\t\tfor(int idx = 0; idx < sides; idx++) {\n\t\t\tif((idx+1) < sides) _fillTriangle(cx,cy,Xpoints[idx],Ypoints[idx],Xpoints[idx+1],Ypoints[idx+1], fill);\n\t\t\telse _fillTriangle(cx,cy,Xpoints[idx],Ypoints[idx],Xpoints[0],Ypoints[0], fill);\n\t\t}\n\t}\n\n\tif (th) {\n\t\tfor (int n=0; n<th; n++) {\n\t\t\tif (n > 0) {\n\t\t\t\tfor (int idx = 0; idx < sides; idx++) {\n\t\t\t\t\tXpoints[idx] = cx + sin((float)(idx*rads + deg) * deg_to_rad) * (diameter-n);\n\t\t\t\t\tYpoints[idx] = cy + cos((float)(idx*rads + deg) * deg_to_rad) * (diameter-n);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(int idx = 0; idx < sides; idx++) {\n\t\t\t\tif( (idx+1) < sides)\n\t\t\t\t\t_drawLine(Xpoints[idx],Ypoints[idx],Xpoints[idx+1],Ypoints[idx+1], color); // draw the lines\n\t\t\t\telse\n\t\t\t\t\t_drawLine(Xpoints[idx],Ypoints[idx],Xpoints[0],Ypoints[0], color); // finishes the last line to close up the polygon.\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n// Similar to the Polygon function.\n//=====================================================================================\nvoid EPD_drawStar(int cx, int cy, int diameter, color_t color, bool fill, float factor)\n{\n\tcx += dispWin.x1;\n\tcy += dispWin.y1;\n\n\tfactor = constrain(factor, 1.0, 4.0);\n\tuint8_t sides = 5;\n\tuint8_t rads = 360 / sides;\n\n\tint Xpoints_O[sides], Ypoints_O[sides], Xpoints_I[sides], Ypoints_I[sides];//Xpoints_T[5], Ypoints_T[5];\n\n\tfor(int idx = 0; idx < sides; idx++) {\n\t\t// makes the outer points\n\t\tXpoints_O[idx] = cx + sin((float)(idx*rads + 72) * deg_to_rad) * diameter;\n\t\tYpoints_O[idx] = cy + cos((float)(idx*rads + 72) * deg_to_rad) * diameter;\n\t\t// makes the inner points\n\t\tXpoints_I[idx] = cx + sin((float)(idx*rads + 36) * deg_to_rad) * ((float)(diameter)/factor);\n\t\t// 36 is half of 72, and this will allow the inner and outer points to line up like a triangle.\n\t\tYpoints_I[idx] = cy + cos((float)(idx*rads + 36) * deg_to_rad) * ((float)(diameter)/factor);\n\t}\n\n\tfor(int idx = 0; idx < sides; idx++) {\n\t\tif((idx+1) < sides) {\n\t\t\tif(fill) {// this part below should be self explanatory. It fills in the star.\n\t\t\t\t_fillTriangle(cx,cy,Xpoints_I[idx],Ypoints_I[idx],Xpoints_O[idx],Ypoints_O[idx], color);\n\t\t\t\t_fillTriangle(cx,cy,Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx+1],Ypoints_I[idx+1], color);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_drawLine(Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx+1],Ypoints_I[idx+1], color);\n\t\t\t\t_drawLine(Xpoints_I[idx],Ypoints_I[idx],Xpoints_O[idx],Ypoints_O[idx], color);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif(fill) {\n\t\t\t\t_fillTriangle(cx,cy,Xpoints_I[0],Ypoints_I[0],Xpoints_O[idx],Ypoints_O[idx], color);\n\t\t\t\t_fillTriangle(cx,cy,Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx],Ypoints_I[idx], color);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_drawLine(Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx],Ypoints_I[idx], color);\n\t\t\t\t_drawLine(Xpoints_I[0],Ypoints_I[0],Xpoints_O[idx],Ypoints_O[idx], color);\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n\n// ================ Font and string functions ==================================\n\n//--------------------------------------------------------\nstatic int load_file_font(const char * fontfile, int info)\n{\n\tint err = 0;\n\tchar err_msg[256] = {'\\0'};\n\n\tif (userfont != NULL) {\n\t\tfree(userfont);\n\t\tuserfont = NULL;\n\t}\n\n    struct stat sb;\n\n    // Open the file\n    FILE *fhndl = fopen(fontfile, \"r\");\n    if (!fhndl) {\n    \tsprintf(err_msg, \"Error opening font file '%s'\", fontfile);\n\t\terr = 1;\n\t\tgoto exit;\n    }\n\n\t// Get file size\n    if (stat(fontfile, &sb) != 0) {\n    \tsprintf(err_msg, \"Error getting font file size\");\n\t\terr = 2;\n\t\tgoto exit;\n    }\n\tint fsize = sb.st_size;\n\tif (fsize < 30) {\n\t\tsprintf(err_msg, \"Error getting font file size\");\n\t\terr = 3;\n\t\tgoto exit;\n\t}\n\n\tuserfont = malloc(fsize+4);\n\tif (userfont == NULL) {\n\t\tsprintf(err_msg, \"Font memory allocation error\");\n\t\tfclose(fhndl);\n\t\terr = 4;\n\t\tgoto exit;\n\t}\n\n\tint read = fread(userfont, 1, fsize, fhndl);\n\n\tfclose(fhndl);\n\n\tif (read != fsize) {\n\t\tsprintf(err_msg, \"Font read error\");\n\t\terr = 5;\n\t\tgoto exit;\n\t}\n\n\tuserfont[read] = 0;\n\tif (strstr((char *)(userfont+read-8), \"RPH_font\") == NULL) {\n\t\tsprintf(err_msg, \"Font ID not found\");\n\t\terr = 6;\n\t\tgoto exit;\n\t}\n\n\t// Check size\n\tint size = 0;\n\tint numchar = 0;\n\tint width = userfont[0];\n\tint height = userfont[1];\n\tuint8_t first = 255;\n\tuint8_t last = 0;\n\t//int offst = 0;\n\tint pminwidth = 255;\n\tint pmaxwidth = 0;\n\n\tif (width != 0) {\n\t\t// Fixed font\n\t\tnumchar = userfont[3];\n\t\tfirst = userfont[2];\n\t\tlast = first + numchar - 1;\n\t\tsize = ((width * height * numchar) / 8) + 4;\n\t}\n\telse {\n\t\t// Proportional font\n\t\tsize = 4; // point at first char data\n\t\tuint8_t charCode;\n\t\tint charwidth;\n\n\t\tdo {\n\t\t    charCode = userfont[size];\n\t\t    charwidth = userfont[size+2];\n\n\t\t    if (charCode != 0xFF) {\n\t\t    \tnumchar++;\n\t\t    \tif (charwidth != 0) size += ((((charwidth * userfont[size+3])-1) / 8) + 7);\n\t\t    \telse size += 6;\n\n\t\t    \tif (info) {\n\t    \t\t\tif (charwidth > pmaxwidth) pmaxwidth = charwidth;\n\t    \t\t\tif (charwidth < pminwidth) pminwidth = charwidth;\n\t    \t\t\tif (charCode < first) first = charCode;\n\t    \t\t\tif (charCode > last) last = charCode;\n\t    \t\t}\n\t\t    }\n\t\t    else size++;\n\t\t  } while ((size < (read-8)) && (charCode != 0xFF));\n\t}\n\n\tif (size != (read-8)) {\n\t\tsprintf(err_msg, \"Font size error: found %d expected %d)\", size, (read-8));\n\t\terr = 7;\n\t\tgoto exit;\n\t}\n\n\tif (info) {\n\t\tif (width != 0) {\n\t\t\tprintf(\"Fixed width font:\\r\\n  size: %d  width: %d  height: %d  characters: %d (%d~%d)\",\n\t\t\t\t\tsize, width, height, numchar, first, last);\n\t\t}\n\t\telse {\n\t\t\tprintf(\"Proportional font:\\r\\n  size: %d  width: %d~%d  height: %d  characters: %d (%d~%d)\\n\",\n\t\t\t\t\tsize, pminwidth, pmaxwidth, height, numchar, first, last);\n\t\t}\n\t}\n\nexit:\n\tif (err) {\n\t\tif (userfont) {\n\t\t\tfree(userfont);\n\t\t\tuserfont = NULL;\n\t\t}\n\t\tif (info) printf(\"Error: %d [%s]\\r\\n\", err, err_msg);\n\t}\n\treturn err;\n}\n\n//------------------------------------------------\nint compile_font_file(char *fontfile, uint8_t dbg)\n{\n\tint err = 0;\n\tchar err_msg[128] = {'\\0'};\n\tchar outfile[128] = {'\\0'};\n\tsize_t len;\n    struct stat sb;\n    FILE *ffd = NULL;\n    FILE *ffd_out = NULL;\n    char *sourcebuf = NULL;\n\n    len = strlen(fontfile);\n\n\t// check here that filename end with \".c\".\n\tif ((len < 3) || (len > 125) || (strcmp(fontfile + len - 2, \".c\") != 0)) {\n\t\tsprintf(err_msg, \"not a .c file\");\n\t\terr = 1;\n\t\tgoto exit;\n\t}\n\n\tsprintf(outfile, \"%s\", fontfile);\n\tsprintf(outfile+strlen(outfile)-1, \"fon\");\n\n\t// Open the source file\n    if (stat(fontfile, &sb) != 0) {\n    \tsprintf(err_msg, \"Error opening source file '%s'\", fontfile);\n    \terr = 2;\n\t\tgoto exit;\n    }\n    // Open the file\n    ffd = fopen(fontfile, \"rb\");\n    if (!ffd) {\n    \tsprintf(err_msg, \"Error opening source file '%s'\", fontfile);\n    \terr = 3;\n\t\tgoto exit;\n    }\n\n\t// Open the font file\n    ffd_out= fopen(outfile, \"wb\");\n\tif (!ffd_out) {\n\t\tsprintf(err_msg, \"error opening destination file\");\n\t\terr = 4;\n\t\tgoto exit;\n\t}\n\n\t// Get file size\n\tint fsize = sb.st_size;\n\tif (fsize <= 0) {\n\t\tsprintf(err_msg, \"source file size error\");\n\t\terr = 5;\n\t\tgoto exit;\n\t}\n\n\tsourcebuf = malloc(fsize+4);\n\tif (sourcebuf == NULL) {\n\t\tsprintf(err_msg, \"memory allocation error\");\n\t\terr = 6;\n\t\tgoto exit;\n\t}\n\tchar *fbuf = sourcebuf;\n\n\tint rdsize = fread(fbuf, 1, fsize, ffd);\n\tfclose(ffd);\n\tffd = NULL;\n\n\tif (rdsize != fsize) {\n\t\tsprintf(err_msg, \"error reading from source file\");\n\t\terr = 7;\n\t\tgoto exit;\n\t}\n\n\t*(fbuf+rdsize) = '\\0';\n\n\tfbuf = strchr(fbuf, '{');\t\t\t// beginning of font data\n\tchar *fend = strstr(fbuf, \"};\");\t// end of font data\n\n\tif ((fbuf == NULL) || (fend == NULL) || ((fend-fbuf) < 22)) {\n\t\tsprintf(err_msg, \"wrong source file format\");\n\t\terr = 8;\n\t\tgoto exit;\n\t}\n\n\tfbuf++;\n\t*fend = '\\0';\n\tchar hexstr[5] = {'\\0'};\n\tint lastline = 0;\n\n\tfbuf = strstr(fbuf, \"0x\");\n\tint size = 0;\n\tchar *nextline;\n\tchar *numptr;\n\n\tint bptr = 0;\n\n\twhile ((fbuf != NULL) && (fbuf < fend) && (lastline == 0)) {\n\t\tnextline = strchr(fbuf, '\\n'); // beginning of the next line\n\t\tif (nextline == NULL) {\n\t\t\tnextline = fend-1;\n\t\t\tlastline++;\n\t\t}\n\t\telse nextline++;\n\n\t\twhile (fbuf < nextline) {\n\t\t\tnumptr = strstr(fbuf, \"0x\");\n\t\t\tif ((numptr == NULL) || ((fbuf+4) > nextline)) numptr = strstr(fbuf, \"0X\");\n\t\t\tif ((numptr != NULL) && ((numptr+4) <= nextline)) {\n\t\t\t\tfbuf = numptr;\n\t\t\t\tif (bptr >= 128) {\n\t\t\t\t\t// buffer full, write to file\n                    if (fwrite(outfile, 1, 128, ffd_out) != 128) goto error;\n\t\t\t\t\tbptr = 0;\n\t\t\t\t\tsize += 128;\n\t\t\t\t}\n\t\t\t\tmemcpy(hexstr, fbuf, 4);\n\t\t\t\thexstr[4] = 0;\n\t\t\t\toutfile[bptr++] = (uint8_t)strtol(hexstr, NULL, 0);\n\t\t\t\tfbuf += 4;\n\t\t\t}\n\t\t\telse fbuf = nextline;\n\t\t}\n\t\tfbuf = nextline;\n\t}\n\n\tif (bptr > 0) {\n\t\tsize += bptr;\n        if (fwrite(outfile, 1, bptr, ffd_out) != bptr) goto error;\n\t}\n\n\t// write font ID\n\tsprintf(outfile, \"RPH_font\");\n    if (fwrite(outfile, 1, 8, ffd_out) != 8) goto error;\n\n\t// === Test compiled font ===\n\tsprintf(outfile, \"%s\", fontfile);\n\tsprintf(outfile+strlen(outfile)-1, \"fon\");\n\n\tuint8_t *uf = userfont; // save userfont pointer\n\tuserfont = NULL;\n\tif (load_file_font(outfile, 1) == 0) {\n\t\tsprintf(err_msg, \"Error compiling file!\");\n\t}\n\telse {\n\t\tfree(userfont);\n\t\tsprintf(err_msg, \"File compiled successfully.\");\n\t}\n\tuserfont = uf; // restore userfont\n\n\tgoto exit;\n\nerror:\n\tsprintf(err_msg, \"error writing to destination file\");\n\terr = 9;\n\nexit:\n\tif (sourcebuf) free(sourcebuf);\n\tif (ffd) fclose(ffd);\n\tif (ffd_out) fclose(ffd_out);\n\n\tif (dbg) printf(\"%s\\r\\n\", err_msg);\n\n\treturn err;\n}\n\n\n// -----------------------------------------------------------------------------------------\n// Individual Proportional Font Character Format:\n// -----------------------------------------------------------------------------------------\n// Character Code\n// yOffset\t\t\t\t(start Y of visible pixels)\n// Width\t\t\t\t(width of the visible pixels)\n// Height\t\t\t\t(height of the visible pixels)\n// xOffset\t\t\t\t(start X of visible pixels)\n// xDelta\t\t\t\t(the distance to move the cursor. Effective width of the character.)\n// Data[n]\n// -----------------------------------------------------------------------------------------\n\n//---------------------------------------------------------------------------------------------\n// Character drawing rectangle is (0, 0) (xDelta-1, cfont.y_size-1)\n// Character visible pixels rectangle is (xOffset, yOffset) (xOffset+Width-1, yOffset+Height-1)\n//---------------------------------------------------------------------------------------------\n\n//----------------------------------\nvoid getFontCharacters(uint8_t *buf)\n{\n    if (cfont.bitmap == 2) {\n    \t//For 7 segment font only characters 0,1,2,3,4,5,6,7,8,9, . , - , : , / are available.\n\t\tfor (uint8_t n=0; n < 11; n++) {\n\t\t\tbuf[n] = n + 0x30;\n\t\t}\n\t\tbuf[11] = '.';\n\t\tbuf[12] = '-';\n\t\tbuf[13] = '/';\n\t\tbuf[14] = '\\0';\n    \treturn;\n    }\n\n    if (cfont.x_size > 0) {\n\t\tfor (uint8_t n=0; n < cfont.numchars; n++) {\n\t\t\tbuf[n] = cfont.offset + n;\n\t\t}\n\t\tbuf[cfont.numchars] = '\\0';\n\t\treturn;\n\t}\n\n\tuint16_t tempPtr = 4; // point at first char data\n\tuint8_t cc, cw, ch, n;\n\n\tn = 0;\n    cc = cfont.font[tempPtr++];\n    while (cc != 0xFF)  {\n    \tcfont.numchars++;\n        tempPtr++;\n        cw = cfont.font[tempPtr++];\n        ch = cfont.font[tempPtr++];\n        tempPtr++;\n        tempPtr++;\n\t\tif (cw != 0) {\n\t\t\t// packed bits\n\t\t\ttempPtr += (((cw * ch)-1) / 8) + 1;\n\t\t}\n\t\tbuf[n++] = cc;\n\t    cc = cfont.font[tempPtr++];\n\t}\n\tbuf[n] = '\\0';\n}\n\n// Set max width & height of the proportional font\n//-----------------------------\nstatic void getMaxWidthHeight()\n{\n\tuint16_t tempPtr = 4; // point at first char data\n\tuint8_t cc, cw, ch, cd, cy;\n\n\tcfont.numchars = 0;\n\tcfont.max_x_size = 0;\n\n    cc = cfont.font[tempPtr++];\n    while (cc != 0xFF)  {\n    \tcfont.numchars++;\n        cy = cfont.font[tempPtr++];\n        cw = cfont.font[tempPtr++];\n        ch = cfont.font[tempPtr++];\n        tempPtr++;\n        cd = cfont.font[tempPtr++];\n        cy += ch;\n\t\tif (cw > cfont.max_x_size) cfont.max_x_size = cw;\n\t\tif (cd > cfont.max_x_size) cfont.max_x_size = cd;\n\t\tif (ch > cfont.y_size) cfont.y_size = ch;\n\t\tif (cy > cfont.y_size) cfont.y_size = cy;\n\t\tif (cw != 0) {\n\t\t\t// packed bits\n\t\t\ttempPtr += (((cw * ch)-1) / 8) + 1;\n\t\t}\n\t    cc = cfont.font[tempPtr++];\n\t}\n    cfont.size = tempPtr;\n}\n\n// Return the Glyph data for an individual character in the proportional font\n//------------------------------------\nstatic uint8_t getCharPtr(uint8_t c) {\n  uint16_t tempPtr = 4; // point at first char data\n\n  do {\n\tfontChar.charCode = cfont.font[tempPtr++];\n    if (fontChar.charCode == 0xFF) return 0;\n\n    fontChar.adjYOffset = cfont.font[tempPtr++];\n    fontChar.width = cfont.font[tempPtr++];\n    fontChar.height = cfont.font[tempPtr++];\n    fontChar.xOffset = cfont.font[tempPtr++];\n    fontChar.xOffset = fontChar.xOffset < 0x80 ? fontChar.xOffset : -(0xFF - fontChar.xOffset);\n    fontChar.xDelta = cfont.font[tempPtr++];\n\n    if (c != fontChar.charCode && fontChar.charCode != 0xFF) {\n      if (fontChar.width != 0) {\n        // packed bits\n        tempPtr += (((fontChar.width * fontChar.height)-1) / 8) + 1;\n      }\n    }\n  } while ((c != fontChar.charCode) && (fontChar.charCode != 0xFF));\n\n  fontChar.dataPtr = tempPtr;\n  if (c == fontChar.charCode) {\n    if (font_forceFixed > 0) {\n      // fix width & offset for forced fixed width\n      fontChar.xDelta = cfont.max_x_size;\n      fontChar.xOffset = (fontChar.xDelta - fontChar.width) / 2;\n    }\n  }\n  else return 0;\n\n  return 1;\n}\n\n/*\n//-----------------------\nstatic void _testFont() {\n  if (cfont.x_size) {\n\t  printf(\"FONT TEST: fixed font\\r\\n\");\n\t  return;\n  }\n  uint16_t tempPtr = 4; // point at first char data\n  uint8_t c = 0x20;\n  for (c=0x20; c <0xFF; c++) {\n\tfontChar.charCode = cfont.font[tempPtr++];\n    if (fontChar.charCode == 0xFF) break;\n    if (fontChar.charCode != c) {\n    \tprintf(\"FONT TEST: last sequential char: %d, expected %d\\r\\n\", fontChar.charCode, c);\n    \tbreak;\n    }\n    c = fontChar.charCode;\n    fontChar.adjYOffset = cfont.font[tempPtr++];\n    fontChar.width = cfont.font[tempPtr++];\n    fontChar.height = cfont.font[tempPtr++];\n    fontChar.xOffset = cfont.font[tempPtr++];\n    fontChar.xOffset = fontChar.xOffset < 0x80 ? fontChar.xOffset : -(0xFF - fontChar.xOffset);\n    fontChar.xDelta = cfont.font[tempPtr++];\n\n    if (fontChar.charCode != 0xFF) {\n      if (fontChar.width != 0) {\n        // packed bits\n        tempPtr += (((fontChar.width * fontChar.height)-1) / 8) + 1;\n      }\n    }\n  }\n  printf(\"FONT TEST: W=%d  H=%d last char: %d [%c]; length: %d\\r\\n\", cfont.max_x_size, cfont.y_size, c, c, tempPtr);\n}\n*/\n\n//===================================================\nvoid EPD_setFont(uint8_t font, const char *font_file)\n{\n  cfont.font = NULL;\n\n  if (font == FONT_7SEG) {\n    cfont.bitmap = 2;\n    cfont.x_size = 24;\n    cfont.y_size = 6;\n    cfont.offset = 0;\n    cfont.color  = _fg;\n  }\n  else {\n\t  if (font == USER_FONT) {\n\t\t  if (load_file_font(font_file, 0) != 0) cfont.font = tft_DefaultFont;\n\t\t  else cfont.font = userfont;\n\t  }\n\t  else if (font == DEJAVU18_FONT) cfont.font = tft_Dejavu18;\n\t  else if (font == DEJAVU24_FONT) cfont.font = tft_Dejavu24;\n\t  else if (font == UBUNTU16_FONT) cfont.font = tft_Ubuntu16;\n\t  else if (font == COMIC24_FONT) cfont.font = tft_Comic24;\n\t  else if (font == MINYA24_FONT) cfont.font = tft_minya24;\n\t  else if (font == TOONEY32_FONT) cfont.font = tft_tooney32;\n\t  else if (font == SMALL_FONT) cfont.font = tft_SmallFont;\n\t  else cfont.font = tft_DefaultFont;\n\n\t  cfont.bitmap = 1;\n\t  cfont.x_size = cfont.font[0];\n\t  cfont.y_size = cfont.font[1];\n\t  if (cfont.x_size > 0) {\n\t\t  cfont.offset = cfont.font[2];\n\t\t  cfont.numchars = cfont.font[3];\n\t\t  cfont.size = cfont.x_size * cfont.y_size * cfont.numchars;\n\t  }\n\t  else {\n\t\t  cfont.offset = 4;\n\t\t  getMaxWidthHeight();\n\t  }\n\t  //_testFont();\n  }\n}\n\n// -----------------------------------------------------------------------------------------\n// Individual Proportional Font Character Format:\n// -----------------------------------------------------------------------------------------\n// Character Code\n// yOffset\t\t\t\t(start Y of visible pixels)\n// Width\t\t\t\t(width of the visible pixels)\n// Height\t\t\t\t(height of the visible pixels)\n// xOffset\t\t\t\t(start X of visible pixels)\n// xDelta\t\t\t\t(the distance to move the cursor. Effective width of the character.)\n// Data[n]\n// -----------------------------------------------------------------------------------------\n//---------------------------------------------------------------------------------------------\n// Character drawing rectangle is (0, 0) (xDelta-1, cfont.y_size-1)\n// Character visible pixels rectangle is (xOffset, yOffset) (xOffset+Width-1, yOffset+Height-1)\n//---------------------------------------------------------------------------------------------\n\n// print non-rotated proportional character\n// character is already in fontChar\n//----------------------------------------------\nstatic int printProportionalChar(int x, int y) {\n\tuint8_t ch = 0;\n\tint i, j, char_width;\n\n\tchar_width = ((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta);\n\tint cx, cy;\n\n\tif (!font_transparent) _fillRect(x, y, char_width+1, cfont.y_size, _bg);\n\n\t// draw Glyph\n\tuint8_t mask = 0x80;\n\tfor (j=0; j < fontChar.height; j++) {\n\t\tfor (i=0; i < fontChar.width; i++) {\n\t\t\tif (((i + (j*fontChar.width)) % 8) == 0) {\n\t\t\t\tmask = 0x80;\n\t\t\t\tch = cfont.font[fontChar.dataPtr++];\n\t\t\t}\n\n\t\t\tif ((ch & mask) !=0) {\n\t\t\t\tcx = (uint16_t)(x+fontChar.xOffset+i);\n\t\t\t\tcy = (uint16_t)(y+j+fontChar.adjYOffset);\n\t\t\t\t_drawPixel(cx, cy, _fg);\n\t\t\t}\n\t\t\tmask >>= 1;\n\t\t}\n\t}\n\n\treturn char_width;\n}\n\n// non-rotated fixed width character\n//----------------------------------------------\nstatic void printChar(uint8_t c, int x, int y) {\n\tuint8_t i, j, ch, fz, mask;\n\tuint16_t k, temp, cx, cy;\n\n\t// fz = bytes per char row\n\tfz = cfont.x_size/8;\n\tif (cfont.x_size % 8) fz++;\n\n\t// get character position in buffer\n\ttemp = ((c-cfont.offset)*((fz)*cfont.y_size))+4;\n\n\tif (!font_transparent) _fillRect(x, y, cfont.x_size, cfont.y_size, _bg);\n\n\tfor (j=0; j<cfont.y_size; j++) {\n\t\tfor (k=0; k < fz; k++) {\n\t\t\tch = cfont.font[temp+k];\n\t\t\tmask=0x80;\n\t\t\tfor (i=0; i<8; i++) {\n\t\t\t\tif ((ch & mask) !=0) {\n\t\t\t\t\tcx = (uint16_t)(x+i+(k*8));\n\t\t\t\t\tcy = (uint16_t)(y+j);\n\t\t\t\t\t_drawPixel(cx, cy, _fg);\n\t\t\t\t}\n\t\t\t\tmask >>= 1;\n\t\t\t}\n\t\t}\n\t\ttemp += (fz);\n\t}\n}\n\n// print rotated proportional character\n// character is already in fontChar\n//---------------------------------------------------\nstatic int rotatePropChar(int x, int y, int offset) {\n  uint8_t ch = 0;\n  double radian = font_rotate * DEG_TO_RAD;\n  float cos_radian = cos(radian);\n  float sin_radian = sin(radian);\n\n  uint8_t mask = 0x80;\n  for (int j=0; j < fontChar.height; j++) {\n    for (int i=0; i < fontChar.width; i++) {\n      if (((i + (j*fontChar.width)) % 8) == 0) {\n        mask = 0x80;\n        ch = cfont.font[fontChar.dataPtr++];\n      }\n\n      int newX = (int)(x + (((offset + i) * cos_radian) - ((j+fontChar.adjYOffset)*sin_radian)));\n      int newY = (int)(y + (((j+fontChar.adjYOffset) * cos_radian) + ((offset + i) * sin_radian)));\n\n      if ((ch & mask) != 0) _drawPixel(newX,newY,_fg);\n      else if (!font_transparent) _drawPixel(newX,newY,_bg);\n\n      mask >>= 1;\n    }\n  }\n\n  return fontChar.xDelta+1;\n}\n\n// rotated fixed width character\n//--------------------------------------------------------\nstatic void rotateChar(uint8_t c, int x, int y, int pos) {\n  uint8_t i,j,ch,fz,mask;\n  uint16_t temp;\n  int newx,newy;\n  double radian = font_rotate*0.0175;\n  float cos_radian = cos(radian);\n  float sin_radian = sin(radian);\n  int zz;\n\n  if( cfont.x_size < 8 ) fz = cfont.x_size;\n  else fz = cfont.x_size/8;\n  temp=((c-cfont.offset)*((fz)*cfont.y_size))+4;\n\n  for (j=0; j<cfont.y_size; j++) {\n    for (zz=0; zz<(fz); zz++) {\n      ch = cfont.font[temp+zz];\n      mask = 0x80;\n      for (i=0; i<8; i++) {\n        newx=(int)(x+(((i+(zz*8)+(pos*cfont.x_size))*cos_radian)-((j)*sin_radian)));\n        newy=(int)(y+(((j)*cos_radian)+((i+(zz*8)+(pos*cfont.x_size))*sin_radian)));\n\n        if ((ch & mask) != 0) _drawPixel(newx,newy,_fg);\n        else if (!font_transparent) _drawPixel(newx,newy,_bg);\n        mask >>= 1;\n      }\n    }\n    temp+=(fz);\n  }\n  // calculate x,y for the next char\n  EPD_X = (int)(x + ((pos+1) * cfont.x_size * cos_radian));\n  EPD_Y = (int)(y + ((pos+1) * cfont.x_size * sin_radian));\n}\n\n//----------------------\nstatic int _7seg_width()\n{\n\treturn (2 * (2 * cfont.y_size + 1)) + cfont.x_size;\n}\n\n//-----------------------\nstatic int _7seg_height()\n{\n\treturn (3 * (2 * cfont.y_size + 1)) + (2 * cfont.x_size);\n}\n\n// Returns the string width in pixels.\n// Useful for positions strings on the screen.\n//===============================\nint EPD_getStringWidth(char* str)\n{\n    int strWidth = 0;\n\n\tif (cfont.bitmap == 2) strWidth = ((_7seg_width()+2) * strlen(str)) - 2;\t// 7-segment font\n\telse if (cfont.x_size != 0) strWidth = strlen(str) * cfont.x_size;\t\t\t// fixed width font\n\telse {\n\t\t// calculate the width of the string of proportional characters\n\t\tchar* tempStrptr = str;\n\t\twhile (*tempStrptr != 0) {\n\t\t\tif (getCharPtr(*tempStrptr++)) {\n\t\t\t\tstrWidth += (((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta) + 1);\n\t\t\t}\n\t\t}\n\t\tstrWidth--;\n\t}\n\treturn strWidth;\n}\n\n//===============================================\nvoid EPD_clearStringRect(int x, int y, char *str)\n{\n\tint w = EPD_getStringWidth(str);\n\tint h = EPD_getfontheight();\n\tEPD_fillRect(x+dispWin.x1, y+dispWin.y1, w, h, _bg);\n}\n\n//==============================================================================\n/**\n * bit-encoded bar position of all digits' bcd segments\n *\n *           6\n * \t\t  +-----+\n * \t\t3 |  .\t| 2\n * \t\t  +--5--+\n * \t\t1 |  .\t| 0\n * \t\t  +--.--+\n * \t\t     4\n */\nstatic const uint16_t font_bcd[] = {\n  0x200, // 0010 0000 0000  // -\n  0x080, // 0000 1000 0000  // .\n  0x06C, // 0100 0110 1100  // /, degree\n  0x05f, // 0000 0101 1111, // 0\n  0x005, // 0000 0000 0101, // 1\n  0x076, // 0000 0111 0110, // 2\n  0x075, // 0000 0111 0101, // 3\n  0x02d, // 0000 0010 1101, // 4\n  0x079, // 0000 0111 1001, // 5\n  0x07b, // 0000 0111 1011, // 6\n  0x045, // 0000 0100 0101, // 7\n  0x07f, // 0000 0111 1111, // 8\n  0x07d, // 0000 0111 1101  // 9\n  0x900  // 1001 0000 0000  // :\n};\n\n//-----------------------------------------------------------------------------------------------\nstatic void barVert(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, color_t outline) {\n  _fillTriangle(x+1, y+2*w, x+w, y+w+1, x+2*w-1, y+2*w, color);\n  _fillTriangle(x+1, y+2*w+l+1, x+w, y+3*w+l, x+2*w-1, y+2*w+l+1, color);\n  _fillRect(x, y+2*w+1, 2*w+1, l, color);\n  if (cfont.offset) {\n    _drawTriangle(x+1, y+2*w, x+w, y+w+1, x+2*w-1, y+2*w, outline);\n    _drawTriangle(x+1, y+2*w+l+1, x+w, y+3*w+l, x+2*w-1, y+2*w+l+1, outline);\n    _drawRect(x, y+2*w+1, 2*w+1, l, outline);\n  }\n}\n\n//----------------------------------------------------------------------------------------------\nstatic void barHor(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, color_t outline) {\n  _fillTriangle(x+2*w, y+2*w-1, x+w+1, y+w, x+2*w, y+1, color);\n  _fillTriangle(x+2*w+l+1, y+2*w-1, x+3*w+l, y+w, x+2*w+l+1, y+1, color);\n  _fillRect(x+2*w+1, y, l, 2*w+1, color);\n  if (cfont.offset) {\n    _drawTriangle(x+2*w, y+2*w-1, x+w+1, y+w, x+2*w, y+1, outline);\n    _drawTriangle(x+2*w+l+1, y+2*w-1, x+3*w+l, y+w, x+2*w+l+1, y+1, outline);\n    _drawRect(x+2*w+1, y, l, 2*w+1, outline);\n  }\n}\n\n//--------------------------------------------------------------------------------------------\nstatic void _draw7seg(int16_t x, int16_t y, int8_t num, int16_t w, int16_t l, color_t color) {\n  /* TODO: clipping */\n  if (num < 0x2D || num > 0x3A) return;\n\n  int16_t c = font_bcd[num-0x2D];\n  int16_t d = 2*w+l+1;\n\n  // === Clear unused segments ===\n  /*\n  if (!(c & 0x001)) barVert(x+d, y+d, w, l, _bg, _bg);\n  if (!(c & 0x002)) barVert(x,   y+d, w, l, _bg, _bg);\n  if (!(c & 0x004)) barVert(x+d, y, w, l, _bg, _bg);\n  if (!(c & 0x008)) barVert(x,   y, w, l, _bg, _bg);\n  if (!(c & 0x010)) barHor(x, y+2*d, w, l, _bg, _bg);\n  if (!(c & 0x020)) barHor(x, y+d, w, l, _bg, _bg);\n  if (!(c & 0x040)) barHor(x, y, w, l, _bg, _bg);\n\n  if (!(c & 0x080)) {\n    // low point\n    _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, _bg);\n    if (cfont.offset) _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, _bg);\n  }\n  if (!(c & 0x100)) {\n    // down middle point\n    _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, _bg);\n    if (cfont.offset) _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, _bg);\n  }\n  if (!(c & 0x800)) {\n\t// up middle point\n    _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, _bg);\n    if (cfont.offset) _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, _bg);\n  }\n  if (!(c & 0x200)) {\n    // middle, minus\n    _fillRect(x+2*w+1, y+d, l, 2*w+1, _bg);\n    if (cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, _bg);\n  }\n  */\n  barVert(x+d, y+d, w, l, _bg, _bg);\n  barVert(x,   y+d, w, l, _bg, _bg);\n  barVert(x+d, y, w, l, _bg, _bg);\n  barVert(x,   y, w, l, _bg, _bg);\n  barHor(x, y+2*d, w, l, _bg, _bg);\n  barHor(x, y+d, w, l, _bg, _bg);\n  barHor(x, y, w, l, _bg, _bg);\n\n  _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, _bg);\n  _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, _bg);\n  _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, _bg);\n  _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, _bg);\n  _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, _bg);\n  _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, _bg);\n  _fillRect(x+2*w+1, y+d, l, 2*w+1, _bg);\n  _drawRect(x+2*w+1, y+d, l, 2*w+1, _bg);\n\n  // === Draw used segments ===\n  if (c & 0x001) barVert(x+d, y+d, w, l, color, cfont.color);\t// down right\n  if (c & 0x002) barVert(x,   y+d, w, l, color, cfont.color);\t// down left\n  if (c & 0x004) barVert(x+d, y, w, l, color, cfont.color);\t\t// up right\n  if (c & 0x008) barVert(x,   y, w, l, color, cfont.color);\t\t// up left\n  if (c & 0x010) barHor(x, y+2*d, w, l, color, cfont.color);\t// down\n  if (c & 0x020) barHor(x, y+d, w, l, color, cfont.color);\t\t// middle\n  if (c & 0x040) barHor(x, y, w, l, color, cfont.color);\t\t// up\n\n  if (c & 0x080) {\n    // low point\n    _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, color);\n    if (cfont.offset) _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, cfont.color);\n  }\n  if (c & 0x100) {\n    // down middle point\n    _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, color);\n    if (cfont.offset) _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, cfont.color);\n  }\n  if (c & 0x800) {\n\t// up middle point\n    _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, color);\n    if (cfont.offset) _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, cfont.color);\n  }\n  if (c & 0x200) {\n    // middle, minus\n    _fillRect(x+2*w+1, y+d, l, 2*w+1, color);\n    if (cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, cfont.color);\n  }\n}\n//==============================================================================\n\n//======================================\nvoid EPD_print(char *st, int x, int y) {\n\tint stl, i, tmpw, tmph, fh;\n\tuint8_t ch;\n\n\tif (cfont.bitmap == 0) return; // wrong font selected\n\n\t// ** Rotated strings cannot be aligned\n\tif ((font_rotate != 0) && ((x <= CENTER) || (y <= CENTER))) return;\n\n\tif ((x < LASTX) || (font_rotate == 0)) EPD_OFFSET = 0;\n\n\tif ((x >= LASTX) && (x < LASTY)) x = EPD_X + (x-LASTX);\n\telse if (x > CENTER) x += dispWin.x1;\n\n\tif (y >= LASTY) y = EPD_Y + (y-LASTY);\n\telse if (y > CENTER) y += dispWin.y1;\n\n\t// ** Get number of characters in string to print\n\tstl = strlen(st);\n\n\t// ** Calculate CENTER, RIGHT or BOTTOM position\n\ttmpw = EPD_getStringWidth(st);\t// string width in pixels\n\tfh = cfont.y_size;\t\t\t// font height\n\tif ((cfont.x_size != 0) && (cfont.bitmap == 2)) {\n\t\t// 7-segment font\n\t\tfh = (3 * (2 * cfont.y_size + 1)) + (2 * cfont.x_size);  // 7-seg character height\n\t}\n\n\tif (x == RIGHT) x = dispWin.x2 - tmpw + dispWin.x1;\n\telse if (x == CENTER) x = (((dispWin.x2 - dispWin.x1 + 1) - tmpw) / 2) + dispWin.x1;\n\n\tif (y == BOTTOM) y = dispWin.y2 - fh + dispWin.y1;\n\telse if (y==CENTER) y = (((dispWin.y2 - dispWin.y1 + 1) - (fh/2)) / 2) + dispWin.y1;\n\n\tif (x < dispWin.x1) x = dispWin.x1;\n\tif (y < dispWin.y1) y = dispWin.y1;\n\tif ((x > dispWin.x2) || (y > dispWin.y2)) return;\n\n\t EPD_X = x;\n\t EPD_Y = y;\n\n\t// ** Adjust y position\n\ttmph = cfont.y_size; // font height\n\t// for non-proportional fonts, char width is the same for all chars\n\ttmpw = cfont.x_size;\n\tif (cfont.x_size != 0) {\n\t\tif (cfont.bitmap == 2) {\t// 7-segment font\n\t\t\ttmpw = _7seg_width();\t// character width\n\t\t\ttmph = _7seg_height();\t// character height\n\t\t}\n\t}\n\telse EPD_OFFSET = 0;\t// fixed font; offset not needed\n\n\tif (( EPD_Y + tmph - 1) > dispWin.y2) return;\n\n\tint offset = EPD_OFFSET;\n\n\tfor (i=0; i<stl; i++) {\n\t\tch = st[i]; // get string character\n\n\t\tif (ch == 0x0D) { // === '\\r', erase to eol ====\n\t\t\tif ((!font_transparent) && (font_rotate==0)) _fillRect( EPD_X, EPD_Y,  dispWin.x2+1- EPD_X, tmph, _bg);\n\t\t}\n\n\t\telse if (ch == 0x0A) { // ==== '\\n', new line ====\n\t\t\tif (cfont.bitmap == 1) {\n\t\t\t\t EPD_Y += tmph + font_line_space;\n\t\t\t\tif ( EPD_Y > (dispWin.y2-tmph)) break;\n\t\t\t\t EPD_X = dispWin.x1;\n\t\t\t}\n\t\t}\n\n\t\telse { // ==== other characters ====\n\t\t\tif (cfont.x_size == 0) {\n\t\t\t\t// for proportional font get character data to 'fontChar'\n\t\t\t\tif (getCharPtr(ch)) tmpw = fontChar.xDelta;\n\t\t\t\telse continue;\n\t\t\t}\n\n\t\t\t// check if character can be displayed in the current line\n\t\t\tif (( EPD_X+tmpw) > (dispWin.x2)) {\n\t\t\t\tif (text_wrap == 0) break;\n\t\t\t\t EPD_Y += tmph + font_line_space;\n\t\t\t\tif ( EPD_Y > (dispWin.y2-tmph)) break;\n\t\t\t\t EPD_X = dispWin.x1;\n\t\t\t}\n\n\t\t\t// Let's print the character\n\t\t\tif (cfont.x_size == 0) {\n\t\t\t\t// == proportional font\n\t\t\t\tif (font_rotate == 0) EPD_X += printProportionalChar( EPD_X, EPD_Y) + 1;\n\t\t\t\telse {\n\t\t\t\t\t// rotated proportional font\n\t\t\t\t\toffset += rotatePropChar(x, y, offset);\n\t\t\t\t\tEPD_OFFSET = offset;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (cfont.bitmap == 1) {\n\t\t\t\t\t// == fixed font\n\t\t\t\t\tif ((ch < cfont.offset) || ((ch-cfont.offset) > cfont.numchars)) ch = cfont.offset;\n\t\t\t\t\tif (font_rotate == 0) {\n\t\t\t\t\t\tprintChar(ch, EPD_X, EPD_Y);\n\t\t\t\t\t\t EPD_X += tmpw;\n\t\t\t\t\t}\n\t\t\t\t\telse rotateChar(ch, x, y, i);\n\t\t\t\t}\n\t\t\t\telse if (cfont.bitmap == 2) {\n\t\t\t\t\t// == 7-segment font ==\n\t\t\t\t\t_draw7seg( EPD_X, EPD_Y, ch, cfont.y_size, cfont.x_size, _fg);\n\t\t\t\t\t EPD_X += (tmpw + 2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n// ================ Service functions ==========================================\n\n//=====================================================================\nvoid EPD_setclipwin(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)\n{\n\tdispWin.x1 = x1;\n\tdispWin.y1 = y1;\n\tdispWin.x2 = x2;\n\tdispWin.y2 = y2;\n\n\tif (dispWin.x2 >= EPD_DISPLAY_WIDTH) dispWin.x2 = EPD_DISPLAY_WIDTH-1;\n\tif (dispWin.y2 >= EPD_DISPLAY_HEIGHT) dispWin.y2 = EPD_DISPLAY_HEIGHT-1;\n\tif (dispWin.x1 > dispWin.x2) dispWin.x1 = dispWin.x2;\n\tif (dispWin.y1 > dispWin.y2) dispWin.y1 = dispWin.y2;\n}\n\n//=====================\nvoid EPD_resetclipwin()\n{\n\tdispWin.x2 = EPD_DISPLAY_WIDTH-1;\n\tdispWin.y2 = EPD_DISPLAY_HEIGHT-1;\n\tdispWin.x1 = 0;\n\tdispWin.y1 = 0;\n}\n\n//==========================================================================\nvoid set_7seg_font_atrib(uint8_t l, uint8_t w, int outline, color_t color) {\n\tif (cfont.bitmap != 2) return;\n\n\tif (l < 6) l = 6;\n    if (l > 40) l = 40;\n    if (w < 1) w = 1;\n    if (w > (l/2)) w = l/2;\n    if (w > 12) w = 12;\n\n    cfont.x_size = l;\n\tcfont.y_size = w;\n\tcfont.offset = outline;\n\tcfont.color  = color;\n}\n\n//==========================================\nint EPD_getfontsize(int *width, int* height)\n{\n  if (cfont.bitmap == 1) {\n    if (cfont.x_size != 0) *width = cfont.x_size;\t// fixed width font\n    else *width = cfont.max_x_size;\t\t\t\t\t// proportional font\n    *height = cfont.y_size;\n  }\n  else if (cfont.bitmap == 2) {\n\t// 7-segment font\n    *width = _7seg_width();\n    *height = _7seg_height();\n  }\n  else {\n    *width = 0;\n    *height = 0;\n    return 0;\n  }\n  return 1;\n}\n\n//=====================\nint EPD_getfontheight()\n{\n  if (cfont.bitmap == 1) return cfont.y_size;\t\t\t// Bitmap font\n  else if (cfont.bitmap == 2) return _7seg_height();\t// 7-segment font\n  return 0;\n}\n\n//====================\nvoid EPD_saveClipWin()\n{\n\tdispWinTemp.x1 = dispWin.x1;\n\tdispWinTemp.y1 = dispWin.y1;\n\tdispWinTemp.x2 = dispWin.x2;\n\tdispWinTemp.y2 = dispWin.y2;\n}\n\n//=======================\nvoid EPD_restoreClipWin()\n{\n\tdispWin.x1 = dispWinTemp.x1;\n\tdispWin.y1 = dispWinTemp.y1;\n\tdispWin.x2 = dispWinTemp.x2;\n\tdispWin.y2 = dispWinTemp.y2;\n}\n\n\n// ================ JPG SUPPORT ================================================\n\n// RGB to GRAYSCALE constants\n// 0.2989  0.5870  0.1140\n#define GS_FACT_R 0.2989\n#define GS_FACT_G 0.4870\n#define GS_FACT_B 0.2140\n\n// User defined device identifier\ntypedef struct {\n\tFILE\t\t*fhndl;\t\t\t// File handler for input function\n    int\t\t\tx;\t\t\t\t// image top left point X position\n    int\t\t\ty;\t\t\t\t// image top left point Y position\n    uint8_t\t\t*membuff;\t\t// memory buffer containing the image\n    uint32_t\tbufsize;\t\t// size of the memory buffer\n    uint32_t\tbufptr;\t\t\t// memory buffer current position\n} JPGIODEV;\n\n\n// User defined call-back function to input JPEG data from file\n//---------------------\nstatic UINT tjd_input (\n\tJDEC* jd,\t\t// Decompression object\n\tBYTE* buff,\t\t// Pointer to the read buffer (NULL:skip)\n\tUINT nd\t\t\t// Number of bytes to read/skip from input stream\n)\n{\n\tint rb = 0;\n\t// Device identifier for the session (5th argument of jd_prepare function)\n\tJPGIODEV *dev = (JPGIODEV*)jd->device;\n\n\tif (buff) {\t// Read nd bytes from the input strem\n\t\trb = fread(buff, 1, nd, dev->fhndl);\n\t\treturn rb;\t// Returns actual number of bytes read\n\t}\n\telse {\t// Remove nd bytes from the input stream\n\t\tif (fseek(dev->fhndl, nd, SEEK_CUR) >= 0) return nd;\n\t\telse return 0;\n\t}\n}\n\n// User defined call-back function to input JPEG data from memory buffer\n//-------------------------\nstatic UINT tjd_buf_input (\n\tJDEC* jd,\t\t// Decompression object\n\tBYTE* buff,\t\t// Pointer to the read buffer (NULL:skip)\n\tUINT nd\t\t\t// Number of bytes to read/skip from input stream\n)\n{\n\t// Device identifier for the session (5th argument of jd_prepare function)\n\tJPGIODEV *dev = (JPGIODEV*)jd->device;\n\tif (!dev->membuff) return 0;\n\tif (dev->bufptr >= (dev->bufsize + 2)) return 0; // end of stream\n\n\tif ((dev->bufptr + nd) > (dev->bufsize + 2)) nd = (dev->bufsize + 2) - dev->bufptr;\n\n\tif (buff) {\t// Read nd bytes from the input strem\n\t\tmemcpy(buff, dev->membuff + dev->bufptr, nd);\n\t\tdev->bufptr += nd;\n\t\treturn nd;\t// Returns number of bytes read\n\t}\n\telse {\t// Remove nd bytes from the input stream\n\t\tdev->bufptr += nd;\n\t\treturn nd;\n\t}\n}\n\n// User defined call-back function to output RGB bitmap to display device\n//----------------------\nstatic UINT tjd_output (\n\tJDEC* jd,\t\t// Decompression object of current session\n\tvoid* bitmap,\t// Bitmap data to be output\n\tJRECT* rect\t\t// Rectangular region to output\n)\n{\n\t// Device identifier for the session (5th argument of jd_prepare function)\n\tJPGIODEV *dev = (JPGIODEV*)jd->device;\n\n\t// ** Put the rectangular into the display device **\n\tint x;\n\tint y;\n\tint dleft, dtop, dright, dbottom;\n\tBYTE *src = (BYTE*)bitmap;\n\n\tint left = rect->left + dev->x;\n\tint top = rect->top + dev->y;\n\tint right = rect->right + dev->x;\n\tint bottom = rect->bottom + dev->y;\n\n\tif ((left > dispWin.x2) || (top > dispWin.y2)) return 1;\t// out of screen area, return\n\tif ((right < dispWin.x1) || (bottom < dispWin.y1)) return 1;// out of screen area, return\n\n\tif (left < dispWin.x1) dleft = dispWin.x1;\n\telse dleft = left;\n\tif (top < dispWin.y1) dtop = dispWin.y1;\n\telse dtop = top;\n\tif (right > dispWin.x2) dright = dispWin.x2;\n\telse dright = right;\n\tif (bottom > dispWin.y2) dbottom = dispWin.y2;\n\telse dbottom = bottom;\n\n\tif ((dleft > dispWin.x2) || (dtop > dispWin.y2)) return 1;\t\t// out of screen area, return\n\tif ((dright < dispWin.x1) || (dbottom < dispWin.y1)) return 1;\t// out of screen area, return\n\n\tuint32_t len = ((dright-dleft+1) * (dbottom-dtop+1));\t// calculate length of data\n\n\tfloat gs_clr = 0;\n\tuint8_t rgb_color[3];\n\tuint8_t last_lvl, i;\n\tuint8_t pix;\n\tif ((len > 0) && (len <= JPG_IMAGE_LINE_BUF_SIZE)) {\n\t\tfor (y = top; y <= bottom; y++) {\n\t\t\tfor (x = left; x <= right; x++) {\n\t\t\t\t// Clip to display area\n\t\t\t\tif ((x >= dleft) && (y >= dtop) && (x <= dright) && (y <= dbottom)) {\n\t\t\t\t\t// Directly convert color to 4-bit gray scale\n\t\t\t\t\tpix = 0;\n\t\t\t\t\tpix |= ((*src++) >> 4) & 0x08;\n\t\t\t\t\tpix |= ((*src++) >> 5) & 0x06;\n\t\t\t\t\tpix |= ((*src++) >> 7);\n\t\t\t\t\tpix ^= 0x0F;\n\n\n\t\t\t\t\t/* Convert rgb color to gray scale\n\t\t\t\t\tmemcpy(rgb_color, src, 3);\n\t\t\t\t\tsrc += 3;\n\t\t\t\t    gs_clr = (GS_FACT_R * rgb_color[0]) + (GS_FACT_G * rgb_color[1]) + (GS_FACT_B * rgb_color[2]);\n\t\t\t\t    if (gs_clr > 255) gs_clr = 255;\n\t\t\t\t    // Use only 4 bits & invert\n\t\t\t\t    //pix = ((uint8_t)gs_clr >> 4) ^ 0x0F;\n\t\t\t\t    pix = (uint8_t)gs_clr;\n\n\t\t\t\t    // Using gray scale lookup table\n\t\t\t\t    last_lvl = 0;\n\t\t\t\t    i = 0;\n\t\t\t\t    for (i=0; i<16; i++) {\n\t\t\t\t    \tif ((pix > last_lvl) && (pix <= lvl_buf_jpg[i])) {\n\t\t\t\t    \t\tpix = 15 - i;\n\t\t\t\t\t        last_lvl = lvl_buf[i];\n\t\t\t\t\t        break;\n\t\t\t\t        }\n\t\t\t\t        last_lvl = lvl_buf[i];\n\t\t\t\t    }\n\t\t\t\t\t*/\n\t\t\t\t    gs_disp_buffer[(y * EPD_DISPLAY_WIDTH) + x] = pix;\n\t\t    \t\tgs_used_shades |= (1 << pix);\n\t\t\t\t}\n\t\t\t\telse src += 3; // skip\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tprintf(\"Data size error: %d jpg: (%d,%d,%d,%d) disp: (%d,%d,%d,%d)\\r\\n\", len, left,top,right,bottom, dleft,dtop,dright,dbottom);\n\t\treturn 0;  // stop decompression\n\t}\n\n\treturn 1;\t// Continue to decompression\n}\n\n// X & Y can be < 0 !\n//=================================================================================\nint EPD_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size)\n{\n\tJPGIODEV dev;\n    struct stat sb;\n\tchar *work = NULL;\t\t// Pointer to the working buffer (must be 4-byte aligned)\n\tUINT sz_work = 3800;\t// Size of the working buffer (must be power of 2)\n\tJDEC jd;\t\t\t\t// Decompression object (70 bytes)\n\tJRESULT rc;\n\tint res = -10;\n\n    if (fname == NULL) {\n    \t// image from buffer\n    \tdev.fhndl = NULL;\n        dev.membuff = buf;\n        dev.bufsize = size;\n        dev.bufptr = 0;\n    }\n    else {\n    \t// image from file\n        dev.membuff = NULL;\n        dev.bufsize = 0;\n        dev.bufptr = 0;\n\n        if (stat(fname, &sb) != 0) {\n        \tif (image_debug) printf(\"File error: %ss\\r\\n\", strerror(errno));\n        \tres = -11;\n            goto exit;\n        }\n\n        dev.fhndl = fopen(fname, \"r\");\n        if (!dev.fhndl) {\n        \tif (image_debug) printf(\"Error opening file: %s\\r\\n\", strerror(errno));\n        \tres = -12;\n            goto exit;\n        }\n    }\n\n\tif (scale > 3) scale = 3;\n\n\twork = malloc(sz_work);\n\tif (work) {\n\t\tif (dev.membuff) rc = jd_prepare(&jd, tjd_buf_input, (void *)work, sz_work, &dev);\n\t\telse rc = jd_prepare(&jd, tjd_input, (void *)work, sz_work, &dev);\n\t\tif (rc == JDR_OK) {\n\t\t\tif (x == CENTER) x = ((dispWin.x2 - dispWin.x1 + 1 - (int)(jd.width >> scale)) / 2) + dispWin.x1;\n\t\t\telse if (x == RIGHT) x = dispWin.x2 + 1 - (int)(jd.width >> scale);\n\n\t\t\tif (y == CENTER) y = ((dispWin.y2 - dispWin.y1 + 1 - (int)(jd.height >> scale)) / 2) + dispWin.y1;\n\t\t\telse if (y == BOTTOM) y = dispWin.y2 + 1 - (int)(jd.height >> scale);\n\n\t\t\tif (x < ((dispWin.x2-1) * -1)) x = (dispWin.x2-1) * -1;\n\t\t\tif (y < ((dispWin.y2-1)) * -1) y = (dispWin.y2-1) * -1;\n\t\t\tif (x > (dispWin.x2-1)) x = dispWin.x2 - 1;\n\t\t\tif (y > (dispWin.y2-1)) y = dispWin.y2-1;\n\n\t\t\tdev.x = x;\n\t\t\tdev.y = y;\n\n\t\t\t// Start to decode the JPEG file\n\t\t\trc = jd_decomp(&jd, tjd_output, scale);\n\n\t\t\tif (rc != JDR_OK) {\n\t\t\t\tif (image_debug) printf(\"jpg decompression error %d\\r\\n\", rc);\n\t\t\t\tres = rc * -1;\n\t\t\t}\n\t\t\tres = 0;\n\t\t\tif (image_debug) printf(\"Jpg size: %dx%d, position; %d,%d, scale: %d, bytes used: %d\\r\\n\", jd.width, jd.height, x, y, scale, jd.sz_pool);\n\t\t}\n\t\telse {\n\t\t\tif (image_debug) printf(\"jpg prepare error %d\\r\\n\", rc);\n\t\t\tres = rc * -1;\n\t\t}\n\t}\n\telse {\n\t\tif (image_debug) printf(\"work buffer allocation error\\r\\n\");\n\t\tres = -13;\n\t}\n\nexit:\n\tif (work) free(work);  // free work buffer\n    if (dev.fhndl) fclose(dev.fhndl);  // close input file\n    return res;\n}\n\n"
  },
  {
    "path": "components/epaper/EPD.h",
    "content": "/*\n * High level EPD functions\n * Author:  LoBo 06/2017, https://github/loboris\n * \n */\n\n#ifndef _EPD_H_\n#define _EPD_H_\n\n#include <stdlib.h>\n#include \"EPDspi.h\"\n\ntypedef uint8_t color_t;\n\ntypedef struct {\n\tuint16_t        x1;\n\tuint16_t        y1;\n\tuint16_t        x2;\n\tuint16_t        y2;\n} dispWin_t;\n\ntypedef struct {\n\tuint8_t \t*font;\n\tuint8_t \tx_size;\n\tuint8_t \ty_size;\n\tuint8_t\t    offset;\n\tuint16_t\tnumchars;\n    uint16_t\tsize;\n\tuint8_t \tmax_x_size;\n    uint8_t     bitmap;\n\tcolor_t     color;\n} Font_t;\n\n\n\n//==========================================================================================\n// ==== Global variables ===================================================================\n//==========================================================================================\nuint8_t   orientation;\t\t// current screen orientation\nuint16_t  font_rotate;   \t// current font font_rotate angle (0~395)\nuint8_t   font_transparent;\t// if not 0 draw fonts transparent\nuint8_t   font_forceFixed;  // if not zero force drawing proportional fonts with fixed width\nuint8_t   font_buffered_char;\nuint8_t   font_line_space;\t// additional spacing between text lines; added to font height\nuint8_t   text_wrap;        // if not 0 wrap long text to the new line, else clip\ncolor_t   _fg;            \t// current foreground color for fonts\ncolor_t   _bg;            \t// current background for non transparent fonts\ndispWin_t dispWin;\t\t\t// display clip window\nfloat\t  _angleOffset;\t\t// angle offset for arc, polygon and line by angle functions\n\nFont_t cfont;\t\t\t\t\t// Current font structure\nuint8_t image_debug;\n\nint\tEPD_X;\t\t\t\t\t// X position of the next character after EPD_print() function\nint\tEPD_Y;\t\t\t\t\t// Y position of the next character after EPD_print() function\n// =========================================================================================\n\n\n// Buffer is created during jpeg decode for sending data\n// Total size of the buffer is  2 * (JPG_IMAGE_LINE_BUF_SIZE * 3)\n// The size must be multiple of 256 bytes !!\n#define JPG_IMAGE_LINE_BUF_SIZE 512\n\n// --- Constants for ellipse function ---\n#define EPD_ELLIPSE_UPPER_RIGHT 0x01\n#define EPD_ELLIPSE_UPPER_LEFT  0x02\n#define EPD_ELLIPSE_LOWER_LEFT  0x04\n#define EPD_ELLIPSE_LOWER_RIGHT 0x08\n\n// Constants for Arc function\n// number representing the maximum angle (e.g. if 100, then if you pass in start=0 and end=50, you get a half circle)\n// this can be changed with setArcParams function at runtime\n#define DEFAULT_ARC_ANGLE_MAX 360\n// rotational offset in degrees defining position of value 0 (-90 will put it at the top of circle)\n// this can be changed with setAngleOffset function at runtime\n#define DEFAULT_ANGLE_OFFSET -90\n\n#define PI 3.14159265359\n\n#define MIN_POLIGON_SIDES\t3\n#define MAX_POLIGON_SIDES\t60\n\n// === Color names constants ===\n#define EPD_BLACK 15\n#define EPD_WHITE 0\n\n// === Color invert constants ===\n#define INVERT_ON\t\t1\n#define INVERT_OFF\t\t0\n\n// === Screen orientation constants ===\n#define LANDSCAPE_0\t\t1\n#define LANDSCAPE_180\t2\n\n// === Special coordinates constants ===\n#define CENTER\t-9003\n#define RIGHT\t-9004\n#define BOTTOM\t-9004\n\n#define LASTX\t7000\n#define LASTY\t8000\n\n// === Embedded fonts constants ===\n#define DEFAULT_FONT\t0\n#define DEJAVU18_FONT\t1\n#define DEJAVU24_FONT\t2\n#define UBUNTU16_FONT\t3\n#define COMIC24_FONT\t4\n#define MINYA24_FONT\t5\n#define TOONEY32_FONT\t6\n#define SMALL_FONT\t\t7\n#define FONT_7SEG\t\t8\n#define USER_FONT\t\t9  // font will be read from file\n\n\n\n// ===== PUBLIC FUNCTIONS =========================================================================\n\n/*\n * Draw pixel at given x,y coordinates\n * \n * Params:\n *       x: horizontal position\n *       y: vertical position\n *   color: pixel color\n*/\n//------------------------------------------------------\nvoid EPD_drawPixel(int16_t x, int16_t y, color_t color);\n\n/*\n * Read pixel color value from display GRAM at given x,y coordinates\n * \n * Params:\n *       x: horizontal position\n *       y: vertical position\n * \n * Returns:\n *      pixel color at x,y\n*/\n//------------------------------------------\ncolor_t EPD_readPixel(int16_t x, int16_t y);\n\n/*\n * Draw vertical line at given x,y coordinates\n * \n * Params:\n *       x: horizontal start position\n *       y: vertical start position\n *       h: line height in pixels\n *   color: line color\n*/\n//---------------------------------------------------------------------\nvoid EPD_drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color);\n\n/*\n * Draw horizontal line at given x,y coordinates\n * \n * Params:\n *       x: horizontal start position\n *       y: vertical start position\n *       w: line width in pixels\n *   color: line color\n*/\n//---------------------------------------------------------------------\nvoid EPD_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color);\n\n/*\n * Draw line on screen\n * \n * Params:\n *       x0: horizontal start position\n *       y0: vertical start position\n *       x1: horizontal end position\n *       y1: vertical end position\n *   color: line color\n*/\n//-------------------------------------------------------------------------------\nvoid EPD_drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color);\n\n\n/*\n * Draw line on screen from (x,y) point at given angle\n * Line drawing angle starts at lower right quadrant of the screen and is offseted by\n * '_angleOffset' global variable (default: -90 degrees)\n *\n * Params:\n *       x: horizontal start position\n *       y: vertical start position\n *   start: start offset from (x,y)\n *     len: length of the line\n *   angle: line angle in degrees\n *   color: line color\n*/\n//-----------------------------------------------------------------------------------------------------------\nvoid EPD_drawLineByAngle(uint16_t x, uint16_t y, uint16_t start, uint16_t len, uint16_t angle, color_t color);\n\n/*\n * Fill given rectangular screen region with color\n * \n * Params:\n *       x: horizontal rect start position\n *       y: vertical rect start position\n *       w: rectangle width\n *       h: rectangle height\n *   color: fill color\n*/\n//---------------------------------------------------------------------------\nvoid EPD_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color);\n\n/*\n * Draw rectangle on screen\n * \n * Params:\n *       x: horizontal rect start position\n *       y: vertical rect start position\n *       w: rectangle width\n *       h: rectangle height\n *   color: rect line color\n*/\n//------------------------------------------------------------------------------\nvoid EPD_drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color);\n\n/*\n * Draw rectangle with rounded corners on screen\n * \n * Params:\n *       x: horizontal rect start position\n *       y: vertical rect start position\n *       w: rectangle width\n *       h: rectangle height\n *       r: corner radius\n *   color: rectangle color\n*/\n//----------------------------------------------------------------------------------------------\nvoid EPD_drawRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color);\n\n/*\n * Fill given rectangular screen region with rounded corners with color\n * \n * Params:\n *       x: horizontal rect start position\n *       y: vertical rect start position\n *       w: rectangle width\n *       h: rectangle height\n *       r: corner radius\n *   color: fill color\n*/\n//----------------------------------------------------------------------------------------------\nvoid EPD_fillRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color);\n\n/*\n * Fill the whole screen with color\n * \n * Params:\n *   color: fill color\n*/\n//--------------------------------\nvoid EPD_fillScreen(color_t color);\n\n/*\n * Fill the current clip window with color\n *\n * Params:\n *   color: fill color\n*/\n//---------------------------------\nvoid EPD_fillWindow(color_t color);\n\n/*\n * Draw triangle on screen\n * \n * Params:\n *       x0: first triangle point x position\n *       y0: first triangle point y position\n *       x0: second triangle point x position\n *       y0: second triangle point y position\n *       x0: third triangle point x position\n *       y0: third triangle point y position\n *   color: triangle color\n*/\n//-----------------------------------------------------------------------------------------------------------------\nvoid EPD_drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color);\n\n/*\n * Fill triangular screen region with color\n * \n * Params:\n *       x0: first triangle point x position\n *       y0: first triangle point y position\n *       x0: second triangle point x position\n *       y0: second triangle point y position\n *       x0: third triangle point x position\n *       y0: third triangle point y position\n *   color: fill color\n*/\n//-----------------------------------------------------------------------------------------------------------------\nvoid EPD_fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color);\n\n/*\n * Draw circle on screen\n * \n * Params:\n *       x: circle center x position\n *       y: circle center x position\n *       r: circle radius\n *   color: circle color\n*/\n//-------------------------------------------------------------------\nvoid EPD_drawCircle(int16_t x, int16_t y, int radius, color_t color);\n\n/*\n * Fill circle on screen with color\n * \n * Params:\n *       x: circle center x position\n *       y: circle center x position\n *       r: circle radius\n *   color: circle fill color\n*/\n//-------------------------------------------------------------------\nvoid EPD_fillCircle(int16_t x, int16_t y, int radius, color_t color);\n\n/*\n * Draw ellipse on screen\n * \n * Params:\n *       x0: ellipse center x position\n *       y0: ellipse center x position\n *       rx: ellipse horizontal radius\n *       ry: ellipse vertical radius\n *   option: drawing options, multiple options can be combined\n                1 (TFT_ELLIPSE_UPPER_RIGHT) draw upper right corner\n                2 (TFT_ELLIPSE_UPPER_LEFT)  draw upper left corner\n                4 (TFT_ELLIPSE_LOWER_LEFT)  draw lower left corner\n                8 (TFT_ELLIPSE_LOWER_RIGHT) draw lower right corner\n             to draw the whole ellipse use option value 15 (1 | 2 | 4 | 8)\n * \n *   color: circle color\n*/\n//------------------------------------------------------------------------------------------------------\nvoid EPD_drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option);\n\n/*\n * Fill elliptical region on screen\n * \n * Params:\n *       x0: ellipse center x position\n *       y0: ellipse center x position\n *       rx: ellipse horizontal radius\n *       ry: ellipse vertical radius\n *   option: drawing options, multiple options can be combined\n                1 (TFT_ELLIPSE_UPPER_RIGHT) fill upper right corner\n                2 (TFT_ELLIPSE_UPPER_LEFT)  fill upper left corner\n                4 (TFT_ELLIPSE_LOWER_LEFT)  fill lower left corner\n                8 (TFT_ELLIPSE_LOWER_RIGHT) fill lower right corner\n             to fill the whole ellipse use option value 15 (1 | 2 | 4 | 8)\n * \n *   color: fill color\n*/\n//------------------------------------------------------------------------------------------------------\nvoid EPD_fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option);\n\n\n/*\n * Draw circle arc on screen\n * Arc drawing angle starts at lower right quadrant of the screen and is offseted by\n * '_angleOffset' global variable (default: -90 degrees)\n *\n * Params:\n *        cx: arc center X position\n *        cy: arc center Y position\n *        th: thickness of the drawn arc\n *        ry: arc vertical radius\n *     start: arc start angle in degrees\n *       end: arc end angle in degrees\n *     color: arc outline color\n * fillcolor: arc fill color\n*/\n//----------------------------------------------------------------------------------------------------------------------------\nvoid EPD_drawArc(uint16_t cx, uint16_t cy, uint16_t r, uint16_t th, float start, float end, color_t color, color_t fillcolor);\n\n\n/*\n * Draw polygon on screen\n *\n * Params:\n *        cx: polygon center X position\n *        cy: arc center Y position\n *     sides: number of polygon sides; MAX_POLIGON_SIDES ~ MAX_POLIGON_SIDES (3 ~ 60)\n *  diameter: diameter of the circle inside which the polygon is drawn\n *     color: polygon outline color\n *      fill: polygon fill color; if same as color, polygon is not filled\n *       deg: polygon rotation angle; 0 ~ 360\n *        th: thickness of the polygon outline\n*/\n//--------------------------------------------------------------------------------------------------------------\nvoid EPD_drawPolygon(int cx, int cy, int sides, int diameter, color_t color, color_t fill, int deg, uint8_t th);\n\n\n//--------------------------------------------------------------------------------------\n//void EPD_drawStar(int cx, int cy, int diameter, color_t color, bool fill, float factor);\n\n\n/*\n * Set the font used for writing the text to display.\n *\n * ------------------------------------------------------------------------------------\n * For 7 segment font only characters 0,1,2,3,4,5,6,7,8,9, . , - , : , / are available.\n *   Character ‘/‘ draws the degree sign.\n * ------------------------------------------------------------------------------------\n *\n * Params:\n *\t\t\t font: font number; use defined font names\n *\t\tfont_file: pointer to font file name; NULL for embeded fonts\n */\n//----------------------------------------------------\nvoid EPD_setFont(uint8_t font, const char *font_file);\n\n/*\n * Returns current font height & width in pixels.\n *\n * Params:\n *\t\t width: pointer to returned font width\n *\t\theight: pointer to returned font height\n */\n//-------------------------------------------\nint EPD_getfontsize(int *width, int* height);\n\n\n/*\n * Returns current font height in pixels.\n *\n */\n//----------------------\nint EPD_getfontheight();\n\n/*\n * Write text to display.\n *\n * Rotation of the displayed text depends on 'font_rotate' variable (0~360)\n * if 'font_transparent' variable is set to 1, no background pixels will be printed\n *\n * If the text does not fit the screen width it will be clipped (if text_wrap=0),\n * or continued on next line (if text_wrap=1)\n *\n * Two special characters are allowed in strings:\n * \t\t‘\\r’ CR (0x0D), clears the display to EOL\n * \t\t‘\\n’ LF (ox0A), continues to the new line, x=0\n *\n * Params:\n *\t   st:\tpointer to null terminated string to be printed\n *\t\tx:\thorizontal position of the upper left point in pixels\n *\t\t\t\tSpecial values can be entered:\n *\t\t\t\t\tCENTER, centers the text\n *\t\t\t\t\tRIGHT, right justifies the text\n *\t\t\t\t\tLASTX, continues from last X position; offset can be used: LASTX+n\n *\t\ty: vertical position of the upper left point in pixels\n *\t\t\t\tSpecial values can be entered:\n *\t\t\t\t\tCENTER, centers the text\n *\t\t\t\t\tBOTTOM, bottom justifies the text\n *\t\t\t\t\tLASTY, continues from last Y position; offset can be used: LASTY+n\n *\n */\n//-------------------------------------\nvoid EPD_print(char *st, int x, int y);\n\n/*\n * Set atributes for 7 segment vector font\n * == 7 segment font must be the current font to this function to have effect ==\n *\n * Params:\n *\t   \t   l:\t6~40; distance between bars in pixels\n *\t   \t   w:\t1~12, max l/2;  bar width in pixels\n *   outline:\tdraw font outline if set to 1\n *\t   color:\tfont outline color, only used if outline=1\n *\n */\n//-------------------------------------------------------------------------\nvoid set_7seg_font_atrib(uint8_t l, uint8_t w, int outline, color_t color);\n\n/*\n * Sets the clipping area coordinates.\n * All writing to screen is clipped to that area.\n * Starting x & y in all functions will be adjusted to the clipping area.\n *\n * Params:\n *\t\tx1,y1:\tupper left point of the clipping area\n *\t\tx2,y2:\tbottom right point of the clipping area\n *\n */\n//----------------------------------------------------------------------\nvoid EPD_setclipwin(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);\n\n/*\n * Resets the clipping area to full screen (0,0),(_wodth,_height)\n *\n */\n//----------------------\nvoid EPD_resetclipwin();\n\n/*\n * Save current clipping area to temporary variable\n *\n */\n//---------------------\nvoid EPD_saveClipWin();\n\n/*\n * Restore current clipping area from temporary variable\n *\n */\n//------------------------\nvoid EPD_restoreClipWin();\n\n/*\n * returns the string width in pixels.\n * Useful for positions strings on the screen.\n */\n//--------------------------------\nint EPD_getStringWidth(char* str);\n\n\n/*\n * Fills the rectangle occupied by string with current background color\n */\nvoid EPD_clearStringRect(int x, int y, char *str);\n\n\n/*\n * Compile font c source file to .fnt file\n * which can be used in EPD_setFont() function to select external font\n * Created file have the same name as source file and extension .fnt\n *\n * Params:\n *\t\tfontfile: pointer to c source font file name; must have .c extension\n *\t\t\t dbg: if set to 1, prints debug information\n *\n * Returns:\n * \t\t0 on success\n * \t\terr no on error\n *\n */\n//------------------------------------------------\nint compile_font_file(char *fontfile, uint8_t dbg);\n\n/*\n * Get all font's characters to buffer\n */\nvoid getFontCharacters(uint8_t *buf);\n\n/*\n * Decodes and displays JPG image. RGB colors are converted to 4-bit Gray scale\n * Limits:\n * \t\tBaseline only. Progressive and Lossless JPEG format are not supported.\n *\t\tImage size: Up to 65520 x 65520 pixels\n *\t\tColor space: YCbCr three components only. Gray scale image is not supported.\n *\t\tSampling factor: 4:4:4, 4:2:2 or 4:2:0.\n *\n * Params:\n *       x: image left position; constants CENTER & RIGHT can be used; negative value is accepted\n *       y: image top position;  constants CENTER & BOTTOM can be used; negative value is accepted\n *   scale: image scale factor: 0~3; if scale>0, image is scaled by factor 1/(2^scale) (1/2, 1/4 or 1/8)\n *   fname: pointer to the name of the file from which the image will be read\n *   \t\tif set to NULL, image will be read from memory buffer pointed to by 'buf'\n *     buf: pointer to the memory buffer from which the image will be read; used if fname=NULL\n *    size: size of the memory buffer from which the image will be read; used if fname=NULL & buf!=NULL\n *\n */\nint EPD_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size);\n\n#endif\n"
  },
  {
    "path": "components/epaper/EPDspi.c",
    "content": "/*\n *  Author: LoBo (loboris@gmail.com, loboris.github)\n *\n *  Module supporting SPI ePaper displays\n *\n * HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS\n * USING DIRECT or DMA SPI TRANSFER MODEs\n *\n*/\n\n\n#include \"spi_master_lobo.h\"\n#include <errno.h>\n#include <stdio.h>\n#include <time.h>\n#include <string.h>\n#include \"esp_system.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_heap_alloc_caps.h\"\n#include \"soc/spi_reg.h\"\n#include \"EPDspi.h\"\n\n#define EPD_DEBUG 1\n\n#define EPD2X9 1\n\n\t#define xDot 128\n\t#define yDot 296\n\t#define DELAYTIME 1500\n\nstatic uint8_t GDOControl[] = {0x01, (yDot-1)%256, (yDot-1)/256, 0x00};\nstatic uint8_t softstart[4] = {0x0c, 0xd7, 0xd6, 0x9d};\nstatic uint8_t VCOMVol[2] = {0x2c, 0xa8};\t\t\t// VCOM 7c\nstatic uint8_t DummyLine[2] = {0x3a, 0x1a};\t\t\t// 4 dummy line per gate\nstatic uint8_t Gatetime[2] = {0x3b, 0x08};\t\t\t// 2us per line\nstatic uint8_t RamDataEntryMode[2] = {0x11, 0x01};\t// Ram data entry mode\nstatic uint8_t Border[2] = {0x3c, 0x61};\t\t\t// Border control ( 0x61: white border; 0x51: black border\n\n/*\nThere are totally 20 phases for programmable Source waveform of different phase length.\nThe phase period defined as TP [n] * T FRAME , where TP [n] range from 0 to 15.\nTP [n] = 0 indicates phase skipped\nSource Voltage Level: VS [n-XY] is constant in each phase\nVS [n-XY] indicates the voltage in phase n for transition from GS X to GS Y\n 00 – VSS\n 01 – VSH\n 10 – VSL\n 11 – NA\nVS [n-XY] and TP[n] are stored in waveform lookup table register [LUT].\n\nVS coding: VS[0-11] VS[0-10] VS[0-01] VS[0-00]\n\n*/\n//                                   ---                                             VS                                             ----  ----           TP                            ----\n//uint8_t LUTDefault_full[31] = {0x32, 0x02,0x02,0x01,0x11,0x12,0x12,0x22,0x22,0x66,0x69,0x69,0x59,0x58,0x99,0x99,0x88,0x00,0x00,0x00,0x00, 0xF8,0xB4,0x13,0x51,0x35,0x51,0x51,0x19,0x01,0x00};\nuint8_t LUTDefault_full[31] = {0x32, 0x11,0x11,0x10,0x02,0x02,0x22,0x22,0x22,0x22,0x22,0x51,0x51,0x55,0x88,0x08,0x08,0x88,0x88,0x00,0x00, 0x34,0x23,0x12,0x21,0x24,0x28,0x22,0x21,0xA1,0x01};\nuint8_t LUTDefault_part[31] = {0x32, 0x10,0x18,0x18,0x08,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x13,0x14,0x44,0x12,0x00,0x00,0x00,0x00,0x00,0x00};\nuint8_t LUT_gs[31]\t\t\t= {0x32, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};\nuint8_t LUTFastest[31]\t\t= {0x32, 0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};\n\nuint8_t lvl_buf[16] = {32,70,110,150,185,210,220,225,230,235,240,243,248,251,253,255};\nuint8_t lvl_buf_jpg[16] = {4,8,12,16,22,30,40,60,80,110,140,180,220,240,250,255};\n\nuint8_t *LUT_part = LUTDefault_part;\nspi_lobo_device_handle_t disp_spi = NULL;\nuint8_t *gs_disp_buffer = NULL;\nuint8_t *disp_buffer = NULL;\nuint8_t *drawBuff = NULL;\nuint8_t *gs_drawBuff = NULL;\nint _width = EPD_DISPLAY_WIDTH;\nint _height = EPD_DISPLAY_HEIGHT;\nuint8_t _gs = 0;\n\nuint16_t gs_used_shades = 0;\n\n//-----------------------------------------------------------\nstatic void IRAM_ATTR _dma_send(uint8_t *data, uint32_t size)\n{\n    //Fill DMA descriptors\n    spi_lobo_dmaworkaround_transfer_active(disp_spi->host->dma_chan); //mark channel as active\n    spi_lobo_setup_dma_desc_links(disp_spi->host->dmadesc_tx, size, data, false);\n    disp_spi->host->hw->user.usr_mosi_highpart=0;\n    disp_spi->host->hw->dma_out_link.addr=(int)(&disp_spi->host->dmadesc_tx[0]) & 0xFFFFF;\n    disp_spi->host->hw->dma_out_link.start=1;\n    disp_spi->host->hw->user.usr_mosi_highpart=0;\n\n\tdisp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = (size * 8) - 1;\n\n\t// Start transfer\n\tdisp_spi->host->hw->cmd.usr = 1;\n\t// Wait for SPI bus ready\n\twhile (disp_spi->host->hw->cmd.usr);\n\n\t//Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.\n    if (disp_spi->host->dma_chan) spi_lobo_dmaworkaround_idle(disp_spi->host->dma_chan);\n\n    // Reset DMA\n\tdisp_spi->host->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;\n\tdisp_spi->host->hw->dma_out_link.start=0;\n\tdisp_spi->host->hw->dma_in_link.start=0;\n\tdisp_spi->host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);\n\tdisp_spi->host->hw->dma_conf.out_data_burst_en=1;\n}\n\n//--------------------------------------------------------------------------\nstatic void IRAM_ATTR _direct_send(uint8_t *data, uint32_t len, uint8_t rep)\n{\n\tuint32_t cidx = 0;\t// buffer index\n\tuint32_t wd = 0;\n\tint idx = 0;\n\tint bits = 0;\n\tint wbits = 0;\n\n    taskDISABLE_INTERRUPTS();\n\n\twhile (len) {\n\n\t\twd |= (uint32_t)data[idx] << wbits;\n\t\twbits += 8;\n\t\tif (wbits == 32) {\n\t\t\tbits += wbits;\n\t\t\twbits = 0;\n\t\t\tdisp_spi->host->hw->data_buf[idx++] = wd;\n\t\t\twd = 0;\n\t\t}\n    \tlen--;\t\t\t\t\t// Decrement data counter\n        if (rep == 0) cidx++;\t// if not repeating data, increment buffer index\n    }\n\tif (bits) {\n\t\twhile (disp_spi->host->hw->cmd.usr);\t\t\t\t\t\t// Wait for SPI bus ready\n\t\t// Load send buffer\n\t\tdisp_spi->host->hw->user.usr_mosi_highpart = 0;\n\t\tdisp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1;\n\t\tdisp_spi->host->hw->user.usr_mosi = 1;\n\t\tdisp_spi->host->hw->miso_dlen.usr_miso_dbitlen = 0;\n\t\tdisp_spi->host->hw->user.usr_miso = 0;\n        disp_spi->host->hw->cmd.usr = 1;\t\t\t\t\t\t\t// Start transfer\n\t}\n\t// Wait for SPI bus ready\n\twhile (disp_spi->host->hw->cmd.usr);\n    taskENABLE_INTERRUPTS();\n}\n\n// ================================================================\n// === Main function to send data to display ======================\n// If  rep==true:  repeat sending data to display 'len' times\n// If rep==false:  send 'len' data bytes from buffer to display\n// ** Device must already be selected and address window set **\n// ================================================================\n//---------------------------------------------------------------------------\nstatic void IRAM_ATTR SPI_send_data(uint8_t *data, uint32_t len, uint8_t rep)\n{\n\tif (len == 0) return;\n\n\tif ((len*8) <= 512) _direct_send(data, len, rep);\n\telse if (rep == 0)  _dma_send(data, len);\n\telse {\n\t\t// ==== Repeat data, more than 512 bits total ====\n\t\tuint8_t *transbuf = pvPortMallocCaps(len, MALLOC_CAP_DMA);\n\t\tif (transbuf == NULL) return;\n\n\t\tmemset(transbuf, data[0], len);\n\t\t_dma_send(transbuf, len);\n\t\tfree(transbuf);\n\t}\n}\n\n// Send one byte to display\n//-------------------------------------\nvoid IRAM_ATTR SPI_Write(uint8_t value)\n{\n\tdisp_spi->host->hw->data_buf[0] = (uint32_t)value;\n\t// Load send buffer\n\tdisp_spi->host->hw->user.usr_mosi_highpart = 0;\n\tdisp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7;\n\tdisp_spi->host->hw->user.usr_mosi = 1;\n\tdisp_spi->host->hw->miso_dlen.usr_miso_dbitlen = 0;\n\tdisp_spi->host->hw->user.usr_miso = 0;\n\t// Start transfer\n\tdisp_spi->host->hw->cmd.usr = 1;\n\t// Wait for SPI bus ready\n\twhile (disp_spi->host->hw->cmd.usr);\n}\n\n// Check display busy line and wait while busy\n//-----------------------\nstatic uint8_t ReadBusy()\n{\n\tfor (int i=0; i<400; i++){\n\t\tif (isEPD_BUSY == EPD_BUSY_LEVEL) return 1;\n\t\tvTaskDelay(10 / portTICK_RATE_MS);\n\t}\n\treturn 0;\n}\n\n//-----------------------\nstatic uint8_t WaitBusy()\n{\n\tif (isEPD_BUSY != EPD_BUSY_LEVEL) return 1;\n\tvTaskDelay(10 / portTICK_RATE_MS);\n\tif (isEPD_BUSY != EPD_BUSY_LEVEL) return 1;\n\treturn 0;\n}\n\n// Write one command without parameters\n//---------------------------------------\nstatic void EPD_WriteCMD(uint8_t command)\n{\n\tspi_lobo_device_select(disp_spi, 0);\n\tEPD_DC_0;\t\t// command write\n\tSPI_Write(command);\n}\n\n// Write command with one paramet\n//---------------------------------------\nstatic void EPD_WriteCMD_p1(uint8_t command,uint8_t para)\n{\n\tspi_lobo_device_select(disp_spi, 0);\n\t//ReadBusy();\n\tEPD_DC_0;\t\t// command write\n\tSPI_Write(command);\n\tEPD_DC_1;\t\t// data write\n\tSPI_Write(para);\n\tspi_lobo_device_deselect(disp_spi);\n}\n\n//----------------\nvoid EPD_PowerOn()\n{\n\tEPD_WriteCMD_p1(0x22,0xc0);\n\tEPD_WriteCMD(0x20);\n\t//EPD_WriteCMD(0xff);\n\tspi_lobo_device_deselect(disp_spi);\n#if EPD_DEBUG\n\tif (!WaitBusy()) printf(\"[EPD] NOT BUSY\\r\\n\");\n\tif (!ReadBusy()) printf(\"[EPD] NOT READY\\r\\n\");\n#else\n\tWaitBusy();\n\tReadBusy();\n#endif\n}\n\n//-----------------\nvoid EPD_PowerOff()\n{\n\tEPD_WriteCMD_p1(0x22,0x03);\n\tEPD_WriteCMD(0x20);\n\t//EPD_WriteCMD(0xff);\n\tspi_lobo_device_deselect(disp_spi);\n#if EPD_DEBUG\n\tif (!WaitBusy()) printf(\"[EPD] NOT BUSY\\r\\n\");\n\tif (!ReadBusy()) printf(\"[EPD] NOT READY\\r\\n\");\n#else\n\tWaitBusy();\n\tReadBusy();\n#endif\n#if POWER_Pin\n\tgpio_set_level(DC_Pin, 0);\n\tgpio_set_level(MOSI_Pin, 0);\n\tgpio_set_level(SCK_Pin, 0);\n\tgpio_set_level(RST_Pin, 0);\n\tgpio_set_level(CS_Pin, 0);\n\tgpio_set_level(POWER_Pin, 0);\n#endif\n}\n\n// Send command with multiple parameters\n//----------------------------------------------------\nstatic void EPD_Write(uint8_t *value, uint8_t datalen)\n{\n\tuint8_t i = 0;\n\tuint8_t *ptemp;\n\n\tptemp = value;\n\tspi_lobo_device_select(disp_spi, 0);\n\t//ReadBusy();\n\tEPD_DC_0;\t\t\t// When DC is 0, write command\n\tSPI_Write(*ptemp);\t//The first byte is written with the command value\n\tptemp++;\n\tEPD_DC_1;\t\t\t// When DC is 1, write data\n\tfor(i= 0;i<datalen-1;i++){\t// sub the data\n\t\tSPI_Write(*ptemp);\n\t\tptemp++;\n\t}\n\tspi_lobo_device_deselect(disp_spi);\n}\n\n// Send data buffer to display\n//----------------------------------------------------------------------------\nstatic void EPD_WriteDispRam(uint8_t XSize, uint16_t YSize,\tuint8_t *Dispbuff)\n{\n\tif (XSize%8 != 0) XSize = XSize+(8-XSize%8);\n\tXSize = XSize/8;\n\n\tspi_lobo_device_select(disp_spi, 0);\n\t//ReadBusy();\n\tEPD_DC_0;\t\t//command write\n\tSPI_Write(0x24);\n\tEPD_DC_1;\t\t//data write\n\tSPI_send_data(Dispbuff, XSize*YSize, 0);\n\tspi_lobo_device_deselect(disp_spi);\n}\n\n// Fill the display with value\n//-------------------------------------------------------------------------------\nstatic void EPD_WriteDispRamMono(uint8_t XSize, uint16_t YSize,\tuint8_t dispdata)\n{\n\tif (XSize%8 != 0) XSize = XSize+(8-XSize%8);\n\tXSize = XSize/8;\n\n\tspi_lobo_device_select(disp_spi, 0);\n\t//ReadBusy();\n\tEPD_DC_0;\t\t// command write\n\tSPI_Write(0x24);\n\tEPD_DC_1;\t\t// data write\n\tSPI_send_data(&dispdata, XSize*YSize, 1);\n\tspi_lobo_device_deselect(disp_spi);\n}\n\n/*\n  === Set RAM X - Address Start / End Position (44h) ===\n  Specify the start/end positions of the window address in the X direction by 8 times address unit.\n  Data is written to the RAM within the area determined by the addresses specified by XSA [4:0] and XEA [4:0].\n  These addresses must be set before the RAM write. It allows on XEA [4:0] ≤ XSA [4:0].\n  The settings follow the condition on 00h ≤ XSA [4:0], XEA [4:0] ≤ 1Dh.\n  The windows is followed by the control setting of Data Entry Setting (R11h)\n\n  === Set RAM Y - Address Start / End Position (45h) ===\n  Specify the start/end positions of the window address in the Y direction by an address unit.\n  Data is written to the RAM within the area determined by the addresses specified by YSA [8:0] and YEA [8:0].\n  These addresses must be set before the RAM write.\n  It allows YEA [8:0] ≤ YSA [8:0].\n  The settings follow the condition on 00h ≤ YSA [8:0], YEA [8:0] ≤ 13Fh.\n  The windows is followed by the control setting of Data Entry Setting (R11h)\n */\n//--------------------------------------------------------------------------------------\nstatic void EPD_SetRamArea(uint8_t Xstart, uint8_t Xend, uint16_t Ystart, uint16_t Yend)\n{\n    uint8_t RamAreaX[3];\t// X start and end\n\tuint8_t RamAreaY[5]; \t// Y start and end\n\tRamAreaX[0] = 0x44;\t// command\n\tRamAreaX[1] = Xstart;\n\tRamAreaX[2] = Xend;\n\tRamAreaY[0] = 0x45;\t// command\n\tRamAreaY[1] = Ystart & 0xFF;\n\tRamAreaY[2] = Ystart >> 8;\n\tRamAreaY[3] = Yend & 0xFF;\n    RamAreaY[4] = Yend >> 8;\n\tEPD_Write(RamAreaX, sizeof(RamAreaX));\n\tEPD_Write(RamAreaY, sizeof(RamAreaY));\n}\n\n//Set RAM X and Y address counter\n/*\n  === Set RAM Address Counter (4Eh-4Fh) ===\n  adrX[4:0]: Make initial settings for the RAM X address in the address counter (AC).\n  adrY[8:0]: Make initial settings for the RAM Y address in the address counter (AC).\n  After RAM data is written, the address counter is automatically updated according to the settings with AM, ID\n   bits and setting for a new RAM address is not required in the address counter.\n  Therefore, data is written consecutively without setting an address.\n  The address counter is not automatically updated when data is read out from the RAM.\n  RAM address setting cannot be made during the standby mode.\n  The address setting should be made within the area designated with window addresses which is controlled\n   by the Data Entry Setting (R11h) {AM, ID[1:0]} ; RAM Address XStart / XEnd Position (R44h) and RAM Address Ystart /Yend Position (R45h).\n   Otherwise undesirable image will be displayed on the Panel.\n*/\n//----------------------------------------------------------\nstatic void EPD_SetRamPointer(uint8_t addrX, uint16_t addrY)\n{\n    uint8_t RamPointerX[2];\t// default (0,0)\n\tuint8_t RamPointerY[3];\n\t//Set RAM X address counter\n\tRamPointerX[0] = 0x4e;\n\tRamPointerX[1] = addrX;\n\t//Set RAM Y address counter\n\tRamPointerY[0] = 0x4f;\n\tRamPointerY[1] = addrY & 0xFF;\n\tRamPointerY[2] = addrY >> 8;\n\n\tEPD_Write(RamPointerX, sizeof(RamPointerX));\n\tEPD_Write(RamPointerY, sizeof(RamPointerY));\n}\n\n\n//Set RAM X and Y address Start / End position\n//Set RAM X and Y address counter\n//----------------------------------------------------------------------------------------------\nstatic void part_display(uint8_t RAM_XST, uint8_t RAM_XEND ,uint16_t RAM_YST, uint16_t RAM_YEND)\n{\n\tEPD_SetRamArea(RAM_XST, RAM_XEND, RAM_YST, RAM_YEND);\n    EPD_SetRamPointer (RAM_XST, RAM_YST);\n}\n\n//Initialize the display\n//--------------------\nstatic void EPD_Init()\n{\n#if POWER_Pin\n\tgpio_set_level(POWER_Pin, 1);\n\tvTaskDelay(100 / portTICK_RATE_MS);\n#else\n\tvTaskDelay(10 / portTICK_RATE_MS);\n#endif\n\t// reset\n\tEPD_RST_0;\n\tvTaskDelay(10 / portTICK_RATE_MS);\n#if EPD_DEBUG\n\tuint32_t t1 = clock();\n#endif\n\tEPD_RST_1;\n\tfor (int n=0; n<50; n++) {\n\t\tvTaskDelay(10 / portTICK_RATE_MS);\n\t\tif (isEPD_BUSY == EPD_BUSY_LEVEL) break;\n\t}\n\n\tSPI_Write(0x12); // software reset\n\tvTaskDelay(10 / portTICK_RATE_MS);\n\tReadBusy();\n\n\t// set registers\n\tEPD_Write(GDOControl, sizeof(GDOControl));\t// Panel configuration, Gate selection\n\tEPD_Write(softstart, sizeof(softstart));\t// X decrease, Y decrease\n\tEPD_Write(VCOMVol, sizeof(VCOMVol));\t\t// VCOM setting\n\tEPD_Write(DummyLine, sizeof(DummyLine));\t// dummy line per gate\n\tEPD_Write(Gatetime, sizeof(Gatetime));\t\t// Gate time setting\n\tEPD_Write(Border, sizeof(Border));\n\tEPD_Write(RamDataEntryMode, sizeof(RamDataEntryMode));\t// X increase, Y decrease\n\n\tEPD_SetRamArea(0x00, (xDot-1)/8, yDot-1, 0);\n\tEPD_SetRamPointer(0x00, yDot-1);\n#if EPD_DEBUG\n\tt1 = clock() - t1;\n\tprintf(\"[EPD] Init: %u ms\\r\\n\", t1);\n#endif\n}\n\n//------------------------------\nstatic void EPD_UpdateFull(void)\n{\n\t/*\n\t+ Enable Clock Signal,\n\t+ Then Enable CP\n\t- Then Load Temperature value\n\t- Then Load LUT\n\t- Then INITIAL DISPLAY\n\t+ Then PATTERN DISPLAY\n\t+ Then Disable CP\n\t+ Then Disable OSC\n\t*/\n\tEPD_WriteCMD_p1(0x22,0xC7);\n\tEPD_WriteCMD(0x20);\n\t//EPD_WriteCMD(0xff);\n\tspi_lobo_device_deselect(disp_spi);\n\n#if EPD_DEBUG\n\tif (!WaitBusy()) printf(\"[EPD] NOT BUSY\\r\\n\");\n\tif (!ReadBusy()) printf(\"[EPD] NOT READY\\r\\n\");\n#else\n\tWaitBusy();\n\tReadBusy();\n#endif\n}\n\n//-------------------------------\nstatic void EPD_Update_Part(void)\n{\n\t/*\n\t- Enable Clock Signal,\n\t- Then Enable CP\n\t- Then Load Temperature value\n\t- Then Load LUT\n\t- Then INITIAL DISPLAY\n\t+ Then PATTERN DISPLAY\n\t- Then Disable CP\n\t- Then Disable OSC\n\t*/\n\tEPD_WriteCMD_p1(0x22,0x04);\n\tEPD_WriteCMD(0x20);\n\t//EPD_WriteCMD(0xff);\n\tspi_lobo_device_deselect(disp_spi);\n\n#if EPD_DEBUG\n\tif (!WaitBusy()) printf(\"[EPD] NOT BUSY\\r\\n\");\n\tif (!ReadBusy()) printf(\"[EPD] NOT READY\\r\\n\");\n#else\n\tWaitBusy();\n\tReadBusy();\n#endif\n}\n\n/*******************************************************************************\nFull screen initialization\n********************************************************************************/\nstatic void EPD_init_Full(void)\n{\n\tEPD_Init();\t\t\t// Reset and set register\n\tEPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));\n\n\tEPD_PowerOn();\n}\n\n/*******************************************************************************\nPart screen initialization\n********************************************************************************/\nstatic void EPD_init_Part(void)\n{\n\tEPD_Init();\t\t\t// display\n\tEPD_Write((uint8_t *)LUT_part, 31);\n\tEPD_PowerOn();\n}\n/********************************************************************************\nparameter:\n\tLabel  :\n       \t\t=1 Displays the contents of the DisBuffer\n\t   \t\t=0 Displays the contents of the first byte in DisBuffer,\n********************************************************************************/\nstatic void EPD_Dis_Full(uint8_t *DisBuffer,uint8_t type)\n{\n    EPD_SetRamPointer(0x00, yDot-1);\t// set ram pointer\n\tif (type == 0){\n\t\t// Fill screen with white\n\t\tEPD_WriteDispRamMono(xDot, yDot, 0xff);\n\t}\n\telse {\n\t\t// Fill screen from buffer\n\t\tEPD_WriteDispRam(xDot, yDot, (uint8_t *)DisBuffer);\n\t}\n\tEPD_UpdateFull();\n\n}\n\n/********************************************************************************\nWARNING: X is smaller screen dimension (0~127) !\n         Y is larger screen dimension (0~295) !\nparameter:\n\t\txStart :   X direction Start coordinate\n\t\txEnd   :   X direction end coordinate\n\t\tyStart :   Y direction Start coordinate\n\t\tyEnd   :   Y direction end coordinate\n\t\tDisBuffer : Display content\n\t\ttype  :\n       \t\t=1 Displays the contents of the DisBuffer\n\t   \t\t=0 Displays the contents of the first byte in DisBuffer,\n********************************************************************************/\nstatic void EPD_Dis_Part(uint8_t xStart, uint8_t xEnd, uint16_t yStart, uint16_t yEnd, uint8_t *DisBuffer, uint8_t type)\n{\n\tif (type == 0) {\n\t\t// Repeated color\n\t\tpart_display(xStart/8, xEnd/8, yEnd, yStart);\n\t\tEPD_WriteDispRamMono(xEnd-xStart+1, yEnd-yStart+1, DisBuffer[0]);\n \t\tEPD_Update_Part();\n\t\tpart_display(xStart/8, xEnd/8, yEnd, yStart);\n\t\tEPD_WriteDispRamMono(xEnd-xStart+1, yEnd-yStart+1, DisBuffer[0]);\n\t}\n\telse {\n\t\t// From buffer\n\t\tpart_display(xStart/8, xEnd/8, yEnd, yStart);\n\t\tEPD_WriteDispRam(xEnd-xStart+1, yEnd-yStart+1,DisBuffer);\n\t\tEPD_Update_Part();\n\t\tpart_display(xStart/8, xEnd/8, yEnd, yStart);\n\t\tEPD_WriteDispRam(xEnd-xStart+1, yEnd-yStart+1,DisBuffer);\n\t}\n}\n\n//======================================================================================================================================\n\n// Clear full screen\n//=========================\nvoid EPD_DisplayClearFull()\n{\n\tuint8_t m;\n\tEPD_init_Full();\n\n#if EPD_DEBUG\n\tuint32_t t1 = clock();\n#endif\n\tm = 0x00;\n\tEPD_Dis_Full(&m, 0);  //all black\n#if EPD_DEBUG\n\tt1 = clock() - t1;\n\tprintf(\"[EPD] Clear black: %u ms\\r\\n\", t1);\n\tt1 = clock();\n#endif\n\tm = 0xff;\n\tEPD_Dis_Full(&m, 0);  //all white\n#if EPD_DEBUG\n\tt1 = clock() - t1;\n\tprintf(\"[EPD] Clear white: %u ms\\r\\n\", t1);\n#endif\n}\n\n// Partial clear screen\n//=========================\nvoid EPD_DisplayClearPart()\n{\n\tuint8_t m = 0xFF;\n\tEPD_init_Part();\n#if EPD_DEBUG\n\tuint32_t t1 = clock();\n\tEPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0);\t//all white\n\tm = 0x00;\n\tEPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0);\t//all black\n\tm = 0xFF;\n\tEPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0);\t//all white\n\tt1 = clock() - t1;\n\tprintf(\"[EPD] Part Clear: %u ms\\r\\n\", t1);\n#else\n\tEPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0);\t//all white\n\tm = 0x00;\n\tEPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0);\t//all black\n\tm = 0xFF;\n\tEPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0);\t//all white\n#endif\n}\n\n//==================================\nvoid EPD_DisplaySetFull(uint8_t val)\n{\n\tEPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));\n#if EPD_DEBUG\n\tuint32_t t1 = clock();\n\tEPD_Dis_Full(&val, 0);\n\tt1 = clock() - t1;\n\tprintf(\"[EPD] Display Set Full: %u ms [%02x]\\r\\n\", t1, val);\n#else\n\tEPD_Dis_Full(&val, 0);\n#endif\n}\n\n//======================================================================================\nvoid EPD_DisplaySetPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t val)\n{\n\tEPD_Write((uint8_t *)LUT_part, 31);\n#if EPD_DEBUG\n\tuint32_t t1 = clock();\n\tEPD_Dis_Part(yStart,yEnd,xStart,xEnd, &val,0);\n\tt1 = clock() - t1;\n\tprintf(\"[EPD] Display Set Part: %u ms [%02x]\\r\\n\", t1, val);\n#else\n\tEPD_Dis_Part(yStart,yEnd,xStart,xEnd, &val,0);\n#endif\n}\n\n//======================================\nvoid EPD_DisplayFull(uint8_t *DisBuffer)\n{\n\tEPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));\n#if EPD_DEBUG\n\tuint32_t t1 = clock();\n\tEPD_Dis_Full((uint8_t *)DisBuffer,1);\n\tt1 = clock() - t1;\n\tprintf(\"[EPD] Display Full: %u ms\\r\\n\", t1);\n#else\n\tEPD_Dis_Full((uint8_t *)DisBuffer,1);\n#endif\n}\n\n//==========================================================================================\nvoid EPD_DisplayPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t *DisBuffer)\n{\n\tEPD_Write((uint8_t *)LUT_part, 31);\n#if EPD_DEBUG\n\tuint32_t t1 = clock();\n\tEPD_Dis_Part(yStart,yEnd,xStart,xEnd,(uint8_t *)DisBuffer,1);\n\tt1 = clock() - t1;\n\tprintf(\"[EPD] Display Part: %u ms [%02x:%02x]\\r\\n\", t1, LUT_gs[1], LUT_gs[21]);\n#else\n\tEPD_Dis_Part(yStart,yEnd,xStart,xEnd,(uint8_t *)DisBuffer,1);\n#endif\n}\n\n//============\nvoid EPD_Cls()\n{\n\tEPD_DisplaySetPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, 0xFF);\n\tmemset(disp_buffer, 0xFF, _width * (_height/8));\n\tmemset(gs_disp_buffer, 0, _width * _height);\n\tgs_used_shades = 0;\n}\n\n//-------------------------------------------------------------------------------\nvoid EPD_gsUpdate(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t gs)\n{\n\tuint8_t val, buf_val, new_val;\n\tint count=0, changed=0;\n\tint x;\n\tuint8_t y;\n\tfor (x=xStart; x<=xEnd; x++) {\n\t\tfor (y=yStart; y<=yEnd; y++) {\n\t\t\tval = gs_drawBuff[(y * (xEnd-xStart+1)) + x];\n\t\t\tif (val > 15) val >>= 4;\n\t\t\tif (val == gs) {\n\t\t\t\tbuf_val = drawBuff[(x * ((yEnd-yStart+1)>>3)) + (y>>3)];\n\t\t\t\tnew_val = buf_val;\n\t\t\t\tif (gs > 0) new_val &= (0x80 >> (y % 8)) ^ 0xFF;\n\t\t\t\telse new_val |= (0x80 >> (y % 8));\n\t\t\t\tif (new_val != buf_val) {\n\t\t\t\t\tdrawBuff[(x * (_height>>3)) + (y>>3)] = new_val;\n\t\t\t\t\tchanged++;\n\t\t\t\t}\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (changed) {\n\t\t#if EPD_DEBUG\n\t\tprintf(\"[EPD] GS Update %02x, count=%d changed=%d\\r\\n\", gs, count, changed);\n\t\t#endif\n\t\tuint8_t *_lutPart = LUT_part;\n\t\tmemset(LUT_gs+1, 0, 30);\n\t\tif (gs > 0) {\n\t\t\tif (gs > 0) {\n\t\t\t\tLUT_gs[1] = 0x18;\n\t\t\t\tLUT_gs[21] = gs;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tLUT_gs[1] = 0x28;\n\t\t\tLUT_gs[2] = 0x00;\n\t\t\tLUT_gs[21] = 15;\n\t\t}\n\t\tLUT_part = LUT_gs;\n\t\tEPD_DisplayPart(xStart, xEnd, yStart, yEnd, drawBuff);\n\n\t\tLUT_part = _lutPart;\n\t}\n}\n\n//-----------------------------------------------------------------------\nvoid EPD_Update(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd)\n{\n\tif (_gs == 0) EPD_DisplayPart(xStart, xEnd, yStart, yEnd, drawBuff);\n\telse {\n\t\tfor (int n=0; n<16; n++) {\n\t\t\tif (gs_used_shades & (1<<n)) EPD_gsUpdate(xStart, xEnd, yStart, yEnd, n);\n\t\t}\n\t}\n}\n\n//-------------------\nvoid EPD_UpdateScreen()\n{\n\tEPD_Update(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1);\n}\n\n//------------------------\nvoid EPD_wait(uint32_t ms)\n{\n\tif (ms < 100) ms = 100;\n\tuint32_t n = 0;\n\twhile (n < ms) {\n\t\tvTaskDelay(100 / portTICK_RATE_MS);\n\t\tn += 100;\n\t}\n}\n\n\n"
  },
  {
    "path": "components/epaper/EPDspi.h",
    "content": "/*\n *  Author: LoBo (loboris@gmail.com, loboris.github)\n *\n *  Module supporting SPI ePaper displays\n *\n * HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS\n * USING DIRECT or DMA SPI TRANSFER MODEs\n *\n*/\n\n\n#ifndef _EPDSPI_H_\n#define _EPDSPI_H_\n\n#include <stdint.h>\n#include \"spi_master_lobo.h\"\n\n#define EPD_DISPLAY_WIDTH\t296\n#define EPD_DISPLAY_HEIGHT\t128\n\n#define SCK_Pin\t\t18\n#define MOSI_Pin\t23\n//#define MISO_Pin\t19\n#define DC_Pin\t\t26\n#define BUSY_Pin\t32\n#define RST_Pin\t\t27\n#define CS_Pin\t\t5\n// ePaper display can be powered from GPIO\n// if powered directly from Vcc, set this to 0\n#define POWER_Pin\t22\n\n#define DC_VAL (1 << DC_Pin)\n\n#define EPD_CS_0\tgpio_set_level(CS_Pin, 0)\n#define EPD_CS_1\tgpio_set_level(CS_Pin, 1)\n#define isEPD_CS\tgpio_get_level(CS_Pin)\n\n#define EPD_RST_0\tgpio_set_level(RST_Pin, 0)\n#define EPD_RST_1\tgpio_set_level(RST_Pin, 1)\n#define isEPD_RST\tgpio_get_level(RST_Pin)\n\n#define EPD_DC_0\tgpio_set_level(DC_Pin, 0)\n#define EPD_DC_1\tgpio_set_level(DC_Pin, 1)\n\n#define isEPD_BUSY  gpio_get_level(BUSY_Pin)\n\n#define EPD_BUSY_LEVEL 0\n\n// ==================================================\n// Define which spi bus to use VSPI_HOST or HSPI_HOST\n#define SPI_BUS VSPI_HOST\n// ==================================================\n\nspi_lobo_device_handle_t disp_spi;\nuint8_t *gs_disp_buffer;\nuint8_t *disp_buffer;\nuint8_t *gs_drawBuff;\nuint8_t *drawBuff;\nint _width;\nint _height;\nuint16_t gs_used_shades;\nuint8_t _gs;\nuint8_t *LUT_part;\nuint8_t LUTDefault_fastest[31];\nuint8_t LUTDefault_part[31];\nuint8_t LUT_gs[31];\nuint8_t LUTDefault_full[31];\nuint8_t lvl_buf[16];\nuint8_t lvl_buf_jpg[16];\n\nvoid EPD_wait(uint32_t ms);\nvoid EPD_DisplaySetFull(uint8_t val);\nvoid EPD_DisplaySetPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t val);\nvoid EPD_DisplayClearFull();\nvoid EPD_DisplayClearPart();\nvoid EPD_DisplayFull(uint8_t *DisBuffer);\nvoid EPD_DisplayPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t *DisBuffer);\nvoid EPD_gsUpdate(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t gs);\nvoid EPD_Update(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd);\nvoid EPD_UpdateScreen();\nvoid EPD_Cls();\nvoid EPD_PowerOn();\nvoid EPD_PowerOff();\n\n\n#endif\n"
  },
  {
    "path": "components/epaper/SmallFont.c",
    "content": "// SmallFont.c\r\n// Font type    : Full (95 characters)\r\n// Font size    : 8x12 pixels\r\n// Memory usage : 1144 bytes\r\n\r\n#if defined(__AVR__)\r\n\t#include <avr/pgmspace.h>\r\n\t#define fontdatatype const uint8_t\r\n#elif defined(__PIC32MX__)\r\n\t#define PROGMEM\r\n\t#define fontdatatype const unsigned char\r\n#elif defined(__arm__)\r\n\t#define PROGMEM\r\n\t#define fontdatatype const unsigned char\r\n#endif\r\n\r\nconst unsigned char tft_SmallFont[1144] =\r\n{\r\n0x08,0x0C,0x20,0x5F,\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // <space>\r\n0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00,  // !\r\n0x00,0x28,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // \"\r\n0x00,0x00,0x28,0x28,0xFC,0x28,0x50,0xFC,0x50,0x50,0x00,0x00,  // #\r\n0x00,0x20,0x78,0xA8,0xA0,0x60,0x30,0x28,0xA8,0xF0,0x20,0x00,  // $\r\n0x00,0x00,0x48,0xA8,0xB0,0x50,0x28,0x34,0x54,0x48,0x00,0x00,  // %\r\n0x00,0x00,0x20,0x50,0x50,0x78,0xA8,0xA8,0x90,0x6C,0x00,0x00,  // &\r\n0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // '\r\n0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x04,0x00,  // (\r\n0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x40,0x00,  // )\r\n0x00,0x00,0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,0x00,0x00,  // *\r\n0x00,0x00,0x20,0x20,0x20,0xF8,0x20,0x20,0x20,0x00,0x00,0x00,  // +\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80,  // ,\r\n0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,  // -\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,  // .\r\n0x00,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x00,  // /\r\n\r\n0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00,  // 0\r\n0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,  // 1\r\n0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x40,0x80,0xF8,0x00,0x00,  // 2\r\n0x00,0x00,0x70,0x88,0x08,0x30,0x08,0x08,0x88,0x70,0x00,0x00,  // 3\r\n0x00,0x00,0x10,0x30,0x50,0x50,0x90,0x78,0x10,0x18,0x00,0x00,  // 4\r\n0x00,0x00,0xF8,0x80,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,0x00,  // 5\r\n0x00,0x00,0x70,0x90,0x80,0xF0,0x88,0x88,0x88,0x70,0x00,0x00,  // 6\r\n0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x20,0x20,0x20,0x00,0x00,  // 7\r\n0x00,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00,  // 8\r\n0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x48,0x70,0x00,0x00,  // 9\r\n0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x20,0x00,0x00,  // :\r\n0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x20,0x00,  // ;\r\n0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00,  // <\r\n0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,  // =\r\n0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00,  // >\r\n0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00,  // ?\r\n\r\n0x00,0x00,0x70,0x88,0x98,0xA8,0xA8,0xB8,0x80,0x78,0x00,0x00,  // @\r\n0x00,0x00,0x20,0x20,0x30,0x50,0x50,0x78,0x48,0xCC,0x00,0x00,  // A\r\n0x00,0x00,0xF0,0x48,0x48,0x70,0x48,0x48,0x48,0xF0,0x00,0x00,  // B\r\n0x00,0x00,0x78,0x88,0x80,0x80,0x80,0x80,0x88,0x70,0x00,0x00,  // C\r\n0x00,0x00,0xF0,0x48,0x48,0x48,0x48,0x48,0x48,0xF0,0x00,0x00,  // D\r\n0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x48,0xF8,0x00,0x00,  // E\r\n0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x40,0xE0,0x00,0x00,  // F\r\n0x00,0x00,0x38,0x48,0x80,0x80,0x9C,0x88,0x48,0x30,0x00,0x00,  // G\r\n0x00,0x00,0xCC,0x48,0x48,0x78,0x48,0x48,0x48,0xCC,0x00,0x00,  // H\r\n0x00,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,  // I\r\n0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0xE0,0x00,  // J\r\n0x00,0x00,0xEC,0x48,0x50,0x60,0x50,0x50,0x48,0xEC,0x00,0x00,  // K\r\n0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x44,0xFC,0x00,0x00,  // L\r\n0x00,0x00,0xD8,0xD8,0xD8,0xD8,0xA8,0xA8,0xA8,0xA8,0x00,0x00,  // M\r\n0x00,0x00,0xDC,0x48,0x68,0x68,0x58,0x58,0x48,0xE8,0x00,0x00,  // N\r\n0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00,  // O\r\n\r\n0x00,0x00,0xF0,0x48,0x48,0x70,0x40,0x40,0x40,0xE0,0x00,0x00,  // P\r\n0x00,0x00,0x70,0x88,0x88,0x88,0x88,0xE8,0x98,0x70,0x18,0x00,  // Q\r\n0x00,0x00,0xF0,0x48,0x48,0x70,0x50,0x48,0x48,0xEC,0x00,0x00,  // R\r\n0x00,0x00,0x78,0x88,0x80,0x60,0x10,0x08,0x88,0xF0,0x00,0x00,  // S\r\n0x00,0x00,0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,  // T\r\n0x00,0x00,0xCC,0x48,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00,  // U\r\n0x00,0x00,0xCC,0x48,0x48,0x50,0x50,0x30,0x20,0x20,0x00,0x00,  // V\r\n0x00,0x00,0xA8,0xA8,0xA8,0x70,0x50,0x50,0x50,0x50,0x00,0x00,  // W\r\n0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x50,0x50,0xD8,0x00,0x00,  // X\r\n0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x20,0x20,0x70,0x00,0x00,  // Y\r\n0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x40,0x48,0xF8,0x00,0x00,  // Z\r\n0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00,  // [\r\n0x00,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x00,0x00,  // <backslash>\r\n0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00,  // ]\r\n0x00,0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // ^\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,  // _\r\n\r\n0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // `\r\n0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x38,0x48,0x3C,0x00,0x00,  // a\r\n0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0x70,0x00,0x00,  // b\r\n0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x40,0x40,0x38,0x00,0x00,  // c\r\n0x00,0x00,0x18,0x08,0x08,0x38,0x48,0x48,0x48,0x3C,0x00,0x00,  // d\r\n0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x78,0x40,0x38,0x00,0x00,  // e\r\n0x00,0x00,0x1C,0x20,0x20,0x78,0x20,0x20,0x20,0x78,0x00,0x00,  // f\r\n0x00,0x00,0x00,0x00,0x00,0x3C,0x48,0x30,0x40,0x78,0x44,0x38,  // g\r\n0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0xEC,0x00,0x00,  // h\r\n0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00,  // i\r\n0x00,0x00,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0xE0,  // j\r\n0x00,0x00,0xC0,0x40,0x40,0x5C,0x50,0x70,0x48,0xEC,0x00,0x00,  // k\r\n0x00,0x00,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,  // l\r\n0x00,0x00,0x00,0x00,0x00,0xF0,0xA8,0xA8,0xA8,0xA8,0x00,0x00,  // m\r\n0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0xEC,0x00,0x00,  // n\r\n0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00,  // o\r\n\r\n0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0x70,0x40,0xE0,  // p\r\n0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x1C,  // q\r\n0x00,0x00,0x00,0x00,0x00,0xD8,0x60,0x40,0x40,0xE0,0x00,0x00,  // r\r\n0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x30,0x08,0x78,0x00,0x00,  // s\r\n0x00,0x00,0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00,  // t\r\n0x00,0x00,0x00,0x00,0x00,0xD8,0x48,0x48,0x48,0x3C,0x00,0x00,  // u\r\n0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x00,0x00,  // v\r\n0x00,0x00,0x00,0x00,0x00,0xA8,0xA8,0x70,0x50,0x50,0x00,0x00,  // w\r\n0x00,0x00,0x00,0x00,0x00,0xD8,0x50,0x20,0x50,0xD8,0x00,0x00,  // x\r\n0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x20,0xC0,  // y\r\n0x00,0x00,0x00,0x00,0x00,0x78,0x10,0x20,0x20,0x78,0x00,0x00,  // z\r\n0x00,0x18,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x18,0x00,  // {\r\n0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,  // |\r\n0x00,0x60,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x60,0x00,  // }\r\n0x40,0xA4,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // ~\r\n};\r\n"
  },
  {
    "path": "components/epaper/Ubuntu16.c",
    "content": "// This comes with no warranty, implied or otherwise\r\n\r\n// This data structure was designed to support Proportional fonts\r\n// on Arduinos. It can however handle any ttf font that has been converted\r\n// using the conversion program. These could be fixed width or proportional \r\n// fonts. Individual characters do not have to be multiples of 8 bits wide. \r\n// Any width is fine and does not need to be fixed.\r\n\r\n// The data bits are packed to minimize data requirements, but the tradeoff\r\n// is that a header is required per character.\r\n\r\n// Ubuntu16.c\r\n// Point Size   : 16\r\n// Memory usage : 1433 bytes\r\n// # characters : 95\r\n\r\n// Header Format (to make Arduino UTFT Compatible):\r\n// ------------------------------------------------\r\n// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)\r\n// Character Height\r\n// First Character (Reserved. 0x00)\r\n// Number Of Characters (Reserved. 0x00)\r\n\r\nconst unsigned char tft_Ubuntu16[] =\r\n{\r\n0x00, 0x10, 0x00, 0x00,\r\n\r\n// Individual Character Format:\r\n// ----------------------------\r\n// Character Code\r\n// Adjusted Y Offset\r\n// Width\r\n// Height\r\n// xOffset\r\n// xDelta (the distance to move the cursor. Effective width of the character.)\r\n// Data[n]\r\n\r\n// NOTE: You can remove any of these characters if they are not needed in\r\n// your application. The first character number in each Glyph indicates\r\n// the ASCII character code. Therefore, these do not have to be sequential.\r\n// Just remove all the content for a particular character to save space.\r\n\r\n// ' '\r\n0x20,0x0D,0x00,0x00,0x00,0x04,\r\n\r\n// '!'\r\n0x21,0x02,0x01,0x0B,0x01,0x04,\r\n0xFC,0x60,\r\n// '\"'\r\n0x22,0x00,0x04,0x04,0x01,0x07,\r\n0x99,0x99,\r\n// '#'\r\n0x23,0x02,0x09,0x0B,0x01,0x0B,\r\n0x11,0x08,0x84,0x5F,0xF2,0x21,0x10,0x89,0xFF,0x44,0x22,0x11,0x00,\r\n// '$'\r\n0x24,0x00,0x07,0x10,0x01,0x09,\r\n0x10,0x20,0xF6,0x08,0x10,0x18,0x08,0x0C,0x0C,0x08,0x3F,0xC2,0x04,0x00,\r\n// '%'\r\n0x25,0x02,0x0C,0x0B,0x01,0x0E,\r\n0x70,0x4D,0x88,0x89,0x08,0x90,0xDA,0x07,0x4E,0x05,0xB0,0x91,0x09,0x11,0x1B,0x20,0xE0,\r\n// '&'\r\n0x26,0x02,0x0A,0x0B,0x01,0x0B,\r\n0x3C,0x18,0x84,0x21,0x08,0x2C,0x0C,0x04,0x8A,0x10,0x83,0x30,0xC7,0xC8,\r\n// '''\r\n0x27,0x00,0x01,0x04,0x01,0x04,\r\n0xF0,\r\n// '('\r\n0x28,0x00,0x04,0x10,0x01,0x05,\r\n0x02,0x44,0x48,0x88,0x88,0x84,0x44,0x20,\r\n// ')'\r\n0x29,0x00,0x04,0x10,0x00,0x05,\r\n0x04,0x22,0x21,0x11,0x11,0x12,0x22,0x40,\r\n// '*'\r\n0x2A,0x02,0x09,0x06,0x00,0x08,\r\n0x08,0x24,0x8F,0x83,0x81,0x41,0x10,\r\n// '+'\r\n0x2B,0x05,0x07,0x07,0x01,0x09,\r\n0x10,0x20,0x47,0xF1,0x02,0x04,0x00,\r\n// ','\r\n0x2C,0x0B,0x02,0x05,0x00,0x04,\r\n0x54,0x80,\r\n// '-'\r\n0x2D,0x08,0x04,0x01,0x01,0x06,\r\n0xF0,\r\n// '.'\r\n0x2E,0x0B,0x01,0x02,0x01,0x04,\r\n0xC0,\r\n// '/'\r\n0x2F,0x00,0x07,0x10,0x00,0x06,\r\n0x02,0x08,0x10,0x20,0x81,0x02,0x08,0x10,0x40,0x81,0x04,0x08,0x10,0x40,\r\n// '0'\r\n0x30,0x02,0x07,0x0B,0x01,0x09,\r\n0x38,0x8B,0x1C,0x18,0x30,0x60,0xC1,0x86,0x88,0xE0,\r\n// '1'\r\n0x31,0x02,0x04,0x0B,0x01,0x09,\r\n0x13,0x59,0x11,0x11,0x11,0x10,\r\n// '2'\r\n0x32,0x02,0x06,0x0B,0x01,0x09,\r\n0x7A,0x30,0x41,0x08,0x21,0x08,0x42,0x0F,0xC0,\r\n// '3'\r\n0x33,0x02,0x07,0x0B,0x01,0x09,\r\n0x78,0x08,0x08,0x10,0x47,0x01,0x01,0x02,0x0B,0xE0,\r\n// '4'\r\n0x34,0x02,0x07,0x0B,0x01,0x09,\r\n0x04,0x18,0x51,0x22,0x48,0xA1,0x7F,0x04,0x08,0x10,\r\n// '5'\r\n0x35,0x02,0x07,0x0B,0x01,0x09,\r\n0x7E,0x81,0x02,0x07,0x81,0x80,0x81,0x02,0x0B,0xE0,\r\n// '6'\r\n0x36,0x02,0x07,0x0B,0x01,0x09,\r\n0x1C,0x61,0x00,0x0F,0x90,0xA0,0xC1,0x82,0x88,0xE0,\r\n// '7'\r\n0x37,0x02,0x07,0x0B,0x01,0x09,\r\n0xFE,0x04,0x10,0x40,0x82,0x04,0x08,0x20,0x40,0x80,\r\n// '8'\r\n0x38,0x02,0x07,0x0B,0x01,0x09,\r\n0x39,0x8A,0x0C,0x14,0x47,0x11,0x41,0x83,0x89,0xE0,\r\n// '9'\r\n0x39,0x02,0x07,0x0B,0x01,0x09,\r\n0x38,0x8A,0x0C,0x18,0x28,0x4F,0x81,0x04,0x11,0xC0,\r\n// ':'\r\n0x3A,0x05,0x01,0x08,0x01,0x04,\r\n0xC3,\r\n// ';'\r\n0x3B,0x05,0x02,0x0B,0x00,0x04,\r\n0x50,0x05,0x48,\r\n// '<'\r\n0x3C,0x05,0x08,0x07,0x01,0x09,\r\n0x02,0x0C,0x30,0x60,0x30,0x0C,0x02,\r\n// '='\r\n0x3D,0x06,0x07,0x04,0x01,0x09,\r\n0xFE,0x00,0x07,0xF0,\r\n// '>'\r\n0x3E,0x05,0x09,0x07,0x00,0x09,\r\n0x40,0x1C,0x01,0x80,0x70,0x61,0xC1,0x00,\r\n// '?'\r\n0x3F,0x02,0x06,0x0B,0x01,0x07,\r\n0x78,0x30,0x41,0x18,0xC2,0x00,0x00,0x82,0x00,\r\n// '@'\r\n0x40,0x02,0x0D,0x0D,0x01,0x0F,\r\n0x0F,0x81,0x83,0x10,0x0C,0x8F,0xA8,0x84,0xC8,0x26,0x41,0x32,0x09,0x88,0x5A,0x3F,0x90,0x00,0x60,0x00,0xFC,0x00,\r\n// 'A'\r\n0x41,0x02,0x0B,0x0B,0x00,0x0B,\r\n0x04,0x01,0xC0,0x28,0x08,0x81,0x10,0x61,0x08,0x21,0xFC,0x60,0x48,0x0B,0x00,0x80,\r\n// 'B'\r\n0x42,0x02,0x08,0x0B,0x01,0x0A,\r\n0xF8,0x86,0x82,0x82,0x86,0xFC,0x82,0x81,0x81,0x82,0xFC,\r\n// 'C'\r\n0x43,0x02,0x09,0x0B,0x01,0x0B,\r\n0x1F,0x10,0x10,0x10,0x08,0x04,0x02,0x01,0x00,0x40,0x30,0x07,0xC0,\r\n// 'D'\r\n0x44,0x02,0x09,0x0B,0x01,0x0B,\r\n0xFC,0x41,0x20,0x50,0x18,0x0C,0x06,0x03,0x01,0x81,0x41,0x3F,0x00,\r\n// 'E'\r\n0x45,0x02,0x07,0x0B,0x01,0x09,\r\n0xFF,0x02,0x04,0x08,0x1F,0xA0,0x40,0x81,0x03,0xF8,\r\n// 'F'\r\n0x46,0x02,0x07,0x0B,0x01,0x09,\r\n0xFF,0x02,0x04,0x08,0x1F,0xA0,0x40,0x81,0x02,0x00,\r\n// 'G'\r\n0x47,0x02,0x09,0x0B,0x01,0x0B,\r\n0x1F,0x10,0x10,0x10,0x08,0x04,0x02,0x03,0x01,0x40,0xB0,0x47,0xE0,\r\n// 'H'\r\n0x48,0x02,0x09,0x0B,0x01,0x0B,\r\n0x80,0xC0,0x60,0x30,0x18,0x0F,0xFE,0x03,0x01,0x80,0xC0,0x60,0x20,\r\n// 'I'\r\n0x49,0x02,0x01,0x0B,0x01,0x03,\r\n0xFF,0xE0,\r\n// 'J'\r\n0x4A,0x02,0x07,0x0B,0x00,0x08,\r\n0x02,0x04,0x08,0x10,0x20,0x40,0x81,0x02,0x09,0xE0,\r\n// 'K'\r\n0x4B,0x02,0x09,0x0B,0x01,0x0A,\r\n0x81,0x41,0x23,0x12,0x0A,0x06,0x02,0xC1,0x10,0x86,0x40,0xA0,0x20,\r\n// 'L'\r\n0x4C,0x02,0x07,0x0B,0x01,0x08,\r\n0x81,0x02,0x04,0x08,0x10,0x20,0x40,0x81,0x03,0xF8,\r\n// 'M'\r\n0x4D,0x02,0x0B,0x0B,0x01,0x0D,\r\n0x40,0x4C,0x19,0x01,0x28,0xA5,0x14,0x94,0xB2,0x9C,0x33,0x84,0x30,0x06,0x00,0x80,\r\n// 'N'\r\n0x4E,0x02,0x09,0x0B,0x01,0x0B,\r\n0x80,0xE0,0x68,0x32,0x19,0x0C,0x46,0x13,0x05,0x82,0xC0,0xE0,0x20,\r\n// 'O'\r\n0x4F,0x02,0x0B,0x0B,0x01,0x0D,\r\n0x1F,0x04,0x11,0x01,0x40,0x18,0x03,0x00,0x60,0x0C,0x01,0x40,0x44,0x10,0x7C,0x00,\r\n// 'P'\r\n0x50,0x02,0x08,0x0B,0x01,0x0A,\r\n0xFC,0x82,0x81,0x81,0x81,0x82,0xFC,0x80,0x80,0x80,0x80,\r\n// 'Q'\r\n0x51,0x02,0x0B,0x0E,0x01,0x0D,\r\n0x1F,0x04,0x11,0x01,0x40,0x18,0x03,0x00,0x60,0x0C,0x01,0x40,0x44,0x10,0x78,0x02,0x00,0x30,0x01,0x80,\r\n// 'R'\r\n0x52,0x02,0x09,0x0B,0x01,0x0A,\r\n0xFC,0x41,0x20,0x50,0x28,0x14,0x13,0xF1,0x08,0x82,0x40,0xA0,0x20,\r\n// 'S'\r\n0x53,0x02,0x08,0x0B,0x01,0x09,\r\n0x3C,0xC2,0x80,0x80,0x40,0x1C,0x06,0x02,0x02,0x06,0x78,\r\n// 'T'\r\n0x54,0x02,0x09,0x0B,0x00,0x09,\r\n0xFF,0x84,0x02,0x01,0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00,\r\n// 'U'\r\n0x55,0x02,0x09,0x0B,0x01,0x0B,\r\n0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xA0,0x8F,0x80,\r\n// 'V'\r\n0x56,0x02,0x09,0x0B,0x00,0x09,\r\n0x80,0xE0,0xD0,0x48,0x26,0x21,0x10,0x88,0x28,0x14,0x0E,0x02,0x00,\r\n// 'W'\r\n0x57,0x02,0x0D,0x0B,0x00,0x0D,\r\n0x80,0x0E,0x10,0xD0,0x84,0x8E,0x24,0x51,0x22,0x88,0xA2,0x85,0x14,0x38,0xE0,0xC2,0x04,0x10,\r\n// 'X'\r\n0x58,0x02,0x09,0x0B,0x00,0x09,\r\n0xC1,0xA0,0x88,0x86,0xC1,0x40,0x60,0x70,0x6C,0x22,0x20,0xB0,0x60,\r\n// 'Y'\r\n0x59,0x02,0x09,0x0B,0x00,0x09,\r\n0x80,0xA0,0x90,0x44,0x41,0x40,0xA0,0x20,0x10,0x08,0x04,0x02,0x00,\r\n// 'Z'\r\n0x5A,0x02,0x07,0x0B,0x01,0x09,\r\n0xFE,0x04,0x10,0x41,0x02,0x08,0x00,0x41,0x03,0xF8,\r\n// '['\r\n0x5B,0x00,0x03,0x10,0x02,0x05,\r\n0xF2,0x49,0x24,0x92,0x49,0x27,\r\n// '\\'\r\n0x5C,0x00,0x07,0x10,0x00,0x06,\r\n0x80,0x81,0x02,0x02,0x04,0x08,0x08,0x10,0x10,0x20,0x40,0x40,0x81,0x01,\r\n// ']'\r\n0x5D,0x00,0x03,0x10,0x00,0x05,\r\n0xE4,0x92,0x49,0x24,0x92,0x4F,\r\n// '^'\r\n0x5E,0x02,0x07,0x06,0x01,0x09,\r\n0x10,0x70,0xA2,0x24,0x50,0x40,\r\n// '_'\r\n0x5F,0x0F,0x08,0x01,0x00,0x08,\r\n0xFF,\r\n// '`'\r\n0x60,0x01,0x04,0x03,0x01,0x06,\r\n0x86,0x10,\r\n// 'a'\r\n0x61,0x05,0x06,0x08,0x01,0x08,\r\n0x78,0x30,0x5F,0xC6,0x18,0x5F,\r\n// 'b'\r\n0x62,0x01,0x07,0x0C,0x01,0x09,\r\n0x81,0x02,0x04,0x0F,0x90,0xA0,0xC1,0x83,0x06,0x17,0xC0,\r\n// 'c'\r\n0x63,0x05,0x06,0x08,0x01,0x08,\r\n0x3D,0x08,0x20,0x82,0x04,0x0F,\r\n// 'd'\r\n0x64,0x01,0x07,0x0C,0x01,0x09,\r\n0x02,0x04,0x08,0x13,0xE8,0x60,0xC1,0x83,0x05,0x09,0xF0,\r\n// 'e'\r\n0x65,0x05,0x07,0x08,0x01,0x09,\r\n0x3C,0x8A,0x0F,0xF8,0x10,0x10,0x1E,\r\n// 'f'\r\n0x66,0x01,0x05,0x0C,0x01,0x06,\r\n0x7E,0x21,0x0F,0xC2,0x10,0x84,0x21,0x00,\r\n// 'g'\r\n0x67,0x05,0x07,0x0B,0x01,0x09,\r\n0x3E,0x86,0x0C,0x18,0x30,0x50,0x9F,0x02,0x0B,0xE0,\r\n// 'h'\r\n0x68,0x01,0x07,0x0C,0x01,0x09,\r\n0x81,0x02,0x04,0x0F,0x90,0xE0,0xC1,0x83,0x06,0x0C,0x10,\r\n// 'i'\r\n0x69,0x01,0x03,0x0C,0x00,0x03,\r\n0x48,0x04,0x92,0x49,0x20,\r\n// 'j'\r\n0x6A,0x01,0x04,0x0F,0xFF,0x03,\r\n0x22,0x00,0x22,0x22,0x22,0x22,0x22,0xC0,\r\n// 'k'\r\n0x6B,0x01,0x06,0x0C,0x01,0x08,\r\n0x82,0x08,0x20,0x8A,0x4A,0x30,0xA2,0x48,0xA1,\r\n// 'l'\r\n0x6C,0x01,0x04,0x0C,0x01,0x04,\r\n0x88,0x88,0x88,0x88,0x88,0x86,\r\n// 'm'\r\n0x6D,0x05,0x0B,0x08,0x01,0x0D,\r\n0xFB,0xD1,0x8E,0x10,0xC2,0x18,0x43,0x08,0x61,0x0C,0x21,\r\n// 'n'\r\n0x6E,0x05,0x07,0x08,0x01,0x09,\r\n0xFD,0x0E,0x0C,0x18,0x30,0x60,0xC1,\r\n// 'o'\r\n0x6F,0x05,0x08,0x08,0x01,0x0A,\r\n0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C,\r\n// 'p'\r\n0x70,0x05,0x07,0x0B,0x01,0x09,\r\n0xF9,0x0A,0x0C,0x18,0x30,0x61,0x7C,0x81,0x02,0x00,\r\n// 'q'\r\n0x71,0x05,0x07,0x0B,0x01,0x09,\r\n0x3E,0x86,0x0C,0x18,0x30,0x50,0x9F,0x02,0x04,0x08,\r\n// 'r'\r\n0x72,0x05,0x05,0x08,0x01,0x06,\r\n0xFC,0x21,0x08,0x42,0x10,\r\n// 's'\r\n0x73,0x05,0x05,0x08,0x01,0x07,\r\n0x7C,0x20,0xC3,0x04,0x3E,\r\n// 't'\r\n0x74,0x02,0x05,0x0B,0x01,0x07,\r\n0x84,0x21,0xF8,0x42,0x10,0x84,0x1E,\r\n// 'u'\r\n0x75,0x05,0x07,0x08,0x01,0x09,\r\n0x83,0x06,0x0C,0x18,0x30,0x50,0xBF,\r\n// 'v'\r\n0x76,0x05,0x07,0x08,0x00,0x07,\r\n0x83,0x05,0x12,0x22,0x85,0x0E,0x08,\r\n// 'w'\r\n0x77,0x05,0x0D,0x08,0x00,0x0D,\r\n0x82,0x0C,0x10,0x51,0xC4,0x8A,0x26,0x5B,0x14,0x50,0xE3,0x82,0x08,\r\n// 'x'\r\n0x78,0x05,0x08,0x08,0x00,0x08,\r\n0xC3,0x66,0x24,0x18,0x18,0x24,0x42,0xC3,\r\n// 'y'\r\n0x79,0x05,0x07,0x0B,0x00,0x07,\r\n0x82,0x89,0x12,0x22,0x85,0x04,0x08,0x10,0x43,0x00,\r\n// 'z'\r\n0x7A,0x05,0x06,0x08,0x01,0x08,\r\n0xFC,0x10,0x84,0x21,0x08,0x3F,\r\n// '{'\r\n0x7B,0x00,0x05,0x10,0x00,0x05,\r\n0x19,0x08,0x42,0x10,0x98,0x61,0x08,0x42,0x10,0x83,\r\n// '|'\r\n0x7C,0x00,0x01,0x10,0x02,0x05,\r\n0xFF,0xFF,\r\n// '}'\r\n0x7D,0x00,0x05,0x10,0x00,0x05,\r\n0xC1,0x08,0x42,0x10,0x83,0x31,0x08,0x42,0x10,0x98,\r\n// '~'\r\n0x7E,0x07,0x07,0x02,0x01,0x09,\r\n0x73,0x18,\r\n\r\n// Terminator\r\n0xFF\r\n};\r\n"
  },
  {
    "path": "components/epaper/comic24.c",
    "content": "// This comes with no warranty, implied or otherwise\r\n\r\n// This data structure was designed to support Proportional fonts\r\n// on Arduinos. It can however handle any ttf font that has been converted\r\n// using the conversion program. These could be fixed width or proportional \r\n// fonts. Individual characters do not have to be multiples of 8 bits wide. \r\n// Any width is fine and does not need to be fixed.\r\n\r\n// The data bits are packed to minimize data requirements, but the tradeoff\r\n// is that a header is required per character.\r\n\r\n// comic.c\r\n// Point Size   : 24\r\n// Memory usage : 2814 bytes\r\n// # characters : 95\r\n\r\n// Header Format (to make Arduino UTFT Compatible):\r\n// ------------------------------------------------\r\n// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)\r\n// Character Height\r\n// First Character (Reserved. 0x00)\r\n// Number Of Characters (Reserved. 0x00)\r\n\r\nunsigned char tft_Comic24[] = \r\n{\r\n0x00, 0x19, 0x00, 0x00,\r\n\r\n// Individual Character Format:\r\n// ----------------------------\r\n// Character Code\r\n// Adjusted Y Offset\r\n// Width\r\n// Height\r\n// xOffset\r\n// xDelta (the distance to move the cursor. Effective width of the character.)\r\n// Data[n]\r\n\r\n// NOTE: You can remove any of these characters if they are not needed in\r\n// your application. The first character number in each Glyph indicates\r\n// the ASCII character code. Therefore, these do not have to be sequential.\r\n// Just remove all the content for a particular character to save space.\r\n\r\n// ' '\r\n0x20,0x15,0x00,0x00,0x00,0x07,\r\n\r\n// '!'\r\n0x21,0x02,0x02,0x14,0x01,0x06,\r\n0xFF,0xFF,0xFF,0xFC,0x2D,\r\n// '\"'\r\n0x22,0x03,0x06,0x08,0x02,0x0A,\r\n0xCF,0x3C,0xF3,0xCF,0x3C,0xF3,\r\n// '#'\r\n0x23,0x03,0x14,0x12,0x01,0x14,\r\n0x01,0x81,0x80,0x18,0x18,0x01,0x81,0x80,0x30,0x30,0x03,0x03,0x07,0xFF,0xFF,0x7F,0xFF,0xF0,0x60,0x60,0x06,0x06,0x00,0xC0,0xC0,0x0C,0x0C,0x0F,0xFF,0xFE,0xFF,0xFF,0xE1,0x81,0x80,0x18,0x18,0x03,0x83,0x00,0x30,0x30,0x03,0x03,0x00,\r\n// '$'\r\n0x24,0x00,0x0B,0x19,0x02,0x11,\r\n0x0C,0x01,0x80,0x30,0x0F,0x83,0xFC,0xD9,0xBB,0x06,0x60,0xCC,0x19,0x83,0xB0,0x3F,0x83,0xFC,0x1B,0x83,0x18,0x63,0x0C,0x71,0x9F,0x37,0x7F,0xC3,0xF0,0x18,0x03,0x00,0x60,0x0C,0x00,\r\n// '%'\r\n0x25,0x01,0x11,0x14,0x02,0x14,\r\n0x00,0x00,0x00,0x0C,0x0E,0x0E,0x0F,0x86,0x0C,0x67,0x06,0x33,0x03,0x19,0x80,0xF9,0x80,0x38,0xC0,0x00,0xE0,0x00,0x60,0x00,0x70,0x00,0x31,0xE0,0x39,0xF8,0x19,0xCE,0x1C,0xC3,0x0C,0x61,0x86,0x39,0xC6,0x0F,0xC3,0x03,0xC0,\r\n// '&'\r\n0x26,0x03,0x0F,0x13,0x01,0x10,\r\n0x01,0xC0,0x07,0xC0,0x19,0x80,0x33,0x00,0x6E,0x00,0xF8,0x01,0xE0,0x07,0x80,0x1F,0x8C,0x73,0x19,0xC3,0x37,0x07,0xEC,0x07,0xD8,0x07,0x30,0x0E,0x38,0x7E,0x3F,0xEC,0x3F,0x0C,0x00,0x18,\r\n// '''\r\n0x27,0x03,0x02,0x06,0x03,0x09,\r\n0xFF,0xF0,\r\n// '('\r\n0x28,0x02,0x07,0x18,0x01,0x09,\r\n0x06,0x1C,0x71,0xC3,0x0E,0x18,0x30,0xE1,0x83,0x06,0x0C,0x18,0x30,0x60,0xE0,0xC1,0x83,0x83,0x83,0x87,0x83,\r\n// ')'\r\n0x29,0x02,0x06,0x18,0x02,0x09,\r\n0xC3,0x86,0x0C,0x30,0x61,0x86,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x61,0x86,0x31,0xCE,0x30,\r\n// '*'\r\n0x2A,0x03,0x0B,0x09,0x01,0x0D,\r\n0x0C,0x01,0x83,0xBF,0xFF,0xF3,0xFC,0x3C,0x0F,0xC3,0x9C,0x61,0x80,\r\n// '+'\r\n0x2B,0x09,0x0A,0x0A,0x00,0x0C,\r\n0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,0xC0,0x30,0x0C,0x03,0x00,\r\n// ','\r\n0x2C,0x13,0x04,0x06,0x02,0x07,\r\n0x37,0x66,0xEC,\r\n// '-'\r\n0x2D,0x0E,0x08,0x02,0x01,0x0A,\r\n0xFF,0xFF,\r\n// '.'\r\n0x2E,0x12,0x03,0x03,0x02,0x06,\r\n0xFF,0x80,\r\n// '/'\r\n0x2F,0x01,0x0A,0x15,0x01,0x0C,\r\n0x00,0x00,0x30,0x0C,0x06,0x01,0x80,0x60,0x30,0x0C,0x06,0x01,0x80,0xC0,0x30,0x18,0x06,0x03,0x00,0xC0,0x60,0x18,0x0E,0x03,0x00,0xC0,0x00,\r\n// '0'\r\n0x30,0x03,0x0D,0x12,0x01,0x0F,\r\n0x0F,0x80,0xFF,0x0E,0x18,0xE0,0x66,0x03,0x70,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x03,0xB0,0x19,0x81,0xC7,0x1C,0x3F,0xC0,0x7C,0x00,\r\n// '1'\r\n0x31,0x03,0x06,0x12,0x03,0x0B,\r\n0x10,0xC7,0x3C,0xB0,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0xFF,0xF0,\r\n// '2'\r\n0x32,0x03,0x0B,0x12,0x02,0x0F,\r\n0x1F,0x07,0xFB,0xC3,0xE0,0x30,0x06,0x00,0xC0,0x38,0x0E,0x07,0x81,0xE0,0xF8,0x3C,0x07,0x01,0xC0,0x30,0x06,0x00,0xFF,0xDF,0xFC,\r\n// '3'\r\n0x33,0x03,0x0B,0x12,0x02,0x0F,\r\n0x1F,0x0F,0xF9,0xC3,0x80,0x30,0x06,0x00,0xC0,0x78,0x7E,0x0F,0x80,0x78,0x03,0x80,0x30,0x06,0x00,0xF0,0x1F,0x0E,0x7F,0x83,0xE0,\r\n// '4'\r\n0x34,0x03,0x0D,0x12,0x02,0x0F,\r\n0x01,0xC0,0x0E,0x00,0xF0,0x0F,0x80,0x6C,0x07,0x60,0x33,0x03,0x98,0x38,0xC1,0x86,0x1C,0x31,0xFF,0xFF,0xFF,0x80,0x60,0x03,0x00,0x18,0x00,0xC0,0x06,0x00,\r\n// '5'\r\n0x35,0x02,0x0C,0x13,0x02,0x0F,\r\n0x00,0x0F,0xFE,0xFF,0xE6,0x00,0x60,0x0E,0x00,0xEF,0x8F,0xFC,0xF8,0x6E,0x07,0xC0,0x30,0x03,0x00,0x30,0x03,0x00,0x7C,0x06,0xE1,0xE7,0xFC,0x3F,0x00,\r\n// '6'\r\n0x36,0x03,0x0C,0x12,0x01,0x0F,\r\n0x03,0x00,0x70,0x0E,0x01,0xC0,0x38,0x03,0x00,0x60,0x06,0xF8,0xFF,0xEE,0x0E,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x77,0x0E,0x3F,0xC1,0xF8,\r\n// '7'\r\n0x37,0x02,0x0D,0x13,0x01,0x0F,\r\n0x00,0x07,0xFF,0xFF,0xFE,0x00,0xE0,0x0E,0x00,0x60,0x06,0x00,0x30,0x03,0x80,0x18,0x01,0xC0,0x0C,0x00,0x60,0x07,0x00,0x30,0x03,0x80,0x18,0x00,0xC0,0x04,0x00,\r\n// '8'\r\n0x38,0x02,0x0C,0x13,0x01,0x0F,\r\n0x00,0x00,0xFC,0x3F,0xE3,0x07,0x60,0x36,0x03,0x60,0x37,0x8F,0x3F,0xE1,0xFE,0x38,0xE7,0x07,0x60,0x36,0x03,0x60,0x36,0x03,0x30,0x63,0xFE,0x0F,0x80,\r\n// '9'\r\n0x39,0x03,0x0D,0x13,0x01,0x0F,\r\n0x0F,0x01,0xFE,0x1C,0x38,0xC0,0xCC,0x07,0x60,0x1B,0x00,0xD8,0x06,0xE0,0x73,0x87,0x8F,0xF8,0x3E,0xC0,0x0E,0x00,0x60,0x07,0x00,0xF0,0x1F,0x03,0xE0,0x1C,0x00,\r\n// ':'\r\n0x3A,0x09,0x03,0x0B,0x02,0x07,\r\n0xFF,0x80,0x00,0xFF,0x80,\r\n// ';'\r\n0x3B,0x09,0x04,0x0E,0x02,0x07,\r\n0xEE,0xE0,0x00,0x00,0x03,0x7E,0xCC,\r\n// '<'\r\n0x3C,0x09,0x07,0x0A,0x01,0x09,\r\n0x06,0x1C,0x71,0xC7,0x1E,0x1E,0x0E,0x0E,0x0C,\r\n// '='\r\n0x3D,0x0A,0x09,0x09,0x01,0x0C,\r\n0xFF,0xFF,0xC0,0x00,0x00,0x00,0x03,0xFF,0xFF,0x00,0x00,\r\n// '>'\r\n0x3E,0x08,0x08,0x0B,0x01,0x0A,\r\n0x60,0x70,0x38,0x3C,0x1E,0x0F,0x06,0x0C,0x38,0x70,0xC0,\r\n// '?'\r\n0x3F,0x04,0x0B,0x12,0x01,0x0D,\r\n0x1E,0x0F,0xE3,0xC6,0x60,0x60,0x06,0x00,0xC0,0x18,0x07,0x01,0xE0,0xF8,0x3E,0x0F,0x01,0x80,0x00,0x00,0x01,0x80,0x30,0x06,0x00,\r\n// '@'\r\n0x40,0x02,0x13,0x14,0x01,0x16,\r\n0x03,0xF8,0x01,0xFF,0xC0,0x78,0x3C,0x1C,0x01,0xC3,0x00,0x1C,0xC1,0xC1,0x98,0xF8,0x1E,0x3C,0x03,0xC6,0x30,0x79,0x8E,0x0F,0x31,0xC1,0xE6,0x78,0x6C,0x7F,0xFC,0xC7,0x3E,0x18,0x00,0x01,0x80,0x00,0x38,0x00,0x03,0xC0,0xE0,0x1F,0xFC,0x00,0xFE,0x00,\r\n// 'A'\r\n0x41,0x03,0x0E,0x12,0x01,0x11,\r\n0x00,0x80,0x07,0x00,0x1C,0x00,0xF0,0x03,0xC0,0x1D,0x80,0x76,0x03,0x98,0x0E,0x20,0x70,0xC1,0xFF,0x0F,0xFC,0x7C,0x19,0xC0,0x67,0x01,0xB8,0x07,0xE0,0x0F,0x00,0x30,\r\n// 'B'\r\n0x42,0x03,0x0B,0x13,0x03,0x0F,\r\n0x7C,0x1F,0xE3,0x0E,0x60,0xEC,0x0D,0x81,0xB0,0x36,0x0E,0xC3,0x9F,0xE3,0xFC,0x61,0xEC,0x0F,0x80,0xF0,0x1E,0x0E,0xC7,0xDF,0xE3,0xF0,0x00,\r\n// 'C'\r\n0x43,0x03,0x0D,0x12,0x01,0x0E,\r\n0x01,0xF8,0x3F,0xC3,0xC6,0x38,0x31,0x80,0x1C,0x01,0xC0,0x0C,0x00,0x60,0x06,0x00,0x30,0x01,0x80,0x0C,0x00,0x60,0x19,0x81,0xCE,0x3C,0x3F,0xC0,0xF8,0x00,\r\n// 'D'\r\n0x44,0x03,0x0D,0x12,0x02,0x11,\r\n0x60,0x07,0xC0,0x37,0x81,0x8F,0x0C,0x1C,0x60,0x73,0x01,0xD8,0x06,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x1B,0x01,0xDC,0x1C,0xFF,0xC1,0xF8,0x00,\r\n// 'E'\r\n0x45,0x03,0x0D,0x12,0x02,0x0F,\r\n0xFF,0xF7,0xFF,0xF0,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x7E,0xFF,0xF7,0xE0,0x30,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x00,0x7F,0xF1,0xFF,0x80,\r\n// 'F'\r\n0x46,0x03,0x0C,0x12,0x02,0x0F,\r\n0xFF,0xCF,0xFF,0xC0,0x7C,0x00,0xC0,0x0C,0x00,0xC0,0x0D,0xFE,0xFF,0xEF,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,\r\n// 'G'\r\n0x47,0x03,0x0F,0x12,0x01,0x10,\r\n0x03,0xE0,0x0F,0xF0,0x38,0xE0,0xE0,0x03,0x80,0x06,0x00,0x18,0x00,0x30,0x00,0x61,0xFF,0x9F,0xFF,0x3C,0x36,0x00,0x6C,0x01,0x98,0x07,0x30,0x0C,0x30,0x70,0x7F,0xC0,0x3E,0x00,\r\n// 'H'\r\n0x48,0x03,0x0F,0x12,0x02,0x12,\r\n0xC0,0x03,0x80,0x0F,0x00,0x1E,0x00,0x3C,0x00,0x78,0x00,0xF0,0x01,0xE0,0x03,0xC0,0xFF,0xFF,0xFF,0xFC,0x1E,0x00,0x3C,0x00,0x78,0x00,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80,0x0C,\r\n// 'I'\r\n0x49,0x03,0x0C,0x12,0x00,0x0D,\r\n0xFF,0xEF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0xFF,0xFF,0xFF,\r\n// 'J'\r\n0x4A,0x03,0x0E,0x12,0x01,0x10,\r\n0x1F,0xFC,0x7F,0xF0,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0xC0,0xC3,0x06,0x0E,0x18,0x1C,0x60,0x3F,0x80,0x3C,0x00,\r\n// 'K'\r\n0x4B,0x03,0x0C,0x12,0x03,0x0F,\r\n0xC0,0x6C,0x0E,0xC1,0xCC,0x38,0xC7,0x0C,0xE0,0xDC,0x0F,0x80,0xF0,0x0F,0x00,0xF8,0x0F,0xC0,0xDE,0x0C,0xF0,0xC7,0x8C,0x1E,0xC0,0xFC,0x07,\r\n// 'L'\r\n0x4C,0x03,0x0B,0x12,0x01,0x0D,\r\n0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xEF,0xFC,\r\n// 'M'\r\n0x4D,0x03,0x13,0x13,0x01,0x15,\r\n0x0C,0x06,0x01,0x80,0xC0,0x78,0x3C,0x0F,0x07,0x81,0xE0,0xF0,0x3C,0x1E,0x07,0x83,0xC1,0xD8,0xEC,0x3B,0x1D,0x87,0x63,0xB0,0xCC,0xE6,0x38,0xDC,0x47,0x1B,0x8C,0xE3,0xF1,0xB8,0x3C,0x37,0x07,0x86,0xE0,0xF0,0x7C,0x1E,0x0F,0x01,0x81,0x80,\r\n// 'N'\r\n0x4E,0x03,0x11,0x12,0x01,0x13,\r\n0x60,0x01,0x38,0x00,0xDE,0x00,0x6F,0x00,0x37,0xC0,0x1B,0x70,0x0D,0x9C,0x06,0xCF,0x03,0x63,0x81,0xB0,0xE0,0xD8,0x38,0x6C,0x0E,0x36,0x03,0x9B,0x00,0xED,0x80,0x3E,0xC0,0x0F,0x60,0x03,0xB0,0x00,0xC0,\r\n// 'O'\r\n0x4F,0x03,0x11,0x12,0x01,0x13,\r\n0x01,0xF8,0x03,0xFF,0x07,0x81,0xC3,0x00,0x63,0x00,0x1B,0x80,0x0D,0x80,0x07,0xC0,0x03,0xC0,0x01,0xE0,0x00,0xF0,0x00,0xF8,0x00,0x6C,0x00,0x33,0x00,0x31,0xC0,0x38,0x70,0x78,0x1F,0xF8,0x03,0xF0,0x00,\r\n// 'P'\r\n0x50,0x03,0x0B,0x12,0x01,0x0D,\r\n0xFE,0x1F,0xF3,0x0F,0x60,0x7C,0x07,0x80,0xF0,0x1E,0x06,0xC3,0xDF,0xF3,0xF8,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x00,\r\n// 'Q'\r\n0x51,0x03,0x14,0x17,0x01,0x15,\r\n0x01,0xF8,0x00,0x7F,0xE0,0x1E,0x07,0x03,0x80,0x18,0x30,0x01,0xC6,0x00,0x0C,0x60,0x00,0xEC,0x00,0x06,0xC0,0x00,0x6C,0x00,0x06,0xC0,0x00,0x6C,0x00,0x06,0x60,0xE0,0xE7,0x0F,0x0C,0x38,0x79,0xC1,0xC3,0xF8,0x0F,0xFF,0x00,0x3F,0x78,0x00,0x03,0xC0,0x00,0x1E,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x20,\r\n// 'R'\r\n0x52,0x02,0x0D,0x13,0x01,0x0F,\r\n0x00,0x03,0xE0,0x3F,0xC1,0x8F,0x0C,0x0E,0x60,0x33,0x00,0xD8,0x06,0xC0,0x36,0x03,0xB0,0x79,0xFF,0x8F,0xF0,0x7F,0x83,0x1F,0x18,0x3C,0xC0,0xF6,0x01,0xF0,0x06,\r\n// 'S'\r\n0x53,0x03,0x0F,0x13,0x01,0x11,\r\n0x01,0xF0,0x07,0xF8,0x18,0x70,0x60,0x01,0x80,0x03,0x00,0x06,0x00,0x0E,0x00,0x0F,0xF0,0x07,0xF0,0x00,0xF0,0x00,0x70,0x00,0x60,0x00,0xD8,0x01,0xB8,0x06,0x78,0x3C,0x7F,0xE0,0x3F,0x00,\r\n// 'T'\r\n0x54,0x02,0x0F,0x13,0x01,0x10,\r\n0x00,0x01,0xFF,0xFD,0xFF,0xF8,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,\r\n// 'U'\r\n0x55,0x03,0x11,0x12,0x01,0x12,\r\n0x60,0x03,0x30,0x01,0x98,0x00,0xCC,0x00,0x66,0x00,0x33,0x00,0x19,0x80,0x0C,0xC0,0x06,0x60,0x03,0x30,0x01,0x98,0x01,0xCC,0x00,0xC7,0x00,0x61,0x80,0x70,0xE0,0x30,0x38,0x38,0x0F,0xF8,0x01,0xF0,0x00,\r\n// 'V'\r\n0x56,0x03,0x0E,0x13,0x02,0x10,\r\n0x80,0x0F,0x00,0x3C,0x01,0xB0,0x06,0x60,0x31,0x80,0xC6,0x03,0x0C,0x18,0x30,0x60,0xC1,0x81,0x8C,0x06,0x30,0x0D,0x80,0x36,0x00,0xF8,0x01,0xC0,0x07,0x00,0x08,0x00,0x00,0x00,\r\n// 'W'\r\n0x57,0x03,0x17,0x12,0x01,0x19,\r\n0xC0,0x20,0x0F,0xC0,0x60,0x19,0x81,0xC0,0x23,0x03,0x80,0xC6,0x07,0x01,0x86,0x1E,0x03,0x0C,0x36,0x0C,0x18,0x6C,0x18,0x11,0x98,0x60,0x33,0x30,0xC0,0x66,0x61,0x80,0xD8,0x66,0x01,0xB0,0xCC,0x01,0xC1,0xB0,0x03,0x83,0x60,0x07,0x07,0x80,0x0C,0x07,0x00,0x08,0x0E,0x00,\r\n// 'X'\r\n0x58,0x03,0x10,0x12,0x01,0x11,\r\n0x60,0x03,0x70,0x07,0x38,0x0E,0x1C,0x1C,0x0C,0x1C,0x0E,0x38,0x07,0x70,0x03,0xE0,0x01,0xC0,0x03,0xC0,0x07,0xE0,0x07,0x70,0x0E,0x38,0x1C,0x18,0x38,0x1C,0x70,0x0E,0xE0,0x07,0xC0,0x03,\r\n// 'Y'\r\n0x59,0x03,0x0F,0x13,0x00,0x10,\r\n0x60,0x06,0xE0,0x1D,0xC0,0x31,0xC0,0xE1,0xC1,0x83,0x83,0x03,0x8C,0x07,0x18,0x07,0x70,0x0F,0xC0,0x0F,0x80,0x0F,0x00,0x1C,0x00,0x38,0x00,0x60,0x01,0xC0,0x03,0x00,0x06,0x00,0x08,0x00,\r\n// 'Z'\r\n0x5A,0x03,0x0F,0x12,0x01,0x11,\r\n0xFF,0xFF,0xFF,0xFC,0x00,0xF0,0x03,0x80,0x0E,0x00,0x3C,0x00,0xF0,0x03,0xC0,0x07,0x00,0x1E,0x00,0x38,0x00,0xE0,0x03,0xC0,0x07,0x00,0x1C,0x00,0x70,0x00,0xFF,0xFF,0xFF,0xFC,\r\n// '['\r\n0x5B,0x01,0x07,0x1A,0x01,0x09,\r\n0x00,0xFD,0xFB,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x3F,0x7E,0x00,\r\n// '\\'\r\n0x5C,0x03,0x0B,0x14,0x02,0x0D,\r\n0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x60,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x20,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x60,\r\n// ']'\r\n0x5D,0x01,0x07,0x1A,0x02,0x09,\r\n0x01,0xFB,0xF0,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x7E,0xFC,0x00,\r\n// '^'\r\n0x5E,0x02,0x0A,0x06,0x02,0x0E,\r\n0x0C,0x07,0x83,0xF1,0xCE,0xE1,0xF0,0x30,\r\n// '_'\r\n0x5F,0x16,0x0F,0x04,0x00,0x0F,\r\n0x00,0x01,0xFF,0xFF,0xFF,0xF8,0x00,0x00,\r\n// '`'\r\n0x60,0x02,0x05,0x06,0x02,0x0D,\r\n0xC7,0x1C,0x63,0x8C,\r\n// 'a'\r\n0x61,0x09,0x0B,0x0C,0x01,0x0C,\r\n0x0F,0x87,0xF9,0xE3,0x30,0x6E,0x0D,0x81,0xB0,0x36,0x06,0xC0,0xCC,0x39,0xFF,0x9F,0x30,\r\n// 'b'\r\n0x62,0x02,0x0C,0x13,0x01,0x0E,\r\n0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x78,0x7F,0xC7,0x8E,0x60,0x76,0x03,0x60,0x36,0x03,0x60,0x36,0x06,0x70,0xE7,0xFC,0x7F,0x00,\r\n// 'c'\r\n0x63,0x09,0x0A,0x0C,0x01,0x0C,\r\n0x0F,0x07,0xF3,0x0D,0x80,0x60,0x30,0x0C,0x03,0x00,0xC0,0x1C,0x33,0xFC,0x7C,\r\n// 'd'\r\n0x64,0x02,0x0C,0x13,0x01,0x0E,\r\n0x00,0x20,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x61,0xF6,0x3F,0xE7,0x0E,0x60,0x6C,0x06,0xC0,0x6C,0x06,0xC0,0x6E,0x06,0x70,0xE3,0xFE,0x1F,0x60,\r\n// 'e'\r\n0x65,0x09,0x0B,0x0C,0x01,0x0D,\r\n0x1F,0x07,0xF9,0xC7,0x30,0xEC,0x79,0xBE,0x3E,0x07,0x00,0xC0,0x6E,0x1D,0xFF,0x0F,0x80,\r\n// 'f'\r\n0x66,0x02,0x0A,0x14,0x01,0x0C,\r\n0x03,0x83,0xE0,0xE0,0x70,0x18,0x06,0x01,0x83,0xFF,0xFF,0xC6,0x01,0x80,0x60,0x18,0x06,0x01,0x80,0x60,0x18,0x06,0x01,0x80,0x60,\r\n// 'g'\r\n0x67,0x09,0x0A,0x13,0x02,0x0D,\r\n0x0F,0x0F,0xF7,0x0D,0x83,0xC0,0xF0,0x3C,0x1F,0x07,0xC1,0xD8,0xF7,0xEC,0xF3,0x00,0xC0,0x30,0x18,0x06,0x03,0xBF,0xC7,0xE0,\r\n// 'h'\r\n0x68,0x02,0x0B,0x13,0x01,0x0E,\r\n0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x1E,0x6F,0xEF,0x8D,0xE1,0xB8,0x36,0x06,0xC0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0x80,\r\n// 'i'\r\n0x69,0x04,0x02,0x11,0x03,0x07,\r\n0xF0,0x3F,0xFF,0xFF,0xC0,\r\n// 'j'\r\n0x6A,0x04,0x08,0x18,0x00,0x0A,\r\n0x03,0x03,0x00,0x00,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0xC3,0xE3,0x77,0x7E,0x1C,\r\n// 'k'\r\n0x6B,0x03,0x0B,0x13,0x02,0x0E,\r\n0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x36,0x0E,0xC7,0x99,0xE3,0x70,0x7E,0x0F,0xE1,0xCE,0x30,0xE6,0x0E,0xC0,0xF8,0x08,0x00,0x00,\r\n// 'l'\r\n0x6C,0x02,0x02,0x13,0x03,0x07,\r\n0xFF,0xFF,0xFF,0xFF,0xFC,\r\n// 'm'\r\n0x6D,0x09,0x10,0x0C,0x01,0x12,\r\n0x67,0x3C,0x6F,0xFE,0x7D,0xEE,0x79,0x86,0x71,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,\r\n// 'n'\r\n0x6E,0x09,0x0B,0x0C,0x01,0x0D,\r\n0x63,0x8D,0xF9,0xF1,0xBC,0x37,0x06,0xE0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0xB0,0x30,\r\n// 'o'\r\n0x6F,0x09,0x0C,0x0C,0x01,0x0D,\r\n0x0F,0x81,0xFC,0x38,0xC3,0x06,0x60,0x66,0x06,0x60,0x66,0x06,0x60,0xE3,0x1C,0x1F,0x80,0xF0,\r\n// 'p'\r\n0x70,0x08,0x0A,0x14,0x02,0x0D,\r\n0xC0,0x33,0xCF,0xFB,0xC6,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x7C,0x1B,0xFC,0xFE,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,\r\n// 'q'\r\n0x71,0x08,0x0A,0x14,0x01,0x0C,\r\n0x00,0x03,0xF3,0xFD,0xE3,0x60,0xF8,0x3C,0x0F,0x03,0xC0,0xF0,0x76,0x1D,0xFF,0x1F,0x80,0x60,0x18,0x06,0x01,0x80,0x60,0x18,0x06,\r\n// 'r'\r\n0x72,0x09,0x09,0x0C,0x01,0x0B,\r\n0xCF,0x6F,0xFE,0x7C,0x3C,0x1E,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x00,\r\n// 's'\r\n0x73,0x09,0x09,0x0C,0x02,0x0C,\r\n0x03,0x9F,0xDE,0x7C,0x3E,0x07,0xF0,0xFC,0x07,0x01,0xE0,0xFF,0xC7,0xC0,\r\n// 't'\r\n0x74,0x05,0x0A,0x10,0x00,0x0A,\r\n0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,\r\n// 'u'\r\n0x75,0x09,0x0B,0x0C,0x01,0x0C,\r\n0xC0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0xB0,0x36,0x06,0xC0,0xD8,0x19,0xFF,0x1F,0x60,\r\n// 'v'\r\n0x76,0x09,0x0B,0x0D,0x01,0x0C,\r\n0xC0,0x78,0x1F,0x83,0x30,0x67,0x1C,0x63,0x0C,0xE0,0xD8,0x1E,0x03,0xC0,0x30,0x06,0x00,0x00,\r\n// 'w'\r\n0x77,0x09,0x0F,0x0D,0x01,0x11,\r\n0xC1,0x87,0x83,0x0F,0x0E,0x1E,0x1C,0x66,0x7C,0xCC,0xD9,0x99,0x36,0x36,0x6C,0x7C,0xD8,0x70,0xE0,0xE1,0xC0,0x83,0x80,0x00,0x00,\r\n// 'x'\r\n0x78,0x09,0x0D,0x0D,0x01,0x0E,\r\n0x60,0x1B,0x81,0xCE,0x1C,0x39,0xC0,0xFC,0x03,0xC0,0x3C,0x03,0xF0,0x39,0xC3,0x87,0x38,0x1D,0x80,0x70,0x01,0x80,\r\n// 'y'\r\n0x79,0x09,0x0C,0x13,0x00,0x0D,\r\n0xC0,0x3E,0x07,0x60,0x67,0x0C,0x30,0xC3,0x98,0x19,0x81,0xD8,0x0F,0x00,0xF0,0x06,0x00,0x60,0x0C,0x00,0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x30,0x00,\r\n// 'z'\r\n0x7A,0x09,0x0B,0x0C,0x01,0x0D,\r\n0xFF,0xFF,0xFC,0x07,0x00,0xC0,0x30,0x0C,0x03,0x80,0xE0,0x38,0x0E,0x03,0xFF,0xFF,0xF0,\r\n// '{'\r\n0x7B,0x02,0x08,0x18,0x01,0x09,\r\n0x0F,0x1F,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x60,0xE0,0xE0,0x70,0x30,0x30,0x30,0x30,0x30,0x38,0x18,0x1F,0x07,\r\n// '|'\r\n0x7C,0x01,0x02,0x18,0x04,0x0A,\r\n0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\r\n// '}'\r\n0x7D,0x02,0x08,0x18,0x01,0x09,\r\n0x70,0xF8,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x06,0x07,0x07,0x0E,0x0C,0x0C,0x0C,0x0C,0x0C,0x1C,0x18,0xF8,0xE0,\r\n// '~'\r\n0x7E,0x0B,0x0C,0x05,0x01,0x0E,\r\n0x38,0x37,0xE3,0xE7,0x7C,0x3E,0x01,0xC0,\r\n\r\n// Terminator\r\n0xFF\r\n};\r\n"
  },
  {
    "path": "components/epaper/component.mk",
    "content": "#\n# Main Makefile. This is basically the same as a component makefile.\n#\n# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)\n\nCOMPONENT_SRCDIRS := . \nCOMPONENT_ADD_INCLUDEDIRS := .\n"
  },
  {
    "path": "components/epaper/dejavuX.c",
    "content": "// This comes with no warranty, implied or otherwise\r\n\r\n// This data structure was designed to support Proportional fonts\r\n// on Arduinos. It can however handle any ttf font that has been converted\r\n// using the conversion program. These could be fixed width or proportional \r\n// fonts. Individual characters do not have to be multiples of 8 bits wide. \r\n// Any width is fine and does not need to be fixed.\r\n\r\n// The data bits are packed to minimize data requirements, but the tradeoff\r\n// is that a header is required per character.\r\n\r\n// dejavuX.c\r\n// Point Size   : 18\r\n// Memory usage : 4676 bytes\r\n// # characters : 224\r\n\r\n// Header Format (to make Arduino UTFT Compatible):\r\n// ------------------------------------------------\r\n// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)\r\n// Character Height\r\n// First Character (Reserved. 0x00)\r\n// Number Of Characters (Reserved. 0x00)\r\n\r\nconst unsigned char tft_Dejavu18[] =\r\n{\r\n0x00, 0x12, 0x00, 0x00,\r\n\r\n// Individual Character Format:\r\n// ----------------------------\r\n// Character Code\r\n// Adjusted Y Offset\r\n// Width\r\n// Height\r\n// xOffset\r\n// xDelta (the distance to move the cursor. Effective width of the character.)\r\n// Data[n]\r\n\r\n// NOTE: You can remove any of these characters if they are not needed in\r\n// your application. The first character number in each Glyph indicates\r\n// the ASCII character code. Therefore, these do not have to be sequential.\r\n// Just remove all the content for a particular character to save space.\r\n\r\n// ' '\r\n0x20,0x11,0x00,0x00,0x00,0x06,\r\n\r\n// '!'\r\n0x21,0x04,0x02,0x0D,0x03,0x07,\r\n0xFF,0xFF,0xC3,0xC0,\r\n// '\"'\r\n0x22,0x04,0x06,0x05,0x01,0x08,\r\n0xCF,0x3C,0xF3,0xCC,\r\n// '#'\r\n0x23,0x03,0x0C,0x0E,0x01,0x0F,\r\n0x04,0x40,0x44,0x0C,0xC0,0xC8,0x7F,0xF7,0xFF,0x09,0x81,0x90,0xFF,0xEF,0xFE,0x13,0x03,0x30,0x32,0x02,0x20,\r\n// '$'\r\n0x24,0x03,0x0A,0x11,0x01,0x0B,\r\n0x08,0x02,0x03,0xE1,0xFC,0xE9,0x32,0x0F,0x81,0xF8,0x0F,0x02,0x60,0x9A,0x2E,0xFF,0x1F,0x80,0x80,0x20,0x08,0x00,\r\n// '%'\r\n0x25,0x04,0x0F,0x0D,0x01,0x11,\r\n0x78,0x10,0x90,0x43,0x31,0x86,0x62,0x0C,0xC8,0x19,0x10,0x1E,0x4F,0x01,0x12,0x02,0x66,0x08,0xCC,0x31,0x98,0x41,0x21,0x03,0xC0,\r\n// '&'\r\n0x26,0x04,0x0C,0x0D,0x01,0x0D,\r\n0x0F,0x01,0xF8,0x30,0x83,0x00,0x38,0x03,0xC0,0x7E,0x6C,0x76,0xC3,0xCC,0x18,0xE1,0xC7,0xFE,0x3E,0x70,\r\n// '''\r\n0x27,0x04,0x02,0x05,0x01,0x04,\r\n0xFF,0xC0,\r\n// '('\r\n0x28,0x03,0x04,0x10,0x02,0x07,\r\n0x32,0x66,0x4C,0xCC,0xCC,0xC4,0x66,0x23,\r\n// ')'\r\n0x29,0x03,0x04,0x10,0x01,0x07,\r\n0xC4,0x66,0x23,0x33,0x33,0x32,0x66,0x4C,\r\n// '*'\r\n0x2A,0x04,0x07,0x08,0x01,0x09,\r\n0x11,0x25,0x51,0xC3,0x8A,0xA4,0x88,\r\n// '+'\r\n0x2B,0x05,0x0C,0x0C,0x02,0x0F,\r\n0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x0F,0xFF,0xFF,0xF0,0x60,0x06,0x00,0x60,0x06,0x00,0x60,\r\n// ','\r\n0x2C,0x0F,0x03,0x04,0x01,0x06,\r\n0x6D,0x40,\r\n// '-'\r\n0x2D,0x0B,0x05,0x02,0x01,0x07,\r\n0xFF,0xC0,\r\n// '.'\r\n0x2E,0x0F,0x02,0x02,0x02,0x06,\r\n0xF0,\r\n// '/'\r\n0x2F,0x04,0x06,0x0F,0x00,0x06,\r\n0x0C,0x31,0x86,0x18,0xE3,0x0C,0x31,0xC6,0x18,0x63,0x0C,0x00,\r\n// '0'\r\n0x30,0x04,0x09,0x0D,0x01,0x0B,\r\n0x3E,0x3F,0x98,0xD8,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xD8,0xCF,0xE3,0xE0,\r\n// '1'\r\n0x31,0x04,0x08,0x0D,0x02,0x0B,\r\n0x38,0xF8,0xD8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0xFF,\r\n// '2'\r\n0x32,0x04,0x09,0x0D,0x01,0x0B,\r\n0x7C,0x7F,0x21,0xC0,0x60,0x30,0x30,0x18,0x18,0x18,0x18,0x18,0x1F,0xEF,0xF0,\r\n// '3'\r\n0x33,0x04,0x09,0x0D,0x01,0x0B,\r\n0x7E,0x7F,0xA0,0xE0,0x30,0x39,0xF0,0xFC,0x07,0x01,0x80,0xE0,0xFF,0xE7,0xE0,\r\n// '4'\r\n0x34,0x04,0x0A,0x0D,0x01,0x0B,\r\n0x07,0x01,0xC0,0xB0,0x6C,0x13,0x08,0xC6,0x31,0x0C,0xFF,0xFF,0xF0,0x30,0x0C,0x03,0x00,\r\n// '5'\r\n0x35,0x04,0x08,0x0D,0x01,0x0B,\r\n0x7E,0x7E,0x60,0x60,0x7C,0x7E,0x47,0x03,0x03,0x03,0x87,0xFE,0x7C,\r\n// '6'\r\n0x36,0x04,0x09,0x0D,0x01,0x0B,\r\n0x1E,0x1F,0x9C,0x5C,0x0C,0x06,0xF3,0xFD,0xC7,0xC1,0xE0,0xD8,0xEF,0xE1,0xE0,\r\n// '7'\r\n0x37,0x04,0x08,0x0D,0x01,0x0B,\r\n0xFF,0xFF,0x06,0x06,0x06,0x0E,0x0C,0x0C,0x1C,0x18,0x18,0x38,0x30,\r\n// '8'\r\n0x38,0x04,0x09,0x0D,0x01,0x0B,\r\n0x3E,0x3F,0xB8,0xF8,0x3E,0x39,0xF1,0xFD,0xC7,0xC1,0xE0,0xF8,0xEF,0xE3,0xE0,\r\n// '9'\r\n0x39,0x04,0x09,0x0D,0x01,0x0B,\r\n0x3C,0x3F,0xB8,0xD8,0x3C,0x1F,0x1D,0xFE,0x7B,0x01,0x81,0xD1,0xCF,0xC3,0xC0,\r\n// ':'\r\n0x3A,0x08,0x02,0x09,0x02,0x06,\r\n0xF0,0x03,0xC0,\r\n// ';'\r\n0x3B,0x08,0x03,0x0B,0x01,0x06,\r\n0x6C,0x00,0x03,0x6A,0x00,\r\n// '<'\r\n0x3C,0x07,0x0B,0x0A,0x02,0x0F,\r\n0x00,0x20,0x3C,0x1F,0x1F,0x0F,0x81,0xF0,0x0F,0x80,0x3E,0x01,0xE0,0x04,\r\n// '='\r\n0x3D,0x08,0x0B,0x06,0x02,0x0F,\r\n0xFF,0xFF,0xFC,0x00,0x00,0x0F,0xFF,0xFF,0xC0,\r\n// '>'\r\n0x3E,0x07,0x0B,0x0A,0x02,0x0F,\r\n0x80,0x1E,0x01,0xF0,0x07,0xC0,0x3E,0x07,0xC3,0xE3,0xE0,0xF0,0x10,0x00,\r\n// '?'\r\n0x3F,0x04,0x07,0x0D,0x01,0x0A,\r\n0x79,0xFA,0x38,0x30,0x61,0x86,0x18,0x30,0x60,0x01,0x83,0x00,\r\n// '@'\r\n0x40,0x04,0x10,0x10,0x01,0x12,\r\n0x07,0xE0,0x1F,0xF8,0x3C,0x1C,0x70,0x06,0x60,0x07,0xE3,0x63,0xC7,0xE3,0xC6,0x63,0xC6,0x66,0xC7,0xFC,0xE3,0x70,0x60,0x00,0x70,0x00,0x3C,0x30,0x1F,0xF0,0x07,0xC0,\r\n// 'A'\r\n0x41,0x04,0x0C,0x0D,0x00,0x0C,\r\n0x06,0x00,0x60,0x0F,0x00,0xF0,0x19,0x81,0x98,0x19,0x83,0x0C,0x3F,0xC7,0xFE,0x60,0x66,0x06,0xC0,0x30,\r\n// 'B'\r\n0x42,0x04,0x09,0x0D,0x02,0x0C,\r\n0xFC,0x7F,0xB0,0xD8,0x6C,0x37,0xF3,0xF9,0x86,0xC1,0xE0,0xF0,0xFF,0xEF,0xE0,\r\n// 'C'\r\n0x43,0x04,0x0B,0x0D,0x01,0x0D,\r\n0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x9F,0xF0,0xFC,\r\n// 'D'\r\n0x44,0x04,0x0B,0x0D,0x02,0x0E,\r\n0xFE,0x1F,0xF3,0x07,0x60,0x6C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1B,0x07,0x7F,0xCF,0xE0,\r\n// 'E'\r\n0x45,0x04,0x08,0x0D,0x02,0x0B,\r\n0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,\r\n// 'F'\r\n0x46,0x04,0x08,0x0D,0x02,0x0A,\r\n0xFF,0xFF,0xC0,0xC0,0xC0,0xFE,0xFE,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,\r\n// 'G'\r\n0x47,0x04,0x0B,0x0D,0x01,0x0E,\r\n0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x87,0xF0,0xFE,0x03,0xC0,0x6C,0x0D,0xC1,0x9F,0xE0,0xF8,\r\n// 'H'\r\n0x48,0x04,0x0A,0x0D,0x02,0x0E,\r\n0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xFF,0xFF,0xFF,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xC0,\r\n// 'I'\r\n0x49,0x04,0x02,0x0D,0x02,0x06,\r\n0xFF,0xFF,0xFF,0xC0,\r\n// 'J'\r\n0x4A,0x04,0x05,0x11,0xFF,0x06,\r\n0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0xFE,0xE0,\r\n// 'K'\r\n0x4B,0x04,0x0B,0x0D,0x02,0x0C,\r\n0xC1,0x98,0x63,0x18,0x66,0x0D,0x81,0xE0,0x3C,0x06,0xC0,0xCC,0x18,0xC3,0x0C,0x60,0xCC,0x0C,\r\n// 'L'\r\n0x4C,0x04,0x08,0x0D,0x02,0x0A,\r\n0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,\r\n// 'M'\r\n0x4D,0x04,0x0C,0x0D,0x02,0x10,\r\n0xE0,0x7F,0x0F,0xF0,0xFD,0x8B,0xD9,0xBD,0x9B,0xCF,0x3C,0xF3,0xC6,0x3C,0x63,0xC0,0x3C,0x03,0xC0,0x30,\r\n// 'N'\r\n0x4E,0x04,0x0A,0x0D,0x02,0x0E,\r\n0xE0,0xF8,0x3F,0x0F,0xC3,0xD8,0xF6,0x3C,0xCF,0x1B,0xC6,0xF0,0xFC,0x3F,0x07,0xC1,0xC0,\r\n// 'O'\r\n0x4F,0x04,0x0C,0x0D,0x01,0x0E,\r\n0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,\r\n// 'P'\r\n0x50,0x04,0x08,0x0D,0x02,0x0B,\r\n0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0,\r\n// 'Q'\r\n0x51,0x04,0x0C,0x0F,0x01,0x0E,\r\n0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,0x18,0x00,0xC0,\r\n// 'R'\r\n0x52,0x04,0x0A,0x0D,0x02,0x0D,\r\n0xFC,0x3F,0x8C,0x73,0x0C,0xC3,0x31,0xCF,0xE3,0xF0,0xC6,0x30,0xCC,0x33,0x06,0xC1,0xC0,\r\n// 'S'\r\n0x53,0x04,0x0A,0x0D,0x01,0x0B,\r\n0x3E,0x1F,0xCE,0x13,0x00,0xC0,0x1F,0x03,0xF0,0x0E,0x01,0x80,0x68,0x3B,0xFC,0x7E,0x00,\r\n// 'T'\r\n0x54,0x04,0x0C,0x0D,0x00,0x0C,\r\n0xFF,0xFF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,\r\n// 'U'\r\n0x55,0x04,0x0A,0x0D,0x02,0x0E,\r\n0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x36,0x19,0xFE,0x1E,0x00,\r\n// 'V'\r\n0x56,0x04,0x0C,0x0D,0x00,0x0C,\r\n0xC0,0x36,0x06,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,0x06,0x00,\r\n// 'W'\r\n0x57,0x04,0x11,0x0D,0x01,0x13,\r\n0xC1,0xC1,0xE0,0xE0,0xD8,0xF8,0xCC,0x6C,0x66,0x36,0x33,0x1B,0x18,0xD8,0xD8,0x6C,0x6C,0x36,0x36,0x1F,0x1F,0x07,0x07,0x03,0x83,0x81,0xC1,0xC0,\r\n// 'X'\r\n0x58,0x04,0x0B,0x0D,0x01,0x0D,\r\n0x70,0xE6,0x18,0xE6,0x0D,0xC0,0xF0,0x1C,0x03,0x80,0x78,0x1B,0x07,0x30,0xC7,0x30,0x6E,0x0E,\r\n// 'Y'\r\n0x59,0x04,0x0C,0x0D,0x00,0x0C,\r\n0xE0,0x76,0x06,0x30,0xC1,0x98,0x19,0x80,0xF0,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,\r\n// 'Z'\r\n0x5A,0x04,0x0B,0x0D,0x01,0x0D,\r\n0xFF,0xFF,0xFC,0x07,0x01,0xC0,0x30,0x0E,0x03,0x80,0xE0,0x18,0x06,0x01,0xC0,0x7F,0xFF,0xFE,\r\n// '['\r\n0x5B,0x03,0x04,0x10,0x01,0x07,\r\n0xFF,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFF,\r\n// '\\'\r\n0x5C,0x04,0x06,0x0F,0x00,0x06,\r\n0xC3,0x06,0x18,0x61,0xC3,0x0C,0x30,0xE1,0x86,0x18,0x30,0xC0,\r\n// ']'\r\n0x5D,0x03,0x04,0x10,0x02,0x07,\r\n0xFF,0x33,0x33,0x33,0x33,0x33,0x33,0xFF,\r\n// '^'\r\n0x5E,0x04,0x0B,0x05,0x02,0x0F,\r\n0x0E,0x03,0xE0,0xC6,0x30,0x6C,0x06,\r\n// '_'\r\n0x5F,0x13,0x09,0x02,0x00,0x09,\r\n0xFF,0xFF,0xC0,\r\n// '`'\r\n0x60,0x03,0x04,0x03,0x02,0x09,\r\n0xC6,0x30,\r\n// 'a'\r\n0x61,0x07,0x08,0x0A,0x01,0x0A,\r\n0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,\r\n// 'b'\r\n0x62,0x03,0x09,0x0E,0x02,0x0B,\r\n0xC0,0x60,0x30,0x18,0x0D,0xE7,0xFB,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x7F,0xF6,0xF0,\r\n// 'c'\r\n0x63,0x07,0x08,0x0A,0x01,0x09,\r\n0x1E,0x7F,0x61,0xC0,0xC0,0xC0,0xC0,0x61,0x7F,0x1E,\r\n// 'd'\r\n0x64,0x03,0x09,0x0E,0x01,0x0B,\r\n0x01,0x80,0xC0,0x60,0x33,0xDB,0xFF,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x77,0xF9,0xEC,\r\n// 'e'\r\n0x65,0x07,0x0A,0x0A,0x01,0x0B,\r\n0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,\r\n// 'f'\r\n0x66,0x03,0x07,0x0E,0x00,0x06,\r\n0x1E,0x7C,0xC1,0x8F,0xFF,0xCC,0x18,0x30,0x60,0xC1,0x83,0x06,0x00,\r\n// 'g'\r\n0x67,0x07,0x09,0x0E,0x01,0x0B,\r\n0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x68,0x67,0xF1,0xF0,\r\n// 'h'\r\n0x68,0x03,0x08,0x0E,0x02,0x0B,\r\n0xC0,0xC0,0xC0,0xC0,0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,\r\n// 'i'\r\n0x69,0x03,0x02,0x0E,0x02,0x05,\r\n0xF0,0xFF,0xFF,0xF0,\r\n// 'j'\r\n0x6A,0x03,0x04,0x12,0x00,0x05,\r\n0x33,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0xEC,\r\n// 'k'\r\n0x6B,0x03,0x09,0x0E,0x02,0x0A,\r\n0xC0,0x60,0x30,0x18,0x0C,0x36,0x33,0x31,0xB0,0xF0,0x78,0x36,0x19,0x8C,0x66,0x18,\r\n// 'l'\r\n0x6C,0x03,0x02,0x0E,0x02,0x05,\r\n0xFF,0xFF,0xFF,0xF0,\r\n// 'm'\r\n0x6D,0x07,0x0E,0x0A,0x02,0x11,\r\n0xDC,0x7B,0xFB,0xEE,0x79,0xF0,0xC3,0xC3,0x0F,0x0C,0x3C,0x30,0xF0,0xC3,0xC3,0x0F,0x0C,0x30,\r\n// 'n'\r\n0x6E,0x07,0x08,0x0A,0x02,0x0B,\r\n0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,\r\n// 'o'\r\n0x6F,0x07,0x0A,0x0A,0x01,0x0B,\r\n0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,\r\n// 'p'\r\n0x70,0x07,0x09,0x0E,0x02,0x0B,\r\n0xDE,0x7F,0xB8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0xFF,0x6F,0x30,0x18,0x0C,0x06,0x00,\r\n// 'q'\r\n0x71,0x07,0x09,0x0E,0x01,0x0B,\r\n0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x60,0x30,0x18,0x0C,\r\n// 'r'\r\n0x72,0x07,0x06,0x0A,0x02,0x08,\r\n0xDF,0xFE,0x30,0xC3,0x0C,0x30,0xC3,0x00,\r\n// 's'\r\n0x73,0x07,0x08,0x0A,0x01,0x08,\r\n0x7C,0xFE,0xC2,0xE0,0x7C,0x1E,0x06,0x86,0xFE,0x78,\r\n// 't'\r\n0x74,0x04,0x06,0x0D,0x01,0x07,\r\n0x61,0x86,0x3F,0xFD,0x86,0x18,0x61,0x86,0x1F,0x3C,\r\n// 'u'\r\n0x75,0x07,0x08,0x0A,0x02,0x0B,\r\n0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,\r\n// 'v'\r\n0x76,0x07,0x0C,0x0A,0x00,0x0B,\r\n0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,\r\n// 'w'\r\n0x77,0x07,0x0F,0x0A,0x01,0x10,\r\n0x63,0x8C,0xC7,0x19,0x8E,0x31,0xB6,0xC3,0x6D,0x86,0xDB,0x0F,0x1E,0x0E,0x38,0x1C,0x70,0x38,0xE0,\r\n// 'x'\r\n0x78,0x07,0x0A,0x0A,0x01,0x0B,\r\n0xE1,0xD8,0x63,0x30,0xCC,0x1E,0x07,0x83,0x30,0xCC,0x61,0xB8,0x70,\r\n// 'y'\r\n0x79,0x07,0x0C,0x0E,0x00,0x0B,\r\n0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80,\r\n// 'z'\r\n0x7A,0x07,0x08,0x0A,0x01,0x09,\r\n0xFF,0xFF,0x06,0x0C,0x1C,0x38,0x30,0x70,0xFF,0xFF,\r\n// '{'\r\n0x7B,0x03,0x08,0x11,0x02,0x0B,\r\n0x0F,0x1F,0x18,0x18,0x18,0x18,0x38,0xF0,0xF0,0x38,0x18,0x18,0x18,0x18,0x18,0x1F,0x0F,\r\n// '|'\r\n0x7C,0x03,0x02,0x12,0x02,0x06,\r\n0xFF,0xFF,0xFF,0xFF,0xF0,\r\n// '}'\r\n0x7D,0x03,0x08,0x11,0x02,0x0B,\r\n0xF0,0xF8,0x18,0x18,0x18,0x18,0x1C,0x0F,0x0F,0x1C,0x18,0x18,0x18,0x18,0x18,0xF8,0xF0,\r\n// '~'\r\n0x7E,0x08,0x0B,0x05,0x02,0x0F,\r\n0x00,0x0F,0x87,0xFF,0xC3,0xE0,0x00,\r\n// ''\r\n0x7F,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x80,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x81,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x82,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x83,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x84,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x85,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x86,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x87,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x88,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x89,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x8A,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x8B,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x8C,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x8D,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x8E,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x8F,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x90,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x91,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x92,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x93,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x94,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x95,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x96,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x97,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x98,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x99,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x9A,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x9B,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x9C,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x9D,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x9E,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0x9F,0x04,0x09,0x10,0x01,0x0B,\r\n0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,\r\n// ''\r\n0xA0,0x11,0x00,0x00,0x00,0x06,\r\n\r\n// ''\r\n0xA1,0x07,0x02,0x0D,0x03,0x07,\r\n0xF0,0xFF,0xFF,0xC0,\r\n// ''\r\n0xA2,0x04,0x08,0x10,0x02,0x0B,\r\n0x04,0x04,0x04,0x1E,0x7F,0x75,0xC4,0xC4,0xC4,0xC4,0x65,0x7F,0x1E,0x04,0x04,0x04,\r\n// ''\r\n0xA3,0x04,0x09,0x0D,0x01,0x0B,\r\n0x0F,0x0F,0xCE,0x26,0x03,0x01,0x83,0xF9,0xFC,0x30,0x18,0x0C,0x1F,0xFF,0xF8,\r\n// ''\r\n0xA4,0x06,0x0A,0x0A,0x00,0x0B,\r\n0x00,0x10,0x13,0x58,0xFE,0x11,0x0C,0x61,0x10,0xFE,0x35,0x90,0x10,\r\n// ''\r\n0xA5,0x04,0x0A,0x0D,0x01,0x0B,\r\n0xC0,0xD8,0x66,0x18,0xCC,0x33,0x3F,0xF1,0xE0,0x30,0xFF,0xC3,0x00,0xC0,0x30,0x0C,0x00,\r\n// ''\r\n0xA6,0x04,0x02,0x10,0x02,0x06,\r\n0xFF,0xFC,0x3F,0xFF,\r\n// ''\r\n0xA7,0x04,0x07,0x0F,0x01,0x09,\r\n0x3C,0xF9,0x83,0x03,0x0F,0x33,0x63,0x66,0x78,0x60,0x60,0xCF,0x9E,0x00,\r\n// ''\r\n0xA8,0x03,0x06,0x02,0x02,0x09,\r\n0xCF,0x30,\r\n// ''\r\n0xA9,0x04,0x0D,0x0D,0x02,0x12,\r\n0x0F,0x81,0x83,0x18,0x0C,0x8F,0x28,0x80,0xC8,0x06,0x40,0x32,0x01,0x88,0x8A,0x38,0x98,0x0C,0x60,0xC0,0xF8,0x00,\r\n// ''\r\n0xAA,0x04,0x08,0x09,0x01,0x08,\r\n0x7C,0x02,0x7E,0xC2,0x82,0xC6,0x7A,0x00,0xFE,\r\n// ''\r\n0xAB,0x08,0x08,0x08,0x01,0x0B,\r\n0x11,0x33,0x66,0xCC,0xCC,0x66,0x33,0x11,\r\n// ''\r\n0xAC,0x09,0x0B,0x05,0x02,0x0F,\r\n0xFF,0xFF,0xFC,0x01,0x80,0x30,0x06,\r\n// ''\r\n0xAD,0x0B,0x05,0x02,0x01,0x07,\r\n0xFF,0xC0,\r\n// ''\r\n0xAE,0x04,0x0D,0x0D,0x02,0x12,\r\n0x0F,0x81,0x83,0x18,0x0C,0x9E,0x28,0x88,0xC4,0x46,0x3C,0x31,0x21,0x88,0x8A,0x46,0x98,0x0C,0x60,0xC0,0xF8,0x00,\r\n// ''\r\n0xAF,0x04,0x05,0x02,0x02,0x09,\r\n0xFF,0xC0,\r\n// ''\r\n0xB0,0x04,0x06,0x06,0x02,0x09,\r\n0x7B,0x38,0x61,0xCD,0xE0,\r\n// ''\r\n0xB1,0x06,0x0C,0x0B,0x02,0x0F,\r\n0x06,0x00,0x60,0x06,0x0F,0xFF,0xFF,0xF0,0x60,0x06,0x00,0x60,0x00,0x0F,0xFF,0xFF,0xF0,\r\n// ''\r\n0xB2,0x04,0x05,0x07,0x01,0x07,\r\n0x74,0x42,0x22,0x23,0xE0,\r\n// ''\r\n0xB3,0x04,0x05,0x07,0x01,0x07,\r\n0xF0,0x5C,0x30,0x8F,0xC0,\r\n// ''\r\n0xB4,0x03,0x04,0x03,0x03,0x09,\r\n0x36,0xC0,\r\n// ''\r\n0xB5,0x07,0x09,0x0E,0x02,0x0B,\r\n0xC3,0x61,0xB0,0xD8,0x6C,0x36,0x1B,0x0D,0xCE,0xFF,0xEC,0xF0,0x18,0x0C,0x06,0x00,\r\n// ''\r\n0xB6,0x04,0x08,0x0F,0x01,0x0B,\r\n0x3F,0x79,0xF9,0xF9,0xF9,0xF9,0x79,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,\r\n// ''\r\n0xB7,0x0A,0x02,0x02,0x02,0x06,\r\n0xF0,\r\n// ''\r\n0xB8,0x11,0x04,0x03,0x03,0x09,\r\n0x23,0xF0,\r\n// ''\r\n0xB9,0x04,0x05,0x07,0x01,0x07,\r\n0xE1,0x08,0x42,0x13,0xE0,\r\n// ''\r\n0xBA,0x04,0x07,0x09,0x01,0x08,\r\n0x38,0x8A,0x0C,0x18,0x28,0x8E,0x00,0xFE,\r\n// ''\r\n0xBB,0x08,0x08,0x08,0x02,0x0B,\r\n0x88,0xCC,0x66,0x33,0x33,0x66,0xCC,0x88,\r\n// ''\r\n0xBC,0x04,0x10,0x0D,0x01,0x11,\r\n0xE0,0x18,0x20,0x10,0x20,0x20,0x20,0x60,0x20,0x40,0x20,0x80,0xF9,0x86,0x01,0x0A,0x02,0x12,0x06,0x22,0x04,0x3F,0x08,0x02,0x18,0x02,\r\n// ''\r\n0xBD,0x04,0x0F,0x0D,0x01,0x11,\r\n0xE0,0x18,0x40,0x20,0x80,0x81,0x03,0x02,0x04,0x04,0x10,0x3E,0x67,0x00,0x91,0x02,0x02,0x0C,0x08,0x10,0x20,0x40,0x81,0x83,0xE0,\r\n// ''\r\n0xBE,0x04,0x10,0x0D,0x01,0x11,\r\n0xF0,0x18,0x08,0x10,0x70,0x20,0x18,0x60,0x08,0x40,0x18,0x80,0xF1,0x86,0x01,0x0A,0x02,0x12,0x06,0x22,0x04,0x3F,0x08,0x02,0x18,0x02,\r\n// ''\r\n0xBF,0x07,0x07,0x0E,0x02,0x0A,\r\n0x18,0x30,0x00,0xC1,0x83,0x0C,0x18,0x61,0x83,0x07,0x17,0xE7,0x80,\r\n// ''\r\n0xC0,0x01,0x0C,0x10,0x00,0x0C,\r\n0x06,0x00,0x30,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,\r\n// ''\r\n0xC1,0x01,0x0C,0x10,0x00,0x0C,\r\n0x03,0x00,0x60,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,\r\n// ''\r\n0xC2,0x01,0x0C,0x10,0x00,0x0C,\r\n0x06,0x00,0x90,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,\r\n// ''\r\n0xC3,0x01,0x0C,0x10,0x00,0x0C,\r\n0x0C,0x81,0x30,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,\r\n// ''\r\n0xC4,0x01,0x0C,0x10,0x00,0x0C,\r\n0x19,0x81,0x98,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,\r\n// ''\r\n0xC5,0x00,0x0C,0x11,0x00,0x0C,\r\n0x06,0x00,0x90,0x09,0x00,0x90,0x06,0x00,0x60,0x0F,0x00,0xF0,0x19,0x81,0x98,0x19,0x83,0x0C,0x3F,0xC7,0xFE,0x60,0x66,0x06,0xC0,0x30,\r\n// ''\r\n0xC6,0x04,0x10,0x0D,0x00,0x11,\r\n0x07,0xFF,0x07,0xFF,0x06,0xC0,0x0C,0xC0,0x0C,0xC0,0x18,0xFF,0x18,0xFF,0x30,0xC0,0x3F,0xC0,0x3F,0xC0,0x60,0xC0,0x60,0xFF,0xC0,0xFF,\r\n// ''\r\n0xC7,0x04,0x0B,0x10,0x01,0x0D,\r\n0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x9F,0xF0,0xFC,0x02,0x00,0x60,0x3C,\r\n// ''\r\n0xC8,0x01,0x08,0x10,0x02,0x0B,\r\n0x30,0x18,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,\r\n// ''\r\n0xC9,0x01,0x08,0x10,0x02,0x0B,\r\n0x18,0x30,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,\r\n// ''\r\n0xCA,0x01,0x08,0x10,0x02,0x0B,\r\n0x38,0x6C,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,\r\n// ''\r\n0xCB,0x01,0x08,0x10,0x02,0x0B,\r\n0x66,0x66,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,\r\n// ''\r\n0xCC,0x01,0x05,0x10,0x00,0x06,\r\n0x61,0x80,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,\r\n// ''\r\n0xCD,0x01,0x04,0x10,0x01,0x06,\r\n0x6C,0x06,0x66,0x66,0x66,0x66,0x66,0x66,\r\n// ''\r\n0xCE,0x01,0x06,0x10,0x00,0x06,\r\n0x31,0x20,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,\r\n// ''\r\n0xCF,0x01,0x06,0x10,0x00,0x06,\r\n0xCF,0x30,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,\r\n// ''\r\n0xD0,0x04,0x0D,0x0D,0x00,0x0E,\r\n0x3F,0x81,0xFF,0x0C,0x1C,0x60,0x73,0x01,0xFF,0x0F,0xF8,0x66,0x03,0x30,0x19,0x81,0xCC,0x1C,0x7F,0xC3,0xF8,0x00,\r\n// ''\r\n0xD1,0x01,0x0A,0x10,0x02,0x0E,\r\n0x19,0x09,0x80,0x03,0x83,0xE0,0xFC,0x3F,0x0F,0x63,0xD8,0xF3,0x3C,0x6F,0x1B,0xC3,0xF0,0xFC,0x1F,0x07,\r\n// ''\r\n0xD2,0x01,0x0C,0x10,0x01,0x0E,\r\n0x06,0x00,0x30,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,\r\n// ''\r\n0xD3,0x01,0x0C,0x10,0x01,0x0E,\r\n0x03,0x00,0x60,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,\r\n// ''\r\n0xD4,0x01,0x0C,0x10,0x01,0x0E,\r\n0x06,0x00,0x90,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,\r\n// ''\r\n0xD5,0x01,0x0C,0x10,0x01,0x0E,\r\n0x0C,0x81,0x30,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,\r\n// ''\r\n0xD6,0x01,0x0C,0x10,0x01,0x0E,\r\n0x19,0x81,0x98,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,\r\n// ''\r\n0xD7,0x06,0x0A,0x0A,0x02,0x0F,\r\n0x40,0xB8,0x77,0x38,0xFC,0x1E,0x07,0x83,0xF1,0xCE,0xE1,0xD0,0x20,\r\n// ''\r\n0xD8,0x03,0x0E,0x0F,0x00,0x0E,\r\n0x00,0x00,0x3E,0x21,0xFD,0x0E,0x1C,0x70,0x71,0x83,0x66,0x19,0x98,0xC6,0x66,0x19,0xB0,0x63,0x83,0x8E,0x1C,0x2F,0xE1,0x1F,0x00,0x00,0x00,\r\n// ''\r\n0xD9,0x01,0x0A,0x10,0x02,0x0E,\r\n0x18,0x03,0x00,0x03,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xD8,0x67,0xF8,0x78,\r\n// ''\r\n0xDA,0x01,0x0A,0x10,0x02,0x0E,\r\n0x0C,0x06,0x00,0x03,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xD8,0x67,0xF8,0x78,\r\n// ''\r\n0xDB,0x01,0x0A,0x10,0x02,0x0E,\r\n0x0C,0x04,0x80,0x03,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xD8,0x67,0xF8,0x78,\r\n// ''\r\n0xDC,0x01,0x0A,0x10,0x02,0x0E,\r\n0x33,0x0C,0xC0,0x03,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xD8,0x67,0xF8,0x78,\r\n// ''\r\n0xDD,0x01,0x0C,0x10,0x00,0x0C,\r\n0x06,0x00,0xC0,0x00,0x0E,0x07,0x60,0x63,0x0C,0x19,0x81,0x98,0x0F,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,\r\n// ''\r\n0xDE,0x04,0x08,0x0D,0x02,0x0B,\r\n0xC0,0xC0,0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,\r\n// ''\r\n0xDF,0x03,0x09,0x0E,0x02,0x0B,\r\n0x3C,0x3F,0x39,0xD8,0x6C,0x66,0x63,0x31,0x8C,0xC3,0x60,0xF0,0x7A,0x7D,0xF6,0x70,\r\n// ''\r\n0xE0,0x03,0x08,0x0E,0x01,0x0A,\r\n0x30,0x18,0x0C,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,\r\n// ''\r\n0xE1,0x03,0x08,0x0E,0x01,0x0A,\r\n0x06,0x0C,0x18,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,\r\n// ''\r\n0xE2,0x03,0x08,0x0E,0x01,0x0A,\r\n0x18,0x3C,0x66,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,\r\n// ''\r\n0xE3,0x03,0x08,0x0E,0x01,0x0A,\r\n0x32,0x4C,0x00,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,\r\n// ''\r\n0xE4,0x03,0x08,0x0E,0x01,0x0A,\r\n0x66,0x66,0x00,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,\r\n// ''\r\n0xE5,0x01,0x08,0x10,0x01,0x0A,\r\n0x1C,0x22,0x22,0x22,0x1C,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,\r\n// ''\r\n0xE6,0x07,0x0F,0x0A,0x01,0x11,\r\n0x3C,0x78,0xFD,0xF9,0x1E,0x38,0x18,0x33,0xFF,0xFF,0xFF,0xF0,0xC0,0x63,0xC1,0xFD,0xFE,0xF0,0xF8,\r\n// ''\r\n0xE7,0x07,0x08,0x0D,0x01,0x09,\r\n0x1E,0x7F,0x61,0xC0,0xC0,0xC0,0xC0,0x61,0x7F,0x1E,0x04,0x06,0x1E,\r\n// ''\r\n0xE8,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x30,0x06,0x00,0xC0,0x00,0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,\r\n// ''\r\n0xE9,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x06,0x03,0x01,0x80,0x00,0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,\r\n// ''\r\n0xEA,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x0C,0x07,0x83,0x30,0x00,0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,\r\n// ''\r\n0xEB,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x33,0x0C,0xC0,0x00,0x00,0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,\r\n// ''\r\n0xEC,0x03,0x04,0x0E,0x00,0x05,\r\n0xC6,0x30,0x33,0x33,0x33,0x33,0x33,\r\n// ''\r\n0xED,0x03,0x04,0x0E,0x01,0x05,\r\n0x36,0xC0,0x66,0x66,0x66,0x66,0x66,\r\n// ''\r\n0xEE,0x03,0x06,0x0E,0x00,0x05,\r\n0x31,0xEC,0xC0,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC0,\r\n// ''\r\n0xEF,0x03,0x06,0x0E,0x00,0x05,\r\n0xCF,0x30,0x00,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC0,\r\n// ''\r\n0xF0,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x10,0x07,0xC7,0xC0,0x18,0x1F,0x1F,0xE6,0x1F,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,\r\n// ''\r\n0xF1,0x03,0x08,0x0E,0x02,0x0B,\r\n0x32,0x4C,0x00,0x00,0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,\r\n// ''\r\n0xF2,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x30,0x06,0x00,0xC0,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,\r\n// ''\r\n0xF3,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x06,0x03,0x01,0x80,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,\r\n// ''\r\n0xF4,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x0C,0x07,0x83,0x30,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,\r\n// ''\r\n0xF5,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x19,0x09,0x80,0x00,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,\r\n// ''\r\n0xF6,0x03,0x0A,0x0E,0x01,0x0B,\r\n0x33,0x0C,0xC0,0x00,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,\r\n// ''\r\n0xF7,0x07,0x0C,0x08,0x02,0x0F,\r\n0x06,0x00,0x60,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x06,0x00,0x60,\r\n// ''\r\n0xF8,0x06,0x0C,0x0C,0x00,0x0B,\r\n0x00,0x00,0xF2,0x1F,0xC3,0x0C,0x61,0xE6,0x26,0x64,0x67,0x86,0x30,0xC3,0xFC,0x4F,0x00,0x00,\r\n// ''\r\n0xF9,0x03,0x08,0x0E,0x02,0x0B,\r\n0x60,0x30,0x18,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,\r\n// ''\r\n0xFA,0x03,0x08,0x0E,0x02,0x0B,\r\n0x0C,0x18,0x30,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,\r\n// ''\r\n0xFB,0x03,0x08,0x0E,0x02,0x0B,\r\n0x18,0x3C,0x66,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,\r\n// ''\r\n0xFC,0x03,0x08,0x0E,0x02,0x0B,\r\n0x66,0x66,0x00,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,\r\n// ''\r\n0xFD,0x03,0x0C,0x12,0x00,0x0B,\r\n0x03,0x00,0x60,0x0C,0x00,0x00,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80,\r\n// ''\r\n0xFE,0x03,0x09,0x12,0x02,0x0B,\r\n0xC0,0x60,0x30,0x18,0x0D,0xE7,0xFB,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x7F,0xF6,0xF3,0x01,0x80,0xC0,0x60,0x00,\r\n// ''\r\n0xFF,0x03,0x0C,0x12,0x00,0x0B,\r\n0x1B,0x01,0xB0,0x00,0x00,0x00,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80,\r\n\r\n// Terminator\r\n0xFF\r\n};\r\n"
  },
  {
    "path": "components/epaper/minya24.c",
    "content": "// This comes with no warranty, implied or otherwise\r\n\r\n// This data structure was designed to support Proportional fonts\r\n// on Arduinos. It can however handle any ttf font that has been converted\r\n// using the conversion program. These could be fixed width or proportional \r\n// fonts. Individual characters do not have to be multiples of 8 bits wide. \r\n// Any width is fine and does not need to be fixed.\r\n\r\n// The data bits are packed to minimize data requirements, but the tradeoff\r\n// is that a header is required per character.\r\n\r\n// minya24.c\r\n// Point Size   : 24\r\n// Memory usage : 2807 bytes\r\n// # characters : 95\r\n\r\n// Header Format (to make Arduino UTFT Compatible):\r\n// ------------------------------------------------\r\n// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)\r\n// Character Height\r\n// First Character (Reserved. 0x00)\r\n// Number Of Characters (Reserved. 0x00)\r\n\r\nunsigned char tft_minya24[] = \r\n{\r\n0x00, 0x15, 0x00, 0x00,\r\n\r\n// Individual Character Format:\r\n// ----------------------------\r\n// Character Code\r\n// Adjusted Y Offset\r\n// Width\r\n// Height\r\n// xOffset\r\n// xDelta (the distance to move the cursor. Effective width of the character.)\r\n// Data[n]\r\n\r\n// NOTE: You can remove any of these characters if they are not needed in\r\n// your application. The first character number in each Glyph indicates\r\n// the ASCII character code. Therefore, these do not have to be sequential.\r\n// Just remove all the content for a particular character to save space.\r\n\r\n// ' '\r\n0x20,0x13,0x00,0x00,0x00,0x07,\r\n\r\n// '!'\r\n0x21,0x02,0x05,0x12,0x00,0x05,\r\n0x11,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x42,0x01,0xCE,0x73,0x80,\r\n// '\"'\r\n0x22,0x01,0x06,0x08,0x00,0x06,\r\n0x01,0xA6,0xDB,0x6D,0xB6,0xC0,\r\n// '#'\r\n0x23,0x04,0x0C,0x0E,0x00,0x0B,\r\n0x04,0x80,0x6C,0x0C,0x80,0xD8,0x7F,0xE7,0xFE,0x1B,0x01,0xB0,0x7F,0xE7,0xFC,0x12,0x03,0x20,0x32,0x00,0x00,\r\n// '$'\r\n0x24,0x02,0x0A,0x11,0x00,0x0B,\r\n0x04,0x01,0x61,0xF8,0xFE,0x65,0x19,0x06,0x40,0xF0,0x1F,0x01,0xE0,0x4C,0x93,0x7C,0xCF,0xE0,0x60,0x10,0x04,0x00,\r\n// '%'\r\n0x25,0x01,0x0D,0x14,0x01,0x0F,\r\n0x00,0x01,0xC1,0x1F,0x19,0x8C,0xCC,0x6C,0x63,0x61,0x36,0x0F,0xB0,0x1B,0x00,0x18,0x01,0x80,0x0C,0x00,0xCE,0x06,0xF8,0x6C,0x66,0x63,0x33,0x13,0x0F,0x98,0x38,0x00,0x00,\r\n// '&'\r\n0x26,0x02,0x0E,0x11,0x00,0x0D,\r\n0x0E,0x00,0x7C,0x01,0xB0,0x06,0xC0,0x1E,0x00,0x38,0x00,0xC3,0x07,0x8C,0x37,0x60,0xCD,0x86,0x1E,0x18,0x70,0x41,0xE1,0x07,0xC6,0x33,0x9F,0x86,0x38,0x00,\r\n// '''\r\n0x27,0x02,0x03,0x08,0x00,0x03,\r\n0x6D,0xB6,0xD8,\r\n// '('\r\n0x28,0x01,0x05,0x14,0x02,0x07,\r\n0x00,0x8E,0x66,0x33,0x18,0xC6,0x31,0x8C,0x61,0x0C,0x63,0x8C,0x00,\r\n// ')'\r\n0x29,0x01,0x06,0x15,0x00,0x07,\r\n0x01,0x86,0x0C,0x18,0x61,0x82,0x08,0x30,0xC2,0x08,0x61,0x86,0x30,0xC6,0x10,0x00,\r\n// '*'\r\n0x2A,0x04,0x0A,0x0D,0x01,0x0B,\r\n0x08,0x03,0x04,0xC1,0xF6,0x7F,0x07,0x81,0xC0,0xF8,0x3F,0x1B,0xCC,0xD8,0x30,0x0C,0x00,\r\n// '+'\r\n0x2B,0x06,0x0A,0x0A,0x01,0x0B,\r\n0x00,0x03,0x00,0xC0,0x30,0x7F,0xBF,0xE0,0xC0,0x30,0x0C,0x00,0x00,\r\n// ','\r\n0x2C,0x10,0x05,0x07,0x00,0x05,\r\n0x33,0x9C,0x63,0x20,0x00,\r\n// '-'\r\n0x2D,0x09,0x07,0x02,0x00,0x07,\r\n0x7D,0xF8,\r\n// '.'\r\n0x2E,0x10,0x04,0x04,0x01,0x05,\r\n0x6E,0xE6,\r\n// '/'\r\n0x2F,0x01,0x0C,0x13,0x00,0x0B,\r\n0x00,0x00,0x06,0x00,0x60,0x0C,0x00,0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x60,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x30,0x06,0x00,0x40,0x00,\r\n// '0'\r\n0x30,0x08,0x0B,0x0B,0x00,0x0B,\r\n0x0E,0x03,0xE0,0xC6,0x30,0x66,0x0C,0xC0,0x98,0x33,0x06,0x61,0xC7,0xF0,0x7C,0x00,\r\n// '1'\r\n0x31,0x08,0x0A,0x0D,0x00,0x09,\r\n0x04,0x1F,0x03,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x07,0xF9,0xFE,0x00,0x00,\r\n// '2'\r\n0x32,0x06,0x0A,0x0E,0x00,0x0A,\r\n0x0E,0x07,0xC3,0x30,0xCC,0x03,0x01,0x80,0x60,0x30,0x18,0x0C,0x03,0x01,0xF8,0x7F,0xC0,0x20,\r\n// '3'\r\n0x33,0x08,0x09,0x10,0x00,0x08,\r\n0x78,0x3F,0x81,0x81,0x81,0xC0,0xC0,0xE0,0x78,0x06,0x01,0x01,0x80,0xC0,0xE1,0xE0,0xC0,0x00,\r\n// '4'\r\n0x34,0x03,0x0B,0x13,0x00,0x0A,\r\n0x00,0x00,0xC0,0x18,0x03,0x00,0x60,0x08,0x03,0x00,0x60,0x0D,0x83,0x20,0x64,0x18,0x83,0x10,0xC6,0x1F,0xF3,0xFE,0x03,0x00,0x60,0x0C,0x00,\r\n// '5'\r\n0x35,0x09,0x0A,0x0E,0x00,0x0A,\r\n0x3F,0x8F,0xE3,0x00,0x80,0x60,0x1F,0x87,0xF0,0x06,0x01,0x80,0x60,0x19,0x86,0x7F,0x07,0x80,\r\n// '6'\r\n0x36,0x03,0x0A,0x12,0x00,0x0A,\r\n0x00,0x01,0x80,0xE0,0x30,0x18,0x06,0x03,0x00,0xC0,0x60,0x1B,0x87,0xF1,0x86,0x61,0x90,0x66,0x19,0x86,0x3F,0x07,0x80,\r\n// '7'\r\n0x37,0x09,0x0A,0x0E,0x00,0x0A,\r\n0x7F,0x9F,0xF0,0x18,0x0C,0x06,0x01,0x80,0xC0,0x30,0x18,0x06,0x01,0x80,0x40,0x10,0x0C,0x00,\r\n// '8'\r\n0x38,0x03,0x0B,0x11,0x00,0x0B,\r\n0x0F,0x07,0xF0,0xC3,0x30,0x66,0x0C,0x63,0x87,0xE0,0xF8,0x39,0xCE,0x19,0x81,0x30,0x34,0x06,0xC1,0x98,0x71,0xFC,0x1F,0x00,\r\n// '9'\r\n0x39,0x07,0x0A,0x11,0x00,0x0A,\r\n0x1E,0x0F,0xC6,0x19,0x86,0x41,0x98,0x66,0x18,0xFE,0x1D,0x80,0x40,0x30,0x0C,0x06,0x03,0x01,0xC0,0x20,0x00,0x00,\r\n// ':'\r\n0x3A,0x0A,0x05,0x0A,0x00,0x05,\r\n0x33,0x9C,0x60,0x00,0xCE,0x71,0x80,\r\n// ';'\r\n0x3B,0x09,0x05,0x0D,0x00,0x06,\r\n0x33,0xDE,0x60,0x00,0x0E,0x73,0x8C,0xC0,0x00,\r\n// '<'\r\n0x3C,0x06,0x0A,0x0C,0x00,0x09,\r\n0x00,0x00,0xE0,0x70,0x38,0x1C,0x1C,0x03,0x00,0x70,0x0E,0x01,0xC0,0x10,0x00,\r\n// '='\r\n0x3D,0x09,0x08,0x06,0x01,0x0A,\r\n0xFF,0xFE,0x00,0x00,0x7F,0xFF,\r\n// '>'\r\n0x3E,0x06,0x0A,0x0C,0x00,0x09,\r\n0x00,0x18,0x03,0x80,0x70,0x0E,0x00,0xE0,0x30,0x38,0x1C,0x0E,0x02,0x00,0x00,\r\n// '?'\r\n0x3F,0x02,0x09,0x12,0x00,0x09,\r\n0x1E,0x1F,0x98,0x6C,0x30,0x18,0x18,0x38,0x30,0x30,0x18,0x0C,0x02,0x01,0x00,0x00,0x60,0x78,0x3C,0x0C,0x00,\r\n// '@'\r\n0x40,0x02,0x11,0x11,0x00,0x11,\r\n0x01,0xF0,0x03,0xFE,0x03,0x03,0x83,0x00,0xC3,0x04,0x31,0x1F,0x19,0x9F,0x0C,0xCC,0x86,0x4C,0x43,0x24,0x21,0x12,0x39,0x89,0xF7,0x84,0x71,0x83,0x00,0x00,0xC1,0x80,0x3F,0xC0,0x0F,0x80,0x00,\r\n// 'A'\r\n0x41,0x02,0x12,0x13,0x00,0x10,\r\n0x00,0x00,0x01,0xF0,0x00,0x7E,0x00,0x03,0x80,0x01,0xA0,0x00,0x6C,0x00,0x1B,0x00,0x0C,0x40,0x03,0x18,0x01,0x86,0x00,0x61,0x80,0x1F,0xE0,0x0F,0xFC,0x03,0x03,0x01,0x80,0xC0,0x60,0x10,0x18,0x1F,0x9F,0xC7,0xEF,0xF8,0x00,\r\n// 'B'\r\n0x42,0x02,0x0E,0x13,0x00,0x0E,\r\n0x7F,0x81,0xFF,0x81,0x86,0x06,0x18,0x18,0xC0,0x66,0x01,0xFC,0x07,0xFC,0x1C,0x30,0x60,0x61,0x81,0x86,0x06,0x18,0x18,0x60,0x61,0x81,0x06,0x0C,0x18,0xE0,0xFE,0x03,0xE0,0x00,\r\n// 'C'\r\n0x43,0x02,0x0F,0x12,0x00,0x0F,\r\n0x03,0xF0,0x1F,0xE0,0x70,0xC1,0x80,0x83,0x00,0x04,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x06,0x00,0x0E,0x01,0x0E,0x0E,0x0F,0xF8,0x07,0xE0,\r\n// 'D'\r\n0x44,0x02,0x0F,0x13,0x00,0x0F,\r\n0x3F,0xC0,0x7F,0xE0,0x60,0xE0,0xC0,0xC1,0x80,0xC3,0x01,0x86,0x03,0x0C,0x02,0x18,0x04,0x30,0x08,0x60,0x30,0xC0,0x61,0x80,0x83,0x03,0x06,0x0C,0x0C,0x38,0x18,0xE0,0xFF,0x81,0xF8,0x00,\r\n// 'E'\r\n0x45,0x02,0x0D,0x13,0x00,0x0D,\r\n0x3F,0xF1,0xFF,0x86,0x0C,0x30,0x61,0x80,0x0C,0x40,0x62,0x03,0xF0,0x1F,0x80,0xC4,0x06,0x20,0x30,0x01,0x80,0x0C,0x00,0x60,0xC3,0x06,0x7F,0xF3,0xFF,0x80,0x00,\r\n// 'F'\r\n0x46,0x01,0x0E,0x13,0x00,0x0E,\r\n0x00,0x01,0xFF,0xE7,0xFF,0x86,0x06,0x18,0x18,0x63,0x01,0x8C,0x03,0xF0,0x0F,0xC0,0x63,0x01,0x8C,0x06,0x30,0x18,0x00,0x60,0x01,0x80,0x06,0x00,0x3F,0x81,0xFE,0x00,0x00,0x00,\r\n// 'G'\r\n0x47,0x01,0x11,0x14,0x00,0x11,\r\n0x00,0x00,0x03,0xC8,0x03,0xFC,0x03,0x0E,0x03,0x03,0x01,0x00,0x01,0x80,0x00,0xC0,0x00,0x60,0x03,0x30,0x3F,0xD8,0x1F,0x0C,0x01,0x86,0x00,0xC3,0x80,0x60,0xC0,0x30,0x70,0x38,0x1C,0x3C,0x07,0xF6,0x01,0xF3,0x80,0x01,0xE0,\r\n// 'H'\r\n0x48,0x01,0x10,0x13,0x00,0x10,\r\n0x00,0x00,0x7C,0x0F,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x08,0x0C,0x08,0x0F,0xF8,0x0F,0xF8,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x1A,0x7C,0x1F,0x7C,0x10,\r\n// 'I'\r\n0x49,0x02,0x08,0x13,0x00,0x08,\r\n0x7E,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,\r\n// 'J'\r\n0x4A,0x01,0x0C,0x14,0x00,0x0B,\r\n0x00,0x00,0x7E,0x07,0xE0,0x18,0x01,0x80,0x18,0x01,0x80,0x18,0x00,0x80,0x08,0x00,0x80,0x18,0x61,0x84,0x18,0x41,0x8C,0x18,0xC3,0x06,0x70,0x7E,0x01,0x80,\r\n// 'K'\r\n0x4B,0x02,0x11,0x13,0x00,0x10,\r\n0x7E,0x7E,0x3F,0x3E,0x06,0x06,0x03,0x06,0x01,0x86,0x00,0xC6,0x00,0x66,0x00,0x37,0x00,0x1F,0x80,0x0E,0x60,0x06,0x10,0x03,0x0C,0x01,0x06,0x00,0x81,0x00,0x60,0x80,0x30,0x66,0x7E,0x1B,0x3F,0x0F,0x80,0x01,0x80,\r\n// 'L'\r\n0x4C,0x02,0x0D,0x11,0x00,0x0D,\r\n0x7E,0x03,0xF0,0x06,0x00,0x30,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x00,0xC0,0x06,0x00,0x30,0x01,0x81,0x0C,0x08,0x60,0x4F,0xFF,0x7F,0xF8,\r\n// 'M'\r\n0x4D,0x02,0x14,0x12,0x00,0x13,\r\n0x7C,0x07,0x87,0xC0,0x7C,0x0C,0x06,0x00,0xE0,0xE0,0x0E,0x0E,0x00,0xE0,0xE0,0x1B,0x1E,0x01,0xB1,0x60,0x0B,0x16,0x00,0x9B,0x60,0x09,0xA6,0x00,0x9E,0x60,0x08,0xE6,0x00,0x8C,0x60,0x08,0xC6,0x03,0x8C,0x7E,0x78,0x47,0xE0,0x00,0x00,\r\n// 'N'\r\n0x4E,0x01,0x12,0x13,0x00,0x12,\r\n0x00,0x00,0x1F,0x03,0xF3,0xC0,0x7C,0x38,0x10,0x0E,0x04,0x03,0xC1,0x00,0xB0,0x40,0x26,0x10,0x09,0x84,0x02,0x31,0x00,0x8C,0x40,0x21,0x90,0x08,0x74,0x06,0x0F,0x01,0x81,0xC0,0x60,0x70,0x78,0x0C,0x3E,0x03,0x00,0x00,0x40,\r\n// 'O'\r\n0x4F,0x02,0x11,0x12,0x00,0x11,\r\n0x03,0xE0,0x07,0xFC,0x07,0x07,0x06,0x01,0x82,0x00,0x63,0x00,0x11,0x80,0x0C,0x80,0x06,0x40,0x03,0x20,0x01,0x98,0x00,0xCC,0x00,0x66,0x00,0x31,0x80,0x30,0xE0,0x18,0x38,0x18,0x0F,0xF8,0x01,0xF0,0x00,\r\n// 'P'\r\n0x50,0x02,0x0C,0x12,0x00,0x0C,\r\n0x7F,0x07,0xFC,0x10,0x61,0x03,0x10,0x31,0x03,0x10,0x31,0x06,0x10,0xE1,0xFC,0x1E,0x01,0x00,0x18,0x01,0x80,0x18,0x01,0x80,0x7E,0x07,0xF0,\r\n// 'Q'\r\n0x51,0x02,0x13,0x15,0x00,0x11,\r\n0x07,0xE0,0x01,0xFE,0x00,0x60,0x70,0x18,0x06,0x06,0x00,0x60,0xC0,0x0C,0x18,0x00,0xC2,0x00,0x18,0x40,0x03,0x08,0x0C,0x61,0x83,0xCC,0x30,0xCD,0x83,0x09,0xE0,0x60,0x3C,0x06,0x07,0x00,0x7F,0xE3,0x07,0xEC,0x40,0x01,0x98,0x00,0x33,0x00,0x03,0xC0,0x00,0x30,\r\n// 'R'\r\n0x52,0x02,0x0F,0x13,0x00,0x0F,\r\n0x7F,0x80,0xFF,0xE0,0x60,0xE0,0xC0,0x61,0x80,0xC3,0x01,0x86,0x07,0x0C,0x1C,0x1F,0xF0,0x3F,0x80,0x66,0x00,0xC4,0x01,0x8C,0x63,0x18,0xC6,0x11,0x8C,0x33,0x7E,0x7C,0xFC,0x70,0x00,0x00,\r\n// 'S'\r\n0x53,0x01,0x0D,0x13,0x00,0x0D,\r\n0x00,0x60,0x7B,0x07,0xF8,0x71,0xC3,0x06,0x18,0x00,0xC0,0x03,0x80,0x0E,0x00,0x1C,0x00,0x78,0x00,0xC0,0x03,0x30,0x19,0x80,0xCC,0x06,0x30,0x70,0xFF,0x03,0xE0,\r\n// 'T'\r\n0x54,0x01,0x0F,0x12,0x00,0x0F,\r\n0x00,0x00,0xFF,0xF9,0xFF,0xF3,0x18,0x66,0x30,0xCC,0x61,0x90,0xC3,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x0F,0xE0,0x1F,0xC0,\r\n// 'U'\r\n0x55,0x02,0x10,0x11,0x00,0x0F,\r\n0x7C,0x7E,0x7C,0x7E,0x30,0x08,0x30,0x08,0x30,0x08,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x10,0x08,0x18,0x18,0x18,0x18,0x0C,0x30,0x0F,0xF0,0x03,0xC0,\r\n// 'V'\r\n0x56,0x01,0x10,0x12,0x00,0x10,\r\n0x00,0x7E,0xFE,0x7E,0x7E,0x18,0x18,0x30,0x18,0x30,0x18,0x20,0x08,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x40,0x0C,0xC0,0x04,0xC0,0x04,0xC0,0x06,0x80,0x07,0x80,0x07,0x80,0x03,0x00,0x03,0x00,\r\n// 'W'\r\n0x57,0x01,0x14,0x13,0x00,0x14,\r\n0x00,0x00,0x0F,0xC4,0xFF,0xF0,0x4F,0xE3,0x06,0x10,0x30,0xE3,0x01,0x8E,0x30,0x18,0xE3,0x01,0x8E,0x30,0x19,0xA3,0x01,0x9A,0x20,0x09,0xA6,0x00,0xD2,0x60,0x0D,0x36,0x00,0xF3,0x40,0x0F,0x34,0x00,0x63,0xC0,0x06,0x1C,0x00,0x61,0x80,0x00,0x18,0x00,\r\n// 'X'\r\n0x58,0x01,0x10,0x13,0x00,0x10,\r\n0x00,0x00,0x7F,0x7F,0x7E,0x7E,0x0C,0x30,0x06,0x20,0x06,0x60,0x03,0xC0,0x01,0x80,0x01,0x80,0x03,0x80,0x02,0xC0,0x06,0x40,0x04,0x60,0x0C,0x60,0x18,0x30,0x18,0x30,0x7C,0x30,0xFC,0xFE,0x00,0xFF,\r\n// 'Y'\r\n0x59,0x01,0x11,0x13,0x00,0x10,\r\n0x00,0x00,0x7F,0x3F,0xBF,0x07,0x03,0x03,0x00,0xC1,0x00,0x31,0x80,0x18,0x80,0x06,0xC0,0x01,0xC0,0x00,0xE0,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x07,0x80,0x03,0xF8,0x00,0x7C,0x00,\r\n// 'Z'\r\n0x5A,0x02,0x0E,0x12,0x00,0x0D,\r\n0x7F,0xF9,0xFF,0xE6,0x03,0x18,0x18,0x60,0xC1,0x07,0x00,0x18,0x00,0xC0,0x06,0x00,0x18,0x00,0xC0,0x06,0x00,0x18,0x30,0xC0,0xC3,0x03,0x1F,0xFE,0x7F,0xF8,0x00,0x60,\r\n// '['\r\n0x5B,0x01,0x08,0x14,0x01,0x08,\r\n0x00,0x7C,0x7C,0x40,0x40,0x40,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x7E,0x00,\r\n// '\\'\r\n0x5C,0x01,0x0A,0x13,0x00,0x0A,\r\n0x00,0x10,0x06,0x01,0x80,0x30,0x0C,0x01,0x80,0x60,0x0C,0x03,0x00,0x60,0x18,0x06,0x00,0xC0,0x30,0x06,0x01,0x80,0x60,0x08,\r\n// ']'\r\n0x5D,0x01,0x08,0x14,0x00,0x08,\r\n0x00,0x7C,0x7E,0x04,0x04,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x7C,0xFC,\r\n// '^'\r\n0x5E,0x03,0x0B,0x0B,0x00,0x0B,\r\n0x00,0x00,0x40,0x18,0x03,0x00,0xF0,0x32,0x0C,0x63,0x86,0x60,0xC0,0x0C,0x00,0x00,\r\n// '_'\r\n0x5F,0x15,0x11,0x02,0xFF,0x0F,\r\n0x7F,0xFF,0x3F,0xFF,0x80,\r\n// '`'\r\n0x60,0x00,0x06,0x07,0x00,0x06,\r\n0x01,0x87,0x0C,0x18,0x20,0x00,\r\n// 'a'\r\n0x61,0x06,0x0C,0x0D,0x00,0x0B,\r\n0x0E,0x03,0xF0,0x31,0x06,0x10,0x23,0x80,0xF8,0x3D,0x87,0x10,0x61,0x0C,0x18,0x63,0xA7,0xFE,0x1C,0xC0,\r\n// 'b'\r\n0x62,0x01,0x0C,0x14,0x00,0x0C,\r\n0x00,0x07,0xC0,0x3C,0x01,0x80,0x18,0x01,0x80,0x18,0x01,0x98,0x1F,0xC1,0xC6,0x18,0x21,0x83,0x10,0x31,0x03,0x18,0x31,0x83,0x18,0x6F,0xC6,0xF7,0xC0,0x30,\r\n// 'c'\r\n0x63,0x06,0x0B,0x0D,0x00,0x0B,\r\n0x06,0x03,0xF0,0xC7,0x31,0xE4,0x1C,0x80,0x30,0x06,0x00,0x60,0x0C,0x01,0xC3,0x1F,0xC0,0xF0,\r\n// 'd'\r\n0x64,0x01,0x0D,0x13,0x00,0x0D,\r\n0x00,0x00,0x1E,0x00,0xF0,0x01,0x80,0x0C,0x00,0x60,0x03,0x01,0x98,0x3E,0x81,0x9C,0x18,0x60,0xC3,0x04,0x08,0x60,0x41,0x02,0x0C,0x30,0x71,0x91,0xFF,0x87,0x1C,\r\n// 'e'\r\n0x65,0x07,0x0B,0x0C,0x00,0x0B,\r\n0x0F,0x03,0xF0,0xC3,0x30,0x66,0x1C,0xDE,0x1E,0x03,0x00,0x60,0x06,0x18,0x7E,0x07,0x80,\r\n// 'f'\r\n0x66,0x02,0x0A,0x12,0x00,0x08,\r\n0x07,0x07,0xE1,0xB8,0x4E,0x10,0x04,0x07,0xE1,0xF8,0x18,0x06,0x01,0x80,0x60,0x18,0x06,0x01,0x81,0xF8,0x7E,0x00,0x00,\r\n// 'g'\r\n0x67,0x05,0x0A,0x12,0x00,0x0A,\r\n0x00,0x00,0x20,0x18,0x7E,0x3F,0x18,0x64,0x09,0x02,0x61,0x9F,0xC1,0xE0,0x0C,0x01,0x84,0x67,0x19,0x8C,0x7E,0x0F,0x00,\r\n// 'h'\r\n0x68,0x02,0x0E,0x12,0x00,0x0D,\r\n0x78,0x01,0xE0,0x01,0x80,0x06,0x00,0x19,0xC0,0x2F,0x80,0xE6,0x07,0x08,0x18,0x20,0x60,0x81,0x82,0x06,0x08,0x18,0x20,0x60,0x81,0x82,0x1F,0x9E,0x7E,0x78,0x00,0x00,\r\n// 'i'\r\n0x69,0x02,0x08,0x11,0x00,0x08,\r\n0x30,0x78,0x78,0x30,0x00,0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7F,\r\n// 'j'\r\n0x6A,0x02,0x09,0x15,0xFE,0x07,\r\n0x06,0x07,0x03,0x81,0xC0,0x00,0xF8,0x7C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x99,0x8F,0xC3,0xC0,\r\n// 'k'\r\n0x6B,0x02,0x0D,0x12,0x00,0x0D,\r\n0x78,0x03,0xC0,0x06,0x00,0x37,0xC1,0xBC,0x0C,0xC0,0x6C,0x03,0xC0,0x1C,0x00,0xC0,0x07,0x00,0x3E,0x01,0xB8,0x08,0x61,0xC1,0xCF,0x07,0x00,0x10,0x00,0x00,\r\n// 'l'\r\n0x6C,0x02,0x08,0x12,0x00,0x08,\r\n0x78,0x78,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,0x00,\r\n// 'm'\r\n0x6D,0x08,0x14,0x0D,0x00,0x14,\r\n0x40,0xC3,0x0F,0xBE,0xF8,0x1E,0x78,0xC1,0xC7,0x0C,0x18,0x20,0xC1,0x82,0x0C,0x10,0x20,0xC1,0x82,0x08,0x18,0x60,0x81,0x84,0x18,0x7E,0x71,0xE7,0xE7,0x9E,0x00,0x00,0x00,\r\n// 'n'\r\n0x6E,0x06,0x0E,0x0E,0x00,0x0D,\r\n0x79,0xC1,0xEF,0x81,0xE6,0x07,0x08,0x18,0x30,0x60,0xC1,0x82,0x06,0x08,0x18,0x20,0x60,0x81,0x82,0x1F,0x1E,0x7E,0x78,0x00,0x00,\r\n// 'o'\r\n0x6F,0x08,0x0B,0x0C,0x00,0x0C,\r\n0x0F,0x03,0xF8,0xC3,0x30,0x36,0x06,0x80,0xD0,0x1B,0x03,0x60,0x66,0x18,0xFE,0x07,0x80,\r\n// 'p'\r\n0x70,0x07,0x0B,0x10,0x00,0x0B,\r\n0x07,0x1F,0xF1,0xE3,0x18,0x23,0x06,0x60,0xCC,0x19,0x82,0x30,0xC6,0x18,0xFE,0x1B,0x83,0x00,0x60,0x1C,0x07,0x80,\r\n// 'q'\r\n0x71,0x06,0x0D,0x11,0x00,0x0B,\r\n0x0C,0x01,0xF7,0x0C,0xF8,0xC3,0x04,0x18,0x20,0x41,0x02,0x08,0x10,0x60,0x83,0x04,0x0C,0x60,0x7F,0x01,0xE8,0x00,0xC0,0x06,0xC0,0x1E,0x00,0xE0,\r\n// 'r'\r\n0x72,0x08,0x0A,0x0D,0x00,0x09,\r\n0x77,0x3F,0xE3,0xB8,0xCE,0x33,0x0C,0x03,0x00,0xC0,0x30,0x04,0x07,0xC1,0xF0,0x00,0x00,\r\n// 's'\r\n0x73,0x05,0x0A,0x0E,0x00,0x0A,\r\n0x03,0x00,0xC1,0xF0,0xFC,0x63,0x18,0x47,0x00,0xF8,0x07,0x80,0x64,0x19,0x86,0x7F,0x07,0x80,\r\n// 't'\r\n0x74,0x02,0x09,0x13,0x00,0x09,\r\n0x30,0x18,0x0C,0x06,0x02,0x07,0xE3,0xF8,0x40,0x20,0x10,0x08,0x04,0x02,0x11,0x18,0x84,0x62,0x33,0x0F,0x83,0x00,\r\n// 'u'\r\n0x75,0x06,0x0E,0x0E,0x00,0x0D,\r\n0x00,0x03,0xE7,0xC7,0x9F,0x0C,0x30,0x30,0xC0,0xC3,0x03,0x0C,0x0C,0x30,0x30,0xC0,0xC3,0x03,0x0C,0x0E,0x7C,0x1F,0xF8,0x3C,0x00,\r\n// 'v'\r\n0x76,0x07,0x0E,0x0D,0x00,0x0D,\r\n0x01,0xFB,0xF3,0xEF,0xC6,0x06,0x18,0x18,0x60,0x31,0x00,0xCC,0x01,0x30,0x06,0x80,0x0A,0x00,0x38,0x00,0xE0,0x01,0x00,\r\n// 'w'\r\n0x77,0x08,0x11,0x0D,0x00,0x11,\r\n0x04,0x1F,0xFF,0x6F,0xBE,0x31,0x83,0x1C,0xC1,0x9E,0x40,0x4D,0x20,0x34,0xB0,0x1A,0x78,0x05,0x3C,0x03,0x8E,0x01,0x86,0x00,0x43,0x00,0x00,0x00,\r\n// 'x'\r\n0x78,0x08,0x0D,0x0D,0x00,0x0D,\r\n0x0C,0xFB,0xE7,0xDE,0x18,0x31,0x80,0xD8,0x03,0x80,0x18,0x01,0xE0,0x19,0x81,0x8C,0x0E,0x7D,0xF3,0xE4,0x00,0x00,\r\n// 'y'\r\n0x79,0x06,0x0F,0x11,0x00,0x0D,\r\n0x7C,0x01,0xF8,0x00,0xC3,0xF0,0xC7,0xE1,0x82,0x01,0x0C,0x03,0x18,0x06,0x20,0x06,0xC0,0x0D,0x00,0x0E,0x00,0x18,0x00,0x30,0x06,0xC0,0x1F,0x00,0x3E,0x00,0x30,0x00,\r\n// 'z'\r\n0x7A,0x08,0x0B,0x0B,0x00,0x0B,\r\n0x7F,0xCF,0xF9,0x86,0x31,0x86,0x60,0x1C,0x07,0x00,0xC6,0x30,0xCF,0xF9,0xFF,0x00,\r\n// '{'\r\n0x7B,0x02,0x09,0x12,0x00,0x08,\r\n0x07,0x07,0x83,0x01,0x01,0x80,0xC0,0x60,0xE0,0x70,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x1F,0x03,0x80,\r\n// '|'\r\n0x7C,0x02,0x03,0x12,0x01,0x05,\r\n0x49,0x24,0x92,0x6D,0xB6,0xDB,0x6C,\r\n// '}'\r\n0x7D,0x02,0x07,0x11,0x00,0x07,\r\n0x30,0xF0,0x20,0x41,0x83,0x02,0x06,0x0E,0x18,0x60,0xC0,0x81,0x83,0x3C,0x78,\r\n// '~'\r\n0x7E,0x09,0x0D,0x04,0x00,0x0D,\r\n0x18,0x03,0xF1,0x98,0xFC,0x83,0xC0,\r\n\r\n// Terminator\r\n0xFF\r\n};"
  },
  {
    "path": "components/epaper/tooney32.c",
    "content": "// This comes with no warranty, implied or otherwise\r\n\r\n// This data structure was designed to support Proportional fonts\r\n// on Arduinos. It can however handle any ttf font that has been converted\r\n// using the conversion program. These could be fixed width or proportional \r\n// fonts. Individual characters do not have to be multiples of 8 bits wide. \r\n// Any width is fine and does not need to be fixed.\r\n\r\n// The data bits are packed to minimize data requirements, but the tradeoff\r\n// is that a header is required per character.\r\n\r\n// tooney32.c\r\n// Point Size   : 32\r\n// Memory usage : 5470 bytes\r\n// # characters : 95\r\n\r\n// Header Format (to make Arduino UTFT Compatible):\r\n// ------------------------------------------------\r\n// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)\r\n// Character Height\r\n// First Character (Reserved. 0x00)\r\n// Number Of Characters (Reserved. 0x00)\r\n\r\nunsigned char tft_tooney32[] =\r\n{\r\n0x00, 0x20, 0x00, 0x00,\r\n\r\n// Individual Character Format:\r\n// ----------------------------\r\n// Character Code\r\n// Adjusted Y Offset\r\n// Width\r\n// Height\r\n// xOffset\r\n// xDelta (the distance to move the cursor. Effective width of the character.)\r\n// Data[n]\r\n\r\n// NOTE: You can remove any of these characters if they are not needed in\r\n// your application. The first character number in each Glyph indicates\r\n// the ASCII character code. Therefore, these do not have to be sequential.\r\n// Just remove all the content for a particular character to save space.\r\n\r\n// ' '\r\n0x20,0x1E,0x00,0x00,0x00,0x09,\r\n\r\n// '!'\r\n0x21,0x09,0x0B,0x16,0x00,0x0B,\r\n0x3F,0xC8,0x07,0x81,0x70,0x27,0x00,0xE0,0x1C,0x21,0x84,0x30,0x86,0x10,0xC2,0x18,0x43,0xF0,0x61,0x0C,0x13,0x02,0x60,0x4E,0x09,0xE2,0x1F,0x81,0xE0,0x00,0x00,\r\n// '\"'\r\n0x22,0x05,0x0E,0x0A,0xFF,0x0D,\r\n0x04,0x30,0x2D,0x61,0x8C,0x44,0x71,0x31,0x88,0xCE,0x42,0x72,0x18,0xC8,0x7B,0xC0,0xC6,0x00,\r\n// '#'\r\n0x23,0x07,0x18,0x16,0x00,0x18,\r\n0x00,0xFF,0xF8,0x01,0x83,0x08,0x01,0x82,0x08,0x01,0x82,0x08,0x0F,0x06,0x0F,0x10,0x00,0x01,0x30,0x00,0x01,0x30,0x00,0x00,0x20,0x00,0x02,0x7E,0x0C,0x1E,0x7E,0x0C,0x1E,0x60,0x00,0x02,0x60,0x00,0x00,0x40,0x00,0x04,0x40,0x00,0x04,0xC0,0x00,0x04,0xFC,0x10,0x78,0xFC,0x30,0x78,0x08,0x30,0x40,0x18,0x30,0x40,0x1F,0xFF,0x80,0x1F,0xFF,0x80,\r\n// '$'\r\n0x24,0x09,0x0F,0x14,0x00,0x0F,\r\n0x01,0x80,0x04,0xF8,0x18,0x08,0x20,0x10,0xC0,0x41,0x00,0x86,0x01,0x0C,0x12,0x18,0x38,0x30,0x60,0xA0,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x10,0x30,0x20,0x6E,0x40,0xFF,0x81,0x9E,0x00,0x18,0x00,\r\n// '%'\r\n0x25,0x07,0x17,0x16,0x00,0x17,\r\n0x0F,0x81,0xF8,0x20,0x84,0x10,0x80,0x98,0x42,0x00,0x21,0x0C,0x01,0x82,0x18,0x43,0x08,0x30,0x04,0x10,0x70,0x18,0x40,0xE0,0x21,0x00,0xF1,0x82,0x00,0xFF,0x0F,0xC0,0xFC,0x10,0x40,0x18,0x40,0x40,0x21,0x80,0x40,0x82,0x00,0x83,0x0C,0x21,0x04,0x18,0x02,0x18,0x78,0x04,0x21,0x30,0x10,0xC2,0x78,0xC3,0xF8,0x7F,0x07,0xE0,0x7C,0x00,\r\n// '&'\r\n0x26,0x08,0x17,0x17,0x00,0x17,\r\n0x01,0xF6,0x00,0x04,0x1A,0x00,0x10,0x04,0x00,0x40,0x10,0x01,0x00,0x40,0x06,0x00,0x80,0x0C,0x1A,0x00,0x18,0x1F,0xC0,0x30,0x18,0xF8,0x60,0x08,0x09,0x80,0x00,0x33,0x00,0x00,0xCC,0x0C,0x01,0x18,0x3C,0x04,0x30,0x30,0x07,0x60,0x00,0x01,0xE0,0x00,0x07,0xC0,0x00,0x09,0xC0,0x0C,0x23,0xC0,0x38,0x03,0xE1,0xF8,0x03,0xFF,0x70,0x01,0xF8,0x60,0x00,\r\n// '''\r\n0x27,0x05,0x09,0x0A,0xFF,0x08,\r\n0x06,0x05,0x86,0x23,0x13,0x11,0x90,0x90,0xC8,0x78,0x18,0x00,\r\n// '('\r\n0x28,0x05,0x0D,0x1D,0x00,0x0D,\r\n0x03,0x00,0x34,0x01,0x90,0x08,0x40,0x81,0x88,0x1C,0xC1,0xC4,0x08,0x60,0x83,0x04,0x10,0x41,0x82,0x0C,0x10,0x60,0x83,0x04,0x18,0x20,0xC0,0x06,0x04,0x38,0x20,0xC0,0x87,0x06,0x38,0x1C,0xE0,0x67,0x86,0x1C,0x60,0x76,0x01,0xE0,0x0E,0x00,0x60,0x00,\r\n// ')'\r\n0x29,0x05,0x0D,0x1D,0x00,0x0D,\r\n0x01,0x00,0x10,0x01,0x20,0x11,0x03,0x04,0x30,0x11,0xE0,0x8F,0x82,0x1C,0x10,0x70,0x81,0x82,0x0E,0x10,0x30,0x81,0x84,0x0C,0x20,0x61,0x02,0x08,0x10,0x01,0x84,0x08,0x20,0x81,0x18,0x11,0x80,0x8E,0x08,0x78,0x80,0xE4,0x03,0xE0,0x0E,0x00,0x30,0x00,\r\n// '*'\r\n0x2A,0x09,0x0C,0x0D,0x01,0x0D,\r\n0x07,0x00,0x88,0x18,0xE4,0x11,0xC0,0x1F,0x8E,0xC0,0x1C,0x11,0xC8,0xBF,0x8E,0x7D,0xC1,0xE0,0x0C,0x00,\r\n// '+'\r\n0x2B,0x09,0x15,0x14,0x00,0x15,\r\n0x00,0x7C,0x00,0x04,0x10,0x00,0x60,0x80,0x07,0x04,0x00,0x38,0x20,0x01,0xC1,0x00,0xFE,0x0F,0xCC,0x00,0x01,0xE0,0x00,0x0F,0x00,0x00,0x78,0x00,0x03,0xFF,0x07,0xFF,0xF8,0x3F,0x7F,0xC1,0xF0,0x0E,0x08,0x00,0x70,0x40,0x03,0x82,0x00,0x1F,0xF0,0x00,0xFE,0x00,0x03,0xE0,0x00,\r\n// ','\r\n0x2C,0x17,0x09,0x0B,0x00,0x09,\r\n0x1E,0x10,0x98,0x38,0x1C,0x0F,0x0B,0xC4,0xE4,0x32,0x1E,0x0E,0x00,\r\n// '-'\r\n0x2D,0x11,0x09,0x06,0x00,0x09,\r\n0x1B,0x90,0x50,0x39,0x2F,0xE7,0xF0,\r\n// '.'\r\n0x2E,0x16,0x09,0x09,0x00,0x09,\r\n0x1E,0x10,0x90,0x38,0x1C,0x0F,0x07,0xCC,0xFC,0x3C,0x00,\r\n// '/'\r\n0x2F,0x09,0x11,0x19,0x00,0x11,\r\n0x00,0x3F,0x80,0x30,0x40,0x30,0x20,0x18,0x20,0x18,0x10,0x0C,0x08,0x06,0x08,0x06,0x04,0x03,0x04,0x03,0x02,0x01,0x81,0x00,0xC1,0x00,0xC0,0x80,0x60,0x00,0x60,0x40,0x30,0x20,0x18,0x20,0x18,0x10,0x0C,0x08,0x06,0x08,0x06,0x04,0x03,0x04,0x03,0xFE,0x01,0xFE,0x00,0xFE,0x00,0x00,\r\n// '0'\r\n0x30,0x08,0x17,0x17,0x00,0x17,\r\n0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00,\r\n// '1'\r\n0x31,0x09,0x0D,0x16,0x00,0x0D,\r\n0x00,0x30,0x06,0x40,0xC4,0x18,0x43,0x02,0x20,0x13,0xC0,0x9E,0x04,0x30,0x21,0x81,0x0C,0x08,0x60,0x43,0x02,0x18,0x10,0xC0,0x86,0x04,0x30,0x21,0x81,0x98,0x03,0xFF,0xE7,0xFE,0x00,0x00,\r\n// '2'\r\n0x32,0x08,0x12,0x17,0x00,0x12,\r\n0x00,0xF0,0x00,0x81,0x00,0xC0,0x20,0xE0,0x04,0x40,0x01,0x38,0x00,0x2F,0x84,0x08,0xF9,0x82,0x1F,0xE0,0x81,0xF0,0x00,0x1C,0x10,0x06,0x04,0x01,0x03,0x80,0xC0,0xD0,0x20,0x04,0x18,0x01,0x0C,0x00,0x43,0x00,0x11,0x80,0x04,0x60,0x01,0x3F,0xFF,0x4F,0xFF,0xE0,0x00,0x30,\r\n// '3'\r\n0x33,0x08,0x12,0x17,0x00,0x12,\r\n0x0C,0x00,0x05,0xFF,0xE3,0x00,0x08,0xC0,0x02,0x30,0x01,0x0C,0x00,0x43,0x00,0x10,0xC0,0x0C,0x37,0x01,0x0F,0x80,0x23,0xE0,0x08,0x10,0x01,0x0F,0xE0,0x43,0xF8,0x10,0x4E,0x04,0x23,0x01,0x10,0x00,0x08,0x00,0x24,0x00,0x13,0x00,0x08,0xFC,0x0C,0x1F,0xFE,0x00,0xFE,0x00,\r\n// '4'\r\n0x34,0x09,0x12,0x16,0x00,0x12,\r\n0x00,0x0E,0x00,0x04,0x80,0x06,0x20,0x03,0x08,0x01,0x82,0x00,0xC0,0x80,0x40,0x20,0x20,0x08,0x10,0x03,0x88,0x20,0x94,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0xFE,0x09,0xFF,0x83,0x80,0x60,0xC0,0x30,0x10,0x0F,0xF8,0x03,0xFC,0x00,0x00,0x00,\r\n// '5'\r\n0x35,0x08,0x11,0x17,0x00,0x11,\r\n0x00,0x03,0x00,0xFF,0x40,0x80,0x20,0xC0,0x10,0x60,0x08,0x30,0x04,0x30,0x02,0x18,0x1D,0x0C,0x07,0x06,0x01,0x82,0x00,0x43,0x00,0x11,0xFC,0x08,0xFF,0x04,0x17,0x82,0x18,0x01,0x18,0x00,0x08,0x00,0x8C,0x00,0x8C,0x00,0xC7,0xC1,0xC3,0xFF,0x80,0xBF,0x00,\r\n// '6'\r\n0x36,0x08,0x13,0x17,0x00,0x13,\r\n0x00,0x7F,0xC0,0x30,0x08,0x18,0x01,0x06,0x00,0x41,0x80,0x10,0x60,0x02,0x08,0x0C,0x83,0x00,0x30,0x60,0x01,0x18,0x00,0x13,0x00,0x01,0x60,0x00,0x0C,0x00,0x03,0x80,0xC0,0x78,0x3C,0x0F,0x03,0x01,0x60,0x00,0x0E,0x00,0x08,0xE0,0x02,0x1E,0x00,0x81,0xF0,0x60,0x1F,0xF8,0x00,0xFC,0x00,\r\n// '7'\r\n0x37,0x08,0x12,0x17,0x00,0x12,\r\n0x0C,0x00,0x0D,0xFF,0xF3,0x00,0x04,0xC0,0x02,0x30,0x00,0x8C,0x00,0x43,0x00,0x10,0xDC,0x08,0x3F,0x02,0x0E,0x81,0x00,0x60,0x40,0x10,0x20,0x0C,0x08,0x02,0x04,0x01,0x81,0x00,0x40,0x80,0x30,0x20,0x10,0x10,0x0F,0x04,0x03,0xF1,0x00,0x3F,0x40,0x03,0xE0,0x00,0x30,0x00,\r\n// '8'\r\n0x38,0x08,0x12,0x17,0x00,0x12,\r\n0x01,0xF0,0x00,0x83,0x00,0xC0,0x20,0x20,0x08,0x10,0x01,0x0C,0x18,0x43,0x06,0x10,0xC0,0x04,0x38,0x01,0x0C,0x00,0x42,0x00,0x09,0x80,0x01,0xC0,0x00,0x70,0x3C,0x1C,0x0F,0x07,0x00,0x01,0xE0,0x00,0x9C,0x00,0x27,0x80,0x30,0xF8,0x38,0x1F,0xFC,0x01,0xFC,0x00,0x00,0x00,\r\n// '9'\r\n0x39,0x08,0x13,0x17,0x00,0x13,\r\n0x01,0xF8,0x00,0xC0,0xC0,0x20,0x04,0x08,0x00,0x42,0x00,0x08,0xC0,0x00,0x90,0x18,0x16,0x07,0x81,0xC0,0x60,0x38,0x00,0x07,0x80,0x00,0xF0,0x00,0x17,0x00,0x02,0xF0,0x00,0x0F,0x80,0x10,0xE6,0x02,0x08,0x00,0x83,0x00,0x20,0x40,0x0C,0x10,0x03,0x06,0xC1,0xC0,0xFF,0xE0,0x1F,0xF0,0x00,\r\n// ':'\r\n0x3A,0x0E,0x09,0x11,0x00,0x09,\r\n0x0E,0x10,0x90,0x38,0x1C,0x0F,0x07,0xC4,0xFC,0x3C,0x19,0x98,0x38,0x1C,0x0F,0x07,0xCC,0xFC,0x3C,0x00,\r\n// ';'\r\n0x3B,0x0F,0x09,0x13,0x00,0x09,\r\n0x0E,0x10,0x98,0x38,0x1C,0x0F,0x07,0xC4,0xFC,0x3E,0x19,0x98,0x38,0x1C,0x0F,0x03,0xC4,0xE4,0x32,0x1E,0x0E,0x00,\r\n// '<'\r\n0x3C,0x0A,0x13,0x13,0x00,0x13,\r\n0x00,0x00,0xC0,0x00,0x64,0x00,0x60,0x80,0x30,0x10,0x38,0x02,0x18,0x03,0x8C,0x01,0xE3,0x01,0xF0,0xE0,0xF8,0x1C,0x06,0x03,0x80,0x18,0x7E,0x00,0xCF,0xF0,0x06,0x7F,0xC0,0x43,0xFE,0x08,0x0F,0xF9,0x00,0x7F,0xE0,0x01,0xF8,0x00,0x0C,0x00,\r\n// '='\r\n0x3D,0x0D,0x14,0x0E,0x00,0x14,\r\n0x3F,0xFF,0xE6,0x00,0x01,0xE0,0x00,0x1E,0x00,0x01,0xE0,0x00,0x1F,0xFF,0xFE,0xFF,0xFF,0xE6,0x00,0x01,0x60,0x00,0x1E,0x00,0x01,0xE0,0x00,0x1F,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF8,\r\n// '>'\r\n0x3E,0x0A,0x13,0x13,0x00,0x13,\r\n0x38,0x00,0x0C,0xC0,0x03,0x87,0x00,0x70,0x18,0x0E,0x00,0xE1,0xF8,0x03,0x3F,0xC0,0x19,0xFF,0x01,0x0F,0xF8,0x20,0x3C,0x04,0x0C,0x00,0x86,0x00,0xE3,0x00,0x78,0xC0,0x7C,0x38,0x3E,0x07,0x3E,0x00,0xFF,0x00,0x1F,0x00,0x03,0x80,0x00,0x00,\r\n// '?'\r\n0x3F,0x08,0x11,0x16,0x00,0x11,\r\n0x00,0xF0,0x01,0x82,0x01,0x00,0x81,0x00,0x23,0x00,0x0B,0x00,0x05,0xC0,0x02,0xF8,0xC1,0x3F,0x40,0x87,0xE0,0x80,0xE0,0x40,0x30,0x40,0x18,0x20,0x0F,0xE0,0x07,0x30,0x03,0x04,0x03,0x02,0x01,0x81,0x00,0xE0,0x80,0x78,0x80,0x1F,0x80,0x07,0x80,\r\n// '@'\r\n0x40,0x09,0x16,0x16,0x00,0x16,\r\n0x00,0x3F,0x00,0x06,0x03,0x00,0x23,0xFB,0x01,0x3F,0xFC,0x09,0x81,0xF8,0x48,0x7F,0xE2,0x44,0x13,0xD9,0x23,0x8F,0x41,0x1E,0x1F,0x2C,0x51,0x7C,0xE0,0xC5,0xF3,0x8B,0x06,0xCE,0x28,0x3B,0x38,0xE2,0xEE,0x71,0x4D,0x19,0xE3,0x88,0x73,0xFF,0xD1,0xE7,0x9F,0xA3,0xC7,0xF1,0x07,0xE0,0x38,0x07,0xFF,0x80,0x07,0xF8,0x00,\r\n// 'A'\r\n0x41,0x08,0x19,0x17,0x00,0x19,\r\n0x00,0x0C,0x00,0x00,0x09,0x00,0x00,0x08,0x80,0x00,0x0C,0x20,0x00,0x04,0x08,0x00,0x06,0x04,0x00,0x02,0x01,0x00,0x03,0x00,0xC0,0x03,0x00,0x20,0x01,0x00,0x08,0x01,0x80,0x04,0x00,0x80,0x01,0x00,0xC0,0xC0,0x40,0xC0,0x60,0x20,0x40,0x00,0x08,0x60,0x00,0x06,0x40,0x00,0x00,0xF0,0x00,0x00,0xFE,0x1F,0xE1,0xCF,0xCF,0xF1,0x81,0xF4,0x1B,0x80,0x3E,0x0F,0x00,0x0E,0x06,0x00,\r\n// 'B'\r\n0x42,0x09,0x13,0x15,0x00,0x13,\r\n0x3F,0xFC,0x0C,0x00,0x61,0xC0,0x06,0x38,0x00,0x43,0x00,0x04,0x60,0x60,0x8C,0x0C,0x11,0x81,0x02,0x30,0x00,0x46,0x00,0x08,0xC0,0x00,0x98,0x18,0x13,0x03,0x02,0x60,0x60,0x4C,0x00,0x09,0x80,0x01,0x30,0x00,0x44,0x00,0x11,0x80,0x0E,0x3F,0xFF,0x07,0xFF,0x80,\r\n// 'C'\r\n0x43,0x08,0x16,0x17,0x00,0x16,\r\n0x00,0x7E,0x00,0x06,0x02,0x00,0x60,0x06,0x02,0x00,0x06,0x10,0x00,0x00,0xC0,0x00,0x22,0x00,0x01,0x18,0x0F,0x18,0x40,0x7E,0xC3,0x02,0x3E,0x0C,0x08,0xF0,0x30,0x21,0x80,0xC0,0x83,0x03,0x81,0x1A,0x0E,0x03,0xC4,0x18,0x00,0x08,0x70,0x00,0x19,0xE0,0x00,0x23,0xC0,0x01,0x87,0x80,0x1E,0x0F,0xC1,0xE0,0x0F,0xFE,0x00,0x0F,0xC0,0x00,\r\n// 'D'\r\n0x44,0x09,0x16,0x15,0xFF,0x15,\r\n0x1F,0xFE,0x00,0x80,0x06,0x07,0x00,0x06,0x1C,0x00,0x0C,0x30,0x00,0x10,0xC0,0x00,0x23,0x00,0x00,0x8C,0x0F,0x01,0x30,0x3E,0x04,0xC0,0xF8,0x13,0x03,0xE0,0x4C,0x0F,0x01,0x30,0x00,0x04,0xC0,0x00,0x23,0x00,0x00,0x8C,0x00,0x04,0x30,0x00,0x20,0x80,0x01,0x06,0x00,0x18,0x1F,0xFF,0x80,0x3F,0xF0,0x00,\r\n// 'E'\r\n0x45,0x08,0x11,0x17,0x00,0x11,\r\n0x00,0x01,0x0F,0xFF,0x48,0x00,0x2C,0x00,0x17,0x00,0x0B,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x1A,0x98,0x01,0x8C,0x00,0x86,0x00,0x43,0x00,0x31,0x80,0xD4,0xC0,0x02,0x60,0x01,0x30,0x00,0x98,0x00,0x4C,0x00,0x24,0x00,0x17,0xFF,0xEB,0xFF,0xF8,0x00,0x08,\r\n// 'F'\r\n0x46,0x08,0x11,0x16,0xFF,0x10,\r\n0x00,0x01,0x0F,0xFF,0x48,0x00,0x2E,0x00,0x17,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x3A,0x98,0x01,0x8C,0x00,0xC6,0x00,0x43,0x00,0x21,0x81,0xD0,0xC0,0xF0,0x60,0x70,0x30,0x20,0x18,0x10,0x08,0x02,0x0C,0x01,0x07,0xFF,0x03,0xFF,0x00,\r\n// 'G'\r\n0x47,0x08,0x16,0x17,0x00,0x16,\r\n0x00,0x7F,0x00,0x06,0x03,0x00,0x60,0x03,0x82,0x00,0x02,0x10,0x00,0x08,0xC0,0x00,0xC2,0x00,0x06,0x18,0x07,0x30,0x40,0x3C,0x83,0x01,0x3C,0x0C,0x04,0xFF,0xB0,0x14,0x02,0xC0,0x78,0x1B,0x80,0xE0,0x4E,0x01,0x81,0x18,0x00,0x04,0x70,0x00,0x11,0xE0,0x00,0x43,0xC0,0x01,0x07,0x80,0x18,0x0F,0x81,0xC0,0x1F,0xFC,0x00,0x0F,0xC0,0x00,\r\n// 'H'\r\n0x48,0x09,0x16,0x15,0x00,0x16,\r\n0x3F,0xC7,0xF9,0x00,0xE0,0x1E,0x03,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x80,0xF0,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x00,0x09,0x80,0x00,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x3C,0x09,0x80,0xF0,0x26,0x02,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x00,0x20,0x1F,0xFF,0xFF,0xFF,0xF7,0xFC,0x00,0x00,0x00,\r\n// 'I'\r\n0x49,0x09,0x0B,0x15,0x00,0x0B,\r\n0x3F,0xC8,0x07,0x81,0x70,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x4C,0x09,0x81,0x30,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x48,0x07,0x00,0xFF,0xEF,0xF8,\r\n// 'J'\r\n0x4A,0x09,0x0F,0x16,0x00,0x0F,\r\n0x03,0xFC,0x08,0x04,0x38,0x08,0x70,0x10,0x60,0x20,0xC0,0x41,0x80,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x08,0x30,0x10,0xA0,0x23,0x00,0x44,0x00,0x98,0x01,0x20,0x00,0xC0,0x09,0x00,0x27,0xC1,0x8F,0xFE,0x0F,0xF0,0x00,\r\n// 'K'\r\n0x4B,0x08,0x17,0x18,0x00,0x17,\r\n0x00,0x01,0x80,0x7F,0xEE,0x81,0x80,0x38,0x87,0x81,0xE0,0x8F,0x03,0x80,0x86,0x06,0x00,0x8C,0x08,0x07,0x18,0x00,0x1C,0x30,0x00,0x70,0x60,0x01,0x00,0xC0,0x02,0x01,0x80,0x02,0x03,0x00,0x04,0x06,0x04,0x04,0x0C,0x0C,0x04,0x18,0x18,0x06,0x30,0x38,0x00,0x60,0x78,0x09,0x00,0x30,0x26,0x00,0x71,0x8F,0xFF,0xE4,0x0F,0xFC,0xD0,0x00,0x01,0xC0,0x00,0x00,0x00,\r\n// 'L'\r\n0x4C,0x09,0x11,0x16,0x00,0x11,\r\n0x3F,0xF0,0x30,0x04,0x1C,0x06,0x0E,0x02,0x03,0x01,0x01,0x80,0x80,0xC0,0x40,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,0xC6,0x03,0xD3,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x00,0xB0,0x00,0x58,0x00,0x2F,0xFF,0xD7,0xFF,0xF0,0x00,0x30,\r\n// 'M'\r\n0x4D,0x09,0x20,0x16,0x00,0x1F,\r\n0x00,0xF8,0x1F,0x00,0x01,0x84,0x30,0x80,0x01,0x82,0x61,0x00,0x01,0x82,0x40,0x00,0x01,0x81,0xC0,0x80,0x01,0x01,0x80,0x80,0x03,0x00,0x80,0x40,0x02,0x00,0x00,0x40,0x06,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x0C,0x00,0x00,0x10,0x08,0x00,0x00,0x10,0x18,0x08,0x08,0x08,0x10,0x18,0x18,0x08,0x30,0x1C,0x1C,0x04,0x60,0x3C,0x3C,0x02,0x70,0x2E,0x2E,0x06,0x7C,0x27,0x4E,0x3C,0x3F,0x27,0xC6,0xF0,0x07,0xC3,0x8F,0x80,0x01,0x83,0x06,0x00,\r\n// 'N'\r\n0x4E,0x09,0x17,0x15,0x00,0x17,\r\n0x3F,0x07,0xFC,0xC1,0x10,0x07,0xC1,0x78,0x1F,0x81,0xF0,0x23,0x01,0xE0,0x46,0x01,0xC0,0x8C,0x01,0x81,0x18,0x01,0x02,0x30,0x00,0x04,0x60,0x00,0x08,0xC0,0x00,0x11,0x80,0x00,0x23,0x02,0x00,0x46,0x06,0x00,0x8C,0x0E,0x01,0x18,0x1E,0x02,0x30,0x3F,0x04,0x60,0x3F,0x0B,0x00,0x2F,0x17,0xFF,0x8F,0xEF,0xFE,0x0F,0x80,\r\n// 'O'\r\n0x4F,0x08,0x17,0x17,0x00,0x17,\r\n0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00,\r\n// 'P'\r\n0x50,0x09,0x13,0x15,0x00,0x13,\r\n0x3F,0xFC,0x08,0x00,0x43,0x80,0x06,0x70,0x00,0x46,0x00,0x04,0xC0,0x00,0x18,0x00,0x0B,0x01,0x81,0x60,0x30,0x2C,0x04,0x05,0x80,0x00,0x30,0x00,0x26,0x00,0x08,0xC0,0x02,0x18,0x01,0x83,0x01,0xE0,0x60,0x30,0x08,0x04,0x03,0x00,0x80,0x7F,0xE0,0x07,0xF8,0x00,\r\n// 'Q'\r\n0x51,0x09,0x17,0x1C,0x00,0x17,\r\n0x00,0x7E,0x00,0x03,0x01,0x00,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x01,0x08,0x00,0x01,0x30,0x1E,0x02,0x40,0x7E,0x03,0x81,0x1E,0x07,0x02,0x1C,0x0E,0x04,0x18,0x1C,0x04,0x20,0x3C,0x07,0x80,0x78,0x00,0x01,0x30,0x00,0x02,0x70,0x00,0x04,0xF0,0x00,0x10,0xF0,0x00,0x70,0xF0,0x00,0x00,0xFC,0x00,0x40,0xFF,0x81,0x00,0x3F,0x84,0x00,0x0F,0x10,0x00,0x06,0x40,0x00,0x0F,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,\r\n// 'R'\r\n0x52,0x09,0x18,0x17,0x00,0x18,\r\n0x3F,0xFE,0x00,0x60,0x01,0x80,0x70,0x00,0x40,0x70,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x10,0x10,0x30,0x18,0x10,0x30,0x10,0x10,0x30,0x00,0x10,0x30,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x1E,0x30,0x00,0x0A,0x30,0x18,0x06,0x30,0x1C,0x0C,0x20,0x0E,0x18,0x7F,0xFF,0x30,0x7F,0xE7,0x20,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x03,0x00,\r\n// 'S'\r\n0x53,0x07,0x11,0x19,0x00,0x11,\r\n0x00,0x06,0x00,0x02,0x80,0x1E,0x40,0x10,0x20,0x30,0x10,0x30,0x08,0x10,0x04,0x18,0x01,0x08,0x00,0x8C,0x0F,0x46,0x07,0xA3,0x01,0xE1,0xC0,0xE1,0xE0,0x41,0x70,0x21,0x80,0x10,0xC0,0x08,0x70,0x08,0x38,0x04,0x0C,0x04,0x06,0x04,0x03,0x3C,0x01,0xFC,0x00,0xF0,0x00,0x30,0x00,0x00,\r\n// 'T'\r\n0x54,0x08,0x12,0x16,0x01,0x13,\r\n0x30,0x01,0x93,0xFF,0xDC,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0x00,0x01,0xCC,0x07,0x7F,0x01,0xFF,0xC0,0x79,0xB0,0x1C,0x0C,0x04,0x03,0x01,0x00,0xC0,0x40,0x30,0x10,0x0C,0x04,0x03,0x01,0x00,0xC0,0x60,0x60,0x08,0x1F,0xFC,0x07,0xFE,0x00,\r\n// 'U'\r\n0x55,0x09,0x19,0x16,0xFF,0x18,\r\n0x1F,0xF1,0xFF,0x10,0x05,0x00,0x9C,0x07,0xC0,0xCE,0x02,0xE0,0x43,0x01,0x30,0x21,0x80,0x98,0x10,0xC0,0x4C,0x08,0x60,0x26,0x04,0x30,0x13,0x02,0x18,0x09,0x81,0x0C,0x04,0xC0,0x86,0x02,0x60,0x43,0x01,0x30,0x21,0xC0,0x70,0x10,0xE0,0x00,0x10,0x30,0x00,0x08,0x1C,0x00,0x08,0x0F,0x00,0x08,0x03,0xC0,0x08,0x00,0xFC,0x18,0x00,0x1F,0xF8,0x00,0x03,0xF0,0x00,\r\n// 'V'\r\n0x56,0x07,0x19,0x18,0x00,0x19,\r\n0x00,0xC1,0xC0,0x01,0x91,0x98,0x03,0x18,0xC3,0x06,0x04,0x60,0x64,0x02,0x20,0x1F,0x00,0xB0,0x1B,0xC0,0x70,0x0C,0xF0,0x10,0x08,0x38,0x00,0x08,0x0E,0x00,0x04,0x07,0x00,0x04,0x01,0xC0,0x06,0x00,0xE0,0x02,0x00,0x38,0x02,0x00,0x1C,0x01,0x00,0x07,0x01,0x00,0x03,0x81,0x80,0x00,0xE0,0x80,0x00,0x30,0x80,0x00,0x1C,0x40,0x00,0x06,0x40,0x00,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0x60,0x00,\r\n// 'W'\r\n0x57,0x07,0x20,0x18,0x00,0x20,\r\n0x00,0x60,0x03,0x80,0x01,0x90,0x06,0x60,0x0E,0x10,0xC6,0x1C,0x38,0x11,0xA6,0x07,0x60,0x11,0x26,0x01,0x78,0x12,0x1C,0x06,0x78,0x0E,0x1C,0x04,0x3C,0x0C,0x08,0x08,0x1C,0x00,0x08,0x10,0x0C,0x00,0x00,0x10,0x0E,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x07,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x03,0x80,0x00,0x80,0x03,0x80,0x00,0x80,0x01,0xC0,0x81,0x00,0x01,0xC1,0xC0,0x00,0x00,0xE1,0xC2,0x00,0x00,0xE2,0xE4,0x00,0x00,0x74,0xE4,0x00,0x00,0x7C,0x78,0x00,0x00,0x38,0x78,0x00,0x00,0x30,0x30,0x00,\r\n// 'X'\r\n0x58,0x05,0x19,0x1D,0x00,0x18,\r\n0x00,0x01,0x80,0x00,0x01,0x20,0x00,0x61,0x8C,0x00,0x48,0xC3,0x00,0x44,0x40,0x60,0x43,0x60,0x10,0xC0,0xE0,0x18,0xC0,0x30,0x1C,0xC0,0x00,0x18,0x7C,0x00,0x08,0x1F,0x00,0x08,0x03,0x80,0x08,0x00,0xE0,0x04,0x00,0x38,0x02,0x00,0x0C,0x01,0x80,0x04,0x00,0x60,0x06,0x00,0x10,0x02,0x00,0x07,0x03,0x00,0x00,0x41,0x01,0x00,0x63,0x00,0xC0,0x62,0x00,0xF0,0x63,0x80,0x7C,0x61,0xF0,0x4E,0x60,0x7C,0x63,0xE0,0x0F,0x91,0xE0,0x01,0xF0,0x40,0x00,0x70,0x00,0x00,0x00,0x00,0x00,\r\n// 'Y'\r\n0x59,0x06,0x19,0x1B,0x00,0x19,\r\n0x00,0x00,0x60,0x00,0xC0,0x48,0x00,0x80,0x62,0x00,0x88,0x20,0xC0,0x82,0x30,0x11,0x80,0xB0,0x01,0x80,0x30,0x0D,0x80,0x00,0x0C,0xF8,0x00,0x08,0x3E,0x00,0x04,0x07,0x80,0x04,0x01,0xE0,0x04,0x00,0x78,0x04,0x00,0x1C,0x02,0x00,0x0C,0x02,0x00,0x04,0x02,0x00,0x04,0x02,0x00,0x06,0x01,0x00,0x0E,0x01,0x00,0x0C,0x01,0x00,0x07,0x01,0x00,0x03,0xC0,0x80,0x01,0xF0,0x80,0x00,0x3E,0x00,0x00,0x0F,0xC0,0x00,0x03,0xE0,0x00,0x00,0x40,0x00,0x00,\r\n// 'Z'\r\n0x5A,0x08,0x13,0x17,0xFF,0x12,\r\n0x0C,0x00,0x02,0xFF,0xFC,0xC0,0x01,0x98,0x00,0x23,0x00,0x04,0x60,0x01,0x0C,0x00,0x21,0x80,0x08,0x37,0x01,0x07,0xE0,0x60,0xF8,0x08,0x03,0x01,0x00,0x40,0x70,0x18,0x0D,0x02,0x00,0x20,0xC0,0x04,0x18,0x00,0x86,0x00,0x10,0xC0,0x02,0x10,0x00,0x47,0xFF,0xE8,0xFF,0xFE,0x00,0x01,0x80,\r\n// '['\r\n0x5B,0x04,0x0B,0x20,0x00,0x0B,\r\n0x00,0x40,0x19,0xFD,0x60,0x2C,0x05,0x80,0xB0,0x16,0x0E,0xC1,0xD8,0x33,0x04,0x60,0x8C,0x11,0x82,0x30,0x46,0x08,0xC1,0x18,0x23,0x04,0x60,0x8C,0x11,0x82,0xB0,0x76,0x02,0xC0,0x58,0x0B,0x01,0x60,0x2F,0xFD,0xFF,0x80,0x60,0x00,\r\n// '\\'\r\n0x5C,0x09,0x11,0x18,0x00,0x11,\r\n0x3F,0x00,0x30,0x40,0x38,0x10,0x1E,0x08,0x0F,0x04,0x03,0x81,0x01,0xE0,0x80,0x70,0x20,0x3C,0x10,0x1E,0x08,0x07,0x02,0x03,0xC1,0x00,0xE0,0x40,0x78,0x20,0x3C,0x08,0x0F,0x04,0x07,0x82,0x01,0xC0,0x80,0xF0,0x40,0x38,0x10,0x1E,0x08,0x0F,0xFC,0x03,0xFC,0x01,0xFC,\r\n// ']'\r\n0x5D,0x04,0x0C,0x1F,0xFF,0x0B,\r\n0x30,0x02,0xFF,0x60,0x16,0x01,0x60,0x16,0x01,0x60,0x16,0xC1,0x7C,0x16,0xC1,0x6C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x13,0xC1,0x6C,0x16,0x01,0x60,0x16,0x01,0x60,0x16,0x01,0x7F,0xE7,0xFE,0x60,0x00,\r\n// '^'\r\n0x5E,0x1E,0x00,0x00,0x00,0x09,\r\n\r\n// '_'\r\n0x5F,0x20,0x10,0x04,0x00,0x10,\r\n0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\r\n// '`'\r\n0x60,0x00,0x0A,0x09,0x00,0x0B,\r\n0x00,0x06,0x02,0x61,0x8C,0x60,0xBF,0x17,0xFC,0x3E,0x03,0x00,\r\n// 'a'\r\n0x61,0x08,0x19,0x17,0x00,0x19,\r\n0x00,0x0C,0x00,0x00,0x09,0x00,0x00,0x08,0x80,0x00,0x0C,0x20,0x00,0x04,0x08,0x00,0x06,0x04,0x00,0x02,0x01,0x00,0x03,0x00,0xC0,0x03,0x00,0x20,0x01,0x00,0x08,0x01,0x80,0x04,0x00,0x80,0x01,0x00,0xC0,0xC0,0x40,0xC0,0x60,0x20,0x40,0x00,0x08,0x60,0x00,0x06,0x40,0x00,0x00,0xF0,0x00,0x00,0xFE,0x1F,0xE1,0xCF,0xCF,0xF1,0x81,0xF4,0x1B,0x80,0x3E,0x0F,0x00,0x0E,0x06,0x00,\r\n// 'b'\r\n0x62,0x09,0x13,0x15,0x00,0x13,\r\n0x3F,0xFC,0x0C,0x00,0x61,0xC0,0x06,0x38,0x00,0x43,0x00,0x04,0x60,0x60,0x8C,0x0C,0x11,0x81,0x02,0x30,0x00,0x46,0x00,0x08,0xC0,0x00,0x98,0x18,0x13,0x03,0x02,0x60,0x60,0x4C,0x00,0x09,0x80,0x01,0x30,0x00,0x44,0x00,0x11,0x80,0x0E,0x3F,0xFF,0x07,0xFF,0x80,\r\n// 'c'\r\n0x63,0x08,0x16,0x17,0x00,0x16,\r\n0x00,0x7E,0x00,0x06,0x02,0x00,0x60,0x06,0x02,0x00,0x06,0x10,0x00,0x00,0xC0,0x00,0x22,0x00,0x01,0x18,0x0F,0x18,0x40,0x7E,0xC3,0x02,0x3E,0x0C,0x08,0xF0,0x30,0x21,0x80,0xC0,0x83,0x03,0x81,0x1A,0x0E,0x03,0xC4,0x18,0x00,0x08,0x70,0x00,0x19,0xE0,0x00,0x23,0xC0,0x01,0x87,0x80,0x1E,0x0F,0xC1,0xE0,0x0F,0xFE,0x00,0x0F,0xC0,0x00,\r\n// 'd'\r\n0x64,0x09,0x16,0x15,0xFF,0x15,\r\n0x1F,0xFE,0x00,0x80,0x06,0x07,0x00,0x06,0x1C,0x00,0x0C,0x30,0x00,0x10,0xC0,0x00,0x23,0x00,0x00,0x8C,0x0F,0x01,0x30,0x3E,0x04,0xC0,0xF8,0x13,0x03,0xE0,0x4C,0x0F,0x01,0x30,0x00,0x04,0xC0,0x00,0x23,0x00,0x00,0x8C,0x00,0x04,0x30,0x00,0x20,0x80,0x01,0x06,0x00,0x18,0x1F,0xFF,0x80,0x3F,0xF0,0x00,\r\n// 'e'\r\n0x65,0x08,0x11,0x17,0x00,0x11,\r\n0x00,0x01,0x0F,0xFF,0x48,0x00,0x2C,0x00,0x17,0x00,0x0B,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x1A,0x98,0x01,0x8C,0x00,0x86,0x00,0x43,0x00,0x31,0x80,0xD4,0xC0,0x02,0x60,0x01,0x30,0x00,0x98,0x00,0x4C,0x00,0x24,0x00,0x17,0xFF,0xEB,0xFF,0xF8,0x00,0x08,\r\n// 'f'\r\n0x66,0x08,0x11,0x16,0xFF,0x10,\r\n0x00,0x01,0x0F,0xFF,0x48,0x00,0x2E,0x00,0x17,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x3A,0x98,0x01,0x8C,0x00,0xC6,0x00,0x43,0x00,0x21,0x81,0xD0,0xC0,0xF0,0x60,0x70,0x30,0x20,0x18,0x10,0x08,0x02,0x0C,0x01,0x07,0xFF,0x03,0xFF,0x00,\r\n// 'g'\r\n0x67,0x08,0x16,0x17,0x00,0x16,\r\n0x00,0x7F,0x00,0x06,0x03,0x00,0x60,0x03,0x82,0x00,0x02,0x10,0x00,0x08,0xC0,0x00,0xC2,0x00,0x06,0x18,0x07,0x30,0x40,0x3C,0x83,0x01,0x3C,0x0C,0x04,0xFF,0xB0,0x14,0x02,0xC0,0x78,0x1B,0x80,0xE0,0x4E,0x01,0x81,0x18,0x00,0x04,0x70,0x00,0x11,0xE0,0x00,0x43,0xC0,0x01,0x07,0x80,0x18,0x0F,0x81,0xC0,0x1F,0xFC,0x00,0x0F,0xC0,0x00,\r\n// 'h'\r\n0x68,0x09,0x16,0x15,0x00,0x16,\r\n0x3F,0xC7,0xF9,0x00,0xE0,0x1E,0x03,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x80,0xF0,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x00,0x09,0x80,0x00,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x3C,0x09,0x80,0xF0,0x26,0x02,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x00,0x20,0x1F,0xFF,0xFF,0xFF,0xF7,0xFC,0x00,0x00,0x00,\r\n// 'i'\r\n0x69,0x09,0x0B,0x15,0x00,0x0B,\r\n0x3F,0xC8,0x07,0x81,0x70,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x4C,0x09,0x81,0x30,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x48,0x07,0x00,0xFF,0xEF,0xF8,\r\n// 'j'\r\n0x6A,0x09,0x0F,0x16,0x00,0x0F,\r\n0x03,0xFC,0x08,0x04,0x38,0x08,0x70,0x10,0x60,0x20,0xC0,0x41,0x80,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x08,0x30,0x10,0xA0,0x23,0x00,0x44,0x00,0x98,0x01,0x20,0x00,0xC0,0x09,0x00,0x27,0xC1,0x8F,0xFE,0x0F,0xF0,0x00,\r\n// 'k'\r\n0x6B,0x08,0x17,0x18,0x00,0x17,\r\n0x00,0x01,0x80,0x7F,0xEE,0x81,0x80,0x38,0x87,0x81,0xE0,0x8F,0x03,0x80,0x86,0x06,0x00,0x8C,0x08,0x07,0x18,0x00,0x1C,0x30,0x00,0x70,0x60,0x01,0x00,0xC0,0x02,0x01,0x80,0x02,0x03,0x00,0x04,0x06,0x04,0x04,0x0C,0x0C,0x04,0x18,0x18,0x06,0x30,0x38,0x00,0x60,0x78,0x09,0x00,0x30,0x26,0x00,0x71,0x8F,0xFF,0xE4,0x0F,0xFC,0xD0,0x00,0x01,0xC0,0x00,0x00,0x00,\r\n// 'l'\r\n0x6C,0x09,0x11,0x16,0x00,0x11,\r\n0x3F,0xF0,0x30,0x04,0x1C,0x06,0x0E,0x02,0x03,0x01,0x01,0x80,0x80,0xC0,0x40,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,0xC6,0x03,0xD3,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x00,0xB0,0x00,0x58,0x00,0x2F,0xFF,0xD7,0xFF,0xF0,0x00,0x30,\r\n// 'm'\r\n0x6D,0x09,0x20,0x16,0x00,0x1F,\r\n0x00,0xF8,0x1F,0x00,0x01,0x84,0x30,0x80,0x01,0x82,0x61,0x00,0x01,0x82,0x40,0x00,0x01,0x81,0xC0,0x80,0x01,0x01,0x80,0x80,0x03,0x00,0x80,0x40,0x02,0x00,0x00,0x40,0x06,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x0C,0x00,0x00,0x10,0x08,0x00,0x00,0x10,0x18,0x08,0x08,0x08,0x10,0x18,0x18,0x08,0x30,0x1C,0x1C,0x04,0x60,0x3C,0x3C,0x02,0x70,0x2E,0x2E,0x06,0x7C,0x27,0x4E,0x3C,0x3F,0x27,0xC6,0xF0,0x07,0xC3,0x8F,0x80,0x01,0x83,0x06,0x00,\r\n// 'n'\r\n0x6E,0x09,0x17,0x15,0x00,0x17,\r\n0x3F,0x07,0xFC,0xC1,0x10,0x07,0xC1,0x78,0x1F,0x81,0xF0,0x23,0x01,0xE0,0x46,0x01,0xC0,0x8C,0x01,0x81,0x18,0x01,0x02,0x30,0x00,0x04,0x60,0x00,0x08,0xC0,0x00,0x11,0x80,0x00,0x23,0x02,0x00,0x46,0x06,0x00,0x8C,0x0E,0x01,0x18,0x1E,0x02,0x30,0x3F,0x04,0x60,0x3F,0x0B,0x00,0x2F,0x17,0xFF,0x8F,0xEF,0xFE,0x0F,0x80,\r\n// 'o'\r\n0x6F,0x08,0x17,0x17,0x00,0x17,\r\n0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00,\r\n// 'p'\r\n0x70,0x09,0x13,0x15,0x00,0x13,\r\n0x3F,0xFC,0x08,0x00,0x43,0x80,0x06,0x70,0x00,0x46,0x00,0x04,0xC0,0x00,0x18,0x00,0x0B,0x01,0x81,0x60,0x30,0x2C,0x04,0x05,0x80,0x00,0x30,0x00,0x26,0x00,0x08,0xC0,0x02,0x18,0x01,0x83,0x01,0xE0,0x60,0x30,0x08,0x04,0x03,0x00,0x80,0x7F,0xE0,0x07,0xF8,0x00,\r\n// 'q'\r\n0x71,0x09,0x17,0x1C,0x00,0x17,\r\n0x00,0x7E,0x00,0x03,0x01,0x00,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x01,0x08,0x00,0x01,0x30,0x1E,0x02,0x40,0x7E,0x03,0x81,0x1E,0x07,0x02,0x1C,0x0E,0x04,0x18,0x1C,0x04,0x20,0x3C,0x07,0x80,0x78,0x00,0x01,0x30,0x00,0x02,0x70,0x00,0x04,0xF0,0x00,0x10,0xF0,0x00,0x70,0xF0,0x00,0x00,0xFC,0x00,0x40,0xFF,0x81,0x00,0x3F,0x84,0x00,0x0F,0x10,0x00,0x06,0x40,0x00,0x0F,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,\r\n// 'r'\r\n0x72,0x09,0x18,0x17,0x00,0x18,\r\n0x3F,0xFE,0x00,0x60,0x01,0x80,0x70,0x00,0x40,0x70,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x10,0x10,0x30,0x18,0x10,0x30,0x10,0x10,0x30,0x00,0x10,0x30,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x1E,0x30,0x00,0x0A,0x30,0x18,0x06,0x30,0x1C,0x0C,0x20,0x0E,0x18,0x7F,0xFF,0x30,0x7F,0xE7,0x20,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x03,0x00,\r\n// 's'\r\n0x73,0x07,0x11,0x19,0x00,0x11,\r\n0x00,0x06,0x00,0x02,0x80,0x1E,0x40,0x10,0x20,0x30,0x10,0x30,0x08,0x10,0x04,0x18,0x01,0x08,0x00,0x8C,0x0F,0x46,0x07,0xA3,0x01,0xE1,0xC0,0xE1,0xE0,0x41,0x70,0x21,0x80,0x10,0xC0,0x08,0x70,0x08,0x38,0x04,0x0C,0x04,0x06,0x04,0x03,0x3C,0x01,0xFC,0x00,0xF0,0x00,0x30,0x00,0x00,\r\n// 't'\r\n0x74,0x08,0x12,0x16,0x01,0x13,\r\n0x30,0x01,0x93,0xFF,0xDC,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0x00,0x01,0xCC,0x07,0x7F,0x01,0xFF,0xC0,0x79,0xB0,0x1C,0x0C,0x04,0x03,0x01,0x00,0xC0,0x40,0x30,0x10,0x0C,0x04,0x03,0x01,0x00,0xC0,0x60,0x60,0x08,0x1F,0xFC,0x07,0xFE,0x00,\r\n// 'u'\r\n0x75,0x09,0x19,0x16,0xFF,0x18,\r\n0x1F,0xF1,0xFF,0x10,0x05,0x00,0x9C,0x07,0xC0,0xCE,0x02,0xE0,0x43,0x01,0x30,0x21,0x80,0x98,0x10,0xC0,0x4C,0x08,0x60,0x26,0x04,0x30,0x13,0x02,0x18,0x09,0x81,0x0C,0x04,0xC0,0x86,0x02,0x60,0x43,0x01,0x30,0x21,0xC0,0x70,0x10,0xE0,0x00,0x10,0x30,0x00,0x08,0x1C,0x00,0x08,0x0F,0x00,0x08,0x03,0xC0,0x08,0x00,0xFC,0x18,0x00,0x1F,0xF8,0x00,0x03,0xF0,0x00,\r\n// 'v'\r\n0x76,0x07,0x19,0x18,0x00,0x19,\r\n0x00,0xC1,0xC0,0x01,0x91,0x98,0x03,0x18,0xC3,0x06,0x04,0x60,0x64,0x02,0x20,0x1F,0x00,0xB0,0x1B,0xC0,0x70,0x0C,0xF0,0x10,0x08,0x38,0x00,0x08,0x0E,0x00,0x04,0x07,0x00,0x04,0x01,0xC0,0x06,0x00,0xE0,0x02,0x00,0x38,0x02,0x00,0x1C,0x01,0x00,0x07,0x01,0x00,0x03,0x81,0x80,0x00,0xE0,0x80,0x00,0x30,0x80,0x00,0x1C,0x40,0x00,0x06,0x40,0x00,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0x60,0x00,\r\n// 'w'\r\n0x77,0x07,0x20,0x18,0x00,0x20,\r\n0x00,0x60,0x03,0x80,0x01,0x90,0x06,0x60,0x0E,0x10,0xC6,0x1C,0x38,0x11,0xA6,0x07,0x60,0x11,0x26,0x01,0x78,0x12,0x1C,0x06,0x78,0x0E,0x1C,0x04,0x3C,0x0C,0x08,0x08,0x1C,0x00,0x08,0x10,0x0C,0x00,0x00,0x10,0x0E,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x07,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x03,0x80,0x00,0x80,0x03,0x80,0x00,0x80,0x01,0xC0,0x81,0x00,0x01,0xC1,0xC0,0x00,0x00,0xE1,0xC2,0x00,0x00,0xE2,0xE4,0x00,0x00,0x74,0xE4,0x00,0x00,0x7C,0x78,0x00,0x00,0x38,0x78,0x00,0x00,0x30,0x30,0x00,\r\n// 'x'\r\n0x78,0x05,0x19,0x1D,0x00,0x18,\r\n0x00,0x01,0x80,0x00,0x01,0x20,0x00,0x61,0x8C,0x00,0x48,0xC3,0x00,0x44,0x40,0x60,0x43,0x60,0x10,0xC0,0xE0,0x18,0xC0,0x30,0x1C,0xC0,0x00,0x18,0x7C,0x00,0x08,0x1F,0x00,0x08,0x03,0x80,0x08,0x00,0xE0,0x04,0x00,0x38,0x02,0x00,0x0C,0x01,0x80,0x04,0x00,0x60,0x06,0x00,0x10,0x02,0x00,0x07,0x03,0x00,0x00,0x41,0x01,0x00,0x63,0x00,0xC0,0x62,0x00,0xF0,0x63,0x80,0x7C,0x61,0xF0,0x4E,0x60,0x7C,0x63,0xE0,0x0F,0x91,0xE0,0x01,0xF0,0x40,0x00,0x70,0x00,0x00,0x00,0x00,0x00,\r\n// 'y'\r\n0x79,0x06,0x19,0x1B,0x00,0x19,\r\n0x00,0x00,0x60,0x00,0xC0,0x48,0x00,0x80,0x62,0x00,0x88,0x20,0xC0,0x82,0x30,0x11,0x80,0xB0,0x01,0x80,0x30,0x0D,0x80,0x00,0x0C,0xF8,0x00,0x08,0x3E,0x00,0x04,0x07,0x80,0x04,0x01,0xE0,0x04,0x00,0x78,0x04,0x00,0x1C,0x02,0x00,0x0C,0x02,0x00,0x04,0x02,0x00,0x04,0x02,0x00,0x06,0x01,0x00,0x0E,0x01,0x00,0x0C,0x01,0x00,0x07,0x01,0x00,0x03,0xC0,0x80,0x01,0xF0,0x80,0x00,0x3E,0x00,0x00,0x0F,0xC0,0x00,0x03,0xE0,0x00,0x00,0x40,0x00,0x00,\r\n// 'z'\r\n0x7A,0x08,0x13,0x17,0xFF,0x12,\r\n0x0C,0x00,0x02,0xFF,0xFC,0xC0,0x01,0x98,0x00,0x23,0x00,0x04,0x60,0x01,0x0C,0x00,0x21,0x80,0x08,0x37,0x01,0x07,0xE0,0x60,0xF8,0x08,0x03,0x01,0x00,0x40,0x70,0x18,0x0D,0x02,0x00,0x20,0xC0,0x04,0x18,0x00,0x86,0x00,0x10,0xC0,0x02,0x10,0x00,0x47,0xFF,0xE8,0xFF,0xFE,0x00,0x01,0x80,\r\n// '{'\r\n0x7B,0x05,0x0D,0x1F,0x01,0x0E,\r\n0x00,0x10,0x0E,0x81,0x04,0x10,0x21,0x81,0x08,0x08,0xC0,0x46,0x0E,0x30,0x71,0x83,0x0C,0x10,0x60,0x84,0x04,0x60,0x23,0x02,0x18,0x08,0xC0,0x47,0x82,0x3C,0x10,0x60,0x83,0x05,0x18,0x38,0xC0,0x46,0x02,0x38,0x11,0xC0,0x87,0x84,0x1F,0xE0,0x7F,0x00,0x30,0x00,0x00,\r\n// '|'\r\n0x7C,0x1E,0x00,0x00,0x00,0x09,\r\n\r\n// '}'\r\n0x7D,0x04,0x0E,0x1F,0x00,0x0F,\r\n0x30,0x00,0xBC,0x06,0x0C,0x18,0x08,0x60,0x21,0x80,0x46,0x01,0x1F,0x04,0x7C,0x11,0xB0,0x44,0xC1,0x03,0x04,0x0C,0x0C,0x30,0x10,0xE0,0x43,0x81,0x04,0x04,0x30,0x70,0xC1,0x03,0x04,0x0C,0x10,0xF0,0x46,0xC1,0x18,0x04,0x60,0x11,0x80,0x86,0x04,0x18,0x60,0x7F,0x81,0xF8,0x06,0x00,0x00,\r\n// '~'\r\n0x7E,0x1E,0x00,0x00,0x00,0x09,\r\n\r\n\r\n// Terminator\r\n0xFF\r\n};\r\n"
  },
  {
    "path": "components/mkspiffs/.travis.yml",
    "content": "language: cpp\naddons:\n  apt:\n    sources:\n      - ubuntu-toolchain-r-test\n    packages:\n      - g++-4.8\nscript:\n  - export CXX=\"g++-4.8\" CC=\"gcc-4.8\"\n  - make dist\nnotifications:\n  email:\n    recipients:\n    - ivan@esp8266.com\n    on_success: change\n    on_failure: always\ndeploy:\n  provider: releases\n  api_key:\n    secure: k/DDoCfLXIct8TcGjekKm5CAoTL6Wy6LXhI74Ssgc8VSbjJQ1crO2J4V5HnQw7QplgAXwqjkoAUkzEJiz34wqBaAv0w9o8+5jPwCP6rMQ/VEvbn1MPI52KIFbYqKxmXe5J24B00BttbGc773ldXPnvmv+qPWWcXDTpcosni2laBt3z8bxCGVwkQ7nuQUaAelzs21wQuhjmKQ6F1dgNN5XhdJ5qgFYYM8cwiigvcqIaCwLMcrOs7gj22TS242pzp38etWhfxUbqUKejWgOH4qYeU3Tf5gsu4WV0otbqXYMvV18gVSoAiMnodDfYJUNHlfelCAEqebvECrIvvE8D0syuVYz6fh2/BrxZ6HeiYj1CXILghOjPUZZZ7/chKglWnA1vL+6Uxn5LtyTJ5gbgMYXvKQUXrRVZ3Zd9xrmv/YaMnGq+6BDBkS30aXpSK2X0HvW9/6JyQ9L1sjnKdOzDmagvikHm2rrPXBRMMfYTt4nucgUBWqJqyFe0uGva/n8TG5RzOzdOgRxFx/lF8XudtR4Z4gUBUFpve/meVHVVK82+cxzfN97aFdxvBzyGq18EDjOEpDi7k7mZjXUycvD8UZ7o12sxJ0Zr6/9esiFUsaqyE+2Vi6bMbgEHGx7hfWbdfREnpOtjFLH+u5mAPIqOh89a/UJ6SbYm0cON+ewTMUkJ8=\n  file: mkspiffs-$TRAVIS_TAG-linux64.tar.gz\n  on:\n    repo: igrr/mkspiffs\n    tags: true\n"
  },
  {
    "path": "components/mkspiffs/Makefile.projbuild",
    "content": "MKSPIFFS_COMPONENT_PATH := $(COMPONENT_PATH)\nMKSPIFFS_BUILD_DIR=$(abspath $(MKSPIFFS_COMPONENT_PATH)/mkspiffs)\n\n# Custom recursive make for mkspiffs sub-project\nMKSPIFFS_MAKE=+$(MAKE) -C $(MKSPIFFS_COMPONENT_PATH)/src\n\n.PHONY: mkspiffs clean\n\nmkspiffs: $(SDKCONFIG_MAKEFILE)\n\t$(MKSPIFFS_MAKE) all\n\nclean: $(SDKCONFIG_MAKEFILE)\n\t$(MKSPIFFS_MAKE) clean\n\n"
  },
  {
    "path": "components/mkspiffs/component.mk",
    "content": "#\n# Component Makefile\n#\n\nCOMPONENT_SRCDIRS := \nCOMPONENT_ADD_INCLUDEDIRS := \n"
  },
  {
    "path": "components/mkspiffs/src/Makefile",
    "content": "CFLAGS\t\t?= -std=gnu99 -Os -Wall\nCXXFLAGS\t?= -std=gnu++11 -Os -Wall\n\nifeq ($(OS),Windows_NT)\n\tTARGET_OS := WINDOWS\n\tDIST_SUFFIX := windows\n\tARCHIVE_CMD := 7z a\n\tARCHIVE_EXTENSION := zip\n\tTARGET := mkspiffs.exe\n\tCC=gcc.exe\n\tCXX=g++.exe\n\tTARGET_CFLAGS := -mno-ms-bitfields\n\tTARGET_LDFLAGS := -Wl,-static -static-libgcc\n\nelse\n\tUNAME_S := $(shell uname -s)\n\tifeq ($(UNAME_S),Linux)\n\t\tTARGET_OS := LINUX\n\t\tUNAME_P := $(shell uname -p)\n\t\tifeq ($(UNAME_P),x86_64)\n\t\t\tDIST_SUFFIX := linux64\n\t\tendif\n\t\tifneq ($(filter %86,$(UNAME_P)),)\n\t\t\tDIST_SUFFIX := linux32\n\t\tendif\n\t\tCC=gcc\n\t\tCXX=g++\n\t\tTARGET_CFLAGS   = -std=gnu99 -Os -Wall -Itclap -Ispiffs -I. -D$(TARGET_OS) -DVERSION=\\\"$(VERSION)\\\" -D__NO_INLINE__\n\t\tTARGET_CXXFLAGS = -std=gnu++11 -Os -Wall -Itclap -Ispiffs -I. -D$(TARGET_OS) -DVERSION=\\\"$(VERSION)\\\" -D__NO_INLINE__\n\tendif\n\tifeq ($(UNAME_S),Darwin)\n\t\tTARGET_OS := OSX\n\t\tDIST_SUFFIX := osx\n\t\tCC=clang\n\t\tCXX=clang++\n\t\tTARGET_CFLAGS   = -std=gnu99 -Os -Wall -Itclap -Ispiffs -I. -D$(TARGET_OS) -DVERSION=\\\"$(VERSION)\\\" -D__NO_INLINE__ -mmacosx-version-min=10.7 -arch x86_64\n\t\tTARGET_CXXFLAGS = -std=gnu++11 -Os -Wall -Itclap -Ispiffs -I. -D$(TARGET_OS) -DVERSION=\\\"$(VERSION)\\\" -D__NO_INLINE__ -mmacosx-version-min=10.7 -arch x86_64 -stdlib=libc++\n\t\tTARGET_LDFLAGS  = -arch x86_64 -stdlib=libc++\n\tendif\n\tARCHIVE_CMD := tar czf\n\tARCHIVE_EXTENSION := tar.gz\n\tTARGET := mkspiffs\nendif\n\nOBJ             := main.o \\\n                   spiffs/spiffs_cache.o \\\n                   spiffs/spiffs_check.o \\\n                   spiffs/spiffs_gc.o \\\n                   spiffs/spiffs_hydrogen.o \\\n                   spiffs/spiffs_nucleus.o \\\n\t\t\t\t   \nVERSION ?= $(shell git describe --always)\n\n.PHONY: all clean\n\nall: $(TARGET)\n\n$(TARGET):\n\t@echo \"Building mkspiffs ...\"\n\t$(CC) $(TARGET_CFLAGS) -c spiffs/spiffs_cache.c -o spiffs/spiffs_cache.o\n\t$(CC) $(TARGET_CFLAGS) -c spiffs/spiffs_check.c -o spiffs/spiffs_check.o\n\t$(CC) $(TARGET_CFLAGS) -c spiffs/spiffs_gc.c -o spiffs/spiffs_gc.o\n\t$(CC) $(TARGET_CFLAGS) -c spiffs/spiffs_hydrogen.c -o spiffs/spiffs_hydrogen.o\n\t$(CC) $(TARGET_CFLAGS) -c spiffs/spiffs_nucleus.c -o spiffs/spiffs_nucleus.o\n\t$(CXX) $(TARGET_CXXFLAGS) -c main.cpp -o main.o\n\t$(CXX) $(TARGET_CFLAGS) -o $(TARGET) $(OBJ) $(TARGET_LDFLAGS)\n\t\nclean:\n\t@rm -f *.o\n\t@rm -f spiffs/*.o\n\t@rm -f $(TARGET)"
  },
  {
    "path": "components/mkspiffs/src/Makefile.original",
    "content": "CFLAGS\t\t?= -std=gnu99 -Os -Wall\nCXXFLAGS\t?= -std=gnu++11 -Os -Wall\n\nifeq ($(OS),Windows_NT)\n\tTARGET_OS := WINDOWS\n\tDIST_SUFFIX := windows\n\tARCHIVE_CMD := 7z a\n\tARCHIVE_EXTENSION := zip\n\tTARGET := mkspiffs.exe\n\tTARGET_CFLAGS := -mno-ms-bitfields\n\tTARGET_LDFLAGS := -Wl,-static -static-libgcc\n\nelse\n\tUNAME_S := $(shell uname -s)\n\tifeq ($(UNAME_S),Linux)\n\t\tTARGET_OS := LINUX\n\t\tUNAME_P := $(shell uname -p)\n\t\tifeq ($(UNAME_P),x86_64)\n\t\t\tDIST_SUFFIX := linux64\n\t\tendif\n\t\tifneq ($(filter %86,$(UNAME_P)),)\n\t\t\tDIST_SUFFIX := linux32\n\t\tendif\n\tendif\n\tifeq ($(UNAME_S),Darwin)\n\t\tTARGET_OS := OSX\n\t\tDIST_SUFFIX := osx\n\t\tCC=clang\n\t\tCXX=clang++\n\t\tTARGET_CFLAGS   = -mmacosx-version-min=10.7 -arch i386 -arch x86_64\n\t\tTARGET_CXXFLAGS = -mmacosx-version-min=10.7 -arch i386 -arch x86_64 -stdlib=libc++\n\t\tTARGET_LDFLAGS  = -arch i386 -arch x86_64 -stdlib=libc++\n\tendif\n\tARCHIVE_CMD := tar czf\n\tARCHIVE_EXTENSION := tar.gz\n\tTARGET := mkspiffs\nendif\n\nVERSION ?= $(shell git describe --always)\n\nOBJ\t\t:= main.o \\\n\t\t   spiffs/spiffs_cache.o \\\n\t\t   spiffs/spiffs_check.o \\\n\t\t   spiffs/spiffs_gc.o \\\n\t\t   spiffs/spiffs_hydrogen.o \\\n\t\t   spiffs/spiffs_nucleus.o \\\n\nINCLUDES := -Itclap -Ispiffs -I.\n\nCFLAGS   += $(TARGET_CFLAGS)\nCXXFLAGS += $(TARGET_CXXFLAGS)\nLDFLAGS  += $(TARGET_LDFLAGS)\n\nCPPFLAGS += $(INCLUDES) -D$(TARGET_OS) -DVERSION=\\\"$(VERSION)\\\" -D__NO_INLINE__\n\nDIST_NAME := mkspiffs-$(VERSION)-$(DIST_SUFFIX)\nDIST_DIR := $(DIST_NAME)\nDIST_ARCHIVE := $(DIST_NAME).$(ARCHIVE_EXTENSION)\n\n.PHONY: all clean dist\n\nall: $(TARGET)\n\ndist: test $(DIST_ARCHIVE)\n\n$(DIST_ARCHIVE): $(TARGET) $(DIST_DIR)\n\tcp $(TARGET) $(DIST_DIR)/\n\t$(ARCHIVE_CMD) $(DIST_ARCHIVE) $(DIST_DIR)\n\n$(TARGET): $(OBJ)\n\t$(CXX) $^ -o $@ $(LDFLAGS)\n\tstrip $(TARGET)\n\n$(DIST_DIR):\n\t@mkdir -p $@\n\nclean:\n\t@rm -f *.o\n\t@rm -f spiffs/*.o\n\t@rm -f $(TARGET)\n\nSPIFFS_TEST_FS_CONFIG := -s 0x100000 -p 512 -b 0x2000\n\ntest: $(TARGET)\n\tls -1 spiffs > out.list0\n\t./mkspiffs -c spiffs $(SPIFFS_TEST_FS_CONFIG) out.spiffs | sort | sed s/^\\\\/// > out.list1\n\t./mkspiffs -u spiffs_u $(SPIFFS_TEST_FS_CONFIG) out.spiffs | sort | sed s/^\\\\/// > out.list_u\n\t./mkspiffs -l $(SPIFFS_TEST_FS_CONFIG) out.spiffs | cut -f 2 | sort | sed s/^\\\\/// > out.list2\n\tdiff --strip-trailing-cr out.list0 out.list1\n\tdiff --strip-trailing-cr out.list0 out.list2\n\tdiff spiffs spiffs_u\n\trm -f out.{list0,list1,list2,list_u,spiffs}\n\trm -R spiffs_u\n"
  },
  {
    "path": "components/mkspiffs/src/README.md",
    "content": "# mkspiffs\nTool to build and unpack [SPIFFS](https://github.com/pellepl/spiffs) images.\n\n\n## Usage\n\n```\n\n   mkspiffs  {-c <pack_dir>|-u <dest_dir>|-l|-i} [-d <0-5>] [-b <number>]\n             [-p <number>] [-s <number>] [--] [--version] [-h]\n             <image_file>\n\n\nWhere: \n\n   -c <pack_dir>,  --create <pack_dir>\n     (OR required)  create spiffs image from a directory\n         -- OR --\n   -u <dest_dir>,  --unpack <dest_dir>\n     (OR required)  unpack spiffs image to a directory\n         -- OR --\n   -l,  --list\n     (OR required)  list files in spiffs image\n         -- OR --\n   -i,  --visualize\n     (OR required)  visualize spiffs image\n\n\n   -d <0-5>,  --debug <0-5>\n     Debug level. 0 means no debug output.\n\n   -b <number>,  --block <number>\n     fs block size, in bytes\n\n   -p <number>,  --page <number>\n     fs page size, in bytes\n\n   -s <number>,  --size <number>\n     fs image size, in bytes\n\n   --,  --ignore_rest\n     Ignores the rest of the labeled arguments following this flag.\n\n   --version\n     Displays version information and exits.\n\n   -h,  --help\n     Displays usage information and exits.\n\n   <image_file>\n     (required)  spiffs image file\n\n\n```\n## Build\n\nYou need gcc (≥4.8) or clang(≥600.0.57), and make. On Windows, use MinGW.\n\nRun:\n```bash\n$ make dist\n```\n\n### Build status\n\nLinux | Windows\n------|-------\n [![Linux build status](http://img.shields.io/travis/igrr/mkspiffs.svg)](https://travis-ci.org/igrr/mkspiffs) | [![Windows build status](http://img.shields.io/appveyor/ci/igrr/mkspiffs.svg)](https://ci.appveyor.com/project/igrr/mkspiffs)\n\n\n## License\n\nMIT\n\n## To do\n\n- [ ] Add more debug output and print SPIFFS debug output\n- [ ] Error handling\n- [ ] Determine the image size automatically when opening a file\n- [ ] Code cleanup\n"
  },
  {
    "path": "components/mkspiffs/src/appveyor.yml",
    "content": "version: 0.0.{build}\n\nplatform:\n    - x86\n\nskip_commits:\n  message: /\\[ci skip\\]/\n\nmatrix:\n    fast_finish: true\n\nbuild_script:\n    - SET PATH=C:\\MinGW\\bin;C:\\MinGW\\msys\\1.0\\bin;%PATH%\n    - make dist\n\nartifacts:\n  - path: '*.zip'\n\ndeploy:\n    release: $(PRODUCT_VERSION)\n    provider: GitHub\n    auth_token:\n        secure: 'PGg5fnoBpP1Omzr6f3KIYDiD8J30rretQjSl/MITRpzvSCmN88kM6VDMz1TBGZTA'\n    artifact: /.*\\.zip/\n    draft: true\n    prerelease: false\n    on:\n        appveyor_repo_tag: true\n"
  },
  {
    "path": "components/mkspiffs/src/main.cpp",
    "content": "//\n//  main.cpp\n//  make_spiffs\n//\n//  Created by Ivan Grokhotkov on 13/05/15.\n//  Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.\n//\n#define TCLAP_SETBASE_ZERO 1\n#define VERSION \"0.3.6\"\n\n#include <iostream>\n#include \"spiffs/spiffs.h\"\n#include <vector>\n#include <dirent.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <cstring>\n#include <string>\n#include <time.h>\n#include <memory>\n#include <cstdlib>\n#include \"tclap/CmdLine.h\"\n#include \"tclap/UnlabeledValueArg.h\"\n\nstatic std::vector<uint8_t> s_flashmem;\n\nstatic std::string s_dirName;\nstatic std::string s_imageName;\nstatic int s_imageSize;\nstatic int s_pageSize;\nstatic int s_blockSize;\n\ntypedef struct {\n\ttime_t mtime;\n\ttime_t ctime;\n\ttime_t atime;\n\tuint8_t spare[SPIFFS_OBJ_META_LEN - (sizeof(time_t)*3)];\n} spiffs_metadata_t;\n\nenum Action { ACTION_NONE, ACTION_PACK, ACTION_UNPACK, ACTION_LIST, ACTION_VISUALIZE };\nstatic Action s_action = ACTION_NONE;\n\nstatic spiffs s_fs;\n\nstatic std::vector<uint8_t> s_spiffsWorkBuf;\nstatic std::vector<uint8_t> s_spiffsFds;\nstatic std::vector<uint8_t> s_spiffsCache;\n\n\nstatic s32_t api_spiffs_read(u32_t addr, u32_t size, u8_t *dst){\n    memcpy(dst, &s_flashmem[0] + addr, size);\n    return SPIFFS_OK;\n}\n\nstatic s32_t api_spiffs_write(u32_t addr, u32_t size, u8_t *src){\n    memcpy(&s_flashmem[0] + addr, src, size);\n    return SPIFFS_OK;\n}\n\nstatic s32_t api_spiffs_erase(u32_t addr, u32_t size){\n    memset(&s_flashmem[0] + addr, 0xff, size);\n    return SPIFFS_OK;\n}\n\n\nint g_debugLevel = 0;\n\n\n//implementation\n\nint spiffsTryMount(){\n    spiffs_config cfg = {0};\n\n    cfg.phys_addr = 0x0000;\n    cfg.phys_size = (u32_t) s_flashmem.size();\n\n    cfg.phys_erase_block = s_blockSize;\n    cfg.log_block_size = s_blockSize;\n    cfg.log_page_size = s_pageSize;\n\n    cfg.hal_read_f = api_spiffs_read;\n    cfg.hal_write_f = api_spiffs_write;\n    cfg.hal_erase_f = api_spiffs_erase;\n\n    const int maxOpenFiles = 4;\n    s_spiffsWorkBuf.resize(s_pageSize * 2);\n    s_spiffsFds.resize(32 * maxOpenFiles);\n    s_spiffsCache.resize((32 + s_pageSize) * maxOpenFiles);\n\n    return SPIFFS_mount(&s_fs, &cfg,\n        &s_spiffsWorkBuf[0],\n        &s_spiffsFds[0], s_spiffsFds.size(),\n        &s_spiffsCache[0], s_spiffsCache.size(),\n        NULL);\n}\n\nbool spiffsMount(){\n  if(SPIFFS_mounted(&s_fs))\n    return true;\n  int res = spiffsTryMount();\n  return (res == SPIFFS_OK);\n}\n\nbool spiffsFormat(){\n  spiffsMount();\n  SPIFFS_unmount(&s_fs);\n  int formated = SPIFFS_format(&s_fs);\n  if(formated != SPIFFS_OK)\n    return false;\n  return (spiffsTryMount() == SPIFFS_OK);\n}\n\nvoid spiffsUnmount(){\n  if(SPIFFS_mounted(&s_fs))\n    SPIFFS_unmount(&s_fs);\n}\n\n// WHITECAT BEGIN\nint addDir(const char* name) {\n\tspiffs_metadata_t meta;\n\n\tstd::string fileName = name;\n    fileName += \"/.\";\n\n\tstd::cout << fileName << std::endl;\n\t\n    spiffs_file dst = SPIFFS_open(&s_fs, fileName.c_str(), SPIFFS_CREAT, 0);\n    if (dst < 0) {\n        std::cerr << \"SPIFFS_write error(\" << s_fs.err_code << \"): \";\n\n        if (s_fs.err_code == SPIFFS_ERR_FULL) {\n            std::cerr << \"File system is full.\" << std::endl;\n        } else {\n            std::cerr << \"unknown\";\n        }\n        std::cerr << std::endl;\n\n        SPIFFS_close(&s_fs, dst);\n        return 1;\n    }\n\n    SPIFFS_close(&s_fs, dst);\n    if (strlen(name) > 0) {\n\t\t// Get the system time to file timestamps\n\t\tmeta.atime = time(NULL);\n\t\tmeta.ctime = meta.atime;\n\t\tmeta.mtime = meta.atime;\n\t\tSPIFFS_update_meta(&s_fs, fileName.c_str(), &meta);\n\t}\n\n    return 0;\n}\n// WHITECAT END\n\nint addFile(char* name, const char* path) {\n\tspiffs_metadata_t meta;\n\n\tFILE* src = fopen(path, \"rb\");\n    if (!src) {\n        std::cerr << \"error: failed to open \" << path << \" for reading\" << std::endl;\n        return 1;\n    }\n\n    spiffs_file dst = SPIFFS_open(&s_fs, name, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);\n\n    // read file size\n    fseek(src, 0, SEEK_END);\n    size_t size = ftell(src);\n    fseek(src, 0, SEEK_SET);\n\n    if (g_debugLevel > 0) {\n        std::cout << \"file size: \" << size << std::endl;\n    }\n\n    size_t left = size;\n    uint8_t data_byte;\n    while (left > 0){\n        if (1 != fread(&data_byte, 1, 1, src)) {\n            std::cerr << \"fread error!\" << std::endl;\n\n            fclose(src);\n            SPIFFS_close(&s_fs, dst);\n            return 1;\n        }\n        int res = SPIFFS_write(&s_fs, dst, &data_byte, 1);\n        if (res < 0) {\n            std::cerr << \"SPIFFS_write error(\" << s_fs.err_code << \"): \";\n\n            if (s_fs.err_code == SPIFFS_ERR_FULL) {\n                std::cerr << \"File system is full.\" << std::endl;\n            } else {\n                std::cerr << \"unknown\";\n            }\n            std::cerr << std::endl;\n\n            if (g_debugLevel > 0) {\n                std::cout << \"data left: \" << left << std::endl;\n            }\n\n            fclose(src);\n            SPIFFS_close(&s_fs, dst);\n            return 1;\n        }\n        left -= 1;\n    }\n\n\tSPIFFS_close(&s_fs, dst);\n\n\t// Get the system time to file timestamps\n\tmeta.atime = time(NULL);\n\tmeta.ctime = meta.atime;\n\tmeta.mtime = meta.atime;\n\tSPIFFS_update_meta(&s_fs, name, &meta);\n\n    fclose(src);\n\n    return 0;\n}\n\nint addFiles(const char* dirname, const char* subPath) {\n    DIR *dir;\n    struct dirent *ent;\n    bool error = false;\n    std::string dirPath = dirname;\n    dirPath += subPath;\n\n    // Open directory\n    if ((dir = opendir (dirPath.c_str())) != NULL) {\n\n        // Read files from directory.\n        while ((ent = readdir (dir)) != NULL) {\n            // Ignore dir itself.\n            if (ent->d_name[0] == '.')\t\t\t\t\n                continue;            \t\n\n            std::string fullpath = dirPath;\n            fullpath += ent->d_name;\n            struct stat path_stat;\n            stat (fullpath.c_str(), &path_stat);\n\n            if (!S_ISREG(path_stat.st_mode)) {\n                // Check if path is a directory.\n                if (S_ISDIR(path_stat.st_mode)) {\n                    // Prepare new sub path.\n                    std::string newSubPath = subPath;\n                    newSubPath += ent->d_name;\n\t\t\t\t\t\n\t\t\t\t\t// WHITECAT BEGIN\n\t\t\t\t\taddDir(newSubPath.c_str());\n\t\t\t\t\t// WHITECAT END\n\t\t\t\t\t\n                    newSubPath += \"/\";\n\n                    if (addFiles(dirname, newSubPath.c_str()) != 0)\n                    {\n                        std::cerr << \"Error for adding content from \" << ent->d_name << \"!\" << std::endl;\n                    }\n\n                    continue;\n                }\n                else\n                {\n                    std::cerr << \"skipping \" << ent->d_name << std::endl;\n                    continue;\n                }\n            }\n\n            // Filepath with dirname as root folder.\n            std::string filepath = subPath;\n            filepath += ent->d_name;\n            std::cout << filepath << std::endl;\n\n            // Add File to image.\n            if (addFile((char*)filepath.c_str(), fullpath.c_str()) != 0) {\n                std::cerr << \"error adding file!\" << std::endl;\n                error = true;\n                if (g_debugLevel > 0) {\n                    std::cout << std::endl;\n                }\n                break;\n            }\n        } // end while\n        closedir (dir);\n    } else {\n        std::cerr << \"warning: can't read source directory\" << std::endl;\n        return 1;\n    }\n\n    return (error) ? 1 : 0;\n}\n\nvoid listFiles() {\n    spiffs_DIR dir;\n    spiffs_dirent ent;\n\n    SPIFFS_opendir(&s_fs, 0, &dir);\n    spiffs_dirent* it;\n    while (true) {\n        it = SPIFFS_readdir(&dir, &ent);\n        if (!it)\n            break;\n\n        std::cout << it->size << '\\t' << it->name << std::endl;\n    }\n    SPIFFS_closedir(&dir);\n}\n\n/**\n * @brief Check if directory exists.\n * @param path Directory path.\n * @return True if exists otherwise false.\n *\n * @author Pascal Gollor (http://www.pgollor.de/cms/)\n */\nbool dirExists(const char* path) {\n    DIR *d = opendir(path);\n\n    if (d) {\n        closedir(d);\n        return true;\n    }\n\n    return false;\n}\n\n/**\n * @brief Create directory if it not exists.\n * @param path Directory path.\n * @return True or false.\n *\n * @author Pascal Gollor (http://www.pgollor.de/cms/)\n */\nbool dirCreate(const char* path) {\n    // Check if directory also exists.\n    if (dirExists(path)) {\n\t    return false;\n    }\n\n    // platform stuff...\n#if defined(_WIN32)\n    if (_mkdir(path) != 0) {\n#else\n    if (mkdir(path, S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH) != 0) {\n#endif\n\t    std::cerr << \"Can not create directory!!!\" << std::endl;\n\t\treturn false;\n    }\n\n    return true;\n}\n\n/**\n * @brief Unpack file from file system.\n * @param spiffsFile SPIFFS dir entry pointer.\n * @param destPath Destination file path path.\n * @return True or false.\n *\n * @author Pascal Gollor (http://www.pgollor.de/cms/)\n */\nbool unpackFile(spiffs_dirent *spiffsFile, const char *destPath) {\n    u8_t buffer[spiffsFile->size];\n    std::string filename = (const char*)(spiffsFile->name);\n\n    // Open file from spiffs file system.\n    spiffs_file src = SPIFFS_open(&s_fs, (char *)(filename.c_str()), SPIFFS_RDONLY, 0);\n\n    // read content into buffer\n    SPIFFS_read(&s_fs, src, buffer, spiffsFile->size);\n\n    // Close spiffs file.\n    SPIFFS_close(&s_fs, src);\n\n    // Open file.\n    FILE* dst = fopen(destPath, \"wb\");\n\n    // Write content into file.\n    fwrite(buffer, sizeof(u8_t), sizeof(buffer), dst);\n\n    // Close file.\n    fclose(dst);\n\n\n    return true;\n}\n\n/**\n * @brief Unpack files from file system.\n * @param sDest Directory path as std::string.\n * @return True or false.\n *\n * @author Pascal Gollor (http://www.pgollor.de/cms/)\n *\n * todo: Do unpack stuff for directories.\n */\nbool unpackFiles(std::string sDest) {\n    spiffs_DIR dir;\n    spiffs_dirent ent;\n\n    // Add \"./\" to path if is not given.\n    if (sDest.find(\"./\") == std::string::npos && sDest.find(\"/\") == std::string::npos) {\n        sDest = \"./\" + sDest;\n    }\n\n    // Check if directory exists. If it does not then try to create it with permissions 755.\n    if (! dirExists(sDest.c_str())) {\n        std::cout << \"Directory \" << sDest << \" does not exists. Try to create it.\" << std::endl;\n\n        // Try to create directory.\n        if (! dirCreate(sDest.c_str())) {\n            return false;\n        }\n    }\n\n    // Open directory.\n    SPIFFS_opendir(&s_fs, 0, &dir);\n\n    // Read content from directory.\n    spiffs_dirent* it = SPIFFS_readdir(&dir, &ent);\n    while (it) {\n        // Check if content is a file.\n        if ((int)(it->type) == 1) {\n            std::string name = (const char*)(it->name);\n            std::string sDestFilePath = sDest + name;\n            size_t pos = name.find_last_of(\"/\");\n\n            // If file is in sub directory?\n            if (pos > 0) {\n                // Subdir path.\n                std::string path = sDest;\n                path += name.substr(0, pos);\n\n                // Create subddir if subdir not exists.\n                if (!dirExists(path.c_str())) {\n                    if (!dirCreate(path.c_str())) {\n                        return false;\n                    }\n                }\n            }\n\n            // Unpack file to destination directory.\n            if (! unpackFile(it, sDestFilePath.c_str()) ) {\n                std::cout << \"Can not unpack \" << it->name << \"!\" << std::endl;\n                return false;\n            }\n\n            // Output stuff.\n            std::cout\n                << it->name\n                << '\\t'\n                << \" > \" << sDestFilePath\n                << '\\t'\n                << \"size: \" << it->size << \" Bytes\"\n                << std::endl;\n        }\n\n        // Get next file handle.\n        it = SPIFFS_readdir(&dir, &ent);\n    } // end while\n\n    // Close directory.\n    SPIFFS_closedir(&dir);\n\n    return true;\n}\n\n// Actions\n\nint actionPack() {\n    s_flashmem.resize(s_imageSize, 0xff);\n\n    FILE* fdres = fopen(s_imageName.c_str(), \"wb\");\n    if (!fdres) {\n        std::cerr << \"error: failed to open image file\" << std::endl;\n        return 1;\n    }\n\n    spiffsFormat();\n\n\t// WHITECAT BEGIN\n\taddDir(\"\");\n\t// WHITECAT END\n\t\n    int result = addFiles(s_dirName.c_str(), \"/\");\n    spiffsUnmount();\n\n    fwrite(&s_flashmem[0], 4, s_flashmem.size()/4, fdres);\n    fclose(fdres);\n\n    return result;\n}\n\n/**\n * @brief Unpack action.\n * @return 0 success, 1 error\n *\n * @author Pascal Gollor (http://www.pgollor.de/cms/)\n */\nint actionUnpack(void) {\n    int ret = 0;\n    s_flashmem.resize(s_imageSize, 0xff);\n\n    // open spiffs image\n    FILE* fdsrc = fopen(s_imageName.c_str(), \"rb\");\n    if (!fdsrc) {\n        std::cerr << \"error: failed to open image file\" << std::endl;\n        return 1;\n    }\n\n    // read content into s_flashmem\n    ret = fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc);\n\n    // close fiel handle\n    fclose(fdsrc);\n\n    // mount file system\n    spiffsMount();\n\n    // unpack files\n    if (! unpackFiles(s_dirName)) {\n        ret = 1;\n    }\n\n    // unmount file system\n    spiffsUnmount();\n\n    return ret;\n}\n\n\nint actionList() {\n    int ret = 0;\n    s_flashmem.resize(s_imageSize, 0xff);\n\n    FILE* fdsrc = fopen(s_imageName.c_str(), \"rb\");\n    if (!fdsrc) {\n        std::cerr << \"error: failed to open image file\" << std::endl;\n        return 1;\n    }\n\n    ret = fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc);\n    fclose(fdsrc);\n    spiffsMount();\n    listFiles();\n    spiffsUnmount();\n    \n    ret = 0;\n    return ret;\n}\n\nint actionVisualize() {\n    int ret = 0;\n    s_flashmem.resize(s_imageSize, 0xff);\n\n    FILE* fdsrc = fopen(s_imageName.c_str(), \"rb\");\n    if (!fdsrc) {\n        std::cerr << \"error: failed to open image file\" << std::endl;\n        return 1;\n    }\n\n    ret = fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc);\n    fclose(fdsrc);\n\n    spiffsMount();\n    //SPIFFS_vis(&s_fs);\n    uint32_t total, used;\n    SPIFFS_info(&s_fs, &total, &used);\n    std::cout << \"total: \" << total <<  std::endl << \"used: \" << used << std::endl;\n    spiffsUnmount();\n\n    ret = 0;\n    return ret;\n}\n\nvoid processArgs(int argc, const char** argv) {\n    TCLAP::CmdLine cmd(\"\", ' ', VERSION);\n    TCLAP::ValueArg<std::string> packArg( \"c\", \"create\", \"create spiffs image from a directory\", true, \"\", \"pack_dir\");\n    TCLAP::ValueArg<std::string> unpackArg( \"u\", \"unpack\", \"unpack spiffs image to a directory\", true, \"\", \"dest_dir\");\n    TCLAP::SwitchArg listArg( \"l\", \"list\", \"list files in spiffs image\", false);\n    TCLAP::SwitchArg visualizeArg( \"i\", \"visualize\", \"visualize spiffs image\", false);\n    TCLAP::UnlabeledValueArg<std::string> outNameArg( \"image_file\", \"spiffs image file\", true, \"\", \"image_file\"  );\n    TCLAP::ValueArg<int> imageSizeArg( \"s\", \"size\", \"fs image size, in bytes\", false, 0x10000, \"number\" );\n    TCLAP::ValueArg<int> pageSizeArg( \"p\", \"page\", \"fs page size, in bytes\", false, 256, \"number\" );\n    TCLAP::ValueArg<int> blockSizeArg( \"b\", \"block\", \"fs block size, in bytes\", false, 4096, \"number\" );\n    TCLAP::ValueArg<int> debugArg( \"d\", \"debug\", \"Debug level. 0 means no debug output.\", false, 0, \"0-5\" );\n\n    cmd.add( imageSizeArg );\n    cmd.add( pageSizeArg );\n    cmd.add( blockSizeArg );\n    cmd.add(debugArg);\n    std::vector<TCLAP::Arg*> args = {&packArg, &unpackArg, &listArg, &visualizeArg};\n    cmd.xorAdd( args );\n    cmd.add( outNameArg );\n    cmd.parse( argc, argv );\n\n    if (debugArg.getValue() > 0) {\n        std::cout << \"Debug output enabled\" << std::endl;\n        g_debugLevel = debugArg.getValue();\n    }\n\n    if (packArg.isSet()) {\n        s_dirName = packArg.getValue();\n        s_action = ACTION_PACK;\n    } else if (unpackArg.isSet()) {\n        s_dirName = unpackArg.getValue();\n        s_action = ACTION_UNPACK;\n    } else if (listArg.isSet()) {\n        s_action = ACTION_LIST;\n    } else if (visualizeArg.isSet()) {\n        s_action = ACTION_VISUALIZE;\n    }\n\n    s_imageName = outNameArg.getValue();\n    s_imageSize = imageSizeArg.getValue();\n    s_pageSize  = pageSizeArg.getValue();\n    s_blockSize = blockSizeArg.getValue();\n}\n\nint main(int argc, const char * argv[]) {\n\n    try {\n        processArgs(argc, argv);\n    } catch(...) {\n        std::cerr << \"Invalid arguments\" << std::endl;\n        return 1;\n    }\n\n    switch (s_action) {\n    case ACTION_PACK:\n        return actionPack();\n        break;\n    case ACTION_UNPACK:\n    \treturn actionUnpack();\n        break;\n    case ACTION_LIST:\n        return actionList();\n        break;\n    case ACTION_VISUALIZE:\n        return actionVisualize();\n        break;\n    default:\n        break;\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/esp_spiffs.c",
    "content": "/*\n * Lua RTOS, SPIFFS low access\n *\n * Copyright (C) 2015 - 2017\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * \n * Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n * \n * All rights reserved.  \n *\n * Permission to use, copy, modify, and distribute this software\n * and its documentation for any purpose and without fee is hereby\n * granted, provided that the above copyright notice appear in all\n * copies and that both that the copyright notice and this\n * permission notice and warranty disclaimer appear in supporting\n * documentation, and that the name of the author not be used in\n * advertising or publicity pertaining to distribution of the\n * software without specific, written prior permission.\n *\n * The author disclaim all warranties with regard to this\n * software, including all implied warranties of merchantability\n * and fitness.  In no event shall the author be liable for any\n * special, indirect or consequential damages or any damages\n * whatsoever resulting from loss of use, data or profits, whether\n * in an action of contract, negligence or other tortious action,\n * arising out of or in connection with the use or performance of\n * this software.\n */\n\n#include <stdlib.h>\n\n#include \"esp_spiffs.h\"\n#include \"esp_attr.h\"\n\n#include \"spiffs.h\"\n\n#include <esp_spi_flash.h>\n\ns32_t esp32_spi_flash_read(u32_t addr, u32_t size, u8_t *dst) {\n\tu32_t aaddr;\n\tu8_t *buff = NULL;\n\tu8_t *abuff = NULL;\n\tu32_t asize;\n\n\tasize = size;\n\t\n\t// Align address to 4 byte\n\taaddr = (addr + (4 - 1)) & (u32_t)-4;\n\tif (aaddr != addr) {\n\t\taaddr -= 4;\n\t\tasize += (addr - aaddr);\n\t}\n\n\t// Align size to 4 byte\n\tasize = (asize + (4 - 1)) & (u32_t)-4;\n\n\tif ((aaddr != addr) || (asize != size)) {\n\t\t// Align buffer\n\t\tbuff = malloc(asize + 4);\n\t\tif (!buff) {\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tabuff = (u8_t *)(((ptrdiff_t)buff + (4 - 1)) & (u32_t)-4);\n\n\t\tif (spi_flash_read(aaddr, (void *)abuff, asize) != 0) {\n\t\t\tfree(buff);\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tmemcpy(dst, abuff + (addr - aaddr), size);\n\n\t\tfree(buff);\n\t} else {\n\t\tif (spi_flash_read(addr, (void *)dst, size) != 0) {\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\t}\n\t\n    return SPIFFS_OK;\n}\n\ns32_t esp32_spi_flash_write(u32_t addr, u32_t size, const u8_t *src) {\n\tu32_t aaddr;\n\tu8_t *buff = NULL;\n\tu8_t *abuff = NULL;\n\tu32_t asize;\n\n\tasize = size;\n\t\n\t// Align address to 4 byte\n\taaddr = (addr + (4 - 1)) & -4;\n\tif (aaddr != addr) {\n\t\taaddr -= 4;\n\t\tasize += (addr - aaddr);\n\t}\n\n\t// Align size to 4 byte\n\tasize = (asize + (4 - 1)) & -4; \n\n\tif ((aaddr != addr) || (asize != size)) {\n\t\t// Align buffer\n\t\tbuff = malloc(asize + 4);\n\t\tif (!buff) {\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tabuff = (u8_t *)(((ptrdiff_t)buff + (4 - 1)) & -4);\n\n\t\tif (spi_flash_read(aaddr, (void *)abuff, asize) != 0) {\n\t\t\tfree(buff);\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tmemcpy(abuff + (addr - aaddr), src, size);\n\n\t\tif (spi_flash_write(aaddr, (uint32_t *)abuff, asize) != 0) {\n\t\t\tfree(buff);\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tfree(buff);\n\t} else {\n\t\tif (spi_flash_write(addr, (uint32_t *)src, size) != 0) {\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\t}\n\t\n    return SPIFFS_OK;\n}\n\ns32_t IRAM_ATTR esp32_spi_flash_erase(u32_t addr, u32_t size) {\n\tif (spi_flash_erase_sector(addr >> 12) != 0) {\n\t\treturn SPIFFS_ERR_INTERNAL;\n\t}\n\t\n    return SPIFFS_OK;\n}\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/esp_spiffs.h",
    "content": "/*\n * Lua RTOS, write syscall implementation\n *\n * Copyright (C) 2015 - 2017\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * \n * Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n * \n * All rights reserved.  \n *\n * Permission to use, copy, modify, and distribute this software\n * and its documentation for any purpose and without fee is hereby\n * granted, provided that the above copyright notice appear in all\n * copies and that both that the copyright notice and this\n * permission notice and warranty disclaimer appear in supporting\n * documentation, and that the name of the author not be used in\n * advertising or publicity pertaining to distribution of the\n * software without specific, written prior permission.\n *\n * The author disclaim all warranties with regard to this\n * software, including all implied warranties of merchantability\n * and fitness.  In no event shall the author be liable for any\n * special, indirect or consequential damages or any damages\n * whatsoever resulting from loss of use, data or profits, whether\n * in an action of contract, negligence or other tortious action,\n * arising out of or in connection with the use or performance of\n * this software.\n */\n\n#ifndef __ESP_SPIFFS_H__\n#define __ESP_SPIFFS_H__\n\n#include \"spiffs.h\"\n\ns32_t esp32_spi_flash_read(u32_t addr, u32_t size, u8_t *dst);\ns32_t esp32_spi_flash_write(u32_t addr, u32_t size, const u8_t *src);\ns32_t esp32_spi_flash_erase(u32_t addr, u32_t size);\n\n#define low_spiffs_read  (spiffs_read *)esp32_spi_flash_read\n#define low_spiffs_write (spiffs_write *)esp32_spi_flash_write\n#define low_spiffs_erase (spiffs_erase *)esp32_spi_flash_erase\n\n#endif  // __ESP_SPIFFS_H__\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/spiffs.h",
    "content": "/*\n * spiffs.h\n *\n *  Created on: May 26, 2013\n *      Author: petera\n */\n\n#ifndef SPIFFS_H_\n#define SPIFFS_H_\n#if defined(__cplusplus)\nextern \"C\" {\n#endif\n\n#include \"spiffs_config.h\"\n\n#define SPIFFS_OK                       0\n#define SPIFFS_ERR_NOT_MOUNTED          -10000\n#define SPIFFS_ERR_FULL                 -10001\n#define SPIFFS_ERR_NOT_FOUND            -10002\n#define SPIFFS_ERR_END_OF_OBJECT        -10003\n#define SPIFFS_ERR_DELETED              -10004\n#define SPIFFS_ERR_NOT_FINALIZED        -10005\n#define SPIFFS_ERR_NOT_INDEX            -10006\n#define SPIFFS_ERR_OUT_OF_FILE_DESCS    -10007\n#define SPIFFS_ERR_FILE_CLOSED          -10008\n#define SPIFFS_ERR_FILE_DELETED         -10009\n#define SPIFFS_ERR_BAD_DESCRIPTOR       -10010\n#define SPIFFS_ERR_IS_INDEX             -10011\n#define SPIFFS_ERR_IS_FREE              -10012\n#define SPIFFS_ERR_INDEX_SPAN_MISMATCH  -10013\n#define SPIFFS_ERR_DATA_SPAN_MISMATCH   -10014\n#define SPIFFS_ERR_INDEX_REF_FREE       -10015\n#define SPIFFS_ERR_INDEX_REF_LU         -10016\n#define SPIFFS_ERR_INDEX_REF_INVALID    -10017\n#define SPIFFS_ERR_INDEX_FREE           -10018\n#define SPIFFS_ERR_INDEX_LU             -10019\n#define SPIFFS_ERR_INDEX_INVALID        -10020\n#define SPIFFS_ERR_NOT_WRITABLE         -10021\n#define SPIFFS_ERR_NOT_READABLE         -10022\n#define SPIFFS_ERR_CONFLICTING_NAME     -10023\n#define SPIFFS_ERR_NOT_CONFIGURED       -10024\n\n#define SPIFFS_ERR_NOT_A_FS             -10025\n#define SPIFFS_ERR_MOUNTED              -10026\n#define SPIFFS_ERR_ERASE_FAIL           -10027\n#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE   -10028\n\n#define SPIFFS_ERR_NO_DELETED_BLOCKS    -10029\n\n#define SPIFFS_ERR_FILE_EXISTS          -10030\n\n#define SPIFFS_ERR_NOT_A_FILE           -10031\n#define SPIFFS_ERR_RO_NOT_IMPL          -10032\n#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033\n#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034\n#define SPIFFS_ERR_PROBE_NOT_A_FS       -10035\n#define SPIFFS_ERR_NAME_TOO_LONG        -10036\n\n#define SPIFFS_ERR_IX_MAP_UNMAPPED      -10037\n#define SPIFFS_ERR_IX_MAP_MAPPED        -10038\n#define SPIFFS_ERR_IX_MAP_BAD_RANGE     -10039\n\n#define SPIFFS_ERR_INTERNAL             -10050\n\n#define SPIFFS_ERR_TEST                 -10100\n\n\n// spiffs file descriptor index type. must be signed\ntypedef s16_t spiffs_file;\n// spiffs file descriptor flags\ntypedef u16_t spiffs_flags;\n// spiffs file mode\ntypedef u16_t spiffs_mode;\n// object type\ntypedef u8_t spiffs_obj_type;\n\nstruct spiffs_t;\n\n#if SPIFFS_HAL_CALLBACK_EXTRA\n\n/* spi read call function type */\ntypedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);\n/* spi write call function type */\ntypedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);\n/* spi erase call function type */\ntypedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);\n\n#else // SPIFFS_HAL_CALLBACK_EXTRA\n\n/* spi read call function type */\ntypedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);\n/* spi write call function type */\ntypedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);\n/* spi erase call function type */\ntypedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);\n#endif // SPIFFS_HAL_CALLBACK_EXTRA\n\n/* file system check callback report operation */\ntypedef enum {\n  SPIFFS_CHECK_LOOKUP = 0,\n  SPIFFS_CHECK_INDEX,\n  SPIFFS_CHECK_PAGE\n} spiffs_check_type;\n\n/* file system check callback report type */\ntypedef enum {\n  SPIFFS_CHECK_PROGRESS = 0,\n  SPIFFS_CHECK_ERROR,\n  SPIFFS_CHECK_FIX_INDEX,\n  SPIFFS_CHECK_FIX_LOOKUP,\n  SPIFFS_CHECK_DELETE_ORPHANED_INDEX,\n  SPIFFS_CHECK_DELETE_PAGE,\n  SPIFFS_CHECK_DELETE_BAD_FILE\n} spiffs_check_report;\n\n/* file system check callback function */\n#if SPIFFS_HAL_CALLBACK_EXTRA\ntypedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,\n    u32_t arg1, u32_t arg2);\n#else // SPIFFS_HAL_CALLBACK_EXTRA\ntypedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,\n    u32_t arg1, u32_t arg2);\n#endif // SPIFFS_HAL_CALLBACK_EXTRA\n\n/* file system listener callback operation */\ntypedef enum {\n  /* the file has been created */\n  SPIFFS_CB_CREATED = 0,\n  /* the file has been updated or moved to another page */\n  SPIFFS_CB_UPDATED,\n  /* the file has been deleted */\n  SPIFFS_CB_DELETED\n} spiffs_fileop_type;\n\n/* file system listener callback function */\ntypedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix);\n\n#ifndef SPIFFS_DBG\n#define SPIFFS_DBG(...) \\\n    printf(__VA_ARGS__)\n#endif\n#ifndef SPIFFS_GC_DBG\n#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)\n#endif\n#ifndef SPIFFS_CACHE_DBG\n#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)\n#endif\n#ifndef SPIFFS_CHECK_DBG\n#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)\n#endif\n\n/* Any write to the filehandle is appended to end of the file */\n#define SPIFFS_APPEND                   (1<<0)\n#define SPIFFS_O_APPEND                 SPIFFS_APPEND\n/* If the opened file exists, it will be truncated to zero length before opened */\n#define SPIFFS_TRUNC                    (1<<1)\n#define SPIFFS_O_TRUNC                  SPIFFS_TRUNC\n/* If the opened file does not exist, it will be created before opened */\n#define SPIFFS_CREAT                    (1<<2)\n#define SPIFFS_O_CREAT                  SPIFFS_CREAT\n/* The opened file may only be read */\n#define SPIFFS_RDONLY                   (1<<3)\n#define SPIFFS_O_RDONLY                 SPIFFS_RDONLY\n/* The opened file may only be written */\n#define SPIFFS_WRONLY                   (1<<4)\n#define SPIFFS_O_WRONLY                 SPIFFS_WRONLY\n/* The opened file may be both read and written */\n#define SPIFFS_RDWR                     (SPIFFS_RDONLY | SPIFFS_WRONLY)\n#define SPIFFS_O_RDWR                   SPIFFS_RDWR\n/* Any writes to the filehandle will never be cached but flushed directly */\n#define SPIFFS_DIRECT                   (1<<5)\n#define SPIFFS_O_DIRECT                 SPIFFS_DIRECT\n/* If SPIFFS_O_CREAT and SPIFFS_O_EXCL are set, SPIFFS_open() shall fail if the file exists */\n#define SPIFFS_EXCL                     (1<<6)\n#define SPIFFS_O_EXCL                   SPIFFS_EXCL\n\n#define SPIFFS_SEEK_SET                 (0)\n#define SPIFFS_SEEK_CUR                 (1)\n#define SPIFFS_SEEK_END                 (2)\n\n#define SPIFFS_TYPE_FILE                (1)\n#define SPIFFS_TYPE_DIR                 (2)\n#define SPIFFS_TYPE_HARD_LINK           (3)\n#define SPIFFS_TYPE_SOFT_LINK           (4)\n\n#ifndef SPIFFS_LOCK\n#define SPIFFS_LOCK(fs)\n#endif\n\n#ifndef SPIFFS_UNLOCK\n#define SPIFFS_UNLOCK(fs)\n#endif\n\n// phys structs\n\n// spiffs spi configuration struct\ntypedef struct {\n  // physical read function\n  spiffs_read hal_read_f;\n  // physical write function\n  spiffs_write hal_write_f;\n  // physical erase function\n  spiffs_erase hal_erase_f;\n#if SPIFFS_SINGLETON == 0\n  // physical size of the spi flash\n  u32_t phys_size;\n  // physical offset in spi flash used for spiffs,\n  // must be on block boundary\n  u32_t phys_addr;\n  // physical size when erasing a block\n  u32_t phys_erase_block;\n\n  // logical size of a block, must be on physical\n  // block size boundary and must never be less than\n  // a physical block\n  u32_t log_block_size;\n  // logical size of a page, must be at least\n  // log_block_size / 8\n  u32_t log_page_size;\n\n#endif\n#if SPIFFS_FILEHDL_OFFSET\n  // an integer offset added to each file handle\n  u16_t fh_ix_offset;\n#endif\n} spiffs_config;\n\ntypedef struct spiffs_t {\n  // file system configuration\n  spiffs_config cfg;\n  // number of logical blocks\n  u32_t block_count;\n\n  // cursor for free blocks, block index\n  spiffs_block_ix free_cursor_block_ix;\n  // cursor for free blocks, entry index\n  int free_cursor_obj_lu_entry;\n  // cursor when searching, block index\n  spiffs_block_ix cursor_block_ix;\n  // cursor when searching, entry index\n  int cursor_obj_lu_entry;\n\n  // primary work buffer, size of a logical page\n  u8_t *lu_work;\n  // secondary work buffer, size of a logical page\n  u8_t *work;\n  // file descriptor memory area\n  u8_t *fd_space;\n  // available file descriptors\n  u32_t fd_count;\n\n  // last error\n  s32_t err_code;\n\n  // current number of free blocks\n  u32_t free_blocks;\n  // current number of busy pages\n  u32_t stats_p_allocated;\n  // current number of deleted pages\n  u32_t stats_p_deleted;\n  // flag indicating that garbage collector is cleaning\n  u8_t cleaning;\n  // max erase count amongst all blocks\n  spiffs_obj_id max_erase_count;\n\n#if SPIFFS_GC_STATS\n  u32_t stats_gc_runs;\n#endif\n\n#if SPIFFS_CACHE\n  // cache memory\n  void *cache;\n  // cache size\n  u32_t cache_size;\n#if SPIFFS_CACHE_STATS\n  u32_t cache_hits;\n  u32_t cache_misses;\n#endif\n#endif\n\n  // check callback function\n  spiffs_check_callback check_cb_f;\n  // file callback function\n  spiffs_file_callback file_cb_f;\n  // mounted flag\n  u8_t mounted;\n  // user data\n  void *user_data;\n  // config magic\n  u32_t config_magic;\n} spiffs;\n\n/* spiffs file status struct */\ntypedef struct {\n  spiffs_obj_id obj_id;\n  u32_t size;\n  spiffs_obj_type type;\n  spiffs_page_ix pix;\n  u8_t name[SPIFFS_OBJ_NAME_LEN];\n#if SPIFFS_OBJ_META_LEN\n  u8_t meta[SPIFFS_OBJ_META_LEN];\n#endif\n} spiffs_stat;\n\nstruct spiffs_dirent {\n  spiffs_obj_id obj_id;\n  u8_t name[SPIFFS_OBJ_NAME_LEN];\n  spiffs_obj_type type;\n  u32_t size;\n  spiffs_page_ix pix;\n#if SPIFFS_OBJ_META_LEN\n  u8_t meta[SPIFFS_OBJ_META_LEN];\n#endif\n};\n\ntypedef struct {\n  spiffs *fs;\n  spiffs_block_ix block;\n  int entry;\n} spiffs_DIR;\n\n#if SPIFFS_IX_MAP\n\ntypedef struct {\n  // buffer with looked up data pixes\n  spiffs_page_ix *map_buf;\n  // precise file byte offset\n  u32_t offset;\n  // start data span index of lookup buffer\n  spiffs_span_ix start_spix;\n  // end data span index of lookup buffer\n  spiffs_span_ix end_spix;\n} spiffs_ix_map;\n\n#endif\n\n// functions\n\n#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n/**\n * Special function. This takes a spiffs config struct and returns the number\n * of blocks this file system was formatted with. This function relies on\n * that following info is set correctly in given config struct:\n *\n * phys_addr, log_page_size, and log_block_size.\n *\n * Also, hal_read_f must be set in the config struct.\n *\n * One must be sure of the correct page size and that the physical address is\n * correct in the probed file system when calling this function. It is not\n * checked if the phys_addr actually points to the start of the file system,\n * so one might get a false positive if entering a phys_addr somewhere in the\n * middle of the file system at block boundary. In addition, it is not checked\n * if the page size is actually correct. If it is not, weird file system sizes\n * will be returned.\n *\n * If this function detects a file system it returns the assumed file system\n * size, which can be used to set the phys_size.\n *\n * Otherwise, it returns an error indicating why it is not regarded as a file\n * system.\n *\n * Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK\n * macros. It returns the error code directly, instead of as read by\n * SPIFFS_errno.\n *\n * @param config        essential parts of the physical and logical\n *                      configuration of the file system.\n */\ns32_t SPIFFS_probe_fs(spiffs_config *config);\n#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n\n/**\n * Initializes the file system dynamic parameters and mounts the filesystem.\n * If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS\n * if the flash does not contain a recognizable file system.\n * In this case, SPIFFS_format must be called prior to remounting.\n * @param fs            the file system struct\n * @param config        the physical and logical configuration of the file system\n * @param work          a memory work buffer comprising 2*config->log_page_size\n *                      bytes used throughout all file system operations\n * @param fd_space      memory for file descriptors\n * @param fd_space_size memory size of file descriptors\n * @param cache         memory for cache, may be null\n * @param cache_size    memory size of cache\n * @param check_cb_f    callback function for reporting during consistency checks\n */\ns32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,\n    u8_t *fd_space, u32_t fd_space_size,\n    void *cache, u32_t cache_size,\n    spiffs_check_callback check_cb_f);\n\n/**\n * Unmounts the file system. All file handles will be flushed of any\n * cached writes and closed.\n * @param fs            the file system struct\n */\nvoid SPIFFS_unmount(spiffs *fs);\n\n/**\n * Creates a new file.\n * @param fs            the file system struct\n * @param path          the path of the new file\n * @param mode          ignored, for posix compliance\n */\ns32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);\n\n/**\n * Opens/creates a file.\n * @param fs            the file system struct\n * @param path          the path of the new file\n * @param flags         the flags for the open command, can be combinations of\n *                      SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,\n *                      SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL\n * @param mode          ignored, for posix compliance\n */\nspiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);\n\n/**\n * Opens a file by given dir entry.\n * Optimization purposes, when traversing a file system with SPIFFS_readdir\n * a normal SPIFFS_open would need to traverse the filesystem again to find\n * the file, whilst SPIFFS_open_by_dirent already knows where the file resides.\n * @param fs            the file system struct\n * @param e             the dir entry to the file\n * @param flags         the flags for the open command, can be combinations of\n *                      SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,\n *                      SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.\n *                      SPIFFS_CREAT will have no effect in this case.\n * @param mode          ignored, for posix compliance\n */\nspiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);\n\n/**\n * Opens a file by given page index.\n * Optimization purposes, opens a file by directly pointing to the page\n * index in the spi flash.\n * If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE\n * is returned.\n * @param fs            the file system struct\n * @param page_ix       the page index\n * @param flags         the flags for the open command, can be combinations of\n *                      SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,\n *                      SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.\n *                      SPIFFS_CREAT will have no effect in this case.\n * @param mode          ignored, for posix compliance\n */\nspiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);\n\n/**\n * Reads from given filehandle.\n * @param fs            the file system struct\n * @param fh            the filehandle\n * @param buf           where to put read data\n * @param len           how much to read\n * @returns number of bytes read, or -1 if error\n */\ns32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);\n\n/**\n * Writes to given filehandle.\n * @param fs            the file system struct\n * @param fh            the filehandle\n * @param buf           the data to write\n * @param len           how much to write\n * @returns number of bytes written, or -1 if error\n */\ns32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);\n\n/**\n * Moves the read/write file offset. Resulting offset is returned or negative if error.\n * lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.\n * @param fs            the file system struct\n * @param fh            the filehandle\n * @param offs          how much/where to move the offset\n * @param whence        if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes\n *                      if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset\n *                      if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative\n */\ns32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);\n\n/**\n * Removes a file by path\n * @param fs            the file system struct\n * @param path          the path of the file to remove\n */\ns32_t SPIFFS_remove(spiffs *fs, const char *path);\n\n/**\n * Removes a file by filehandle\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to remove\n */\ns32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);\n\n/**\n * Gets file status by path\n * @param fs            the file system struct\n * @param path          the path of the file to stat\n * @param s             the stat struct to populate\n */\ns32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);\n\n/**\n * Gets file status by filehandle\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to stat\n * @param s             the stat struct to populate\n */\ns32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);\n\n/**\n * Flushes all pending write operations from cache for given file\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to flush\n */\ns32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);\n\n/**\n * Closes a filehandle. If there are pending write operations, these are finalized before closing.\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to close\n */\ns32_t SPIFFS_close(spiffs *fs, spiffs_file fh);\n\n/**\n * Renames a file\n * @param fs            the file system struct\n * @param old           path of file to rename\n * @param newPath       new path of file\n */\ns32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);\n\n#if SPIFFS_OBJ_META_LEN\n/**\n * Updates file's metadata\n * @param fs            the file system struct\n * @param path          path to the file\n * @param meta          new metadata. must be SPIFFS_OBJ_META_LEN bytes long.\n */\ns32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta);\n\n/**\n * Updates file's metadata\n * @param fs            the file system struct\n * @param fh            file handle of the file\n * @param meta          new metadata. must be SPIFFS_OBJ_META_LEN bytes long.\n */\ns32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta);\n#endif\n\n/**\n * Returns last error of last file operation.\n * @param fs            the file system struct\n */\ns32_t SPIFFS_errno(spiffs *fs);\n\n/**\n * Clears last error.\n * @param fs            the file system struct\n */\nvoid SPIFFS_clearerr(spiffs *fs);\n\n/**\n * Opens a directory stream corresponding to the given name.\n * The stream is positioned at the first entry in the directory.\n * On hydrogen builds the name argument is ignored as hydrogen builds always correspond\n * to a flat file structure - no directories.\n * @param fs            the file system struct\n * @param name          the name of the directory\n * @param d             pointer the directory stream to be populated\n */\nspiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);\n\n/**\n * Closes a directory stream\n * @param d             the directory stream to close\n */\ns32_t SPIFFS_closedir(spiffs_DIR *d);\n\n/**\n * Reads a directory into given spifs_dirent struct.\n * @param d             pointer to the directory stream\n * @param e             the dirent struct to be populated\n * @returns null if error or end of stream, else given dirent is returned\n */\nstruct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);\n\n/**\n * Runs a consistency check on given filesystem.\n * @param fs            the file system struct\n */\ns32_t SPIFFS_check(spiffs *fs);\n\n/**\n * Returns number of total bytes available and number of used bytes.\n * This is an estimation, and depends on if there a many files with little\n * data or few files with much data.\n * NB: If used number of bytes exceeds total bytes, a SPIFFS_check should\n * run. This indicates a power loss in midst of things. In worst case\n * (repeated powerlosses in mending or gc) you might have to delete some files.\n *\n * @param fs            the file system struct\n * @param total         total number of bytes in filesystem\n * @param used          used number of bytes in filesystem\n */\ns32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);\n\n/**\n * Formats the entire file system. All data will be lost.\n * The filesystem must not be mounted when calling this.\n *\n * NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount\n * MUST be called prior to formatting in order to configure the filesystem.\n * If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling\n * SPIFFS_format.\n * If SPIFFS_mount fails, SPIFFS_format can be called directly without calling\n * SPIFFS_unmount first.\n *\n * @param fs            the file system struct\n */\ns32_t SPIFFS_format(spiffs *fs);\n\n/**\n * Returns nonzero if spiffs is mounted, or zero if unmounted.\n * @param fs            the file system struct\n */\nu8_t SPIFFS_mounted(spiffs *fs);\n\n/**\n * Tries to find a block where most or all pages are deleted, and erase that\n * block if found. Does not care for wear levelling. Will not move pages\n * around.\n * If parameter max_free_pages are set to 0, only blocks with only deleted\n * pages will be selected.\n *\n * NB: the garbage collector is automatically called when spiffs needs free\n * pages. The reason for this function is to give possibility to do background\n * tidying when user knows the system is idle.\n *\n * Use with care.\n *\n * Setting max_free_pages to anything larger than zero will eventually wear\n * flash more as a block containing free pages can be erased.\n *\n * Will set err_no to SPIFFS_OK if a block was found and erased,\n * SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,\n * or other error.\n *\n * @param fs             the file system struct\n * @param max_free_pages maximum number allowed free pages in block\n */\ns32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);\n\n/**\n * Will try to make room for given amount of bytes in the filesystem by moving\n * pages and erasing blocks.\n * If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If\n * there already is this amount (or more) of free space, SPIFFS_gc will\n * silently return. It is recommended to call SPIFFS_info before invoking\n * this method in order to determine what amount of bytes to give.\n *\n * NB: the garbage collector is automatically called when spiffs needs free\n * pages. The reason for this function is to give possibility to do background\n * tidying when user knows the system is idle.\n *\n * Use with care.\n *\n * @param fs            the file system struct\n * @param size          amount of bytes that should be freed\n */\ns32_t SPIFFS_gc(spiffs *fs, u32_t size);\n\n/**\n * Check if EOF reached.\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to check\n */\ns32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);\n\n/**\n * Get position in file.\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to check\n */\ns32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);\n\n/**\n * Registers a callback function that keeps track on operations on file\n * headers. Do note, that this callback is called from within internal spiffs\n * mechanisms. Any operations on the actual file system being callbacked from\n * in this callback will mess things up for sure - do not do this.\n * This can be used to track where files are and move around during garbage\n * collection, which in turn can be used to build location tables in ram.\n * Used in conjuction with SPIFFS_open_by_page this may improve performance\n * when opening a lot of files.\n * Must be invoked after mount.\n *\n * @param fs            the file system struct\n * @param cb_func       the callback on file operations\n */\ns32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);\n\n#if SPIFFS_IX_MAP\n\n/**\n * Maps the first level index lookup to a given memory map.\n * This will make reading big files faster, as the memory map will be used for\n * looking up data pages instead of searching for the indices on the physical\n * medium. When mapping, all affected indicies are found and the information is\n * copied to the array.\n * Whole file or only parts of it may be mapped. The index map will cover file\n * contents from argument offset until and including arguments (offset+len).\n * It is valid to map a longer range than the current file size. The map will\n * then be populated when the file grows.\n * On garbage collections and file data page movements, the map array will be\n * automatically updated. Do not tamper with the map array, as this contains\n * the references to the data pages. Modifying it from outside will corrupt any\n * future readings using this file descriptor.\n * The map will no longer be used when the file descriptor closed or the file\n * is unmapped.\n * This can be useful to get faster and more deterministic timing when reading\n * large files, or when seeking and reading a lot within a file.\n * @param fs      the file system struct\n * @param fh      the file handle of the file to map\n * @param map     a spiffs_ix_map struct, describing the index map\n * @param offset  absolute file offset where to start the index map\n * @param len     length of the mapping in actual file bytes\n * @param map_buf the array buffer for the look up data - number of required\n *                elements in the array can be derived from function\n *                SPIFFS_bytes_to_ix_map_entries given the length\n */\ns32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,\n    u32_t offset, u32_t len, spiffs_page_ix *map_buf);\n\n/**\n * Unmaps the index lookup from this filehandle. All future readings will\n * proceed as normal, requiring reading of the first level indices from\n * physical media.\n * The map and map buffer given in function SPIFFS_ix_map will no longer be\n * referenced by spiffs.\n * It is not strictly necessary to unmap a file before closing it, as closing\n * a file will automatically unmap it.\n * @param fs      the file system struct\n * @param fh      the file handle of the file to unmap\n */\ns32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh);\n\n/**\n * Moves the offset for the index map given in function SPIFFS_ix_map. Parts or\n * all of the map buffer will repopulated.\n * @param fs      the file system struct\n * @param fh      the mapped file handle of the file to remap\n * @param offset  new absolute file offset where to start the index map\n */\ns32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs);\n\n/**\n * Utility function to get number of spiffs_page_ix entries a map buffer must\n * contain on order to map given amount of file data in bytes.\n * See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.\n * @param fs      the file system struct\n * @param bytes   number of file data bytes to map\n * @return        needed number of elements in a spiffs_page_ix array needed to\n *                map given amount of bytes in a file\n */\ns32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes);\n\n/**\n * Utility function to amount of file data bytes that can be mapped when\n * mapping a file with buffer having given number of spiffs_page_ix entries.\n * See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.\n * @param fs      the file system struct\n * @param map_page_ix_entries   number of entries in a spiffs_page_ix array\n * @return        amount of file data in bytes that can be mapped given a map\n *                buffer having given amount of spiffs_page_ix entries\n */\ns32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);\n\n#endif // SPIFFS_IX_MAP\n\n\n#if SPIFFS_TEST_VISUALISATION\n/**\n * Prints out a visualization of the filesystem.\n * @param fs            the file system struct\n */\ns32_t SPIFFS_vis(spiffs *fs);\n#endif\n\n#if SPIFFS_BUFFER_HELP\n/**\n * Returns number of bytes needed for the filedescriptor buffer given\n * amount of file descriptors.\n */\nu32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);\n\n#if SPIFFS_CACHE\n/**\n * Returns number of bytes needed for the cache buffer given\n * amount of cache pages.\n */\nu32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);\n#endif\n#endif\n\n#if SPIFFS_CACHE\n#endif\n#if defined(__cplusplus)\n}\n#endif\n\n#endif /* SPIFFS_H_ */\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/spiffs_cache.c",
    "content": "/*\n * spiffs_cache.c\n *\n *  Created on: Jun 23, 2013\n *      Author: petera\n */\n\n#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\n#if SPIFFS_CACHE\n\n// returns cached page for give page index, or null if no such cached page\nstatic spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;\n  int i;\n  for (i = 0; i < cache->cpage_count; i++) {\n    spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);\n    if ((cache->cpage_use_map & (1<<i)) &&\n        (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&\n        cp->pix == pix ) {\n      SPIFFS_CACHE_DBG(\"CACHE_GET: have cache page \"_SPIPRIi\" for \"_SPIPRIpg\"\\n\", i, pix);\n      cp->last_access = cache->last_access;\n      return cp;\n    }\n  }\n  //SPIFFS_CACHE_DBG(\"CACHE_GET: no cache for \"_SPIPRIpg\"\\n\", pix);\n  return 0;\n}\n\n// frees cached page\nstatic s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {\n  s32_t res = SPIFFS_OK;\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);\n  if (cache->cpage_use_map & (1<<ix)) {\n    if (write_back &&\n        (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&\n        (cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {\n      u8_t *mem =  spiffs_get_cache_page(fs, cache, ix);\n      res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);\n    }\n\n    cp->flags = 0;\n    cache->cpage_use_map &= ~(1 << ix);\n\n    if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {\n      SPIFFS_CACHE_DBG(\"CACHE_FREE: free cache page \"_SPIPRIi\" objid \"_SPIPRIid\"\\n\", ix, cp->obj_id);\n    } else {\n      SPIFFS_CACHE_DBG(\"CACHE_FREE: free cache page \"_SPIPRIi\" pix \"_SPIPRIpg\"\\n\", ix, cp->pix);\n    }\n  }\n\n  return res;\n}\n\n// removes the oldest accessed cached page\nstatic s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {\n  s32_t res = SPIFFS_OK;\n  spiffs_cache *cache = spiffs_get_cache(fs);\n\n  if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {\n    // at least one free cpage\n    return SPIFFS_OK;\n  }\n\n  // all busy, scan thru all to find the cpage which has oldest access\n  int i;\n  int cand_ix = -1;\n  u32_t oldest_val = 0;\n  for (i = 0; i < cache->cpage_count; i++) {\n    spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);\n    if ((cache->last_access - cp->last_access) > oldest_val &&\n        (cp->flags & flag_mask) == flags) {\n      oldest_val = cache->last_access - cp->last_access;\n      cand_ix = i;\n    }\n  }\n\n  if (cand_ix >= 0) {\n    res = spiffs_cache_page_free(fs, cand_ix, 1);\n  }\n\n  return res;\n}\n\n// allocates a new cached page and returns it, or null if all cache pages are busy\nstatic spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  if (cache->cpage_use_map == 0xffffffff) {\n    // out of cache memory\n    return 0;\n  }\n  int i;\n  for (i = 0; i < cache->cpage_count; i++) {\n    if ((cache->cpage_use_map & (1<<i)) == 0) {\n      spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);\n      cache->cpage_use_map |= (1<<i);\n      cp->last_access = cache->last_access;\n      SPIFFS_CACHE_DBG(\"CACHE_ALLO: allocated cache page \"_SPIPRIi\"\\n\", i);\n      return cp;\n    }\n  }\n  // out of cache entries\n  return 0;\n}\n\n// drops the cache page for give page index\nvoid spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {\n  spiffs_cache_page *cp =  spiffs_cache_page_get(fs, pix);\n  if (cp) {\n    spiffs_cache_page_free(fs, cp->ix, 0);\n  }\n}\n\n// ------------------------------\n\n// reads from spi flash or the cache\ns32_t spiffs_phys_rd(\n    spiffs *fs,\n    u8_t op,\n    spiffs_file fh,\n    u32_t addr,\n    u32_t len,\n    u8_t *dst) {\n  (void)fh;\n  s32_t res = SPIFFS_OK;\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  spiffs_cache_page *cp =  spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));\n  cache->last_access++;\n  if (cp) {\n    // we've already got one, you see\n#if SPIFFS_CACHE_STATS\n    fs->cache_hits++;\n#endif\n    cp->last_access = cache->last_access;\n    u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);\n    memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);\n  } else {\n    if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {\n      // for second layer lookup functions, we do not cache in order to prevent shredding\n      return SPIFFS_HAL_READ(fs, addr, len, dst);\n    }\n#if SPIFFS_CACHE_STATS\n    fs->cache_misses++;\n#endif\n    // this operation will always free one cache page (unless all already free),\n    // the result code stems from the write operation of the possibly freed cache page\n    res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);\n\n    cp = spiffs_cache_page_allocate(fs);\n    if (cp) {\n      cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;\n      cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);\n\n      s32_t res2 = SPIFFS_HAL_READ(fs,\n          addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),\n          SPIFFS_CFG_LOG_PAGE_SZ(fs),\n          spiffs_get_cache_page(fs, cache, cp->ix));\n      if (res2 != SPIFFS_OK) {\n        // honor read failure before possible write failure (bad idea?)\n        res = res2;\n      }\n      u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);\n      memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);\n    } else {\n      // this will never happen, last resort for sake of symmetry\n      s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);\n      if (res2 != SPIFFS_OK) {\n        // honor read failure before possible write failure (bad idea?)\n        res = res2;\n      }\n    }\n  }\n  return res;\n}\n\n// writes to spi flash and/or the cache\ns32_t spiffs_phys_wr(\n    spiffs *fs,\n    u8_t op,\n    spiffs_file fh,\n    u32_t addr,\n    u32_t len,\n    u8_t *src) {\n  (void)fh;\n  spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  spiffs_cache_page *cp =  spiffs_cache_page_get(fs, pix);\n\n  if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {\n    // have a cache page\n    // copy in data to cache page\n\n    if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&\n        (op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {\n      // page is being deleted, wipe from cache - unless it is a lookup page\n      spiffs_cache_page_free(fs, cp->ix, 0);\n      return SPIFFS_HAL_WRITE(fs, addr, len, src);\n    }\n\n    u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);\n    memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);\n\n    cache->last_access++;\n    cp->last_access = cache->last_access;\n\n    if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {\n      // page is being updated, no write-cache, just pass thru\n      return SPIFFS_HAL_WRITE(fs, addr, len, src);\n    } else {\n      return SPIFFS_OK;\n    }\n  } else {\n    // no cache page, no write cache - just write thru\n    return SPIFFS_HAL_WRITE(fs, addr, len, src);\n  }\n}\n\n#if SPIFFS_CACHE_WR\n// returns the cache page that this fd refers, or null if no cache page\nspiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {\n  spiffs_cache *cache = spiffs_get_cache(fs);\n\n  if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {\n    // all cpages free, no cpage cannot be assigned to obj_id\n    return 0;\n  }\n\n  int i;\n  for (i = 0; i < cache->cpage_count; i++) {\n    spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);\n    if ((cache->cpage_use_map & (1<<i)) &&\n        (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&\n        cp->obj_id == fd->obj_id) {\n      return cp;\n    }\n  }\n\n  return 0;\n}\n\n// allocates a new cache page and refers this to given fd - flushes an old cache\n// page if all cache is busy\nspiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {\n  // before this function is called, it is ensured that there is no already existing\n  // cache page with same object id\n  spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);\n  spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);\n  if (cp == 0) {\n    // could not get cache page\n    return 0;\n  }\n\n  cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;\n  cp->obj_id = fd->obj_id;\n  fd->cache_page = cp;\n  return cp;\n}\n\n// unrefers all fds that this cache page refers to and releases the cache page\nvoid spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {\n  if (cp == 0) return;\n  u32_t i;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {\n      cur_fd->cache_page = 0;\n    }\n  }\n  spiffs_cache_page_free(fs, cp->ix, 0);\n\n  cp->obj_id = 0;\n}\n\n#endif\n\n// initializes the cache\nvoid spiffs_cache_init(spiffs *fs) {\n  if (fs->cache == 0) return;\n  u32_t sz = fs->cache_size;\n  u32_t cache_mask = 0;\n  int i;\n  int cache_entries =\n      (sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));\n  if (cache_entries <= 0) return;\n\n  for (i = 0; i < cache_entries; i++) {\n    cache_mask <<= 1;\n    cache_mask |= 1;\n  }\n\n  spiffs_cache cache;\n  memset(&cache, 0, sizeof(spiffs_cache));\n  cache.cpage_count = cache_entries;\n  cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));\n\n  cache.cpage_use_map = 0xffffffff;\n  cache.cpage_use_mask = cache_mask;\n  memcpy(fs->cache, &cache, sizeof(spiffs_cache));\n\n  spiffs_cache *c = spiffs_get_cache(fs);\n\n  memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));\n\n  c->cpage_use_map &= ~(c->cpage_use_mask);\n  for (i = 0; i < cache.cpage_count; i++) {\n    spiffs_get_cache_page_hdr(fs, c, i)->ix = i;\n  }\n}\n\n#endif // SPIFFS_CACHE\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/spiffs_check.c",
    "content": "/*\n * spiffs_check.c\n *\n * Contains functionality for checking file system consistency\n * and mending problems.\n * Three levels of consistency checks are implemented:\n *\n * Look up consistency\n *   Checks if indices in lookup pages are coherent with page headers\n * Object index consistency\n *   Checks if there are any orphaned object indices (missing object index headers).\n *   If an object index is found but not its header, the object index is deleted.\n *   This is critical for the following page consistency check.\n * Page consistency\n *   Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed\n *\n *\n *  Created on: Jul 7, 2013\n *      Author: petera\n */\n\n\n#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\n#if !SPIFFS_READ_ONLY\n\n#if SPIFFS_HAL_CALLBACK_EXTRA\n#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \\\n  do { \\\n    if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \\\n  } while (0)\n#else\n#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \\\n  do { \\\n    if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \\\n  } while (0)\n#endif\n\n//---------------------------------------\n// Look up consistency\n\n// searches in the object indices and returns the referenced page index given\n// the object id and the data span index\n// destroys fs->lu_work\nstatic s32_t spiffs_object_get_data_page_index_reference(\n  spiffs *fs,\n  spiffs_obj_id obj_id,\n  spiffs_span_ix data_spix,\n  spiffs_page_ix *pix,\n  spiffs_page_ix *objix_pix) {\n  s32_t res;\n\n  // calculate object index span index for given data page span index\n  spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n\n  // find obj index for obj id and span index\n  res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix);\n  SPIFFS_CHECK_RES(res);\n\n  // load obj index entry\n  u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix);\n  if (objix_spix == 0) {\n    // get referenced page from object index header\n    addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix);\n  } else {\n    // get referenced page from object index\n    addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix);\n  }\n\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);\n\n  return res;\n}\n\n// copies page contents to a new page\nstatic s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) {\n  s32_t res;\n  res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix);\n  SPIFFS_CHECK_RES(res);\n  res = spiffs_phys_cpy(fs, 0,\n      SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header),\n      SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),\n      SPIFFS_DATA_PAGE_SIZE(fs));\n  SPIFFS_CHECK_RES(res);\n  return res;\n}\n\n// rewrites the object index for given object id and replaces the\n// data page index to a new page index\nstatic s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n  spiffs_page_ix free_pix;\n  obj_id |= SPIFFS_OBJ_ID_IX_FLAG;\n\n  // find free entry\n  res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);\n  SPIFFS_CHECK_RES(res);\n  free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n\n  // calculate object index span index for given data page span index\n  spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n  if (objix_spix == 0) {\n    // calc index in index header\n    entry = data_spix;\n  } else {\n    // calc entry in index\n    entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);\n\n  }\n  // load index\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n  SPIFFS_CHECK_RES(res);\n  spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;\n\n  // be ultra safe, double check header against provided data\n  if (objix_p_hdr->obj_id != obj_id) {\n    spiffs_page_delete(fs, free_pix);\n    return SPIFFS_ERR_CHECK_OBJ_ID_MISM;\n  }\n  if (objix_p_hdr->span_ix != objix_spix) {\n    spiffs_page_delete(fs, free_pix);\n    return SPIFFS_ERR_CHECK_SPIX_MISM;\n  }\n  if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX |\n                            SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) !=\n                                (SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) {\n    spiffs_page_delete(fs, free_pix);\n    return SPIFFS_ERR_CHECK_FLAGS_BAD;\n  }\n\n  // rewrite in mem\n  if (objix_spix == 0) {\n    ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;\n  } else {\n    ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;\n  }\n\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n  SPIFFS_CHECK_RES(res);\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),\n      sizeof(spiffs_obj_id),\n      (u8_t *)&obj_id);\n  SPIFFS_CHECK_RES(res);\n  res = spiffs_page_delete(fs, objix_pix);\n\n  return res;\n}\n\n// deletes an object just by marking object index header as deleted\nstatic s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {\n  spiffs_page_ix objix_hdr_pix;\n  s32_t res;\n  res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);\n  if (res == SPIFFS_ERR_NOT_FOUND) {\n    return SPIFFS_OK;\n  }\n  SPIFFS_CHECK_RES(res);\n  u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE;\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),\n      sizeof(u8_t),\n      (u8_t *)&flags);\n  return res;\n}\n\n// validates the given look up entry\nstatic s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,\n    spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {\n  (void)cur_block;\n  (void)cur_entry;\n  u8_t delete_page = 0;\n  s32_t res = SPIFFS_OK;\n  spiffs_page_ix objix_pix;\n  spiffs_page_ix ref_pix;\n  // check validity, take actions\n  if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||\n      ((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {\n    // look up entry deleted / free but used in page header\n    SPIFFS_CHECK_DBG(\"LU: pix \"_SPIPRIpg\" deleted/free in lu but not on page\\n\", cur_pix);\n    *reload_lu = 1;\n    delete_page = 1;\n    if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {\n      // header says data page\n      // data page can be removed if not referenced by some object index\n      res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        // no object with this id, so remove page safely\n        res = SPIFFS_OK;\n      } else {\n        SPIFFS_CHECK_RES(res);\n        if (ref_pix == cur_pix) {\n          // data page referenced by object index but deleted in lu\n          // copy page to new place and re-write the object index to new place\n          spiffs_page_ix new_pix;\n          res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: data page not found elsewhere, rewriting \"_SPIPRIpg\" to new page \"_SPIPRIpg\"\\n\", cur_pix, new_pix);\n          SPIFFS_CHECK_RES(res);\n          *reload_lu = 1;\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: \"_SPIPRIpg\" rewritten to \"_SPIPRIpg\", affected objix_pix \"_SPIPRIpg\"\\n\", cur_pix, new_pix, objix_pix);\n          res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);\n          if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n            // index bad also, cannot mend this file\n            SPIFFS_CHECK_DBG(\"LU: FIXUP: index bad \"_SPIPRIi\", cannot mend!\\n\", res);\n            res = spiffs_page_delete(fs, new_pix);\n            SPIFFS_CHECK_RES(res);\n            res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);\n            CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);\n          } else {\n            CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);\n          }\n          SPIFFS_CHECK_RES(res);\n        }\n      }\n    } else {\n      // header says index page\n      // index page can be removed if other index with same obj_id and spanix is found\n      res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        // no such index page found, check for a data page amongst page headers\n        // lu cannot be trusted\n        res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);\n        if (res == SPIFFS_OK) { // ignore other errors\n          // got a data page also, assume lu corruption only, rewrite to new page\n          spiffs_page_ix new_pix;\n          res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: ix page with data not found elsewhere, rewriting \"_SPIPRIpg\" to new page \"_SPIPRIpg\"\\n\", cur_pix, new_pix);\n          SPIFFS_CHECK_RES(res);\n          *reload_lu = 1;\n          CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);\n        }\n      } else {\n        SPIFFS_CHECK_RES(res);\n      }\n    }\n  }\n  if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {\n    // look up entry used\n    if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {\n      SPIFFS_CHECK_DBG(\"LU: pix \"_SPIPRIpg\" differ in obj_id lu:\"_SPIPRIid\" ph:\"_SPIPRIid\"\\n\", cur_pix, lu_obj_id, p_hdr->obj_id);\n      delete_page = 1;\n      if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||\n          (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||\n          (p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {\n        // page deleted or not finalized, just remove it\n      } else {\n        if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {\n          // if data page, check for reference to this page\n          res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);\n          if (res == SPIFFS_ERR_NOT_FOUND) {\n            // no object with this id, so remove page safely\n            res = SPIFFS_OK;\n          } else {\n            SPIFFS_CHECK_RES(res);\n            //   if found, rewrite page with object id, update index, and delete current\n            if (ref_pix == cur_pix) {\n              spiffs_page_ix new_pix;\n              res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);\n              SPIFFS_CHECK_RES(res);\n              res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);\n              if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n                // index bad also, cannot mend this file\n                SPIFFS_CHECK_DBG(\"LU: FIXUP: index bad \"_SPIPRIi\", cannot mend!\\n\", res);\n                res = spiffs_page_delete(fs, new_pix);\n                SPIFFS_CHECK_RES(res);\n                res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);\n                *reload_lu = 1;\n                CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);\n              }\n              SPIFFS_CHECK_RES(res);\n            }\n          }\n        } else {\n          // else if index, check for other pages with both obj_id's and spanix\n          spiffs_page_ix objix_pix_lu, objix_pix_ph;\n          // see if other object index page exists for lookup obj id and span index\n          res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu);\n          if (res == SPIFFS_ERR_NOT_FOUND) {\n            res = SPIFFS_OK;\n            objix_pix_lu = 0;\n          }\n          SPIFFS_CHECK_RES(res);\n          // see if other object index exists for page header obj id and span index\n          res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph);\n          if (res == SPIFFS_ERR_NOT_FOUND) {\n            res = SPIFFS_OK;\n            objix_pix_ph = 0;\n          }\n          SPIFFS_CHECK_RES(res);\n          //   if both obj_id's found, just delete current\n          if (objix_pix_ph == 0 || objix_pix_lu == 0) {\n            // otherwise try finding first corresponding data pages\n            spiffs_page_ix data_pix_lu, data_pix_ph;\n            // see if other data page exists for look up obj id and span index\n            res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);\n            if (res == SPIFFS_ERR_NOT_FOUND) {\n              res = SPIFFS_OK;\n              objix_pix_lu = 0;\n            }\n            SPIFFS_CHECK_RES(res);\n            // see if other data page exists for page header obj id and span index\n            res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);\n            if (res == SPIFFS_ERR_NOT_FOUND) {\n              res = SPIFFS_OK;\n              objix_pix_ph = 0;\n            }\n            SPIFFS_CHECK_RES(res);\n\n            spiffs_page_header new_ph;\n            new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);\n            new_ph.span_ix = p_hdr->span_ix;\n            spiffs_page_ix new_pix;\n            if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||\n                (objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {\n              //   got a data page for page header obj id\n              //   rewrite as obj_id_ph\n              new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n              res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);\n              SPIFFS_CHECK_DBG(\"LU: FIXUP: rewrite page \"_SPIPRIpg\" as \"_SPIPRIid\" to pix \"_SPIPRIpg\"\\n\", cur_pix, new_ph.obj_id, new_pix);\n              CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);\n              SPIFFS_CHECK_RES(res);\n              *reload_lu = 1;\n            } else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||\n                (objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {\n              //   got a data page for look up obj id\n              //   rewrite as obj_id_lu\n              new_ph.obj_id =  lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n              SPIFFS_CHECK_DBG(\"LU: FIXUP: rewrite page \"_SPIPRIpg\" as \"_SPIPRIid\"\\n\", cur_pix, new_ph.obj_id);\n              CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);\n              res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);\n              SPIFFS_CHECK_RES(res);\n              *reload_lu = 1;\n            } else {\n              // cannot safely do anything\n              SPIFFS_CHECK_DBG(\"LU: FIXUP: nothing to do, just delete\\n\");\n            }\n          }\n        }\n      }\n    } else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||\n        ((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {\n      SPIFFS_CHECK_DBG(\"LU: \"_SPIPRIpg\" lu/page index marking differ\\n\", cur_pix);\n      spiffs_page_ix data_pix, objix_pix_d;\n      // see if other data page exists for given obj id and span index\n      res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        res = SPIFFS_OK;\n        data_pix = 0;\n      }\n      SPIFFS_CHECK_RES(res);\n      // see if other object index exists for given obj id and span index\n      res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        res = SPIFFS_OK;\n        objix_pix_d = 0;\n      }\n      SPIFFS_CHECK_RES(res);\n\n      delete_page = 1;\n      // if other data page exists and object index exists, just delete page\n      if (data_pix && objix_pix_d) {\n        SPIFFS_CHECK_DBG(\"LU: FIXUP: other index and data page exists, simply remove\\n\");\n      } else\n      // if only data page exists, make this page index\n      if (data_pix && objix_pix_d == 0) {\n        SPIFFS_CHECK_DBG(\"LU: FIXUP: other data page exists, make this index\\n\");\n        CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);\n        spiffs_page_header new_ph;\n        spiffs_page_ix new_pix;\n        new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);\n        new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n        new_ph.span_ix = p_hdr->span_ix;\n        res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);\n        SPIFFS_CHECK_RES(res);\n        res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),\n            SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),\n            SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));\n        SPIFFS_CHECK_RES(res);\n      } else\n      // if only index exists, make data page\n      if (data_pix == 0 && objix_pix_d) {\n        SPIFFS_CHECK_DBG(\"LU: FIXUP: other index page exists, make this data\\n\");\n        CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);\n        spiffs_page_header new_ph;\n        spiffs_page_ix new_pix;\n        new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);\n        new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n        new_ph.span_ix = p_hdr->span_ix;\n        res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);\n        SPIFFS_CHECK_RES(res);\n        res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),\n            SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),\n            SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));\n        SPIFFS_CHECK_RES(res);\n      } else {\n        // if nothing exists, we cannot safely make a decision - delete\n      }\n    }\n    else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {\n      SPIFFS_CHECK_DBG(\"LU: pix \"_SPIPRIpg\" busy in lu but deleted on page\\n\", cur_pix);\n      delete_page = 1;\n    } else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {\n      SPIFFS_CHECK_DBG(\"LU: pix \"_SPIPRIpg\" busy but not final\\n\", cur_pix);\n      // page can be removed if not referenced by object index\n      *reload_lu = 1;\n      res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        // no object with this id, so remove page safely\n        res = SPIFFS_OK;\n        delete_page = 1;\n      } else {\n        SPIFFS_CHECK_RES(res);\n        if (ref_pix != cur_pix) {\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: other finalized page is referred, just delete\\n\");\n          delete_page = 1;\n        } else {\n          // page referenced by object index but not final\n          // just finalize\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: unfinalized page is referred, finalizing\\n\");\n          CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);\n          u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;\n          res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n              0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),\n              sizeof(u8_t), (u8_t*)&flags);\n        }\n      }\n    }\n  }\n\n  if (delete_page) {\n    SPIFFS_CHECK_DBG(\"LU: FIXUP: deleting page \"_SPIPRIpg\"\\n\", cur_pix);\n    CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);\n    res = spiffs_page_delete(fs, cur_pix);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  return res;\n}\n\nstatic s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,\n    const void *user_const_p, void *user_var_p) {\n  (void)user_const_p;\n  (void)user_var_p;\n  s32_t res = SPIFFS_OK;\n  spiffs_page_header p_hdr;\n  spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);\n\n  CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,\n      (cur_block * 256)/fs->block_count, 0);\n\n  // load header\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n  SPIFFS_CHECK_RES(res);\n\n  int reload_lu = 0;\n\n  res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);\n  SPIFFS_CHECK_RES(res);\n\n  if (res == SPIFFS_OK) {\n    return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;\n  }\n  return res;\n}\n\n\n// Scans all object look up. For each entry, corresponding page header is checked for validity.\n// If an object index header page is found, this is also checked\ns32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {\n  (void)check_all_objects;\n  s32_t res = SPIFFS_OK;\n\n  CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);\n\n  res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_OK;\n  }\n\n  if (res != SPIFFS_OK) {\n    CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);\n  }\n\n  CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);\n\n  return res;\n}\n\n//---------------------------------------\n// Page consistency\n\n// Scans all pages (except lu pages), reserves 4 bits in working memory for each page\n// bit 0: 0 == FREE|DELETED, 1 == USED\n// bit 1: 0 == UNREFERENCED, 1 == REFERENCED\n// bit 2: 0 == NOT_INDEX,    1 == INDEX\n// bit 3: unused\n// A consistent file system will have only pages being\n//  * x000 free, unreferenced, not index\n//  * x011 used, referenced only once, not index\n//  * x101 used, unreferenced, index\n// The working memory might not fit all pages so several scans might be needed\nstatic s32_t spiffs_page_consistency_check_i(spiffs *fs) {\n  const u32_t bits = 4;\n  const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;\n\n  s32_t res = SPIFFS_OK;\n  spiffs_page_ix pix_offset = 0;\n\n  // for each range of pages fitting into work memory\n  while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {\n    // set this flag to abort all checks and rescan the page range\n    u8_t restart = 0;\n    memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n\n    spiffs_block_ix cur_block = 0;\n    // build consistency bitmap for id range traversing all blocks\n    while (!restart && cur_block < fs->block_count) {\n      CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,\n          (pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +\n          ((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),\n          0);\n      // traverse each page except for lookup pages\n      spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;\n      while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {\n        //if ((cur_pix & 0xff) == 0)\n        //  SPIFFS_CHECK_DBG(\"PA: processing pix \"_SPIPRIpg\", block \"_SPIPRIbl\" of pix \"_SPIPRIpg\", block \"_SPIPRIbl\"\\n\",\n        //      cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);\n\n        // read header\n        spiffs_page_header p_hdr;\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n            0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n        SPIFFS_CHECK_RES(res);\n\n        u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);\n        const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits);\n        const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits;\n\n        if (within_range &&\n            (p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {\n          // used\n          fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0));\n        }\n        if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&\n            (p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&\n            (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {\n          // found non-deleted index\n          if (within_range) {\n            fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2));\n          }\n\n          // load non-deleted index\n          res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n              0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n          SPIFFS_CHECK_RES(res);\n\n          // traverse index for referenced pages\n          spiffs_page_ix *object_page_index;\n          spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;\n\n          int entries;\n          int i;\n          spiffs_span_ix data_spix_offset;\n          if (p_hdr.span_ix == 0) {\n            // object header page index\n            entries = SPIFFS_OBJ_HDR_IX_LEN(fs);\n            data_spix_offset = 0;\n            object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));\n          } else {\n            // object page index\n            entries = SPIFFS_OBJ_IX_LEN(fs);\n            data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);\n            object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));\n          }\n\n          // for all entries in index\n          for (i = 0; !restart && i < entries; i++) {\n            spiffs_page_ix rpix = object_page_index[i];\n            u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;\n\n            if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs))\n                || (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {\n\n              // bad reference\n              SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\"x bad pix / LU referenced from page \"_SPIPRIpg\"\\n\",\n                  rpix, cur_pix);\n              // check for data page elsewhere\n              spiffs_page_ix data_pix;\n              res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n                  data_spix_offset + i, 0, &data_pix);\n              if (res == SPIFFS_ERR_NOT_FOUND) {\n                res = SPIFFS_OK;\n                data_pix = 0;\n              }\n              SPIFFS_CHECK_RES(res);\n              if (data_pix == 0) {\n                // if not, allocate free page\n                spiffs_page_header new_ph;\n                new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);\n                new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n                new_ph.span_ix = data_spix_offset + i;\n                res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);\n                SPIFFS_CHECK_RES(res);\n                SPIFFS_CHECK_DBG(\"PA: FIXUP: found no existing data page, created new @ \"_SPIPRIpg\"\\n\", data_pix);\n              }\n              // remap index\n              SPIFFS_CHECK_DBG(\"PA: FIXUP: rewriting index pix \"_SPIPRIpg\"\\n\", cur_pix);\n              res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,\n                  data_spix_offset + i, data_pix, cur_pix);\n              if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n                // index bad also, cannot mend this file\n                SPIFFS_CHECK_DBG(\"PA: FIXUP: index bad \"_SPIPRIi\", cannot mend - delete object\\n\", res);\n                CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);\n                // delete file\n                res = spiffs_page_delete(fs, cur_pix);\n              } else {\n                CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);\n              }\n              SPIFFS_CHECK_RES(res);\n              restart = 1;\n\n            } else if (rpix_within_range) {\n\n              // valid reference\n              // read referenced page header\n              spiffs_page_header rp_hdr;\n              res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                  0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);\n              SPIFFS_CHECK_RES(res);\n\n              // cross reference page header check\n              if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||\n                  rp_hdr.span_ix != data_spix_offset + i ||\n                  (rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=\n                      (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {\n               SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" has inconsistent page header ix id/span:\"_SPIPRIid\"/\"_SPIPRIsp\", ref id/span:\"_SPIPRIid\"/\"_SPIPRIsp\" flags:\"_SPIPRIfl\"\\n\",\n                    rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,\n                    rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);\n               // try finding correct page\n               spiffs_page_ix data_pix;\n               res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n                   data_spix_offset + i, rpix, &data_pix);\n               if (res == SPIFFS_ERR_NOT_FOUND) {\n                 res = SPIFFS_OK;\n                 data_pix = 0;\n               }\n               SPIFFS_CHECK_RES(res);\n               if (data_pix == 0) {\n                 // not found, this index is badly borked\n                 SPIFFS_CHECK_DBG(\"PA: FIXUP: index bad, delete object id \"_SPIPRIid\"\\n\", p_hdr.obj_id);\n                 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);\n                 res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);\n                 SPIFFS_CHECK_RES(res);\n                 break;\n               } else {\n                 // found it, so rewrite index\n                 SPIFFS_CHECK_DBG(\"PA: FIXUP: found correct data pix \"_SPIPRIpg\", rewrite ix pix \"_SPIPRIpg\" id \"_SPIPRIid\"\\n\",\n                     data_pix, cur_pix, p_hdr.obj_id);\n                 res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);\n                 if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n                   // index bad also, cannot mend this file\n                   SPIFFS_CHECK_DBG(\"PA: FIXUP: index bad \"_SPIPRIi\", cannot mend!\\n\", res);\n                   CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);\n                   res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);\n                 } else {\n                   CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);\n                 }\n                 SPIFFS_CHECK_RES(res);\n                 restart = 1;\n               }\n              }\n              else {\n                // mark rpix as referenced\n                const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits);\n                const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits;\n                if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) {\n                  SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" multiple referenced from page \"_SPIPRIpg\"\\n\",\n                      rpix, cur_pix);\n                  // Here, we should have fixed all broken references - getting this means there\n                  // must be multiple files with same object id. Only solution is to delete\n                  // the object which is referring to this page\n                  SPIFFS_CHECK_DBG(\"PA: FIXUP: removing object \"_SPIPRIid\" and page \"_SPIPRIpg\"\\n\",\n                      p_hdr.obj_id, cur_pix);\n                  CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);\n                  res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);\n                  SPIFFS_CHECK_RES(res);\n                  // extra precaution, delete this page also\n                  res = spiffs_page_delete(fs, cur_pix);\n                  SPIFFS_CHECK_RES(res);\n                  restart = 1;\n                }\n                fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1));\n              }\n            }\n          } // for all index entries\n        } // found index\n\n        // next page\n        cur_pix++;\n      }\n      // next block\n      cur_block++;\n    }\n    // check consistency bitmap\n    if (!restart) {\n      spiffs_page_ix objix_pix;\n      spiffs_page_ix rpix;\n\n      u32_t byte_ix;\n      u8_t bit_ix;\n      for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {\n        for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) {\n          u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;\n          spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix;\n\n          // 000 ok - free, unreferenced, not index\n\n          if (bitmask == 0x1) {\n\n            // 001\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" USED, UNREFERENCED, not index\\n\", cur_pix);\n\n            u8_t rewrite_ix_to_this = 0;\n            u8_t delete_page = 0;\n            // check corresponding object index entry\n            spiffs_page_header p_hdr;\n            res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n            SPIFFS_CHECK_RES(res);\n\n            res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,\n                &rpix, &objix_pix);\n            if (res == SPIFFS_OK) {\n              if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {\n                // pointing to a bad page altogether, rewrite index to this\n                rewrite_ix_to_this = 1;\n                SPIFFS_CHECK_DBG(\"PA: corresponding ref is bad: \"_SPIPRIpg\", rewrite to this \"_SPIPRIpg\"\\n\", rpix, cur_pix);\n              } else {\n                // pointing to something else, check what\n                spiffs_page_header rp_hdr;\n                res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                    0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);\n                SPIFFS_CHECK_RES(res);\n                if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&\n                    ((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==\n                        (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {\n                  // pointing to something else valid, just delete this page then\n                  SPIFFS_CHECK_DBG(\"PA: corresponding ref is good but different: \"_SPIPRIpg\", delete this \"_SPIPRIpg\"\\n\", rpix, cur_pix);\n                  delete_page = 1;\n                } else {\n                  // pointing to something weird, update index to point to this page instead\n                  if (rpix != cur_pix) {\n                    SPIFFS_CHECK_DBG(\"PA: corresponding ref is weird: \"_SPIPRIpg\" %s%s%s%s, rewrite this \"_SPIPRIpg\"\\n\", rpix,\n                        (rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? \"\" : \"INDEX \",\n                            (rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? \"\" : \"DELETED \",\n                                (rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? \"NOTUSED \" : \"\",\n                                    (rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? \"NOTFINAL \" : \"\",\n                        cur_pix);\n                    rewrite_ix_to_this = 1;\n                  } else {\n                    // should not happen, destined for fubar\n                  }\n                }\n              }\n            } else if (res == SPIFFS_ERR_NOT_FOUND) {\n              SPIFFS_CHECK_DBG(\"PA: corresponding ref not found, delete \"_SPIPRIpg\"\\n\", cur_pix);\n              delete_page = 1;\n              res = SPIFFS_OK;\n            }\n\n            if (rewrite_ix_to_this) {\n              // if pointing to invalid page, redirect index to this page\n              SPIFFS_CHECK_DBG(\"PA: FIXUP: rewrite index id \"_SPIPRIid\" data spix \"_SPIPRIsp\" to point to this pix: \"_SPIPRIpg\"\\n\",\n                  p_hdr.obj_id, p_hdr.span_ix, cur_pix);\n              res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);\n              if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n                // index bad also, cannot mend this file\n                SPIFFS_CHECK_DBG(\"PA: FIXUP: index bad \"_SPIPRIi\", cannot mend!\\n\", res);\n                CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);\n                res = spiffs_page_delete(fs, cur_pix);\n                SPIFFS_CHECK_RES(res);\n                res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);\n              } else {\n                CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);\n              }\n              SPIFFS_CHECK_RES(res);\n              restart = 1;\n              continue;\n            } else if (delete_page) {\n              SPIFFS_CHECK_DBG(\"PA: FIXUP: deleting page \"_SPIPRIpg\"\\n\", cur_pix);\n              CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);\n              res = spiffs_page_delete(fs, cur_pix);\n            }\n            SPIFFS_CHECK_RES(res);\n          }\n          if (bitmask == 0x2) {\n\n            // 010\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" FREE, REFERENCED, not index\\n\", cur_pix);\n\n            // no op, this should be taken care of when checking valid references\n          }\n\n          // 011 ok - busy, referenced, not index\n\n          if (bitmask == 0x4) {\n\n            // 100\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" FREE, unreferenced, INDEX\\n\", cur_pix);\n\n            // this should never happen, major fubar\n          }\n\n          // 101 ok - busy, unreferenced, index\n\n          if (bitmask == 0x6) {\n\n            // 110\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" FREE, REFERENCED, INDEX\\n\", cur_pix);\n\n            // no op, this should be taken care of when checking valid references\n          }\n          if (bitmask == 0x7) {\n\n            // 111\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" USED, REFERENCED, INDEX\\n\", cur_pix);\n\n            // no op, this should be taken care of when checking valid references\n          }\n        }\n      }\n    }\n\n    SPIFFS_CHECK_DBG(\"PA: processed \"_SPIPRIpg\", restart \"_SPIPRIi\"\\n\", pix_offset, restart);\n    // next page range\n    if (!restart) {\n      pix_offset += pages_per_scan;\n    }\n  } // while page range not reached end\n  return res;\n}\n\n// Checks consistency amongst all pages and fixes irregularities\ns32_t spiffs_page_consistency_check(spiffs *fs) {\n  CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);\n  s32_t res = spiffs_page_consistency_check_i(fs);\n  if (res != SPIFFS_OK) {\n    CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);\n  }\n  CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);\n  return res;\n}\n\n//---------------------------------------\n// Object index consistency\n\n// searches for given object id in temporary object id index,\n// returns the index or -1\nstatic int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {\n  u32_t i;\n  spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;\n  obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n  for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {\n    if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {\n      return i;\n    }\n  }\n  return -1;\n}\n\nstatic s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,\n    int cur_entry, const void *user_const_p, void *user_var_p) {\n  (void)user_const_p;\n  s32_t res_c = SPIFFS_VIS_COUNTINUE;\n  s32_t res = SPIFFS_OK;\n  u32_t *log_ix = (u32_t*)user_var_p;\n  spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;\n\n  CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,\n      (cur_block * 256)/fs->block_count, 0);\n\n  if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {\n    spiffs_page_header p_hdr;\n    spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);\n\n    // load header\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n    SPIFFS_CHECK_RES(res);\n\n    if (p_hdr.span_ix == 0 &&\n        (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==\n        (SPIFFS_PH_FLAG_DELET)) {\n      SPIFFS_CHECK_DBG(\"IX: pix \"_SPIPRIpg\", obj id:\"_SPIPRIid\" spix:\"_SPIPRIsp\" header not fully deleted - deleting\\n\",\n          cur_pix, obj_id, p_hdr.span_ix);\n      CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);\n      res = spiffs_page_delete(fs, cur_pix);\n      SPIFFS_CHECK_RES(res);\n      return res_c;\n    }\n\n    if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==\n        (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {\n      return res_c;\n    }\n\n    if (p_hdr.span_ix == 0) {\n      // objix header page, register objid as reachable\n      int r = spiffs_object_index_search(fs, obj_id);\n      if (r == -1) {\n        // not registered, do it\n        obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n        (*log_ix)++;\n        if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {\n          *log_ix = 0;\n        }\n      }\n    } else { // span index\n      // objix page, see if header can be found\n      int r = spiffs_object_index_search(fs, obj_id);\n      u8_t delete = 0;\n      if (r == -1) {\n        // not in temporary index, try finding it\n        spiffs_page_ix objix_hdr_pix;\n        res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);\n        res_c = SPIFFS_VIS_COUNTINUE_RELOAD;\n        if (res == SPIFFS_OK) {\n          // found, register as reachable\n          obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n        } else if (res == SPIFFS_ERR_NOT_FOUND) {\n          // not found, register as unreachable\n          delete = 1;\n          obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n        } else {\n          SPIFFS_CHECK_RES(res);\n        }\n        (*log_ix)++;\n        if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {\n          *log_ix = 0;\n        }\n      } else {\n        // in temporary index, check reachable flag\n        if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {\n          // registered as unreachable\n          delete = 1;\n        }\n      }\n\n      if (delete) {\n        SPIFFS_CHECK_DBG(\"IX: FIXUP: pix \"_SPIPRIpg\", obj id:\"_SPIPRIid\" spix:\"_SPIPRIsp\" is orphan index - deleting\\n\",\n            cur_pix, obj_id, p_hdr.span_ix);\n        CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);\n        res = spiffs_page_delete(fs, cur_pix);\n        SPIFFS_CHECK_RES(res);\n      }\n    } // span index\n  } // valid object index id\n\n  return res_c;\n}\n\n// Removes orphaned and partially deleted index pages.\n// Scans for index pages. When an index page is found, corresponding index header is searched for.\n// If no such page exists, the index page cannot be reached as no index header exists and must be\n// deleted.\ns32_t spiffs_object_index_consistency_check(spiffs *fs) {\n  s32_t res = SPIFFS_OK;\n  // impl note:\n  // fs->work is used for a temporary object index memory, listing found object ids and\n  // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.\n  // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate\n  // a reachable/unreachable object id.\n  memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n  u32_t obj_id_log_ix = 0;\n  CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);\n  res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,\n        0, 0);\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_OK;\n  }\n  if (res != SPIFFS_OK) {\n    CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);\n  }\n  CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);\n  return res;\n}\n\n#endif // !SPIFFS_READ_ONLY\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/spiffs_config.h",
    "content": "/*\n * spiffs_config.h\n *\n *  Created on: Jul 3, 2013\n *      Author: petera\n */\n\n#ifndef SPIFFS_CONFIG_H_\n#define SPIFFS_CONFIG_H_\n\n// ----------- 8< ------------\n// Following includes are for the linux test build of spiffs\n// These may/should/must be removed/altered/replaced in your target\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stddef.h>\n#include <unistd.h>\n#include <stdint.h>\n#include <ctype.h>\n// ----------- >8 ------------\n\ntypedef signed int s32_t;\ntypedef unsigned int u32_t;\ntypedef signed short s16_t;\ntypedef unsigned short u16_t;\ntypedef signed char s8_t;\ntypedef unsigned char u8_t;\n\n// compile time switches\n\n// Set generic spiffs debug output call.\n#ifndef SPIFFS_DBG\n#define SPIFFS_DBG(...) //printf(__VA_ARGS__)\n#endif\n// Set spiffs debug output call for garbage collecting.\n#ifndef SPIFFS_GC_DBG\n#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)\n#endif\n// Set spiffs debug output call for caching.\n#ifndef SPIFFS_CACHE_DBG\n#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)\n#endif\n// Set spiffs debug output call for system consistency checks.\n#ifndef SPIFFS_CHECK_DBG\n#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)\n#endif\n\n\n// Defines spiffs debug print formatters\n// some general signed number\n#ifndef _SPIPRIi\n#define _SPIPRIi   \"%d\"\n#endif\n// address\n#ifndef _SPIPRIad\n#define _SPIPRIad  \"%08x\"\n#endif\n// block\n#ifndef _SPIPRIbl\n#define _SPIPRIbl  \"%04x\"\n#endif\n// page\n#ifndef _SPIPRIpg\n#define _SPIPRIpg  \"%04x\"\n#endif\n// span index\n#ifndef _SPIPRIsp\n#define _SPIPRIsp  \"%04x\"\n#endif\n// file descriptor\n#ifndef _SPIPRIfd\n#define _SPIPRIfd  \"%d\"\n#endif\n// file object id\n#ifndef _SPIPRIid\n#define _SPIPRIid  \"%04x\"\n#endif\n// file flags\n#ifndef _SPIPRIfl\n#define _SPIPRIfl  \"%02x\"\n#endif\n\n// Enable/disable API functions to determine exact number of bytes\n// for filedescriptor and cache buffers. Once decided for a configuration,\n// this can be disabled to reduce flash.\n#ifndef SPIFFS_BUFFER_HELP\n#define SPIFFS_BUFFER_HELP              0\n#endif\n\n// Enables/disable memory read caching of nucleus file system operations.\n// If enabled, memory area must be provided for cache in SPIFFS_mount.\n#ifndef  SPIFFS_CACHE\n#define SPIFFS_CACHE                    1\n#endif\n#if SPIFFS_CACHE\n// Enables memory write caching for file descriptors in hydrogen\n#ifndef  SPIFFS_CACHE_WR\n#define SPIFFS_CACHE_WR                 1\n#endif\n\n// Enable/disable statistics on caching. Debug/test purpose only.\n#ifndef  SPIFFS_CACHE_STATS\n#define SPIFFS_CACHE_STATS              0\n#endif\n#endif\n\n// Always check header of each accessed page to ensure consistent state.\n// If enabled it will increase number of reads, will increase flash.\n#ifndef SPIFFS_PAGE_CHECK\n#define SPIFFS_PAGE_CHECK               1\n#endif\n\n// Define maximum number of gc runs to perform to reach desired free pages.\n#ifndef SPIFFS_GC_MAX_RUNS\n#define SPIFFS_GC_MAX_RUNS              5\n#endif\n\n// Enable/disable statistics on gc. Debug/test purpose only.\n#ifndef SPIFFS_GC_STATS\n#define SPIFFS_GC_STATS                 0\n#endif\n\n// Garbage collecting examines all pages in a block which and sums up\n// to a block score. Deleted pages normally gives positive score and\n// used pages normally gives a negative score (as these must be moved).\n// To have a fair wear-leveling, the erase age is also included in score,\n// whose factor normally is the most positive.\n// The larger the score, the more likely it is that the block will\n// picked for garbage collection.\n\n// Garbage collecting heuristics - weight used for deleted pages.\n#ifndef SPIFFS_GC_HEUR_W_DELET\n#define SPIFFS_GC_HEUR_W_DELET          (5)\n#endif\n// Garbage collecting heuristics - weight used for used pages.\n#ifndef SPIFFS_GC_HEUR_W_USED\n#define SPIFFS_GC_HEUR_W_USED           (-1)\n#endif\n// Garbage collecting heuristics - weight used for time between\n// last erased and erase of this block.\n#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE\n#define SPIFFS_GC_HEUR_W_ERASE_AGE      (50)\n#endif\n\n// Object name maximum length. Note that this length include the\n// zero-termination character, meaning maximum string of characters\n// can at most be SPIFFS_OBJ_NAME_LEN - 1.\n#ifndef SPIFFS_OBJ_NAME_LEN\n#define SPIFFS_OBJ_NAME_LEN             (64)\n#endif\n\n// Maximum length of the metadata associated with an object.\n// Setting to non-zero value enables metadata-related API but also\n// changes the on-disk format, so the change is not backward-compatible.\n//\n// Do note: the meta length must never exceed\n// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64)\n//\n// This is derived from following:\n// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +\n// spiffs_object_ix_header fields + at least some LUT entries)\n#ifndef SPIFFS_OBJ_META_LEN\n#define SPIFFS_OBJ_META_LEN             (64)\n#endif\n\n// Size of buffer allocated on stack used when copying data.\n// Lower value generates more read/writes. No meaning having it bigger\n// than logical page size.\n#ifndef SPIFFS_COPY_BUFFER_STACK\n#define SPIFFS_COPY_BUFFER_STACK        (256)\n#endif\n\n// Enable this to have an identifiable spiffs filesystem. This will look for\n// a magic in all sectors to determine if this is a valid spiffs system or\n// not on mount point. If not, SPIFFS_format must be called prior to mounting\n// again.\n#ifndef SPIFFS_USE_MAGIC\n#define SPIFFS_USE_MAGIC                (1)\n#endif\n\n#if SPIFFS_USE_MAGIC\n// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is\n// enabled, the magic will also be dependent on the length of the filesystem.\n// For example, a filesystem configured and formatted for 4 megabytes will not\n// be accepted for mounting with a configuration defining the filesystem as 2\n// megabytes.\n#ifndef SPIFFS_USE_MAGIC_LENGTH\n#define SPIFFS_USE_MAGIC_LENGTH         (1)\n#endif\n#endif\n\n// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level\n// These should be defined on a multithreaded system\n\n// define this to enter a mutex if you're running on a multithreaded system\n#ifndef SPIFFS_LOCK\n#define SPIFFS_LOCK(fs)\n#endif\n// define this to exit a mutex if you're running on a multithreaded system\n#ifndef SPIFFS_UNLOCK\n#define SPIFFS_UNLOCK(fs)\n#endif\n\n// Enable if only one spiffs instance with constant configuration will exist\n// on the target. This will reduce calculations, flash and memory accesses.\n// Parts of configuration must be defined below instead of at time of mount.\n#ifndef SPIFFS_SINGLETON\n#define SPIFFS_SINGLETON 0\n#endif\n\n#if SPIFFS_SINGLETON\n// Instead of giving parameters in config struct, singleton build must\n// give parameters in defines below.\n#ifndef SPIFFS_CFG_PHYS_SZ\n#define SPIFFS_CFG_PHYS_SZ(ignore)        (1024*1024*2)\n#endif\n#ifndef SPIFFS_CFG_PHYS_ERASE_SZ\n#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore)  (65536)\n#endif\n#ifndef SPIFFS_CFG_PHYS_ADDR\n#define SPIFFS_CFG_PHYS_ADDR(ignore)      (0)\n#endif\n#ifndef SPIFFS_CFG_LOG_PAGE_SZ\n#define SPIFFS_CFG_LOG_PAGE_SZ(ignore)    (256)\n#endif\n#ifndef SPIFFS_CFG_LOG_BLOCK_SZ\n#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore)   (65536)\n#endif\n#endif\n\n// Enable this if your target needs aligned data for index tables\n#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES\n#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES       1\n#endif\n\n// Enable this if you want the HAL callbacks to be called with the spiffs struct\n#ifndef SPIFFS_HAL_CALLBACK_EXTRA\n#define SPIFFS_HAL_CALLBACK_EXTRA         0\n#endif\n\n// Enable this if you want to add an integer offset to all file handles\n// (spiffs_file). This is useful if running multiple instances of spiffs on\n// same target, in order to recognise to what spiffs instance a file handle\n// belongs.\n// NB: This adds config field fh_ix_offset in the configuration struct when\n// mounting, which must be defined.\n#ifndef SPIFFS_FILEHDL_OFFSET\n#define SPIFFS_FILEHDL_OFFSET                 0\n#endif\n\n// Enable this to compile a read only version of spiffs.\n// This will reduce binary size of spiffs. All code comprising modification\n// of the file system will not be compiled. Some config will be ignored.\n// HAL functions for erasing and writing to spi-flash may be null. Cache\n// can be disabled for even further binary size reduction (and ram savings).\n// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.\n// If the file system cannot be mounted due to aborted erase operation and\n// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be\n// returned.\n// Might be useful for e.g. bootloaders and such.\n#ifndef SPIFFS_READ_ONLY\n#define SPIFFS_READ_ONLY                      0\n#endif\n\n// Enable this to add a temporal file cache using the fd buffer.\n// The effects of the cache is that SPIFFS_open will find the file faster in\n// certain cases. It will make it a lot easier for spiffs to find files\n// opened frequently, reducing number of readings from the spi flash for\n// finding those files.\n// This will grow each fd by 6 bytes. If your files are opened in patterns\n// with a degree of temporal locality, the system is optimized.\n// Examples can be letting spiffs serve web content, where one file is the css.\n// The css is accessed for each html file that is opened, meaning it is\n// accessed almost every second time a file is opened. Another example could be\n// a log file that is often opened, written, and closed.\n// The size of the cache is number of given file descriptors, as it piggybacks\n// on the fd update mechanism. The cache lives in the closed file descriptors.\n// When closed, the fd know the whereabouts of the file. Instead of forgetting\n// this, the temporal cache will keep handling updates to that file even if the\n// fd is closed. If the file is opened again, the location of the file is found\n// directly. If all available descriptors become opened, all cache memory is\n// lost.\n#ifndef SPIFFS_TEMPORAL_FD_CACHE\n#define SPIFFS_TEMPORAL_FD_CACHE              1\n#endif\n\n// Temporal file cache hit score. Each time a file is opened, all cached files\n// will lose one point. If the opened file is found in cache, that entry will\n// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this\n// value for the specific access patterns of the application. However, it must\n// be between 1 (no gain for hitting a cached entry often) and 255.\n#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE\n#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE       8\n#endif\n\n// Enable to be able to map object indices to memory.\n// This allows for faster and more deterministic reading if cases of reading\n// large files and when changing file offset by seeking around a lot.\n// When mapping a file's index, the file system will be scanned for index pages\n// and the info will be put in memory provided by user. When reading, the\n// memory map can be looked up instead of searching for index pages on the\n// medium. This way, user can trade memory against performance.\n// Whole, parts of, or future parts not being written yet can be mapped. The\n// memory array will be owned by spiffs and updated accordingly during garbage\n// collecting or when modifying the indices. The latter is invoked by when the\n// file is modified in some way. The index buffer is tied to the file\n// descriptor.\n#ifndef SPIFFS_IX_MAP\n#define SPIFFS_IX_MAP                         1\n#endif\n\n// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function\n// in the api. This function will visualize all filesystem using given printf\n// function.\n#ifndef SPIFFS_TEST_VISUALISATION\n#define SPIFFS_TEST_VISUALISATION         0\n#endif\n#if SPIFFS_TEST_VISUALISATION\n#ifndef spiffs_printf\n#define spiffs_printf(...)                printf(__VA_ARGS__)\n#endif\n// spiffs_printf argument for a free page\n#ifndef SPIFFS_TEST_VIS_FREE_STR\n#define SPIFFS_TEST_VIS_FREE_STR          \"_\"\n#endif\n// spiffs_printf argument for a deleted page\n#ifndef SPIFFS_TEST_VIS_DELE_STR\n#define SPIFFS_TEST_VIS_DELE_STR          \"/\"\n#endif\n// spiffs_printf argument for an index page for given object id\n#ifndef SPIFFS_TEST_VIS_INDX_STR\n#define SPIFFS_TEST_VIS_INDX_STR(id)      \"i\"\n#endif\n// spiffs_printf argument for a data page for given object id\n#ifndef SPIFFS_TEST_VIS_DATA_STR\n#define SPIFFS_TEST_VIS_DATA_STR(id)      \"d\"\n#endif\n#endif\n\n// Types depending on configuration such as the amount of flash bytes\n// given to spiffs file system in total (spiffs_file_system_size),\n// the logical block size (log_block_size), and the logical page size\n// (log_page_size)\n\n// Block index type. Make sure the size of this type can hold\n// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size\ntypedef u16_t spiffs_block_ix;\n// Page index type. Make sure the size of this type can hold\n// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size\ntypedef u16_t spiffs_page_ix;\n// Object id type - most significant bit is reserved for index flag. Make sure the\n// size of this type can hold the highest object id on a full system,\n// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2\ntypedef u16_t spiffs_obj_id;\n// Object span index type. Make sure the size of this type can\n// hold the largest possible span index on the system -\n// i.e. (spiffs_file_system_size / log_page_size) - 1\ntypedef u16_t spiffs_span_ix;\n\n#endif /* SPIFFS_CONFIG_H_ */\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/spiffs_gc.c",
    "content": "#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\n#if !SPIFFS_READ_ONLY\n\n// Erases a logical block and updates the erase counter.\n// If cache is enabled, all pages that might be cached in this block\n// is dropped.\nstatic s32_t spiffs_gc_erase_block(\n    spiffs *fs,\n    spiffs_block_ix bix) {\n  s32_t res;\n\n  SPIFFS_GC_DBG(\"gc: erase block \"_SPIPRIbl\"\\n\", bix);\n  res = spiffs_erase_block(fs, bix);\n  SPIFFS_CHECK_RES(res);\n\n#if SPIFFS_CACHE\n  {\n    u32_t i;\n    for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {\n      spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);\n    }\n  }\n#endif\n  return res;\n}\n\n// Searches for blocks where all entries are deleted - if one is found,\n// the block is erased. Compared to the non-quick gc, the quick one ensures\n// that no updates are needed on existing objects on pages that are erased.\ns32_t spiffs_gc_quick(\n    spiffs *fs, u16_t max_free_pages) {\n  s32_t res = SPIFFS_OK;\n  u32_t blocks = fs->block_count;\n  spiffs_block_ix cur_block = 0;\n  u32_t cur_block_addr = 0;\n  int cur_entry = 0;\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n\n  SPIFFS_GC_DBG(\"gc_quick: running\\n\");\n#if SPIFFS_GC_STATS\n  fs->stats_gc_runs++;\n#endif\n\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n\n  // find fully deleted blocks\n  // check each block\n  while (res == SPIFFS_OK && blocks--) {\n    u16_t deleted_pages_in_block = 0;\n    u16_t free_pages_in_block = 0;\n\n    int obj_lookup_page = 0;\n    // check each object lookup page\n    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each entry\n      while (res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page &&\n          cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n        if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n          deleted_pages_in_block++;\n        } else if (obj_id == SPIFFS_OBJ_ID_FREE) {\n          // kill scan, go for next block\n          free_pages_in_block++;\n          if (free_pages_in_block > max_free_pages) {\n            obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);\n            res = 1; // kill object lu loop\n            break;\n          }\n        }  else {\n          // kill scan, go for next block\n          obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);\n          res = 1; // kill object lu loop\n          break;\n        }\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n    if (res == 1) res = SPIFFS_OK;\n\n    if (res == SPIFFS_OK &&\n        deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&\n        free_pages_in_block <= max_free_pages) {\n      // found a fully deleted block\n      fs->stats_p_deleted -= deleted_pages_in_block;\n      res = spiffs_gc_erase_block(fs, cur_block);\n      return res;\n    }\n\n    cur_entry = 0;\n    cur_block++;\n    cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n  } // per block\n\n  if (res == SPIFFS_OK) {\n    res = SPIFFS_ERR_NO_DELETED_BLOCKS;\n  }\n  return res;\n}\n\n// Checks if garbage collecting is necessary. If so a candidate block is found,\n// cleansed and erased\ns32_t spiffs_gc_check(\n    spiffs *fs,\n    u32_t len) {\n  s32_t res;\n  s32_t free_pages =\n      (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)\n      - fs->stats_p_allocated - fs->stats_p_deleted;\n  int tries = 0;\n\n  if (fs->free_blocks > 3 &&\n      (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {\n    return SPIFFS_OK;\n  }\n\n  u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);\n//  if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {\n//    SPIFFS_GC_DBG(\"gc: full freeblk:\"_SPIPRIi\" needed:\"_SPIPRIi\" free:\"_SPIPRIi\" dele:\"_SPIPRIi\"\\n\", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);\n//    return SPIFFS_ERR_FULL;\n//  }\n  if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {\n    SPIFFS_GC_DBG(\"gc_check: full freeblk:\"_SPIPRIi\" needed:\"_SPIPRIi\" free:\"_SPIPRIi\" dele:\"_SPIPRIi\"\\n\", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);\n    return SPIFFS_ERR_FULL;\n  }\n\n  do {\n    SPIFFS_GC_DBG(\"\\ngc_check #\"_SPIPRIi\": run gc free_blocks:\"_SPIPRIi\" pfree:\"_SPIPRIi\" pallo:\"_SPIPRIi\" pdele:\"_SPIPRIi\" [\"_SPIPRIi\"] len:\"_SPIPRIi\" of \"_SPIPRIi\"\\n\",\n        tries,\n        fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),\n        len, (u32_t)(free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));\n\n    spiffs_block_ix *cands;\n    int count;\n    spiffs_block_ix cand;\n    s32_t prev_free_pages = free_pages;\n    // if the fs is crammed, ignore block age when selecting candidate - kind of a bad state\n    res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);\n    SPIFFS_CHECK_RES(res);\n    if (count == 0) {\n      SPIFFS_GC_DBG(\"gc_check: no candidates, return\\n\");\n      return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;\n    }\n#if SPIFFS_GC_STATS\n    fs->stats_gc_runs++;\n#endif\n    cand = cands[0];\n    fs->cleaning = 1;\n    //SPIFFS_GC_DBG(\"gcing: cleaning block \"_SPIPRIi\"\\n\", cand);\n    res = spiffs_gc_clean(fs, cand);\n    fs->cleaning = 0;\n    if (res < 0) {\n      SPIFFS_GC_DBG(\"gc_check: cleaning block \"_SPIPRIi\", result \"_SPIPRIi\"\\n\", cand, res);\n    } else {\n      SPIFFS_GC_DBG(\"gc_check: cleaning block \"_SPIPRIi\", result \"_SPIPRIi\"\\n\", cand, res);\n    }\n    SPIFFS_CHECK_RES(res);\n\n    res = spiffs_gc_erase_page_stats(fs, cand);\n    SPIFFS_CHECK_RES(res);\n\n    res = spiffs_gc_erase_block(fs, cand);\n    SPIFFS_CHECK_RES(res);\n\n    free_pages =\n          (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)\n          - fs->stats_p_allocated - fs->stats_p_deleted;\n\n    if (prev_free_pages <= 0 && prev_free_pages == free_pages) {\n      // abort early to reduce wear, at least tried once\n      SPIFFS_GC_DBG(\"gc_check: early abort, no result on gc when fs crammed\\n\");\n      break;\n    }\n\n  } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||\n      (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));\n\n  free_pages =\n        (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)\n        - fs->stats_p_allocated - fs->stats_p_deleted;\n  if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {\n    res = SPIFFS_ERR_FULL;\n  }\n\n  SPIFFS_GC_DBG(\"gc_check: finished, \"_SPIPRIi\" dirty, blocks \"_SPIPRIi\" free, \"_SPIPRIi\" pages free, \"_SPIPRIi\" tries, res \"_SPIPRIi\"\\n\",\n      fs->stats_p_allocated + fs->stats_p_deleted,\n      fs->free_blocks, free_pages, tries, res);\n\n  return res;\n}\n\n// Updates page statistics for a block that is about to be erased\ns32_t spiffs_gc_erase_page_stats(\n    spiffs *fs,\n    spiffs_block_ix bix) {\n  s32_t res = SPIFFS_OK;\n  int obj_lookup_page = 0;\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  int cur_entry = 0;\n  u32_t dele = 0;\n  u32_t allo = 0;\n\n  // check each object lookup page\n  while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n    int entry_offset = obj_lookup_page * entries_per_page;\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n        0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n    // check each entry\n    while (res == SPIFFS_OK &&\n        cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n      spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n      if (obj_id == SPIFFS_OBJ_ID_FREE) {\n      } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n        dele++;\n      } else {\n        allo++;\n      }\n      cur_entry++;\n    } // per entry\n    obj_lookup_page++;\n  } // per object lookup page\n  SPIFFS_GC_DBG(\"gc_check: wipe pallo:\"_SPIPRIi\" pdele:\"_SPIPRIi\"\\n\", allo, dele);\n  fs->stats_p_allocated -= allo;\n  fs->stats_p_deleted -= dele;\n  return res;\n}\n\n// Finds block candidates to erase\ns32_t spiffs_gc_find_candidate(\n    spiffs *fs,\n    spiffs_block_ix **block_candidates,\n    int *candidate_count,\n    char fs_crammed) {\n  s32_t res = SPIFFS_OK;\n  u32_t blocks = fs->block_count;\n  spiffs_block_ix cur_block = 0;\n  u32_t cur_block_addr = 0;\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  int cur_entry = 0;\n\n  // using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score\n  int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));\n  *candidate_count = 0;\n  memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n\n  // divide up work area into block indices and scores\n  spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;\n  s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));\n\n   // align cand_scores on s32_t boundary\n  cand_scores = (s32_t*)(((intptr_t)cand_scores + sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1));\n\n  *block_candidates = cand_blocks;\n\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n\n  // check each block\n  while (res == SPIFFS_OK && blocks--) {\n    u16_t deleted_pages_in_block = 0;\n    u16_t used_pages_in_block = 0;\n\n    int obj_lookup_page = 0;\n    // check each object lookup page\n    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each entry\n      while (res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page &&\n          cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n        if (obj_id == SPIFFS_OBJ_ID_FREE) {\n          // when a free entry is encountered, scan logic ensures that all following entries are free also\n          res = 1; // kill object lu loop\n          break;\n        } else  if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n          deleted_pages_in_block++;\n        } else {\n          used_pages_in_block++;\n        }\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n    if (res == 1) res = SPIFFS_OK;\n\n    // calculate score and insert into candidate table\n    // stoneage sort, but probably not so many blocks\n    if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) {\n      // read erase count\n      spiffs_obj_id erase_count;\n      res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,\n          SPIFFS_ERASE_COUNT_PADDR(fs, cur_block),\n          sizeof(spiffs_obj_id), (u8_t *)&erase_count);\n      SPIFFS_CHECK_RES(res);\n\n      spiffs_obj_id erase_age;\n      if (fs->max_erase_count > erase_count) {\n        erase_age = fs->max_erase_count - erase_count;\n      } else {\n        erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);\n      }\n\n      s32_t score =\n          deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +\n          used_pages_in_block * SPIFFS_GC_HEUR_W_USED +\n          erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);\n      int cand_ix = 0;\n      SPIFFS_GC_DBG(\"gc_check: bix:\"_SPIPRIbl\" del:\"_SPIPRIi\" use:\"_SPIPRIi\" score:\"_SPIPRIi\"\\n\", cur_block, deleted_pages_in_block, used_pages_in_block, score);\n      while (cand_ix < max_candidates) {\n        if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {\n          cand_blocks[cand_ix] = cur_block;\n          cand_scores[cand_ix] = score;\n          break;\n        } else if (cand_scores[cand_ix] < score) {\n          int reorder_cand_ix = max_candidates - 2;\n          while (reorder_cand_ix >= cand_ix) {\n            cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];\n            cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];\n            reorder_cand_ix--;\n          }\n          cand_blocks[cand_ix] = cur_block;\n          cand_scores[cand_ix] = score;\n          break;\n        }\n        cand_ix++;\n      }\n      (*candidate_count)++;\n    }\n\n    cur_entry = 0;\n    cur_block++;\n    cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n  } // per block\n\n  return res;\n}\n\ntypedef enum {\n  FIND_OBJ_DATA,\n  MOVE_OBJ_DATA,\n  MOVE_OBJ_IX,\n  FINISHED\n} spiffs_gc_clean_state;\n\ntypedef struct {\n  spiffs_gc_clean_state state;\n  spiffs_obj_id cur_obj_id;\n  spiffs_span_ix cur_objix_spix;\n  spiffs_page_ix cur_objix_pix;\n  spiffs_page_ix cur_data_pix;\n  int stored_scan_entry_index;\n  u8_t obj_id_found;\n} spiffs_gc;\n\n// Empties given block by moving all data into free pages of another block\n// Strategy:\n//   loop:\n//   scan object lookup for object data pages\n//   for first found id, check spix and load corresponding object index page to memory\n//   push object scan lookup entry index\n//     rescan object lookup, find data pages with same id and referenced by same object index\n//     move data page, update object index in memory\n//     when reached end of lookup, store updated object index\n//   pop object scan lookup entry index\n//   repeat loop until end of object lookup\n//   scan object lookup again for remaining object index pages, move to new page in other block\n//\ns32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {\n  s32_t res = SPIFFS_OK;\n  const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n  // this is the global localizer being pushed and popped\n  int cur_entry = 0;\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  spiffs_gc gc; // our stack frame/state\n  spiffs_page_ix cur_pix = 0;\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n\n  SPIFFS_GC_DBG(\"gc_clean: cleaning block \"_SPIPRIbl\"\\n\", bix);\n\n  memset(&gc, 0, sizeof(spiffs_gc));\n  gc.state = FIND_OBJ_DATA;\n\n  if (fs->free_cursor_block_ix == bix) {\n    // move free cursor to next block, cannot use free pages from the block we want to clean\n    fs->free_cursor_block_ix = (bix+1)%fs->block_count;\n    fs->free_cursor_obj_lu_entry = 0;\n    SPIFFS_GC_DBG(\"gc_clean: move free cursor to block \"_SPIPRIbl\"\\n\", fs->free_cursor_block_ix);\n  }\n\n  while (res == SPIFFS_OK && gc.state != FINISHED) {\n    SPIFFS_GC_DBG(\"gc_clean: state = \"_SPIPRIi\" entry:\"_SPIPRIi\"\\n\", gc.state, cur_entry);\n    gc.obj_id_found = 0; // reset (to no found data page)\n\n    // scan through lookup pages\n    int obj_lookup_page = cur_entry / entries_per_page;\n    u8_t scan = 1;\n    // check each object lookup page\n    while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),\n          SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each object lookup entry\n      while (scan && res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n        cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);\n\n        // act upon object id depending on gc state\n        switch (gc.state) {\n        case FIND_OBJ_DATA:\n          // find a data page\n          if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&\n              ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {\n            // found a data page, stop scanning and handle in switch case below\n            SPIFFS_GC_DBG(\"gc_clean: FIND_DATA state:\"_SPIPRIi\" - found obj id \"_SPIPRIid\"\\n\", gc.state, obj_id);\n            gc.obj_id_found = 1;\n            gc.cur_obj_id = obj_id;\n            gc.cur_data_pix = cur_pix;\n            scan = 0;\n          }\n          break;\n        case MOVE_OBJ_DATA:\n          // evacuate found data pages for corresponding object index we have in memory,\n          // update memory representation\n          if (obj_id == gc.cur_obj_id) {\n            spiffs_page_header p_hdr;\n            res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n            SPIFFS_CHECK_RES(res);\n            SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA found data page \"_SPIPRIid\":\"_SPIPRIsp\" @ \"_SPIPRIpg\"\\n\", gc.cur_obj_id, p_hdr.span_ix, cur_pix);\n            if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {\n              SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA no objix spix match, take in another run\\n\");\n            } else {\n              spiffs_page_ix new_data_pix;\n              if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {\n                // move page\n                res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);\n                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA move objix \"_SPIPRIid\":\"_SPIPRIsp\" page \"_SPIPRIpg\" to \"_SPIPRIpg\"\\n\", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);\n                SPIFFS_CHECK_RES(res);\n                // move wipes obj_lu, reload it\n                res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n                    0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),\n                    SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n                SPIFFS_CHECK_RES(res);\n              } else {\n                // page is deleted but not deleted in lookup, scrap it -\n                // might seem unnecessary as we will erase this block, but\n                // we might get aborted\n                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA wipe objix \"_SPIPRIid\":\"_SPIPRIsp\" page \"_SPIPRIpg\"\\n\", obj_id, p_hdr.span_ix, cur_pix);\n                res = spiffs_page_delete(fs, cur_pix);\n                SPIFFS_CHECK_RES(res);\n                new_data_pix = SPIFFS_OBJ_ID_FREE;\n              }\n              // update memory representation of object index page with new data page\n              if (gc.cur_objix_spix == 0) {\n                // update object index header page\n                ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;\n                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA wrote page \"_SPIPRIpg\" to objix_hdr entry \"_SPIPRIsp\" in mem\\n\", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));\n              } else {\n                // update object index page\n                ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;\n                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA wrote page \"_SPIPRIpg\" to objix entry \"_SPIPRIsp\" in mem\\n\", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));\n              }\n            }\n          }\n          break;\n        case MOVE_OBJ_IX:\n          // find and evacuate object index pages\n          if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&\n              (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {\n            // found an index object id\n            spiffs_page_header p_hdr;\n            spiffs_page_ix new_pix;\n            // load header\n            res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n            SPIFFS_CHECK_RES(res);\n            if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {\n              // move page\n              res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);\n              SPIFFS_GC_DBG(\"gc_clean: MOVE_OBJIX move objix \"_SPIPRIid\":\"_SPIPRIsp\" page \"_SPIPRIpg\" to \"_SPIPRIpg\"\\n\", obj_id, p_hdr.span_ix, cur_pix, new_pix);\n              SPIFFS_CHECK_RES(res);\n              spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&p_hdr,\n                  SPIFFS_EV_IX_MOV, obj_id, p_hdr.span_ix, new_pix, 0);\n              // move wipes obj_lu, reload it\n              res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n                  0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),\n                  SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n              SPIFFS_CHECK_RES(res);\n            } else {\n              // page is deleted but not deleted in lookup, scrap it -\n              // might seem unnecessary as we will erase this block, but\n              // we might get aborted\n              SPIFFS_GC_DBG(\"gc_clean: MOVE_OBJIX wipe objix \"_SPIPRIid\":\"_SPIPRIsp\" page \"_SPIPRIpg\"\\n\", obj_id, p_hdr.span_ix, cur_pix);\n              res = spiffs_page_delete(fs, cur_pix);\n              if (res == SPIFFS_OK) {\n                spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,\n                    SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);\n              }\n            }\n            SPIFFS_CHECK_RES(res);\n          }\n          break;\n        default:\n          scan = 0;\n          break;\n        } // switch gc state\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop\n    } // per object lookup page\n    if (res != SPIFFS_OK) break;\n\n    // state finalization and switch\n    switch (gc.state) {\n    case FIND_OBJ_DATA:\n      if (gc.obj_id_found) {\n        // handle found data page -\n        // find out corresponding obj ix page and load it to memory\n        spiffs_page_header p_hdr;\n        spiffs_page_ix objix_pix;\n        gc.stored_scan_entry_index = cur_entry; // push cursor\n        cur_entry = 0; // restart scan from start\n        gc.state = MOVE_OBJ_DATA;\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n            0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n        SPIFFS_CHECK_RES(res);\n        gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);\n        SPIFFS_GC_DBG(\"gc_clean: FIND_DATA find objix span_ix:\"_SPIPRIsp\"\\n\", gc.cur_objix_spix);\n        res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);\n        if (res == SPIFFS_ERR_NOT_FOUND) {\n          // on borked systems we might get an ERR_NOT_FOUND here -\n          // this is handled by simply deleting the page as it is not referenced\n          // from anywhere\n          SPIFFS_GC_DBG(\"gc_clean: FIND_OBJ_DATA objix not found! Wipe page \"_SPIPRIpg\"\\n\", gc.cur_data_pix);\n          res = spiffs_page_delete(fs, gc.cur_data_pix);\n          SPIFFS_CHECK_RES(res);\n          // then we restore states and continue scanning for data pages\n          cur_entry = gc.stored_scan_entry_index; // pop cursor\n          gc.state = FIND_OBJ_DATA;\n          break; // done\n        }\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_GC_DBG(\"gc_clean: FIND_DATA found object index at page \"_SPIPRIpg\"\\n\", objix_pix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n            0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        // cannot allow a gc if the presumed index in fact is no index, a\n        // check must run or lot of data may be lost\n        SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);\n        gc.cur_objix_pix = objix_pix;\n      } else {\n        // no more data pages found, passed thru all block, start evacuating object indices\n        gc.state = MOVE_OBJ_IX;\n        cur_entry = 0; // restart entry scan index\n      }\n      break;\n    case MOVE_OBJ_DATA: {\n      // store modified objix (hdr) page residing in memory now that all\n      // data pages belonging to this object index and residing in the block\n      // we want to evacuate\n      spiffs_page_ix new_objix_pix;\n      gc.state = FIND_OBJ_DATA;\n      cur_entry = gc.stored_scan_entry_index; // pop cursor\n      if (gc.cur_objix_spix == 0) {\n        // store object index header page\n        res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix);\n        SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA store modified objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", new_objix_pix, 0);\n        SPIFFS_CHECK_RES(res);\n      } else {\n        // store object index page\n        res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);\n        SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA store modified objix page, \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", new_objix_pix, objix->p_hdr.span_ix);\n        SPIFFS_CHECK_RES(res);\n        spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n            SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n      }\n    }\n    break;\n    case MOVE_OBJ_IX:\n      // scanned thru all block, no more object indices found - our work here is done\n      gc.state = FINISHED;\n      break;\n    default:\n      cur_entry = 0;\n      break;\n    } // switch gc.state\n    SPIFFS_GC_DBG(\"gc_clean: state-> \"_SPIPRIi\"\\n\", gc.state);\n  } // while state != FINISHED\n\n\n  return res;\n}\n\n#endif // !SPIFFS_READ_ONLY\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/spiffs_hydrogen.c",
    "content": "/*\n * spiffs_hydrogen.c\n *\n *  Created on: Jun 16, 2013\n *      Author: petera\n */\n\n#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\n#if SPIFFS_FILEHDL_OFFSET\n#define SPIFFS_FH_OFFS(fs, fh)   ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0)\n#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0)\n#else\n#define SPIFFS_FH_OFFS(fs, fh)   (fh)\n#define SPIFFS_FH_UNOFFS(fs, fh) (fh)\n#endif\n\n#if SPIFFS_CACHE == 1\nstatic s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);\n#endif\n\n#if SPIFFS_BUFFER_HELP\nu32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) {\n  return num_descs * sizeof(spiffs_fd);\n}\n#if SPIFFS_CACHE\nu32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) {\n  return sizeof(spiffs_cache) + num_pages * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs));\n}\n#endif\n#endif\n\nu8_t SPIFFS_mounted(spiffs *fs) {\n  return SPIFFS_CHECK_MOUNT(fs);\n}\n\ns32_t SPIFFS_format(spiffs *fs) {\n#if SPIFFS_READ_ONLY\n  (void)fs;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  if (SPIFFS_CHECK_MOUNT(fs)) {\n    fs->err_code = SPIFFS_ERR_MOUNTED;\n    return -1;\n  }\n\n  s32_t res;\n  SPIFFS_LOCK(fs);\n\n  spiffs_block_ix bix = 0;\n  while (bix < fs->block_count) {\n    fs->max_erase_count = 0;\n    res = spiffs_erase_block(fs, bix);\n    if (res != SPIFFS_OK) {\n      res = SPIFFS_ERR_ERASE_FAIL;\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    bix++;\n  }\n\n  SPIFFS_UNLOCK(fs);\n\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\n#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n\ns32_t SPIFFS_probe_fs(spiffs_config *config) {\n  s32_t res = spiffs_probe(config);\n  return res;\n}\n\n#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n\ns32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,\n    u8_t *fd_space, u32_t fd_space_size,\n    void *cache, u32_t cache_size,\n    spiffs_check_callback check_cb_f) {\n  void *user_data;\n  SPIFFS_LOCK(fs);\n  user_data = fs->user_data;\n  memset(fs, 0, sizeof(spiffs));\n  memcpy(&fs->cfg, config, sizeof(spiffs_config));\n  fs->user_data = user_data;\n  fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n  fs->work = &work[0];\n  fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];\n  memset(fd_space, 0, fd_space_size);\n  // align fd_space pointer to pointer size byte boundary\n  u8_t ptr_size = sizeof(void*);\n  u8_t addr_lsb = ((u8_t)(intptr_t)fd_space) & (ptr_size-1);\n  if (addr_lsb) {\n    fd_space += (ptr_size-addr_lsb);\n    fd_space_size -= (ptr_size-addr_lsb);\n  }\n  fs->fd_space = fd_space;\n  fs->fd_count = (fd_space_size/sizeof(spiffs_fd));\n\n  // align cache pointer to 4 byte boundary\n  addr_lsb = ((u8_t)(intptr_t)cache) & (ptr_size-1);\n  if (addr_lsb) {\n    u8_t *cache_8 = (u8_t *)cache;\n    cache_8 += (ptr_size-addr_lsb);\n    cache = cache_8;\n    cache_size -= (ptr_size-addr_lsb);\n  }\n  if (cache_size & (ptr_size-1)) {\n    cache_size -= (cache_size & (ptr_size-1));\n  }\n\n#if SPIFFS_CACHE\n  fs->cache = cache;\n  fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs)*32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs)*32 : cache_size;\n  spiffs_cache_init(fs);\n#endif\n\n  s32_t res;\n\n#if SPIFFS_USE_MAGIC\n  res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE;\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#endif\n\n  fs->config_magic = SPIFFS_CONFIG_MAGIC;\n\n  res = spiffs_obj_lu_scan(fs);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_DBG(\"page index byte len:         \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs));\n  SPIFFS_DBG(\"object lookup pages:         \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_OBJ_LOOKUP_PAGES(fs));\n  SPIFFS_DBG(\"page pages per block:        \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_PAGES_PER_BLOCK(fs));\n  SPIFFS_DBG(\"page header length:          \"_SPIPRIi\"\\n\", (u32_t)sizeof(spiffs_page_header));\n  SPIFFS_DBG(\"object header index entries: \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_OBJ_HDR_IX_LEN(fs));\n  SPIFFS_DBG(\"object index entries:        \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_OBJ_IX_LEN(fs));\n  SPIFFS_DBG(\"available file descriptors:  \"_SPIPRIi\"\\n\", (u32_t)fs->fd_count);\n  SPIFFS_DBG(\"free blocks:                 \"_SPIPRIi\"\\n\", (u32_t)fs->free_blocks);\n\n  fs->check_cb_f = check_cb_f;\n\n  fs->mounted = 1;\n\n  SPIFFS_UNLOCK(fs);\n\n  return 0;\n}\n\nvoid SPIFFS_unmount(spiffs *fs) {\n  if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return;\n  SPIFFS_LOCK(fs);\n  u32_t i;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->file_nbr != 0) {\n#if SPIFFS_CACHE\n      (void)spiffs_fflush_cache(fs, cur_fd->file_nbr);\n#endif\n      spiffs_fd_return(fs, cur_fd->file_nbr);\n    }\n  }\n  fs->mounted = 0;\n\n  SPIFFS_UNLOCK(fs);\n}\n\ns32_t SPIFFS_errno(spiffs *fs) {\n  return fs->err_code;\n}\n\nvoid SPIFFS_clearerr(spiffs *fs) {\n  fs->err_code = SPIFFS_OK;\n}\n\ns32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)path; (void)mode;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  (void)mode;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n  spiffs_obj_id obj_id;\n  s32_t res;\n\n  res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (const u8_t*)path);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  SPIFFS_UNLOCK(fs);\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\nspiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) {\n  (void)mode;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  spiffs_page_ix pix;\n\n#if SPIFFS_READ_ONLY\n  // not valid flags in read only mode\n  flags &= ~(SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_TRUNC);\n#endif // SPIFFS_READ_ONLY\n\n  s32_t res = spiffs_fd_find_new(fs, &fd, path);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);\n  if ((flags & SPIFFS_O_CREAT) == 0) {\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  if (res == SPIFFS_OK &&\n      (flags & (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) == (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) {\n    // creat and excl and file exists - fail\n    res = SPIFFS_ERR_FILE_EXISTS;\n    spiffs_fd_return(fs, fd->file_nbr);\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  if ((flags & SPIFFS_O_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {\n#if !SPIFFS_READ_ONLY\n    spiffs_obj_id obj_id;\n    // no need to enter conflicting name here, already looked for it above\n    res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, 0);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, &pix);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    flags &= ~SPIFFS_O_TRUNC;\n#endif // !SPIFFS_READ_ONLY\n  } else {\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n  res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);\n  if (res < SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#if !SPIFFS_READ_ONLY\n  if (flags & SPIFFS_O_TRUNC) {\n    res = spiffs_object_truncate(fd, 0, 0);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n#endif // !SPIFFS_READ_ONLY\n\n  fd->fdoffset = 0;\n\n  SPIFFS_UNLOCK(fs);\n\n  return SPIFFS_FH_OFFS(fs, fd->file_nbr);\n}\n\nspiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n\n  s32_t res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_open_by_page(fs, e->pix, fd, flags, mode);\n  if (res < SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#if !SPIFFS_READ_ONLY\n  if (flags & SPIFFS_O_TRUNC) {\n    res = spiffs_object_truncate(fd, 0, 0);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n#endif // !SPIFFS_READ_ONLY\n\n  fd->fdoffset = 0;\n\n  SPIFFS_UNLOCK(fs);\n\n  return SPIFFS_FH_OFFS(fs, fd->file_nbr);\n}\n\nspiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n\n  s32_t res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if (SPIFFS_IS_LOOKUP_PAGE(fs, page_ix)) {\n    res = SPIFFS_ERR_NOT_A_FILE;\n    spiffs_fd_return(fs, fd->file_nbr);\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  res = spiffs_object_open_by_page(fs, page_ix, fd, flags, mode);\n  if (res == SPIFFS_ERR_IS_FREE ||\n      res == SPIFFS_ERR_DELETED ||\n      res == SPIFFS_ERR_NOT_FINALIZED ||\n      res == SPIFFS_ERR_NOT_INDEX ||\n      res == SPIFFS_ERR_INDEX_SPAN_MISMATCH) {\n    res = SPIFFS_ERR_NOT_A_FILE;\n  }\n  if (res < SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if !SPIFFS_READ_ONLY\n  if (flags & SPIFFS_O_TRUNC) {\n    res = spiffs_object_truncate(fd, 0, 0);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n#endif // !SPIFFS_READ_ONLY\n\n  fd->fdoffset = 0;\n\n  SPIFFS_UNLOCK(fs);\n\n  return SPIFFS_FH_OFFS(fs, fd->file_nbr);\n}\n\nstatic s32_t spiffs_hydro_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_O_RDONLY) == 0) {\n    res = SPIFFS_ERR_NOT_READABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  if (fd->size == SPIFFS_UNDEFINED_LEN && len > 0) {\n    // special case for zero sized files\n    res = SPIFFS_ERR_END_OF_OBJECT;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  if (fd->fdoffset + len >= fd->size) {\n    // reading beyond file size\n    s32_t avail = fd->size - fd->fdoffset;\n    if (avail <= 0) {\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_END_OF_OBJECT);\n    }\n    res = spiffs_object_read(fd, fd->fdoffset, avail, (u8_t*)buf);\n    if (res == SPIFFS_ERR_END_OF_OBJECT) {\n      fd->fdoffset += avail;\n      SPIFFS_UNLOCK(fs);\n      return avail;\n    } else {\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n      len = avail;\n    }\n  } else {\n    // reading within file size\n    res = spiffs_object_read(fd, fd->fdoffset, len, (u8_t*)buf);\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n  fd->fdoffset += len;\n\n  SPIFFS_UNLOCK(fs);\n\n  return len;\n}\n\ns32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {\n  s32_t res = spiffs_hydro_read(fs, fh, buf, len);\n  if (res == SPIFFS_ERR_END_OF_OBJECT) {\n    res = 0;\n  }\n  return res;\n}\n\n\n#if !SPIFFS_READ_ONLY\nstatic s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) {\n  (void)fs;\n  s32_t res = SPIFFS_OK;\n  s32_t remaining = len;\n  if (fd->size != SPIFFS_UNDEFINED_LEN && offset < fd->size) {\n    s32_t m_len = MIN((s32_t)(fd->size - offset), len);\n    res = spiffs_object_modify(fd, offset, (u8_t *)buf, m_len);\n    SPIFFS_CHECK_RES(res);\n    remaining -= m_len;\n    u8_t *buf_8 = (u8_t *)buf;\n    buf_8 += m_len;\n    buf = buf_8;\n    offset += m_len;\n  }\n  if (remaining > 0) {\n    res = spiffs_object_append(fd, offset, (u8_t *)buf, remaining);\n    SPIFFS_CHECK_RES(res);\n  }\n  return len;\n\n}\n#endif // !SPIFFS_READ_ONLY\n\ns32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)fh; (void)buf; (void)len;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  u32_t offset;\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_O_WRONLY) == 0) {\n    res = SPIFFS_ERR_NOT_WRITABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  if ((fd->flags & SPIFFS_O_APPEND)) {\n    fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;\n  }\n\n  offset = fd->fdoffset;\n\n#if SPIFFS_CACHE_WR\n  if (fd->cache_page == 0) {\n    // see if object id is associated with cache already\n    fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);\n  }\n#endif\n  if (fd->flags & SPIFFS_O_APPEND) {\n    if (fd->size == SPIFFS_UNDEFINED_LEN) {\n      offset = 0;\n    } else {\n      offset = fd->size;\n    }\n#if SPIFFS_CACHE_WR\n    if (fd->cache_page) {\n      offset = MAX(offset, fd->cache_page->offset + fd->cache_page->size);\n    }\n#endif\n  }\n\n#if SPIFFS_CACHE_WR\n  if ((fd->flags & SPIFFS_O_DIRECT) == 0) {\n    if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) {\n      // small write, try to cache it\n      u8_t alloc_cpage = 1;\n      if (fd->cache_page) {\n        // have a cached page for this fd already, check cache page boundaries\n        if (offset < fd->cache_page->offset || // writing before cache\n            offset > fd->cache_page->offset + fd->cache_page->size || // writing after cache\n            offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page\n        {\n          // boundary violation, write back cache first and allocate new\n          SPIFFS_CACHE_DBG(\"CACHE_WR_DUMP: dumping cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\", boundary viol, offs:\"_SPIPRIi\" size:\"_SPIPRIi\"\\n\",\n              fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);\n          res = spiffs_hydro_write(fs, fd,\n              spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),\n              fd->cache_page->offset, fd->cache_page->size);\n          spiffs_cache_fd_release(fs, fd->cache_page);\n          SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n        } else {\n          // writing within cache\n          alloc_cpage = 0;\n        }\n      }\n\n      if (alloc_cpage) {\n        fd->cache_page = spiffs_cache_page_allocate_by_fd(fs, fd);\n        if (fd->cache_page) {\n          fd->cache_page->offset = offset;\n          fd->cache_page->size = 0;\n          SPIFFS_CACHE_DBG(\"CACHE_WR_ALLO: allocating cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\"\\n\",\n              fd->cache_page->ix, fd->file_nbr, fd->obj_id);\n        }\n      }\n\n      if (fd->cache_page) {\n        u32_t offset_in_cpage = offset - fd->cache_page->offset;\n        SPIFFS_CACHE_DBG(\"CACHE_WR_WRITE: storing to cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\", offs \"_SPIPRIi\":\"_SPIPRIi\" len \"_SPIPRIi\"\\n\",\n            fd->cache_page->ix, fd->file_nbr, fd->obj_id,\n            offset, offset_in_cpage, len);\n        spiffs_cache *cache = spiffs_get_cache(fs);\n        u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);\n        memcpy(&cpage_data[offset_in_cpage], buf, len);\n        fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);\n        fd->fdoffset += len;\n        SPIFFS_UNLOCK(fs);\n        return len;\n      } else {\n        res = spiffs_hydro_write(fs, fd, buf, offset, len);\n        SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n        fd->fdoffset += len;\n        SPIFFS_UNLOCK(fs);\n        return res;\n      }\n    } else {\n      // big write, no need to cache it - but first check if there is a cached write already\n      if (fd->cache_page) {\n        // write back cache first\n        SPIFFS_CACHE_DBG(\"CACHE_WR_DUMP: dumping cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\", big write, offs:\"_SPIPRIi\" size:\"_SPIPRIi\"\\n\",\n            fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);\n        res = spiffs_hydro_write(fs, fd,\n            spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),\n            fd->cache_page->offset, fd->cache_page->size);\n        spiffs_cache_fd_release(fs, fd->cache_page);\n        SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n        // data written below\n      }\n    }\n  }\n#endif\n\n  res = spiffs_hydro_write(fs, fd, buf, offset, len);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  fd->fdoffset += len;\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  s32_t fileSize = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;\n\n  switch (whence) {\n  case SPIFFS_SEEK_CUR:\n    offs = fd->fdoffset+offs;\n    break;\n  case SPIFFS_SEEK_END:\n    offs = fileSize + offs;\n    break;\n  }\n\n  if ((offs > fileSize)) {\n    fd->fdoffset = fileSize;\n    res = SPIFFS_ERR_END_OF_OBJECT;\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  spiffs_span_ix data_spix = offs / SPIFFS_DATA_PAGE_SIZE(fs);\n  spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n  if (fd->cursor_objix_spix != objix_spix) {\n    spiffs_page_ix pix;\n    res = spiffs_obj_lu_find_id_and_span(\n        fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, &pix);\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    fd->cursor_objix_spix = objix_spix;\n    fd->cursor_objix_pix = pix;\n  }\n  fd->fdoffset = offs;\n\n  SPIFFS_UNLOCK(fs);\n\n  return offs;\n}\n\ns32_t SPIFFS_remove(spiffs *fs, const char *path) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)path;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  spiffs_page_ix pix;\n  s32_t res;\n\n  res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_open_by_page(fs, pix, fd, 0,0);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_truncate(fd, 0, 1);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)fh;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_O_WRONLY) == 0) {\n    res = SPIFFS_ERR_NOT_WRITABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n#if SPIFFS_CACHE_WR\n  spiffs_cache_fd_release(fs, fd->cache_page);\n#endif\n\n  res = spiffs_object_truncate(fd, 0, 1);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\nstatic s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {\n  (void)fh;\n  spiffs_page_object_ix_header objix_hdr;\n  spiffs_obj_id obj_id;\n  s32_t res =_spiffs_rd(fs,  SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,\n      SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n  u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , pix)) +\n      SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_obj_id);\n  res =_spiffs_rd(fs,  SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, fh,\n      obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n  s->obj_id = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n  s->type = objix_hdr.type;\n  s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;\n  s->pix = pix;\n  strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN);\n#if SPIFFS_OBJ_META_LEN\n  memcpy(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);\n#endif\n\n  return res;\n}\n\ns32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n\n  s32_t res;\n  spiffs_page_ix pix;\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_stat_pix(fs, pix, 0, s);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n}\n\ns32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  res = spiffs_stat_pix(fs, fd->objix_hdr_pix, fh, s);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n}\n\n// Checks if there are any cached writes for the object id associated with\n// given filehandle. If so, these writes are flushed.\n#if SPIFFS_CACHE == 1\nstatic s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {\n  (void)fs;\n  (void)fh;\n  s32_t res = SPIFFS_OK;\n#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n  if ((fd->flags & SPIFFS_O_DIRECT) == 0) {\n    if (fd->cache_page == 0) {\n      // see if object id is associated with cache already\n      fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);\n    }\n    if (fd->cache_page) {\n      SPIFFS_CACHE_DBG(\"CACHE_WR_DUMP: dumping cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\", flush, offs:\"_SPIPRIi\" size:\"_SPIPRIi\"\\n\",\n          fd->cache_page->ix, fd->file_nbr,  fd->obj_id, fd->cache_page->offset, fd->cache_page->size);\n      res = spiffs_hydro_write(fs, fd,\n          spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),\n          fd->cache_page->offset, fd->cache_page->size);\n      if (res < SPIFFS_OK) {\n        fs->err_code = res;\n      }\n      spiffs_cache_fd_release(fs, fd->cache_page);\n    }\n  }\n#endif\n\n  return res;\n}\n#endif\n\ns32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {\n  (void)fh;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  s32_t res = SPIFFS_OK;\n#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR\n  SPIFFS_LOCK(fs);\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fflush_cache(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs,res);\n  SPIFFS_UNLOCK(fs);\n#endif\n\n  return res;\n}\n\ns32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n\n  s32_t res = SPIFFS_OK;\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n#if SPIFFS_CACHE\n  res = spiffs_fflush_cache(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#endif\n  res = spiffs_fd_return(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n}\n\ns32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)old_path; (void)new_path;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(new_path) > SPIFFS_OBJ_NAME_LEN - 1 ||\n      strlen(old_path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n\n  spiffs_page_ix pix_old, pix_dummy;\n  spiffs_fd *fd;\n\n  s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)old_path, &pix_old);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)new_path, &pix_dummy);\n  if (res == SPIFFS_ERR_NOT_FOUND) {\n    res = SPIFFS_OK;\n  } else if (res == SPIFFS_OK) {\n    res = SPIFFS_ERR_CONFLICTING_NAME;\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_open_by_page(fs, pix_old, fd, 0, 0);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (const u8_t*)new_path,\n      0, 0, &pix_dummy);\n#if SPIFFS_TEMPORAL_FD_CACHE\n  if (res == SPIFFS_OK) {\n    spiffs_fd_temporal_cache_rehash(fs, old_path, new_path);\n  }\n#endif\n\n  spiffs_fd_return(fs, fd->file_nbr);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n\n#if SPIFFS_OBJ_META_LEN\ns32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)name; (void)meta;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_page_ix pix, pix_dummy;\n  spiffs_fd *fd;\n\n  s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)name, &pix);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_open_by_page(fs, pix, fd, 0, 0);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,\n      0, &pix_dummy);\n\n  spiffs_fd_return(fs, fd->file_nbr);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)fh; (void)meta;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  s32_t res;\n  spiffs_fd *fd;\n  spiffs_page_ix pix_dummy;\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_O_WRONLY) == 0) {\n    res = SPIFFS_ERR_NOT_WRITABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,\n      0, &pix_dummy);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n#endif // SPIFFS_OBJ_META_LEN\n\nspiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {\n  (void)name;\n\n  if (!SPIFFS_CHECK_CFG((fs))) {\n    (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;\n    return 0;\n  }\n\n  if (!SPIFFS_CHECK_MOUNT(fs)) {\n    fs->err_code = SPIFFS_ERR_NOT_MOUNTED;\n    return 0;\n  }\n\n  d->fs = fs;\n  d->block = 0;\n  d->entry = 0;\n  return d;\n}\n\nstatic s32_t spiffs_read_dir_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  (void)user_const_p;\n  s32_t res;\n  spiffs_page_object_ix_header objix_hdr;\n  if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||\n      (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {\n    return SPIFFS_VIS_COUNTINUE;\n  }\n\n  spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);\n  if (res != SPIFFS_OK) return res;\n  if ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) &&\n      objix_hdr.p_hdr.span_ix == 0 &&\n      (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==\n          (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {\n    struct spiffs_dirent *e = (struct spiffs_dirent*)user_var_p;\n    e->obj_id = obj_id;\n    strcpy((char *)e->name, (char *)objix_hdr.name);\n    e->type = objix_hdr.type;\n    e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;\n    e->pix = pix;\n#if SPIFFS_OBJ_META_LEN\n  memcpy(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);\n#endif\n    return SPIFFS_OK;\n  }\n  return SPIFFS_VIS_COUNTINUE;\n}\n\nstruct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {\n  if (!SPIFFS_CHECK_MOUNT(d->fs)) {\n    d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;\n    return 0;\n  }\n  SPIFFS_LOCK(d->fs);\n\n  spiffs_block_ix bix;\n  int entry;\n  s32_t res;\n  struct spiffs_dirent *ret = 0;\n\n  res = spiffs_obj_lu_find_entry_visitor(d->fs,\n      d->block,\n      d->entry,\n      SPIFFS_VIS_NO_WRAP,\n      0,\n      spiffs_read_dir_v,\n      0,\n      e,\n      &bix,\n      &entry);\n  if (res == SPIFFS_OK) {\n    d->block = bix;\n    d->entry = entry + 1;\n    e->obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n    ret = e;\n  } else {\n    d->fs->err_code = res;\n  }\n  SPIFFS_UNLOCK(d->fs);\n  return ret;\n}\n\ns32_t SPIFFS_closedir(spiffs_DIR *d) {\n  SPIFFS_API_CHECK_CFG(d->fs);\n  SPIFFS_API_CHECK_MOUNT(d->fs);\n  return 0;\n}\n\ns32_t SPIFFS_check(spiffs *fs) {\n#if SPIFFS_READ_ONLY\n  (void)fs;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  res = spiffs_lookup_consistency_check(fs, 0);\n\n  res = spiffs_object_index_consistency_check(fs);\n\n  res = spiffs_page_consistency_check(fs);\n\n  res = spiffs_obj_lu_scan(fs);\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {\n  s32_t res = SPIFFS_OK;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs);\n  u32_t blocks = fs->block_count;\n  u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs);\n  u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs);\n  u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page\n\n  if (total) {\n    *total = total_data_pages * data_page_size;\n  }\n\n  if (used) {\n    *used = fs->stats_p_allocated * data_page_size;\n  }\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)max_free_pages;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  res = spiffs_gc_quick(fs, max_free_pages);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  SPIFFS_UNLOCK(fs);\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\n\ns32_t SPIFFS_gc(spiffs *fs, u32_t size) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)size;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  res = spiffs_gc_check(fs, size);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  SPIFFS_UNLOCK(fs);\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if SPIFFS_CACHE_WR\n  res = spiffs_fflush_cache(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#endif\n\n  res = (fd->fdoffset >= (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size));\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if SPIFFS_CACHE_WR\n  res = spiffs_fflush_cache(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#endif\n\n  res = fd->fdoffset;\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) {\n  SPIFFS_LOCK(fs);\n  fs->file_cb_f = cb_func;\n  SPIFFS_UNLOCK(fs);\n  return 0;\n}\n\n#if SPIFFS_IX_MAP\n\ns32_t SPIFFS_ix_map(spiffs *fs,  spiffs_file fh, spiffs_ix_map *map,\n    u32_t offset, u32_t len, spiffs_page_ix *map_buf) {\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if (fd->ix_map) {\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_MAPPED);\n  }\n\n  map->map_buf = map_buf;\n  map->offset = offset;\n  // nb: spix range includes last\n  map->start_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);\n  map->end_spix = (offset + len) / SPIFFS_DATA_PAGE_SIZE(fs);\n  memset(map_buf, 0, sizeof(spiffs_page_ix) * (map->end_spix - map->start_spix + 1));\n  fd->ix_map = map;\n\n  // scan for pixes\n  res = spiffs_populate_ix_map(fs, fd, 0, map->end_spix - map->start_spix + 1);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_ix_unmap(spiffs *fs,  spiffs_file fh) {\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if (fd->ix_map == 0) {\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);\n  }\n\n  fd->ix_map = 0;\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset) {\n  s32_t res = SPIFFS_OK;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if (fd->ix_map == 0) {\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);\n  }\n\n  spiffs_ix_map *map = fd->ix_map;\n\n  s32_t spix_diff = offset / SPIFFS_DATA_PAGE_SIZE(fs) - map->start_spix;\n  map->offset = offset;\n\n  // move existing pixes if within map offs\n  if (spix_diff != 0) {\n    // move vector\n    int i;\n    const s32_t vec_len = map->end_spix - map->start_spix + 1; // spix range includes last\n    map->start_spix += spix_diff;\n    map->end_spix += spix_diff;\n    if (spix_diff >= vec_len) {\n      // moving beyond range\n      memset(&map->map_buf, 0, vec_len * sizeof(spiffs_page_ix));\n      // populate_ix_map is inclusive\n      res = spiffs_populate_ix_map(fs, fd, 0, vec_len-1);\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    } else if (spix_diff > 0) {\n      // diff positive\n      for (i = 0; i < vec_len - spix_diff; i++) {\n        map->map_buf[i] = map->map_buf[i + spix_diff];\n      }\n      // memset is non-inclusive\n      memset(&map->map_buf[vec_len - spix_diff], 0, spix_diff * sizeof(spiffs_page_ix));\n      // populate_ix_map is inclusive\n      res = spiffs_populate_ix_map(fs, fd, vec_len - spix_diff, vec_len-1);\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    } else {\n      // diff negative\n      for (i = vec_len - 1; i >= -spix_diff; i--) {\n        map->map_buf[i] = map->map_buf[i + spix_diff];\n      }\n      // memset is non-inclusive\n      memset(&map->map_buf[0], 0, -spix_diff * sizeof(spiffs_page_ix));\n      // populate_ix_map is inclusive\n      res = spiffs_populate_ix_map(fs, fd, 0, -spix_diff - 1);\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    }\n\n  }\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes) {\n  SPIFFS_API_CHECK_CFG(fs);\n  // always add one extra page, the offset might change to the middle of a page\n  return (bytes + SPIFFS_DATA_PAGE_SIZE(fs) ) / SPIFFS_DATA_PAGE_SIZE(fs);\n}\n\ns32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries) {\n  SPIFFS_API_CHECK_CFG(fs);\n  return map_page_ix_entries * SPIFFS_DATA_PAGE_SIZE(fs);\n}\n\n#endif // SPIFFS_IX_MAP\n\n#if SPIFFS_TEST_VISUALISATION\ns32_t SPIFFS_vis(spiffs *fs) {\n  s32_t res = SPIFFS_OK;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  spiffs_block_ix bix = 0;\n\n  while (bix < fs->block_count) {\n    // check each object lookup page\n    int obj_lookup_page = 0;\n    int cur_entry = 0;\n\n    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each entry\n      while (res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n        if (cur_entry == 0) {\n          spiffs_printf(_SPIPRIbl\" \", bix);\n        } else if ((cur_entry & 0x3f) == 0) {\n          spiffs_printf(\"     \");\n        }\n        if (obj_id == SPIFFS_OBJ_ID_FREE) {\n          spiffs_printf(SPIFFS_TEST_VIS_FREE_STR);\n        } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n          spiffs_printf(SPIFFS_TEST_VIS_DELE_STR);\n        } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG){\n          spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id));\n        } else {\n          spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id));\n        }\n        cur_entry++;\n        if ((cur_entry & 0x3f) == 0) {\n          spiffs_printf(\"\\n\");\n        }\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n\n    spiffs_obj_id erase_count;\n    res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,\n        SPIFFS_ERASE_COUNT_PADDR(fs, bix),\n        sizeof(spiffs_obj_id), (u8_t *)&erase_count);\n    SPIFFS_CHECK_RES(res);\n\n    if (erase_count != (spiffs_obj_id)-1) {\n      spiffs_printf(\"\\tera_cnt: \"_SPIPRIi\"\\n\", erase_count);\n    } else {\n      spiffs_printf(\"\\tera_cnt: N/A\\n\");\n    }\n\n    bix++;\n  } // per block\n\n  spiffs_printf(\"era_cnt_max: \"_SPIPRIi\"\\n\", fs->max_erase_count);\n  spiffs_printf(\"last_errno:  \"_SPIPRIi\"\\n\", fs->err_code);\n  spiffs_printf(\"blocks:      \"_SPIPRIi\"\\n\", fs->block_count);\n  spiffs_printf(\"free_blocks: \"_SPIPRIi\"\\n\", fs->free_blocks);\n  spiffs_printf(\"page_alloc:  \"_SPIPRIi\"\\n\", fs->stats_p_allocated);\n  spiffs_printf(\"page_delet:  \"_SPIPRIi\"\\n\", fs->stats_p_deleted);\n  SPIFFS_UNLOCK(fs);\n  u32_t total, used;\n  SPIFFS_info(fs, &total, &used);\n  spiffs_printf(\"used:        \"_SPIPRIi\" of \"_SPIPRIi\"\\n\", used, total);\n  return res;\n}\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/spiffs_nucleus.c",
    "content": "#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\nstatic s32_t spiffs_page_data_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) {\n  s32_t res = SPIFFS_OK;\n  if (pix == (spiffs_page_ix)-1) {\n    // referring to page 0xffff...., bad object index\n    return SPIFFS_ERR_INDEX_REF_FREE;\n  }\n  if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n    // referring to an object lookup page, bad object index\n    return SPIFFS_ERR_INDEX_REF_LU;\n  }\n  if (pix > SPIFFS_MAX_PAGES(fs)) {\n    // referring to a bad page\n    return SPIFFS_ERR_INDEX_REF_INVALID;\n  }\n#if SPIFFS_PAGE_CHECK\n  spiffs_page_header ph;\n  res = _spiffs_rd(\n      fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,\n      fd->file_nbr,\n      SPIFFS_PAGE_TO_PADDR(fs, pix),\n      sizeof(spiffs_page_header),\n      (u8_t *)&ph);\n  SPIFFS_CHECK_RES(res);\n  SPIFFS_VALIDATE_DATA(ph, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, spix);\n#endif\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\nstatic s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) {\n  s32_t res = SPIFFS_OK;\n  if (pix == (spiffs_page_ix)-1) {\n    // referring to page 0xffff...., bad object index\n    return SPIFFS_ERR_INDEX_FREE;\n  }\n  if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n    // referring to an object lookup page, bad object index\n    return SPIFFS_ERR_INDEX_LU;\n  }\n  if (pix > SPIFFS_MAX_PAGES(fs)) {\n    // referring to a bad page\n    return SPIFFS_ERR_INDEX_INVALID;\n  }\n#if SPIFFS_PAGE_CHECK\n  spiffs_page_header ph;\n  res = _spiffs_rd(\n      fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n      fd->file_nbr,\n      SPIFFS_PAGE_TO_PADDR(fs, pix),\n      sizeof(spiffs_page_header),\n      (u8_t *)&ph);\n  SPIFFS_CHECK_RES(res);\n  SPIFFS_VALIDATE_OBJIX(ph, fd->obj_id, spix);\n#endif\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_CACHE\n\ns32_t spiffs_phys_rd(\n    spiffs *fs,\n    u32_t addr,\n    u32_t len,\n    u8_t *dst) {\n  return SPIFFS_HAL_READ(fs, addr, len, dst);\n}\n\ns32_t spiffs_phys_wr(\n    spiffs *fs,\n    u32_t addr,\n    u32_t len,\n    u8_t *src) {\n  return SPIFFS_HAL_WRITE(fs, addr, len, src);\n}\n\n#endif\n\n#if !SPIFFS_READ_ONLY\ns32_t spiffs_phys_cpy(\n    spiffs *fs,\n    spiffs_file fh,\n    u32_t dst,\n    u32_t src,\n    u32_t len) {\n  (void)fh;\n  s32_t res;\n  u8_t b[SPIFFS_COPY_BUFFER_STACK];\n  while (len > 0) {\n    u32_t chunk_size = MIN(SPIFFS_COPY_BUFFER_STACK, len);\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVS, fh, src, chunk_size, b);\n    SPIFFS_CHECK_RES(res);\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVD,  fh, dst, chunk_size, b);\n    SPIFFS_CHECK_RES(res);\n    len -= chunk_size;\n    src += chunk_size;\n    dst += chunk_size;\n  }\n  return SPIFFS_OK;\n}\n#endif // !SPIFFS_READ_ONLY\n\n// Find object lookup entry containing given id with visitor.\n// Iterate over object lookup pages in each block until a given object id entry is found.\n// When found, the visitor function is called with block index, entry index and user data.\n// If visitor returns SPIFFS_VIS_CONTINUE, the search goes on. Otherwise, the search will be\n// ended and visitor's return code is returned to caller.\n// If no visitor is given (0) the search returns on first entry with matching object id.\n// If no match is found in all look up, SPIFFS_VIS_END is returned.\n// @param fs                    the file system\n// @param starting_block        the starting block to start search in\n// @param starting_lu_entry     the look up index entry to start search in\n// @param flags                 ored combination of SPIFFS_VIS_CHECK_ID, SPIFFS_VIS_CHECK_PH,\n//                              SPIFFS_VIS_NO_WRAP\n// @param obj_id                argument object id\n// @param v                     visitor callback function\n// @param user_const_p          any const pointer, passed to the callback visitor function\n// @param user_var_p            any pointer, passed to the callback visitor function\n// @param block_ix              reported block index where match was found\n// @param lu_entry              reported look up index where match was found\ns32_t spiffs_obj_lu_find_entry_visitor(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    u8_t flags,\n    spiffs_obj_id obj_id,\n    spiffs_visitor_f v,\n    const void *user_const_p,\n    void *user_var_p,\n    spiffs_block_ix *block_ix,\n    int *lu_entry) {\n  s32_t res = SPIFFS_OK;\n  s32_t entry_count = fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs);\n  spiffs_block_ix cur_block = starting_block;\n  u32_t cur_block_addr = starting_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  int cur_entry = starting_lu_entry;\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n\n  // wrap initial\n  if (cur_entry > (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) - 1) {\n    cur_entry = 0;\n    cur_block++;\n    cur_block_addr = cur_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n    if (cur_block >= fs->block_count) {\n      if (flags & SPIFFS_VIS_NO_WRAP) {\n        return SPIFFS_VIS_END;\n      } else {\n        // block wrap\n        cur_block = 0;\n        cur_block_addr = 0;\n      }\n    }\n  }\n\n  // check each block\n  while (res == SPIFFS_OK && entry_count > 0) {\n    int obj_lookup_page = cur_entry / entries_per_page;\n    // check each object lookup page\n    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each entry\n      while (res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page && // for non-last obj lookup pages\n          cur_entry < (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) // for last obj lookup page\n      {\n        if ((flags & SPIFFS_VIS_CHECK_ID) == 0 || obj_lu_buf[cur_entry-entry_offset] == obj_id) {\n          if (block_ix) *block_ix = cur_block;\n          if (lu_entry) *lu_entry = cur_entry;\n          if (v) {\n            res = v(\n                fs,\n                (flags & SPIFFS_VIS_CHECK_PH) ? obj_id : obj_lu_buf[cur_entry-entry_offset],\n                cur_block,\n                cur_entry,\n                user_const_p,\n                user_var_p);\n            if (res == SPIFFS_VIS_COUNTINUE || res == SPIFFS_VIS_COUNTINUE_RELOAD) {\n              if (res == SPIFFS_VIS_COUNTINUE_RELOAD) {\n                res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n                    0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n                SPIFFS_CHECK_RES(res);\n              }\n              res = SPIFFS_OK;\n              cur_entry++;\n              entry_count--;\n              continue;\n            } else {\n              return res;\n            }\n          } else {\n            return SPIFFS_OK;\n          }\n        }\n        entry_count--;\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n    cur_entry = 0;\n    cur_block++;\n    cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n    if (cur_block >= fs->block_count) {\n      if (flags & SPIFFS_VIS_NO_WRAP) {\n        return SPIFFS_VIS_END;\n      } else {\n        // block wrap\n        cur_block = 0;\n        cur_block_addr = 0;\n      }\n    }\n  } // per block\n\n  SPIFFS_CHECK_RES(res);\n\n  return SPIFFS_VIS_END;\n}\n\n#if !SPIFFS_READ_ONLY\ns32_t spiffs_erase_block(\n    spiffs *fs,\n    spiffs_block_ix bix) {\n  s32_t res;\n  u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix);\n  s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n\n  // here we ignore res, just try erasing the block\n  while (size > 0) {\n    SPIFFS_DBG(\"erase \"_SPIPRIad\":\"_SPIPRIi\"\\n\", addr,  SPIFFS_CFG_PHYS_ERASE_SZ(fs));\n    SPIFFS_HAL_ERASE(fs, addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));\n\n    addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);\n    size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);\n  }\n  fs->free_blocks++;\n\n  // register erase count for this block\n  res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,\n      SPIFFS_ERASE_COUNT_PADDR(fs, bix),\n      sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count);\n  SPIFFS_CHECK_RES(res);\n\n#if SPIFFS_USE_MAGIC\n  // finally, write magic\n  spiffs_obj_id magic = SPIFFS_MAGIC(fs, bix);\n  res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,\n      SPIFFS_MAGIC_PADDR(fs, bix),\n      sizeof(spiffs_obj_id), (u8_t *)&magic);\n  SPIFFS_CHECK_RES(res);\n#endif\n\n  fs->max_erase_count++;\n  if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) {\n    fs->max_erase_count = 0;\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\ns32_t spiffs_probe(\n    spiffs_config *cfg) {\n  s32_t res;\n  u32_t paddr;\n  spiffs dummy_fs; // create a dummy fs struct just to be able to use macros\n  memcpy(&dummy_fs.cfg, cfg, sizeof(spiffs_config));\n  dummy_fs.block_count = 0;\n\n  // Read three magics, as one block may be in an aborted erase state.\n  // At least two of these must contain magic and be in decreasing order.\n  spiffs_obj_id magic[3];\n  spiffs_obj_id bix_count[3];\n\n  spiffs_block_ix bix;\n  for (bix = 0; bix < 3; bix++) {\n    paddr = SPIFFS_MAGIC_PADDR(&dummy_fs, bix);\n#if SPIFFS_HAL_CALLBACK_EXTRA\n    // not any proper fs to report here, so callback with null\n    // (cross fingers that no-one gets angry)\n    res = cfg->hal_read_f((void *)0, paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]);\n#else\n    res = cfg->hal_read_f(paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]);\n#endif\n    bix_count[bix] = magic[bix] ^ SPIFFS_MAGIC(&dummy_fs, 0);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  // check that we have sane number of blocks\n  if (bix_count[0] < 3) return SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS;\n  // check that the order is correct, take aborted erases in calculation\n  // first block aborted erase\n  if (magic[0] == (spiffs_obj_id)(-1) && bix_count[1] - bix_count[2] == 1) {\n    return (bix_count[1]+1) * cfg->log_block_size;\n  }\n  // second block aborted erase\n  if (magic[1] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[2] == 2) {\n    return bix_count[0] * cfg->log_block_size;\n  }\n  // third block aborted erase\n  if (magic[2] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[1] == 1) {\n    return bix_count[0] * cfg->log_block_size;\n  }\n  // no block has aborted erase\n  if (bix_count[0] - bix_count[1] == 1 && bix_count[1] - bix_count[2] == 1) {\n    return bix_count[0] * cfg->log_block_size;\n  }\n\n  return SPIFFS_ERR_PROBE_NOT_A_FS;\n}\n#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n\n\nstatic s32_t spiffs_obj_lu_scan_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  (void)bix;\n  (void)user_const_p;\n  (void)user_var_p;\n  if (obj_id == SPIFFS_OBJ_ID_FREE) {\n    if (ix_entry == 0) {\n      fs->free_blocks++;\n      // todo optimize further, return SPIFFS_NEXT_BLOCK\n    }\n  } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n    fs->stats_p_deleted++;\n  } else {\n    fs->stats_p_allocated++;\n  }\n\n  return SPIFFS_VIS_COUNTINUE;\n}\n\n\n// Scans thru all obj lu and counts free, deleted and used pages\n// Find the maximum block erase count\n// Checks magic if enabled\ns32_t spiffs_obj_lu_scan(\n    spiffs *fs) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n#if SPIFFS_USE_MAGIC\n  spiffs_block_ix unerased_bix = (spiffs_block_ix)-1;\n#endif\n\n  // find out erase count\n  // if enabled, check magic\n  bix = 0;\n  spiffs_obj_id erase_count_final;\n  spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE;\n  spiffs_obj_id erase_count_max = 0;\n  while (bix < fs->block_count) {\n#if SPIFFS_USE_MAGIC\n    spiffs_obj_id magic;\n    res = _spiffs_rd(fs,\n        SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_MAGIC_PADDR(fs, bix) ,\n        sizeof(spiffs_obj_id), (u8_t *)&magic);\n\n    SPIFFS_CHECK_RES(res);\n    if (magic != SPIFFS_MAGIC(fs, bix)) {\n      if (unerased_bix == (spiffs_block_ix)-1) {\n        // allow one unerased block as it might be powered down during an erase\n        unerased_bix = bix;\n      } else {\n        // more than one unerased block, bail out\n        SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS);\n      }\n    }\n#endif\n    spiffs_obj_id erase_count;\n    res = _spiffs_rd(fs,\n        SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_ERASE_COUNT_PADDR(fs, bix) ,\n        sizeof(spiffs_obj_id), (u8_t *)&erase_count);\n    SPIFFS_CHECK_RES(res);\n    if (erase_count != SPIFFS_OBJ_ID_FREE) {\n      erase_count_min = MIN(erase_count_min, erase_count);\n      erase_count_max = MAX(erase_count_max, erase_count);\n    }\n    bix++;\n  }\n\n  if (erase_count_min == 0 && erase_count_max == SPIFFS_OBJ_ID_FREE) {\n    // clean system, set counter to zero\n    erase_count_final = 0;\n  } else if (erase_count_max - erase_count_min > (SPIFFS_OBJ_ID_FREE)/2) {\n    // wrap, take min\n    erase_count_final = erase_count_min+1;\n  } else {\n    erase_count_final = erase_count_max+1;\n  }\n\n  fs->max_erase_count = erase_count_final;\n\n#if SPIFFS_USE_MAGIC\n  if (unerased_bix != (spiffs_block_ix)-1) {\n    // found one unerased block, remedy\n    SPIFFS_DBG(\"mount: erase block \"_SPIPRIbl\"\\n\", bix);\n#if SPIFFS_READ_ONLY\n    res = SPIFFS_ERR_RO_ABORTED_OPERATION;\n#else\n    res = spiffs_erase_block(fs, unerased_bix);\n#endif // SPIFFS_READ_ONLY\n    SPIFFS_CHECK_RES(res);\n  }\n#endif\n\n  // count blocks\n\n  fs->free_blocks = 0;\n  fs->stats_p_allocated = 0;\n  fs->stats_p_deleted = 0;\n\n  res = spiffs_obj_lu_find_entry_visitor(fs,\n      0,\n      0,\n      0,\n      0,\n      spiffs_obj_lu_scan_v,\n      0,\n      0,\n      &bix,\n      &entry);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_OK;\n  }\n\n  SPIFFS_CHECK_RES(res);\n\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\n// Find free object lookup entry\n// Iterate over object lookup pages in each block until a free object id entry is found\ns32_t spiffs_obj_lu_find_free(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    spiffs_block_ix *block_ix,\n    int *lu_entry) {\n  s32_t res;\n  if (!fs->cleaning && fs->free_blocks < 2) {\n    res = spiffs_gc_quick(fs, 0);\n    if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) {\n      res = SPIFFS_OK;\n    }\n    SPIFFS_CHECK_RES(res);\n    if (fs->free_blocks < 2) {\n      return SPIFFS_ERR_FULL;\n    }\n  }\n  res = spiffs_obj_lu_find_id(fs, starting_block, starting_lu_entry,\n      SPIFFS_OBJ_ID_FREE, block_ix, lu_entry);\n  if (res == SPIFFS_OK) {\n    fs->free_cursor_block_ix = *block_ix;\n    fs->free_cursor_obj_lu_entry = (*lu_entry) + 1;\n    if (*lu_entry == 0) {\n      fs->free_blocks--;\n    }\n  }\n  if (res == SPIFFS_ERR_FULL) {\n    SPIFFS_DBG(\"fs full\\n\");\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n// Find object lookup entry containing given id\n// Iterate over object lookup pages in each block until a given object id entry is found\ns32_t spiffs_obj_lu_find_id(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix *block_ix,\n    int *lu_entry) {\n  s32_t res = spiffs_obj_lu_find_entry_visitor(\n      fs, starting_block, starting_lu_entry, SPIFFS_VIS_CHECK_ID, obj_id, 0, 0, 0, block_ix, lu_entry);\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_ERR_NOT_FOUND;\n  }\n  return res;\n}\n\n\nstatic s32_t spiffs_obj_lu_find_id_and_span_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  s32_t res;\n  spiffs_page_header ph;\n  spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n  res = _spiffs_rd(fs, 0, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_header), (u8_t *)&ph);\n  SPIFFS_CHECK_RES(res);\n  if (ph.obj_id == obj_id &&\n      ph.span_ix == *((spiffs_span_ix*)user_var_p) &&\n      (ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED)) == SPIFFS_PH_FLAG_DELET &&\n      !((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (ph.flags & SPIFFS_PH_FLAG_IXDELE) == 0 && ph.span_ix == 0) &&\n      (user_const_p == 0 || *((const spiffs_page_ix*)user_const_p) != pix)) {\n    return SPIFFS_OK;\n  } else {\n    return SPIFFS_VIS_COUNTINUE;\n  }\n}\n\n// Find object lookup entry containing given id and span index\n// Iterate over object lookup pages in each block until a given object id entry is found\ns32_t spiffs_obj_lu_find_id_and_span(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix exclusion_pix,\n    spiffs_page_ix *pix) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n\n  res = spiffs_obj_lu_find_entry_visitor(fs,\n      fs->cursor_block_ix,\n      fs->cursor_obj_lu_entry,\n      SPIFFS_VIS_CHECK_ID,\n      obj_id,\n      spiffs_obj_lu_find_id_and_span_v,\n      exclusion_pix ? &exclusion_pix : 0,\n      &spix,\n      &bix,\n      &entry);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_ERR_NOT_FOUND;\n  }\n\n  SPIFFS_CHECK_RES(res);\n\n  if (pix) {\n    *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  fs->cursor_block_ix = bix;\n  fs->cursor_obj_lu_entry = entry;\n\n  return res;\n}\n\n// Find object lookup entry containing given id and span index in page headers only\n// Iterate over object lookup pages in each block until a given object id entry is found\ns32_t spiffs_obj_lu_find_id_and_span_by_phdr(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix exclusion_pix,\n    spiffs_page_ix *pix) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n\n  res = spiffs_obj_lu_find_entry_visitor(fs,\n      fs->cursor_block_ix,\n      fs->cursor_obj_lu_entry,\n      SPIFFS_VIS_CHECK_PH,\n      obj_id,\n      spiffs_obj_lu_find_id_and_span_v,\n      exclusion_pix ? &exclusion_pix : 0,\n      &spix,\n      &bix,\n      &entry);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_ERR_NOT_FOUND;\n  }\n\n  SPIFFS_CHECK_RES(res);\n\n  if (pix) {\n    *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  fs->cursor_block_ix = bix;\n  fs->cursor_obj_lu_entry = entry;\n\n  return res;\n}\n\n#if SPIFFS_IX_MAP\n\n// update index map of given fd with given object index data\nstatic void spiffs_update_ix_map(spiffs *fs,\n    spiffs_fd *fd, spiffs_span_ix objix_spix, spiffs_page_object_ix *objix) {\n#if SPIFFS_SINGLETON\n  (void)fs;\n#endif\n  spiffs_ix_map *map = fd->ix_map;\n  spiffs_span_ix map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix);\n  spiffs_span_ix map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->end_spix);\n\n  // check if updated ix is within map range\n  if (objix_spix < map_objix_start_spix || objix_spix > map_objix_end_spix) {\n    return;\n  }\n\n  // update memory mapped page index buffer to new pages\n\n  // get range of updated object index map data span indices\n  spiffs_span_ix objix_data_spix_start =\n      SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, objix_spix);\n  spiffs_span_ix objix_data_spix_end = objix_data_spix_start +\n      (objix_spix == 0 ? SPIFFS_OBJ_HDR_IX_LEN(fs) : SPIFFS_OBJ_IX_LEN(fs));\n\n  // calc union of object index range and index map range array\n  spiffs_span_ix map_spix = MAX(map->start_spix, objix_data_spix_start);\n  spiffs_span_ix map_spix_end = MIN(map->end_spix + 1, objix_data_spix_end);\n\n  while (map_spix < map_spix_end) {\n    spiffs_page_ix objix_data_pix;\n    if (objix_spix == 0) {\n      // get data page from object index header page\n      objix_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix_header)))[map_spix];\n    } else {\n      // get data page from object index page\n      objix_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, map_spix)];\n    }\n\n    if (objix_data_pix == (spiffs_page_ix)-1) {\n      // reached end of object, abort\n      break;\n    }\n\n    map->map_buf[map_spix - map->start_spix] = objix_data_pix;\n    SPIFFS_DBG(\"map \"_SPIPRIid\":\"_SPIPRIsp\" (\"_SPIPRIsp\"--\"_SPIPRIsp\") objix.spix:\"_SPIPRIsp\" to pix \"_SPIPRIpg\"\\n\",\n        fd->obj_id, map_spix - map->start_spix,\n        map->start_spix, map->end_spix,\n        objix->p_hdr.span_ix,\n        objix_data_pix);\n\n    map_spix++;\n  }\n}\n\ntypedef struct {\n  spiffs_fd *fd;\n  u32_t remaining_objix_pages_to_visit;\n  spiffs_span_ix map_objix_start_spix;\n  spiffs_span_ix map_objix_end_spix;\n} spiffs_ix_map_populate_state;\n\nstatic s32_t spiffs_populate_ix_map_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  (void)user_const_p;\n  s32_t res;\n  spiffs_ix_map_populate_state *state = (spiffs_ix_map_populate_state *)user_var_p;\n  spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n\n  // load header to check it\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix), (u8_t *)objix);\n  SPIFFS_CHECK_RES(res);\n  SPIFFS_VALIDATE_OBJIX(objix->p_hdr, obj_id, objix->p_hdr.span_ix);\n\n  // check if hdr is ok, and if objix range overlap with ix map range\n  if ((objix->p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==\n      (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE) &&\n      objix->p_hdr.span_ix >= state->map_objix_start_spix &&\n      objix->p_hdr.span_ix <= state->map_objix_end_spix) {\n    // ok, load rest of object index\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_PAGE_TO_PADDR(fs, pix) + sizeof(spiffs_page_object_ix),\n        SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix),\n        (u8_t *)objix + sizeof(spiffs_page_object_ix));\n    SPIFFS_CHECK_RES(res);\n\n    spiffs_update_ix_map(fs, state->fd, objix->p_hdr.span_ix, objix);\n\n    state->remaining_objix_pages_to_visit--;\n    SPIFFS_DBG(\"map \"_SPIPRIid\" (\"_SPIPRIsp\"--\"_SPIPRIsp\") remaining objix pages \"_SPIPRIi\"\\n\",\n        state->fd->obj_id,\n        state->fd->ix_map->start_spix, state->fd->ix_map->end_spix,\n        state->remaining_objix_pages_to_visit);\n  }\n\n  if (res == SPIFFS_OK) {\n    res = state->remaining_objix_pages_to_visit ? SPIFFS_VIS_COUNTINUE : SPIFFS_VIS_END;\n  }\n  return res;\n}\n\n// populates index map, from vector entry start to vector entry end, inclusive\ns32_t spiffs_populate_ix_map(spiffs *fs, spiffs_fd *fd, u32_t vec_entry_start, u32_t vec_entry_end) {\n  s32_t res;\n  spiffs_ix_map *map = fd->ix_map;\n  spiffs_ix_map_populate_state state;\n  vec_entry_start = MIN((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_start);\n  vec_entry_end = MAX((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_end);\n  if (vec_entry_start > vec_entry_end) {\n    return SPIFFS_ERR_IX_MAP_BAD_RANGE;\n  }\n  state.map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_start);\n  state.map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_end);\n  state.remaining_objix_pages_to_visit =\n      state.map_objix_end_spix - state.map_objix_start_spix + 1;\n  state.fd = fd;\n\n  res = spiffs_obj_lu_find_entry_visitor(\n      fs,\n      SPIFFS_BLOCK_FOR_PAGE(fs, fd->objix_hdr_pix),\n      SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, fd->objix_hdr_pix),\n      SPIFFS_VIS_CHECK_ID,\n      fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,\n      spiffs_populate_ix_map_v,\n      0,\n      &state,\n      0,\n      0);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_OK;\n  }\n\n  return res;\n}\n\n#endif\n\n\n#if !SPIFFS_READ_ONLY\n// Allocates a free defined page with given obj_id\n// Occupies object lookup entry and page\n// data may be NULL; where only page header is stored, len and page_offs is ignored\ns32_t spiffs_page_allocate_data(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_page_header *ph,\n    u8_t *data,\n    u32_t len,\n    u32_t page_offs,\n    u8_t finalize,\n    spiffs_page_ix *pix) {\n  s32_t res = SPIFFS_OK;\n  spiffs_block_ix bix;\n  int entry;\n\n  // find free entry\n  res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);\n  SPIFFS_CHECK_RES(res);\n\n  // occupy page in object lookup\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id);\n  SPIFFS_CHECK_RES(res);\n\n  fs->stats_p_allocated++;\n\n  // write page header\n  ph->flags &= ~SPIFFS_PH_FLAG_USED;\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_header), (u8_t*)ph);\n  SPIFFS_CHECK_RES(res);\n\n  // write page data\n  if (data) {\n    res = _spiffs_wr(fs,  SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n        0,SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + sizeof(spiffs_page_header) + page_offs, len, data);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  // finalize header if necessary\n  if (finalize && (ph->flags & SPIFFS_PH_FLAG_FINAL)) {\n    ph->flags &= ~SPIFFS_PH_FLAG_FINAL;\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n        0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + offsetof(spiffs_page_header, flags),\n        sizeof(u8_t),\n        (u8_t *)&ph->flags);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  // return written page\n  if (pix) {\n    *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page.\n// If page data is null, provided header is used for metainfo and page data is physically copied.\ns32_t spiffs_page_move(\n    spiffs *fs,\n    spiffs_file fh,\n    u8_t *page_data,\n    spiffs_obj_id obj_id,\n    spiffs_page_header *page_hdr,\n    spiffs_page_ix src_pix,\n    spiffs_page_ix *dst_pix) {\n  s32_t res;\n  u8_t was_final = 0;\n  spiffs_page_header *p_hdr;\n  spiffs_block_ix bix;\n  int entry;\n  spiffs_page_ix free_pix;\n\n  // find free entry\n  res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);\n  SPIFFS_CHECK_RES(res);\n  free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n\n  if (dst_pix) *dst_pix = free_pix;\n\n  p_hdr = page_data ? (spiffs_page_header *)page_data : page_hdr;\n  if (page_data) {\n    // got page data\n    was_final = (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) == 0;\n    // write unfinalized page\n    p_hdr->flags |= SPIFFS_PH_FLAG_FINAL;\n    p_hdr->flags &= ~SPIFFS_PH_FLAG_USED;\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n        0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), page_data);\n  } else {\n    // copy page data\n    res = spiffs_phys_cpy(fs, fh, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_PAGE_TO_PADDR(fs, src_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs));\n  }\n  SPIFFS_CHECK_RES(res);\n\n  // mark entry in destination object lookup\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),\n      sizeof(spiffs_obj_id),\n      (u8_t *)&obj_id);\n  SPIFFS_CHECK_RES(res);\n\n  fs->stats_p_allocated++;\n\n  if (was_final) {\n    // mark finalized in destination page\n    p_hdr->flags &= ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED);\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n        fh,\n        SPIFFS_PAGE_TO_PADDR(fs, free_pix) + offsetof(spiffs_page_header, flags),\n        sizeof(u8_t),\n        (u8_t *)&p_hdr->flags);\n    SPIFFS_CHECK_RES(res);\n  }\n  // mark source deleted\n  res = spiffs_page_delete(fs, src_pix);\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// Deletes a page and removes it from object lookup.\ns32_t spiffs_page_delete(\n    spiffs *fs,\n    spiffs_page_ix pix) {\n  s32_t res;\n  spiffs_page_header hdr;\n  hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED);\n  // mark deleted entry in source object lookup\n  spiffs_obj_id d_obj_id = SPIFFS_OBJ_ID_DELETED;\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_DELE,\n      0,\n      SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_page_ix),\n      sizeof(spiffs_obj_id),\n      (u8_t *)&d_obj_id);\n  SPIFFS_CHECK_RES(res);\n\n  fs->stats_p_deleted++;\n  fs->stats_p_allocated--;\n\n  // mark deleted in source page\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_DELE,\n      0,\n      SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags),\n      sizeof(u8_t),\n      (u8_t *)&hdr.flags);\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// Create an object index header page with empty index and undefined length\ns32_t spiffs_object_create(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    const u8_t name[],\n    const u8_t meta[],\n    spiffs_obj_type type,\n    spiffs_page_ix *objix_hdr_pix) {\n  s32_t res = SPIFFS_OK;\n  spiffs_block_ix bix;\n  spiffs_page_object_ix_header oix_hdr;\n  int entry;\n\n  res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs));\n  SPIFFS_CHECK_RES(res);\n\n  obj_id |= SPIFFS_OBJ_ID_IX_FLAG;\n\n  // find free entry\n  res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);\n  SPIFFS_CHECK_RES(res);\n  SPIFFS_DBG(\"create: found free page @ \"_SPIPRIpg\" bix:\"_SPIPRIbl\" entry:\"_SPIPRIsp\"\\n\", (spiffs_page_ix)SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);\n\n  // occupy page in object lookup\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id);\n  SPIFFS_CHECK_RES(res);\n\n  fs->stats_p_allocated++;\n\n  // write empty object index page\n  oix_hdr.p_hdr.obj_id = obj_id;\n  oix_hdr.p_hdr.span_ix = 0;\n  oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED);\n  oix_hdr.type = type;\n  oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page\n  strncpy((char*)oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN);\n#if SPIFFS_OBJ_META_LEN\n  if (meta) {\n    memcpy(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN);\n  } else {\n    memset(oix_hdr.meta, 0xff, SPIFFS_OBJ_META_LEN);\n  }\n#else\n  (void) meta;\n#endif\n\n  // update page\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&oix_hdr);\n\n  SPIFFS_CHECK_RES(res);\n  spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&oix_hdr,\n      SPIFFS_EV_IX_NEW, obj_id, 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), SPIFFS_UNDEFINED_LEN);\n\n  if (objix_hdr_pix) {\n    *objix_hdr_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// update object index header with any combination of name/size/index\n// new_objix_hdr_data may be null, if so the object index header page is loaded\n// name may be null, if so name is not changed\n// size may be null, if so size is not changed\ns32_t spiffs_object_update_index_hdr(\n    spiffs *fs,\n    spiffs_fd *fd,\n    spiffs_obj_id obj_id,\n    spiffs_page_ix objix_hdr_pix,\n    u8_t *new_objix_hdr_data,\n    const u8_t name[],\n    const u8_t meta[],\n    u32_t size,\n    spiffs_page_ix *new_pix) {\n  s32_t res = SPIFFS_OK;\n  spiffs_page_object_ix_header *objix_hdr;\n  spiffs_page_ix new_objix_hdr_pix;\n\n  obj_id |=  SPIFFS_OBJ_ID_IX_FLAG;\n\n  if (new_objix_hdr_data) {\n    // object index header page already given to us, no need to load it\n    objix_hdr = (spiffs_page_object_ix_header *)new_objix_hdr_data;\n  } else {\n    // read object index header page\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n        fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n    SPIFFS_CHECK_RES(res);\n    objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  }\n\n  SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, obj_id, 0);\n\n  // change name\n  if (name) {\n    strncpy((char*)objix_hdr->name, (const char*)name, SPIFFS_OBJ_NAME_LEN);\n  }\n#if SPIFFS_OBJ_META_LEN\n  if (meta) {\n    memcpy(objix_hdr->meta, meta, SPIFFS_OBJ_META_LEN);\n  }\n#else\n  (void) meta;\n#endif\n  if (size) {\n    objix_hdr->size = size;\n  }\n\n  // move and update page\n  res = spiffs_page_move(fs, fd == 0 ? 0 : fd->file_nbr, (u8_t*)objix_hdr, obj_id, 0, objix_hdr_pix, &new_objix_hdr_pix);\n\n  if (res == SPIFFS_OK) {\n    if (new_pix) {\n      *new_pix = new_objix_hdr_pix;\n    }\n    // callback on object index update\n    spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr,\n        new_objix_hdr_data ? SPIFFS_EV_IX_UPD : SPIFFS_EV_IX_UPD_HDR,\n            obj_id, objix_hdr->p_hdr.span_ix, new_objix_hdr_pix, objix_hdr->size);\n    if (fd) fd->objix_hdr_pix = new_objix_hdr_pix; // if this is not in the registered cluster\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\nvoid spiffs_cb_object_event(\n    spiffs *fs,\n    spiffs_page_object_ix *objix,\n    int ev,\n    spiffs_obj_id obj_id_raw,\n    spiffs_span_ix spix,\n    spiffs_page_ix new_pix,\n    u32_t new_size) {\n#if SPIFFS_IX_MAP == 0\n  (void)objix;\n#endif\n  // update index caches in all file descriptors\n  spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG;\n  u32_t i;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n#if SPIFFS_TEMPORAL_FD_CACHE\n    if (cur_fd->score == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;\n#else\n    if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;\n#endif\n    if (spix == 0) {\n      if (ev != SPIFFS_EV_IX_DEL) {\n        SPIFFS_DBG(\"       callback: setting fd \"_SPIPRIfd\":\"_SPIPRIid\" objix_hdr_pix to \"_SPIPRIpg\", size:\"_SPIPRIi\"\\n\", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);\n        cur_fd->objix_hdr_pix = new_pix;\n        if (new_size != 0) {\n          cur_fd->size = new_size;\n        }\n      } else {\n        cur_fd->file_nbr = 0;\n        cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED;\n      }\n    }\n    if (cur_fd->cursor_objix_spix == spix) {\n      if (ev != SPIFFS_EV_IX_DEL) {\n        SPIFFS_DBG(\"       callback: setting fd \"_SPIPRIfd\":\"_SPIPRIid\" span:\"_SPIPRIsp\" objix_pix to \"_SPIPRIpg\"\\n\", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);\n        cur_fd->cursor_objix_pix = new_pix;\n      } else {\n        cur_fd->cursor_objix_pix = 0;\n      }\n    }\n  }\n\n#if SPIFFS_IX_MAP\n\n  // update index maps\n  if (ev == SPIFFS_EV_IX_UPD || ev == SPIFFS_EV_IX_NEW) {\n    for (i = 0; i < fs->fd_count; i++) {\n      spiffs_fd *cur_fd = &fds[i];\n      // check fd opened, having ix map, match obj id\n      if (cur_fd->file_nbr == 0 ||\n          cur_fd->ix_map == 0 ||\n          (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;\n      SPIFFS_DBG(\"       callback: map ix update fd \"_SPIPRIfd\":\"_SPIPRIid\" span:\"_SPIPRIsp\"\\n\", cur_fd->file_nbr, cur_fd->obj_id, spix);\n      spiffs_update_ix_map(fs, cur_fd, spix, objix);\n    }\n  }\n\n#endif\n\n  // callback to user if object index header\n  if (fs->file_cb_f && spix == 0 && (obj_id_raw & SPIFFS_OBJ_ID_IX_FLAG)) {\n    spiffs_fileop_type op;\n    if (ev == SPIFFS_EV_IX_NEW) {\n      op = SPIFFS_CB_CREATED;\n    } else if (ev == SPIFFS_EV_IX_UPD ||\n        ev == SPIFFS_EV_IX_MOV ||\n        ev == SPIFFS_EV_IX_UPD_HDR) {\n      op = SPIFFS_CB_UPDATED;\n    } else if (ev == SPIFFS_EV_IX_DEL) {\n      op = SPIFFS_CB_DELETED;\n    } else {\n      SPIFFS_DBG(\"       callback: WARNING unknown callback event \"_SPIPRIi\"\\n\", ev);\n      return; // bail out\n    }\n    fs->file_cb_f(fs, op, obj_id, new_pix);\n  }\n}\n\n// Open object by id\ns32_t spiffs_object_open_by_id(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_fd *fd,\n    spiffs_flags flags,\n    spiffs_mode mode) {\n  s32_t res = SPIFFS_OK;\n  spiffs_page_ix pix;\n\n  res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);\n  SPIFFS_CHECK_RES(res);\n\n  res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);\n\n  return res;\n}\n\n// Open object by page index\ns32_t spiffs_object_open_by_page(\n    spiffs *fs,\n    spiffs_page_ix pix,\n    spiffs_fd *fd,\n    spiffs_flags flags,\n    spiffs_mode mode) {\n  (void)mode;\n  s32_t res = SPIFFS_OK;\n  spiffs_page_object_ix_header oix_hdr;\n  spiffs_obj_id obj_id;\n\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n      fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&oix_hdr);\n  SPIFFS_CHECK_RES(res);\n\n  spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(fs, pix);\n  int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix);\n\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n      0,  SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id);\n\n  fd->fs = fs;\n  fd->objix_hdr_pix = pix;\n  fd->size = oix_hdr.size;\n  fd->offset = 0;\n  fd->cursor_objix_pix = pix;\n  fd->cursor_objix_spix = 0;\n  fd->obj_id = obj_id;\n  fd->flags = flags;\n\n  SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);\n\n  SPIFFS_DBG(\"open: fd \"_SPIPRIfd\" is obj id \"_SPIPRIid\"\\n\", fd->file_nbr, fd->obj_id);\n\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\n// Append to object\n// keep current object index (header) page in fs->work buffer\ns32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {\n  spiffs *fs = fd->fs;\n  s32_t res = SPIFFS_OK;\n  u32_t written = 0;\n\n  SPIFFS_DBG(\"append: \"_SPIPRIi\" bytes @ offs \"_SPIPRIi\" of size \"_SPIPRIi\"\\n\", len, offset, fd->size);\n\n  if (offset > fd->size) {\n    SPIFFS_DBG(\"append: offset reversed to size\\n\");\n    offset = fd->size;\n  }\n\n  res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta\n  if (res != SPIFFS_OK) {\n    SPIFFS_DBG(\"append: gc check fail \"_SPIPRIi\"\\n\", res);\n  }\n  SPIFFS_CHECK_RES(res);\n\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n  spiffs_page_header p_hdr;\n\n  spiffs_span_ix cur_objix_spix = 0;\n  spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;\n  spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;\n  spiffs_page_ix new_objix_hdr_page;\n\n  spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);\n  spiffs_page_ix data_page;\n  u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);\n\n  // write all data\n  while (res == SPIFFS_OK && written < len) {\n    // calculate object index page span index\n    cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n\n    // handle storing and loading of object indices\n    if (cur_objix_spix != prev_objix_spix) {\n      // new object index page\n      // within this clause we return directly if something fails, object index mess-up\n      if (written > 0) {\n        // store previous object index page, unless first pass\n        SPIFFS_DBG(\"append: \"_SPIPRIid\" store objix \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n            cur_objix_pix, prev_objix_spix, written);\n        if (prev_objix_spix == 0) {\n          // this is an update to object index header page\n          objix_hdr->size = offset+written;\n          if (offset == 0) {\n            // was an empty object, update same page (size was 0xffffffff)\n            res = spiffs_page_index_check(fs, fd, cur_objix_pix, 0);\n            SPIFFS_CHECK_RES(res);\n            res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n                fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n            SPIFFS_CHECK_RES(res);\n          } else {\n            // was a nonempty object, update to new page\n            res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n                fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page);\n            SPIFFS_CHECK_RES(res);\n            SPIFFS_DBG(\"append: \"_SPIPRIid\" store new objix_hdr, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n                new_objix_hdr_page, 0, written);\n          }\n        } else {\n          // this is an update to an object index page\n          res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);\n          SPIFFS_CHECK_RES(res);\n\n          res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n              fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n          SPIFFS_CHECK_RES(res);\n          spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n              SPIFFS_EV_IX_UPD,fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);\n          // update length in object index header page\n          res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n              fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page);\n          SPIFFS_CHECK_RES(res);\n          SPIFFS_DBG(\"append: \"_SPIPRIid\" store new size I \"_SPIPRIi\" in objix_hdr, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n              offset+written, new_objix_hdr_page, 0, written);\n        }\n        fd->size = offset+written;\n        fd->offset = offset+written;\n      }\n\n      // create or load new object index page\n      if (cur_objix_spix == 0) {\n        // load object index header page, must always exist\n        SPIFFS_DBG(\"append: \"_SPIPRIid\" load objixhdr page \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", fd->obj_id, cur_objix_pix, cur_objix_spix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n            fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n      } else {\n        spiffs_span_ix len_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, (fd->size-1)/SPIFFS_DATA_PAGE_SIZE(fs));\n        // on subsequent passes, create a new object index page\n        if (written > 0 || cur_objix_spix > len_objix_spix) {\n          p_hdr.obj_id = fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n          p_hdr.span_ix = cur_objix_spix;\n          p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);\n          res = spiffs_page_allocate_data(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,\n              &p_hdr, 0, 0, 0, 1, &cur_objix_pix);\n          SPIFFS_CHECK_RES(res);\n          // quick \"load\" of new object index page\n          memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n          memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));\n          spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n              SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);\n          SPIFFS_DBG(\"append: \"_SPIPRIid\" create objix page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id\n              , cur_objix_pix, cur_objix_spix, written);\n        } else {\n          // on first pass, we load existing object index page\n          spiffs_page_ix pix;\n          SPIFFS_DBG(\"append: \"_SPIPRIid\" find objix span_ix:\"_SPIPRIsp\"\\n\", fd->obj_id, cur_objix_spix);\n          if (fd->cursor_objix_spix == cur_objix_spix) {\n            pix = fd->cursor_objix_pix;\n          } else {\n            res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);\n            SPIFFS_CHECK_RES(res);\n          }\n          SPIFFS_DBG(\"append: \"_SPIPRIid\" found object index at page \"_SPIPRIpg\" [fd size \"_SPIPRIi\"]\\n\", fd->obj_id, pix, fd->size);\n          res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n              fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n          SPIFFS_CHECK_RES(res);\n          SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n          cur_objix_pix = pix;\n        }\n        fd->cursor_objix_pix = cur_objix_pix;\n        fd->cursor_objix_spix = cur_objix_spix;\n        fd->offset = offset+written;\n        fd->size = offset+written;\n      }\n      prev_objix_spix = cur_objix_spix;\n    }\n\n    // write data\n    u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);\n    if (page_offs == 0) {\n      // at beginning of a page, allocate and write a new page of data\n      p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n      p_hdr.span_ix = data_spix;\n      p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL);  // finalize immediately\n      res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n          &p_hdr, &data[written], to_write, page_offs, 1, &data_page);\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" store new data page, \"_SPIPRIpg\":\"_SPIPRIsp\" offset:\"_SPIPRIi\", len \"_SPIPRIi\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n          data_page, data_spix, page_offs, to_write, written);\n    } else {\n      // append to existing page, fill out free data in existing page\n      if (cur_objix_spix == 0) {\n        // get data page from object index header page\n        data_page = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];\n      } else {\n        // get data page from object index page\n        data_page = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];\n      }\n\n      res = spiffs_page_data_check(fs, fd, data_page, data_spix);\n      SPIFFS_CHECK_RES(res);\n\n      res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n          fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" store to existing data page, \"_SPIPRIpg\":\"_SPIPRIsp\" offset:\"_SPIPRIi\", len \"_SPIPRIi\", written \"_SPIPRIi\"\\n\", fd->obj_id\n          , data_page, data_spix, page_offs, to_write, written);\n    }\n\n    if (res != SPIFFS_OK) break;\n\n    // update memory representation of object index page with new data page\n    if (cur_objix_spix == 0) {\n      // update object index header page\n      ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_page;\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" wrote page \"_SPIPRIpg\" to objix_hdr entry \"_SPIPRIsp\" in mem\\n\", fd->obj_id\n          , data_page, data_spix);\n      objix_hdr->size = offset+written;\n    } else {\n      // update object index page\n      ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_page;\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" wrote page \"_SPIPRIpg\" to objix entry \"_SPIPRIsp\" in mem\\n\", fd->obj_id\n          , data_page, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));\n    }\n\n    // update internals\n    page_offs = 0;\n    data_spix++;\n    written += to_write;\n  } // while all data\n\n  fd->size = offset+written;\n  fd->offset = offset+written;\n  fd->cursor_objix_pix = cur_objix_pix;\n  fd->cursor_objix_spix = cur_objix_spix;\n\n  // finalize updated object indices\n  s32_t res2 = SPIFFS_OK;\n  if (cur_objix_spix != 0) {\n    // wrote beyond object index header page\n    // write last modified object index page, unless object header index page\n    SPIFFS_DBG(\"append: \"_SPIPRIid\" store objix page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n        cur_objix_pix, cur_objix_spix, written);\n\n    res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);\n    SPIFFS_CHECK_RES(res2);\n\n    res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n        fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n    SPIFFS_CHECK_RES(res2);\n    spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n        SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);\n\n    // update size in object header index page\n    res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n        fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page);\n    SPIFFS_DBG(\"append: \"_SPIPRIid\" store new size II \"_SPIPRIi\" in objix_hdr, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\", res \"_SPIPRIi\"\\n\", fd->obj_id\n        , offset+written, new_objix_hdr_page, 0, written, res2);\n    SPIFFS_CHECK_RES(res2);\n  } else {\n    // wrote within object index header page\n    if (offset == 0) {\n      // wrote to empty object - simply update size and write whole page\n      objix_hdr->size = offset+written;\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" store fresh objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id\n          , cur_objix_pix, cur_objix_spix, written);\n\n      res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);\n      SPIFFS_CHECK_RES(res2);\n\n      res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n          fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n      SPIFFS_CHECK_RES(res2);\n      // callback on object index update\n      spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n          SPIFFS_EV_IX_UPD_HDR, fd->obj_id, objix_hdr->p_hdr.span_ix, cur_objix_pix, objix_hdr->size);\n    } else {\n      // modifying object index header page, update size and make new copy\n      res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n          fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page);\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" store modified objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id\n          , new_objix_hdr_page, 0, written);\n      SPIFFS_CHECK_RES(res2);\n    }\n  }\n\n  return res;\n} // spiffs_object_append\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// Modify object\n// keep current object index (header) page in fs->work buffer\ns32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {\n  spiffs *fs = fd->fs;\n  s32_t res = SPIFFS_OK;\n  u32_t written = 0;\n\n  res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs));\n  SPIFFS_CHECK_RES(res);\n\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n  spiffs_page_header p_hdr;\n\n  spiffs_span_ix cur_objix_spix = 0;\n  spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;\n  spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;\n  spiffs_page_ix new_objix_hdr_pix;\n\n  spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);\n  spiffs_page_ix data_pix;\n  u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);\n\n\n  // write all data\n  while (res == SPIFFS_OK && written < len) {\n    // calculate object index page span index\n    cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n\n    // handle storing and loading of object indices\n    if (cur_objix_spix != prev_objix_spix) {\n      // new object index page\n      // within this clause we return directly if something fails, object index mess-up\n      if (written > 0) {\n        // store previous object index (header) page, unless first pass\n        if (prev_objix_spix == 0) {\n          // store previous object index header page\n          res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n              fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix);\n          SPIFFS_DBG(\"modify: store modified objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", new_objix_hdr_pix, 0, written);\n          SPIFFS_CHECK_RES(res);\n        } else {\n          // store new version of previous object index page\n          spiffs_page_ix new_objix_pix;\n\n          res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);\n          SPIFFS_CHECK_RES(res);\n\n          res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);\n          SPIFFS_DBG(\"modify: store previous modified objix page, \"_SPIPRIid\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", new_objix_pix, objix->p_hdr.span_ix, written);\n          SPIFFS_CHECK_RES(res);\n          spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix,\n              SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n        }\n      }\n\n      // load next object index page\n      if (cur_objix_spix == 0) {\n        // load object index header page, must exist\n        SPIFFS_DBG(\"modify: load objixhdr page \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", cur_objix_pix, cur_objix_spix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n            fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n      } else {\n        // load existing object index page on first pass\n        spiffs_page_ix pix;\n        SPIFFS_DBG(\"modify: find objix span_ix:\"_SPIPRIsp\"\\n\", cur_objix_spix);\n        if (fd->cursor_objix_spix == cur_objix_spix) {\n          pix = fd->cursor_objix_pix;\n        } else {\n          res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);\n          SPIFFS_CHECK_RES(res);\n        }\n        SPIFFS_DBG(\"modify: found object index at page \"_SPIPRIpg\"\\n\", pix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n            fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n        cur_objix_pix = pix;\n      }\n      fd->cursor_objix_pix = cur_objix_pix;\n      fd->cursor_objix_spix = cur_objix_spix;\n      fd->offset = offset+written;\n      prev_objix_spix = cur_objix_spix;\n    }\n\n    // write partial data\n    u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);\n    spiffs_page_ix orig_data_pix;\n    if (cur_objix_spix == 0) {\n      // get data page from object index header page\n      orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];\n    } else {\n      // get data page from object index page\n      orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];\n    }\n\n    p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n    p_hdr.span_ix = data_spix;\n    p_hdr.flags = 0xff;\n    if (page_offs == 0 && to_write == SPIFFS_DATA_PAGE_SIZE(fs)) {\n      // a full page, allocate and write a new page of data\n      res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n          &p_hdr, &data[written], to_write, page_offs, 1, &data_pix);\n      SPIFFS_DBG(\"modify: store new data page, \"_SPIPRIpg\":\"_SPIPRIsp\" offset:\"_SPIPRIi\", len \"_SPIPRIi\", written \"_SPIPRIi\"\\n\", data_pix, data_spix, page_offs, to_write, written);\n    } else {\n      // write to existing page, allocate new and copy unmodified data\n\n      res = spiffs_page_data_check(fs, fd, orig_data_pix, data_spix);\n      SPIFFS_CHECK_RES(res);\n\n      res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n          &p_hdr, 0, 0, 0, 0, &data_pix);\n      if (res != SPIFFS_OK) break;\n\n      // copy unmodified data\n      if (page_offs > 0) {\n        // before modification\n        res = spiffs_phys_cpy(fs, fd->file_nbr,\n            SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),\n            SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header),\n            page_offs);\n        if (res != SPIFFS_OK) break;\n      }\n      if (page_offs + to_write < SPIFFS_DATA_PAGE_SIZE(fs)) {\n        // after modification\n        res = spiffs_phys_cpy(fs, fd->file_nbr,\n            SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,\n            SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,\n            SPIFFS_DATA_PAGE_SIZE(fs) - (page_offs + to_write));\n        if (res != SPIFFS_OK) break;\n      }\n\n      res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n          fd->file_nbr,\n          SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);\n      if (res != SPIFFS_OK) break;\n      p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;\n      res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n          fd->file_nbr,\n          SPIFFS_PAGE_TO_PADDR(fs, data_pix) + offsetof(spiffs_page_header, flags),\n          sizeof(u8_t),\n          (u8_t *)&p_hdr.flags);\n      if (res != SPIFFS_OK) break;\n\n      SPIFFS_DBG(\"modify: store to existing data page, src:\"_SPIPRIpg\", dst:\"_SPIPRIpg\":\"_SPIPRIsp\" offset:\"_SPIPRIi\", len \"_SPIPRIi\", written \"_SPIPRIi\"\\n\", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);\n    }\n\n    // delete original data page\n    res = spiffs_page_delete(fs, orig_data_pix);\n    if (res != SPIFFS_OK) break;\n    // update memory representation of object index page with new data page\n    if (cur_objix_spix == 0) {\n      // update object index header page\n      ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_pix;\n      SPIFFS_DBG(\"modify: wrote page \"_SPIPRIpg\" to objix_hdr entry \"_SPIPRIsp\" in mem\\n\", data_pix, data_spix);\n    } else {\n      // update object index page\n      ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_pix;\n      SPIFFS_DBG(\"modify: wrote page \"_SPIPRIpg\" to objix entry \"_SPIPRIsp\" in mem\\n\", data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));\n    }\n\n    // update internals\n    page_offs = 0;\n    data_spix++;\n    written += to_write;\n  } // while all data\n\n  fd->offset = offset+written;\n  fd->cursor_objix_pix = cur_objix_pix;\n  fd->cursor_objix_spix = cur_objix_spix;\n\n  // finalize updated object indices\n  s32_t res2 = SPIFFS_OK;\n  if (cur_objix_spix != 0) {\n    // wrote beyond object index header page\n    // write last modified object index page\n    // move and update page\n    spiffs_page_ix new_objix_pix;\n\n    res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);\n    SPIFFS_CHECK_RES(res2);\n\n    res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);\n    SPIFFS_DBG(\"modify: store modified objix page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", new_objix_pix, cur_objix_spix, written);\n    fd->cursor_objix_pix = new_objix_pix;\n    fd->cursor_objix_spix = cur_objix_spix;\n    SPIFFS_CHECK_RES(res2);\n    spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix,\n        SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n\n  } else {\n    // wrote within object index header page\n    res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n        fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix);\n    SPIFFS_DBG(\"modify: store modified objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", new_objix_hdr_pix, 0, written);\n    SPIFFS_CHECK_RES(res2);\n  }\n\n  return res;\n} // spiffs_object_modify\n#endif // !SPIFFS_READ_ONLY\n\nstatic s32_t spiffs_object_find_object_index_header_by_name_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  (void)user_var_p;\n  s32_t res;\n  spiffs_page_object_ix_header objix_hdr;\n  spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n  if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||\n      (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {\n    return SPIFFS_VIS_COUNTINUE;\n  }\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);\n  SPIFFS_CHECK_RES(res);\n  if (objix_hdr.p_hdr.span_ix == 0 &&\n      (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==\n          (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {\n    if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) {\n      return SPIFFS_OK;\n    }\n  }\n\n  return SPIFFS_VIS_COUNTINUE;\n}\n\n// Finds object index header page by name\ns32_t spiffs_object_find_object_index_header_by_name(\n    spiffs *fs,\n    const u8_t name[SPIFFS_OBJ_NAME_LEN],\n    spiffs_page_ix *pix) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n\n  res = spiffs_obj_lu_find_entry_visitor(fs,\n      fs->cursor_block_ix,\n      fs->cursor_obj_lu_entry,\n      0,\n      0,\n      spiffs_object_find_object_index_header_by_name_v,\n      name,\n      0,\n      &bix,\n      &entry);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_ERR_NOT_FOUND;\n  }\n  SPIFFS_CHECK_RES(res);\n\n  if (pix) {\n    *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  fs->cursor_block_ix = bix;\n  fs->cursor_obj_lu_entry = entry;\n\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\n// Truncates object to new size. If new size is null, object may be removed totally\ns32_t spiffs_object_truncate(\n    spiffs_fd *fd,\n    u32_t new_size,\n    u8_t remove_full) {\n  s32_t res = SPIFFS_OK;\n  spiffs *fs = fd->fs;\n\n  if ((fd->size == SPIFFS_UNDEFINED_LEN || fd->size == 0) && !remove_full) {\n    // no op\n    return res;\n  }\n\n  // need 2 pages if not removing: object index page + possibly chopped data page\n  if (remove_full == 0) {\n    res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs) * 2);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  spiffs_page_ix objix_pix = fd->objix_hdr_pix;\n  spiffs_span_ix data_spix = (fd->size > 0 ? fd->size-1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs);\n  u32_t cur_size = fd->size == (u32_t)SPIFFS_UNDEFINED_LEN ? 0 : fd->size ;\n  spiffs_span_ix cur_objix_spix = 0;\n  spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n  spiffs_page_ix data_pix;\n  spiffs_page_ix new_objix_hdr_pix;\n\n  // before truncating, check if object is to be fully removed and mark this\n  if (remove_full && new_size == 0) {\n    u8_t flags = ~( SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE);\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n        fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, fd->objix_hdr_pix) + offsetof(spiffs_page_header, flags),\n        sizeof(u8_t),\n        (u8_t *)&flags);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  // delete from end of object until desired len is reached\n  while (cur_size > new_size) {\n    cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n\n    // put object index for current data span index in work buffer\n    if (prev_objix_spix != cur_objix_spix) {\n      if (prev_objix_spix != (spiffs_span_ix)-1) {\n        // remove previous object index page\n        SPIFFS_DBG(\"truncate: delete objix page \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", objix_pix, prev_objix_spix);\n\n        res = spiffs_page_index_check(fs, fd, objix_pix, prev_objix_spix);\n        SPIFFS_CHECK_RES(res);\n\n        res = spiffs_page_delete(fs, objix_pix);\n        SPIFFS_CHECK_RES(res);\n        spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,\n            SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);\n        if (prev_objix_spix > 0) {\n          // Update object index header page, unless we totally want to remove the file.\n          // If fully removing, we're not keeping consistency as good as when storing the header between chunks,\n          // would we be aborted. But when removing full files, a crammed system may otherwise\n          // report ERR_FULL a la windows. We cannot have that.\n          // Hence, take the risk - if aborted, a file check would free the lost pages and mend things\n          // as the file is marked as fully deleted in the beginning.\n          if (remove_full == 0) {\n            SPIFFS_DBG(\"truncate: update objix hdr page \"_SPIPRIpg\":\"_SPIPRIsp\" to size \"_SPIPRIi\"\\n\", fd->objix_hdr_pix, prev_objix_spix, cur_size);\n            res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n                fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix);\n            SPIFFS_CHECK_RES(res);\n          }\n          fd->size = cur_size;\n        }\n      }\n      // load current object index (header) page\n      if (cur_objix_spix == 0) {\n        objix_pix = fd->objix_hdr_pix;\n      } else {\n        res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);\n        SPIFFS_CHECK_RES(res);\n      }\n\n      SPIFFS_DBG(\"truncate: load objix page \"_SPIPRIpg\":\"_SPIPRIsp\" for data spix:\"_SPIPRIsp\"\\n\", objix_pix, cur_objix_spix, data_spix);\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n          fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n      SPIFFS_CHECK_RES(res);\n      SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n      fd->cursor_objix_pix = objix_pix;\n      fd->cursor_objix_spix = cur_objix_spix;\n      fd->offset = cur_size;\n\n      prev_objix_spix = cur_objix_spix;\n    }\n\n    if (cur_objix_spix == 0) {\n      // get data page from object index header page\n      data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];\n      ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = SPIFFS_OBJ_ID_FREE;\n    } else {\n      // get data page from object index page\n      data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];\n      ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE;\n    }\n\n    SPIFFS_DBG(\"truncate: got data pix \"_SPIPRIpg\"\\n\", data_pix);\n\n    if (new_size == 0 || remove_full || cur_size - new_size >= SPIFFS_DATA_PAGE_SIZE(fs)) {\n      // delete full data page\n      res = spiffs_page_data_check(fs, fd, data_pix, data_spix);\n      if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {\n        SPIFFS_DBG(\"truncate: err validating data pix \"_SPIPRIi\"\\n\", res);\n        break;\n      }\n\n      if (res == SPIFFS_OK) {\n        res = spiffs_page_delete(fs, data_pix);\n        if (res != SPIFFS_OK) {\n          SPIFFS_DBG(\"truncate: err deleting data pix \"_SPIPRIi\"\\n\", res);\n          break;\n        }\n      } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {\n        res = SPIFFS_OK;\n      }\n\n      // update current size\n      if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) {\n        cur_size -= SPIFFS_DATA_PAGE_SIZE(fs);\n      } else {\n        cur_size -= cur_size % SPIFFS_DATA_PAGE_SIZE(fs);\n      }\n      fd->size = cur_size;\n      fd->offset = cur_size;\n      SPIFFS_DBG(\"truncate: delete data page \"_SPIPRIpg\" for data spix:\"_SPIPRIsp\", cur_size:\"_SPIPRIi\"\\n\", data_pix, data_spix, cur_size);\n    } else {\n      // delete last page, partially\n      spiffs_page_header p_hdr;\n      spiffs_page_ix new_data_pix;\n      u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));\n      SPIFFS_DBG(\"truncate: delete \"_SPIPRIi\" bytes from data page \"_SPIPRIpg\" for data spix:\"_SPIPRIsp\", cur_size:\"_SPIPRIi\"\\n\", bytes_to_remove, data_pix, data_spix, cur_size);\n\n      res = spiffs_page_data_check(fs, fd, data_pix, data_spix);\n      if (res != SPIFFS_OK) break;\n\n      p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n      p_hdr.span_ix = data_spix;\n      p_hdr.flags = 0xff;\n      // allocate new page and copy unmodified data\n      res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n          &p_hdr, 0, 0, 0, 0, &new_data_pix);\n      if (res != SPIFFS_OK) break;\n      res = spiffs_phys_cpy(fs, 0,\n          SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + sizeof(spiffs_page_header),\n          SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),\n          SPIFFS_DATA_PAGE_SIZE(fs) - bytes_to_remove);\n      if (res != SPIFFS_OK) break;\n      // delete original data page\n      res = spiffs_page_delete(fs, data_pix);\n      if (res != SPIFFS_OK) break;\n      p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;\n      res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n          fd->file_nbr,\n          SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + offsetof(spiffs_page_header, flags),\n          sizeof(u8_t),\n          (u8_t *)&p_hdr.flags);\n      if (res != SPIFFS_OK) break;\n\n      // update memory representation of object index page with new data page\n      if (cur_objix_spix == 0) {\n        // update object index header page\n        ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;\n        SPIFFS_DBG(\"truncate: wrote page \"_SPIPRIpg\" to objix_hdr entry \"_SPIPRIsp\" in mem\\n\", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));\n      } else {\n        // update object index page\n        ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;\n        SPIFFS_DBG(\"truncate: wrote page \"_SPIPRIpg\" to objix entry \"_SPIPRIsp\" in mem\\n\", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));\n      }\n      cur_size = new_size;\n      fd->size = new_size;\n      fd->offset = cur_size;\n      break;\n    }\n    data_spix--;\n  } // while all data\n\n  // update object indices\n  if (cur_objix_spix == 0) {\n    // update object index header page\n    if (cur_size == 0) {\n      if (remove_full) {\n        // remove object altogether\n        SPIFFS_DBG(\"truncate: remove object index header page \"_SPIPRIpg\"\\n\", objix_pix);\n\n        res = spiffs_page_index_check(fs, fd, objix_pix, 0);\n        SPIFFS_CHECK_RES(res);\n\n        res = spiffs_page_delete(fs, objix_pix);\n        SPIFFS_CHECK_RES(res);\n        spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,\n            SPIFFS_EV_IX_DEL, fd->obj_id, 0, objix_pix, 0);\n      } else {\n        // make uninitialized object\n        SPIFFS_DBG(\"truncate: reset objix_hdr page \"_SPIPRIpg\"\\n\", objix_pix);\n        memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,\n            SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header));\n        res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n            objix_pix, fs->work, 0, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix);\n        SPIFFS_CHECK_RES(res);\n      }\n    } else {\n      // update object index header page\n      SPIFFS_DBG(\"truncate: update object index header page with indices and size\\n\");\n      res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n          objix_pix, fs->work, 0, 0, cur_size, &new_objix_hdr_pix);\n      SPIFFS_CHECK_RES(res);\n    }\n  } else {\n    // update both current object index page and object index header page\n    spiffs_page_ix new_objix_pix;\n\n    res = spiffs_page_index_check(fs, fd, objix_pix, cur_objix_spix);\n    SPIFFS_CHECK_RES(res);\n\n    // move and update object index page\n    res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix_hdr, fd->obj_id, 0, objix_pix, &new_objix_pix);\n    SPIFFS_CHECK_RES(res);\n    spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr,\n        SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n    SPIFFS_DBG(\"truncate: store modified objix page, \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", new_objix_pix, cur_objix_spix);\n    fd->cursor_objix_pix = new_objix_pix;\n    fd->cursor_objix_spix = cur_objix_spix;\n    fd->offset = cur_size;\n    // update object index header page with new size\n    res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n        fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix);\n    SPIFFS_CHECK_RES(res);\n  }\n  fd->size = cur_size;\n\n  return res;\n} // spiffs_object_truncate\n#endif // !SPIFFS_READ_ONLY\n\ns32_t spiffs_object_read(\n    spiffs_fd *fd,\n    u32_t offset,\n    u32_t len,\n    u8_t *dst) {\n  s32_t res = SPIFFS_OK;\n  spiffs *fs = fd->fs;\n  spiffs_page_ix objix_pix;\n  spiffs_page_ix data_pix;\n  spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);\n  u32_t cur_offset = offset;\n  spiffs_span_ix cur_objix_spix;\n  spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n\n  while (cur_offset < offset + len) {\n#if SPIFFS_IX_MAP\n    // check if we have a memory, index map and if so, if we're within index map's range\n    // and if so, if the entry is populated\n    if (fd->ix_map && data_spix >= fd->ix_map->start_spix && data_spix <= fd->ix_map->end_spix\n        && fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix]) {\n      data_pix = fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix];\n    } else {\n#endif\n      cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n      if (prev_objix_spix != cur_objix_spix) {\n        // load current object index (header) page\n        if (cur_objix_spix == 0) {\n          objix_pix = fd->objix_hdr_pix;\n        } else {\n          SPIFFS_DBG(\"read: find objix \"_SPIPRIid\":\"_SPIPRIsp\"\\n\", fd->obj_id, cur_objix_spix);\n          if (fd->cursor_objix_spix == cur_objix_spix) {\n            objix_pix = fd->cursor_objix_pix;\n          } else {\n            res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);\n            SPIFFS_CHECK_RES(res);\n          }\n        }\n        SPIFFS_DBG(\"read: load objix page \"_SPIPRIpg\":\"_SPIPRIsp\" for data spix:\"_SPIPRIsp\"\\n\", objix_pix, cur_objix_spix, data_spix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n            fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_VALIDATE_OBJIX(objix->p_hdr, fd->obj_id, cur_objix_spix);\n\n        fd->offset = cur_offset;\n        fd->cursor_objix_pix = objix_pix;\n        fd->cursor_objix_spix = cur_objix_spix;\n\n        prev_objix_spix = cur_objix_spix;\n      }\n\n      if (cur_objix_spix == 0) {\n        // get data page from object index header page\n        data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];\n      } else {\n        // get data page from object index page\n        data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];\n      }\n#if SPIFFS_IX_MAP\n    }\n#endif\n    // all remaining data\n    u32_t len_to_read = offset + len - cur_offset;\n    // remaining data in page\n    len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));\n    // remaining data in file\n    len_to_read = MIN(len_to_read, fd->size);\n    SPIFFS_DBG(\"read: offset:\"_SPIPRIi\" rd:\"_SPIPRIi\" data spix:\"_SPIPRIsp\" is data_pix:\"_SPIPRIpg\" addr:\"_SPIPRIad\"\\n\", cur_offset, len_to_read, data_spix, data_pix,\n        (u32_t)(SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))));\n    if (len_to_read <= 0) {\n      res = SPIFFS_ERR_END_OF_OBJECT;\n      break;\n    }\n    res = spiffs_page_data_check(fs, fd, data_pix, data_spix);\n    SPIFFS_CHECK_RES(res);\n    res = _spiffs_rd(\n        fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,\n        fd->file_nbr,\n        SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)),\n        len_to_read,\n        dst);\n    SPIFFS_CHECK_RES(res);\n    dst += len_to_read;\n    cur_offset += len_to_read;\n    fd->offset = cur_offset;\n    data_spix++;\n  }\n\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\ntypedef struct {\n  spiffs_obj_id min_obj_id;\n  spiffs_obj_id max_obj_id;\n  u32_t compaction;\n  const u8_t *conflicting_name;\n} spiffs_free_obj_id_state;\n\nstatic s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,\n    const void *user_const_p, void *user_var_p) {\n  if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) {\n    spiffs_obj_id min_obj_id = *((spiffs_obj_id*)user_var_p);\n    const u8_t *conflicting_name = (const u8_t*)user_const_p;\n\n    // if conflicting name parameter is given, also check if this name is found in object index hdrs\n    if (conflicting_name && (id & SPIFFS_OBJ_ID_IX_FLAG)) {\n      spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n      int res;\n      spiffs_page_object_ix_header objix_hdr;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n          0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);\n      SPIFFS_CHECK_RES(res);\n      if (objix_hdr.p_hdr.span_ix == 0 &&\n          (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==\n              (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {\n        if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) {\n          return SPIFFS_ERR_CONFLICTING_NAME;\n        }\n      }\n    }\n\n    id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n    u32_t bit_ix = (id-min_obj_id) & 7;\n    int byte_ix = (id-min_obj_id) >> 3;\n    if (byte_ix >= 0 && (u32_t)byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs)) {\n      fs->work[byte_ix] |= (1<<bit_ix);\n    }\n  }\n  return SPIFFS_VIS_COUNTINUE;\n}\n\nstatic s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,\n    const void *user_const_p, void *user_var_p) {\n  (void)user_var_p;\n  if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED && (id & SPIFFS_OBJ_ID_IX_FLAG)) {\n    s32_t res;\n    const spiffs_free_obj_id_state *state = (const spiffs_free_obj_id_state*)user_const_p;\n    spiffs_page_object_ix_header objix_hdr;\n\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, ix_entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&objix_hdr);\n    if (res == SPIFFS_OK && objix_hdr.p_hdr.span_ix == 0 &&\n        ((objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) ==\n            (SPIFFS_PH_FLAG_DELET))) {\n      // ok object look up entry\n      if (state->conflicting_name && strcmp((const char *)state->conflicting_name, (char *)objix_hdr.name) == 0) {\n        return SPIFFS_ERR_CONFLICTING_NAME;\n      }\n\n      id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n      if (id >= state->min_obj_id && id <= state->max_obj_id) {\n        u8_t *map = (u8_t *)fs->work;\n        int ix = (id - state->min_obj_id) / state->compaction;\n        //SPIFFS_DBG(\"free_obj_id: add ix \"_SPIPRIi\" for id \"_SPIPRIid\" min\"_SPIPRIid\" max\"_SPIPRIid\" comp:\"_SPIPRIi\"\\n\", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);\n        map[ix]++;\n      }\n    }\n  }\n  return SPIFFS_VIS_COUNTINUE;\n}\n\n// Scans thru all object lookup for object index header pages. If total possible number of\n// object ids cannot fit into a work buffer, these are grouped. When a group containing free\n// object ids is found, the object lu is again scanned for object ids within group and bitmasked.\n// Finally, the bitmask is searched for a free id\ns32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8_t *conflicting_name) {\n  s32_t res = SPIFFS_OK;\n  u32_t max_objects = (fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) / 2;\n  spiffs_free_obj_id_state state;\n  spiffs_obj_id free_obj_id = SPIFFS_OBJ_ID_FREE;\n  state.min_obj_id = 1;\n  state.max_obj_id = max_objects + 1;\n  if (state.max_obj_id & SPIFFS_OBJ_ID_IX_FLAG) {\n    state.max_obj_id = ((spiffs_obj_id)-1) & ~SPIFFS_OBJ_ID_IX_FLAG;\n  }\n  state.compaction = 0;\n  state.conflicting_name = conflicting_name;\n  while (res == SPIFFS_OK && free_obj_id == SPIFFS_OBJ_ID_FREE) {\n    if (state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8) {\n      // possible to represent in bitmap\n      u32_t i, j;\n      SPIFFS_DBG(\"free_obj_id: BITM min:\"_SPIPRIid\" max:\"_SPIPRIid\"\\n\", state.min_obj_id, state.max_obj_id);\n\n      memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n      res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v,\n          conflicting_name, &state.min_obj_id, 0, 0);\n      if (res == SPIFFS_VIS_END) res = SPIFFS_OK;\n      SPIFFS_CHECK_RES(res);\n      // traverse bitmask until found free obj_id\n      for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs); i++) {\n        u8_t mask = fs->work[i];\n        if (mask == 0xff) {\n          continue;\n        }\n        for (j = 0; j < 8; j++) {\n          if ((mask & (1<<j)) == 0) {\n            *obj_id = (i<<3)+j+state.min_obj_id;\n            return SPIFFS_OK;\n          }\n        }\n      }\n      return SPIFFS_ERR_FULL;\n    } else {\n      // not possible to represent all ids in range in a bitmap, compact and count\n      if (state.compaction != 0) {\n        // select element in compacted table, decrease range and recompact\n        u32_t i, min_i = 0;\n        u8_t *map = (u8_t *)fs->work;\n        u8_t min_count = 0xff;\n\n        for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(u8_t); i++) {\n          if (map[i] < min_count) {\n            min_count = map[i];\n            min_i = i;\n            if (min_count == 0) {\n              break;\n            }\n          }\n        }\n\n        if (min_count == state.compaction) {\n          // there are no free objids!\n          SPIFFS_DBG(\"free_obj_id: compacted table is full\\n\");\n          return SPIFFS_ERR_FULL;\n        }\n\n        SPIFFS_DBG(\"free_obj_id: COMP select index:\"_SPIPRIi\" min_count:\"_SPIPRIi\" min:\"_SPIPRIid\" max:\"_SPIPRIid\" compact:\"_SPIPRIi\"\\n\", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);\n\n        if (min_count == 0) {\n          // no id in this range, skip compacting and use directly\n          *obj_id = min_i * state.compaction + state.min_obj_id;\n          return SPIFFS_OK;\n        } else {\n          SPIFFS_DBG(\"free_obj_id: COMP SEL chunk:\"_SPIPRIi\" min:\"_SPIPRIid\" -> \"_SPIPRIid\"\\n\", state.compaction, state.min_obj_id, state.min_obj_id + min_i *  state.compaction);\n          state.min_obj_id += min_i *  state.compaction;\n          state.max_obj_id = state.min_obj_id + state.compaction;\n          // decrease compaction\n        }\n        if ((state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8)) {\n          // no need for compacting, use bitmap\n          continue;\n        }\n      }\n      // in a work memory of log_page_size bytes, we may fit in log_page_size ids\n      // todo what if compaction is > 255 - then we cannot fit it in a byte\n      state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));\n      SPIFFS_DBG(\"free_obj_id: COMP min:\"_SPIPRIid\" max:\"_SPIPRIid\" compact:\"_SPIPRIi\"\\n\", state.min_obj_id, state.max_obj_id, state.compaction);\n\n      memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n      res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, &state, 0, 0, 0);\n      if (res == SPIFFS_VIS_END) res = SPIFFS_OK;\n      SPIFFS_CHECK_RES(res);\n      state.conflicting_name = 0; // searched for conflicting name once, no need to do it again\n    }\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if SPIFFS_TEMPORAL_FD_CACHE\n// djb2 hash\nstatic u32_t spiffs_hash(spiffs *fs, const u8_t *name) {\n  (void)fs;\n  u32_t hash = 5381;\n  u8_t c;\n  int i = 0;\n  while ((c = name[i++]) && i < SPIFFS_OBJ_NAME_LEN) {\n    hash = (hash * 33) ^ c;\n  }\n  return hash;\n}\n#endif\n\ns32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) {\n#if SPIFFS_TEMPORAL_FD_CACHE\n  u32_t i;\n  u16_t min_score = 0xffff;\n  u32_t cand_ix = (u32_t)-1;\n  u32_t name_hash = name ? spiffs_hash(fs, (const u8_t *)name) : 0;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n\n  if (name) {\n    // first, decrease score of all closed descriptors\n    for (i = 0; i < fs->fd_count; i++) {\n      spiffs_fd *cur_fd = &fds[i];\n      if (cur_fd->file_nbr == 0) {\n        if (cur_fd->score > 1) { // score == 0 indicates never used fd\n          cur_fd->score--;\n        }\n      }\n    }\n  }\n\n  // find the free fd with least score\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->file_nbr == 0) {\n      if (name && cur_fd->name_hash == name_hash) {\n        cand_ix = i;\n        break;\n      }\n      if (cur_fd->score < min_score) {\n        min_score = cur_fd->score;\n        cand_ix = i;\n      }\n    }\n  }\n\n  if (cand_ix != (u32_t)-1) {\n    spiffs_fd *cur_fd = &fds[cand_ix];\n    if (name) {\n      if (cur_fd->name_hash == name_hash && cur_fd->score > 0) {\n        // opened an fd with same name hash, assume same file\n        // set search point to saved obj index page and hope we have a correct match directly\n        // when start searching - if not, we will just keep searching until it is found\n        fs->cursor_block_ix = SPIFFS_BLOCK_FOR_PAGE(fs, cur_fd->objix_hdr_pix);\n        fs->cursor_obj_lu_entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, cur_fd->objix_hdr_pix);\n        // update score\n        if (cur_fd->score < 0xffff-SPIFFS_TEMPORAL_CACHE_HIT_SCORE) {\n          cur_fd->score += SPIFFS_TEMPORAL_CACHE_HIT_SCORE;\n        } else {\n          cur_fd->score = 0xffff;\n        }\n      } else {\n        // no hash hit, restore this fd to initial state\n        cur_fd->score = SPIFFS_TEMPORAL_CACHE_HIT_SCORE;\n        cur_fd->name_hash = name_hash;\n      }\n    }\n    cur_fd->file_nbr = cand_ix+1;\n    *fd = cur_fd;\n    return SPIFFS_OK;\n  } else {\n    return SPIFFS_ERR_OUT_OF_FILE_DESCS;\n  }\n#else\n  (void)name;\n  u32_t i;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->file_nbr == 0) {\n      cur_fd->file_nbr = i+1;\n      *fd = cur_fd;\n      return SPIFFS_OK;\n    }\n  }\n  return SPIFFS_ERR_OUT_OF_FILE_DESCS;\n#endif\n}\n\ns32_t spiffs_fd_return(spiffs *fs, spiffs_file f) {\n  if (f <= 0 || f > (s16_t)fs->fd_count) {\n    return SPIFFS_ERR_BAD_DESCRIPTOR;\n  }\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  spiffs_fd *fd = &fds[f-1];\n  if (fd->file_nbr == 0) {\n    return SPIFFS_ERR_FILE_CLOSED;\n  }\n  fd->file_nbr = 0;\n#if SPIFFS_IX_MAP\n  fd->ix_map = 0;\n#endif\n  return SPIFFS_OK;\n}\n\ns32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) {\n  if (f <= 0 || f > (s16_t)fs->fd_count) {\n    return SPIFFS_ERR_BAD_DESCRIPTOR;\n  }\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  *fd = &fds[f-1];\n  if ((*fd)->file_nbr == 0) {\n    return SPIFFS_ERR_FILE_CLOSED;\n  }\n  return SPIFFS_OK;\n}\n\n#if SPIFFS_TEMPORAL_FD_CACHE\nvoid spiffs_fd_temporal_cache_rehash(\n    spiffs *fs,\n    const char *old_path,\n    const char *new_path) {\n  u32_t i;\n  u32_t old_hash = spiffs_hash(fs, (const u8_t *)old_path);\n  u32_t new_hash = spiffs_hash(fs, (const u8_t *)new_path);\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->score > 0 && cur_fd->name_hash == old_hash) {\n      cur_fd->name_hash = new_hash;\n    }\n  }\n}\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/spiffs/spiffs_nucleus.h",
    "content": "/*\n * spiffs_nucleus.h\n *\n *  Created on: Jun 15, 2013\n *      Author: petera\n */\n\n/* SPIFFS layout\n *\n * spiffs is designed for following spi flash characteristics:\n *   - only big areas of data (blocks) can be erased\n *   - erasing resets all bits in a block to ones\n *   - writing pulls ones to zeroes\n *   - zeroes cannot be pulled to ones, without erase\n *   - wear leveling\n *\n * spiffs is also meant to be run on embedded, memory constraint devices.\n *\n * Entire area is divided in blocks. Entire area is also divided in pages.\n * Each block contains same number of pages. A page cannot be erased, but a\n * block can be erased.\n *\n * Entire area must be block_size * x\n * page_size must be block_size / (2^y) where y > 2\n *\n * ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes\n *\n * BLOCK 0  PAGE 0       object lookup 1\n *          PAGE 1       object lookup 2\n *          ...\n *          PAGE n-1     object lookup n\n *          PAGE n       object data 1\n *          PAGE n+1     object data 2\n *          ...\n *          PAGE n+m-1   object data m\n *\n * BLOCK 1  PAGE n+m     object lookup 1\n *          PAGE n+m+1   object lookup 2\n *          ...\n *          PAGE 2n+m-1  object lookup n\n *          PAGE 2n+m    object data 1\n *          PAGE 2n+m    object data 2\n *          ...\n *          PAGE 2n+2m-1 object data m\n * ...\n *\n * n is number of object lookup pages, which is number of pages needed to index all pages\n * in a block by object id\n *   : block_size / page_size * sizeof(obj_id) / page_size\n * m is number data pages, which is number of pages in block minus number of lookup pages\n *   : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size\n * thus, n+m is total number of pages in a block\n *   : block_size / page_size\n *\n * ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256\n *\n * Object lookup pages contain object id entries. Each entry represent the corresponding\n * data page.\n * Assuming a 16 bit object id, an object id being 0xffff represents a free page.\n * An object id being 0x0000 represents a deleted page.\n *\n * ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..\n *     page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..\n *     page 2 : data   : data for object id 0008\n *     page 3 : data   : data for object id 0001\n *     page 4 : data   : data for object id 0aaa\n *     ...\n *\n *\n * Object data pages can be either object index pages or object content.\n * All object data pages contains a data page header, containing object id and span index.\n * The span index denotes the object page ordering amongst data pages with same object id.\n * This applies to both object index pages (when index spans more than one page of entries),\n * and object data pages.\n * An object index page contains page entries pointing to object content page. The entry index\n * in a object index page correlates to the span index in the actual object data page.\n * The first object index page (span index 0) is called object index header page, and also\n * contains object flags (directory/file), size, object name etc.\n *\n * ex:\n *  BLOCK 1\n *    PAGE 256: objectl lookup page 1\n *      [*123] [ 123] [ 123] [ 123]\n *      [ 123] [*123] [ 123] [ 123]\n *      [free] [free] [free] [free] ...\n *    PAGE 257: objectl lookup page 2\n *      [free] [free] [free] [free] ...\n *    PAGE 258: object index page (header)\n *      obj.id:0123 span.ix:0000 flags:INDEX\n *      size:1600 name:ex.txt type:file\n *      [259] [260] [261] [262]\n *    PAGE 259: object data page\n *      obj.id:0123 span.ix:0000 flags:DATA\n *    PAGE 260: object data page\n *      obj.id:0123 span.ix:0001 flags:DATA\n *    PAGE 261: object data page\n *      obj.id:0123 span.ix:0002 flags:DATA\n *    PAGE 262: object data page\n *      obj.id:0123 span.ix:0003 flags:DATA\n *    PAGE 263: object index page\n *      obj.id:0123 span.ix:0001 flags:INDEX\n *      [264] [265] [fre] [fre]\n *      [fre] [fre] [fre] [fre]\n *    PAGE 264: object data page\n *      obj.id:0123 span.ix:0004 flags:DATA\n *    PAGE 265: object data page\n *      obj.id:0123 span.ix:0005 flags:DATA\n *\n */\n#ifndef SPIFFS_NUCLEUS_H_\n#define SPIFFS_NUCLEUS_H_\n\n#define _SPIFFS_ERR_CHECK_FIRST         (SPIFFS_ERR_INTERNAL - 1)\n#define SPIFFS_ERR_CHECK_OBJ_ID_MISM    (SPIFFS_ERR_INTERNAL - 1)\n#define SPIFFS_ERR_CHECK_SPIX_MISM      (SPIFFS_ERR_INTERNAL - 2)\n#define SPIFFS_ERR_CHECK_FLAGS_BAD      (SPIFFS_ERR_INTERNAL - 3)\n#define _SPIFFS_ERR_CHECK_LAST          (SPIFFS_ERR_INTERNAL - 4)\n\n// visitor result, continue searching\n#define SPIFFS_VIS_COUNTINUE            (SPIFFS_ERR_INTERNAL - 20)\n// visitor result, continue searching after reloading lu buffer\n#define SPIFFS_VIS_COUNTINUE_RELOAD     (SPIFFS_ERR_INTERNAL - 21)\n// visitor result, stop searching\n#define SPIFFS_VIS_END                  (SPIFFS_ERR_INTERNAL - 22)\n\n// updating an object index contents\n#define SPIFFS_EV_IX_UPD                (0)\n// creating a new object index\n#define SPIFFS_EV_IX_NEW                (1)\n// deleting an object index\n#define SPIFFS_EV_IX_DEL                (2)\n// moving an object index without updating contents\n#define SPIFFS_EV_IX_MOV                (3)\n// updating an object index header data only, not the table itself\n#define SPIFFS_EV_IX_UPD_HDR            (4)\n\n#define SPIFFS_OBJ_ID_IX_FLAG           ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))\n\n#define SPIFFS_UNDEFINED_LEN            (u32_t)(-1)\n\n#define SPIFFS_OBJ_ID_DELETED           ((spiffs_obj_id)0)\n#define SPIFFS_OBJ_ID_FREE              ((spiffs_obj_id)-1)\n\n#if SPIFFS_USE_MAGIC\n#if !SPIFFS_USE_MAGIC_LENGTH\n#define SPIFFS_MAGIC(fs, bix)           \\\n  ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))\n#else // SPIFFS_USE_MAGIC_LENGTH\n#define SPIFFS_MAGIC(fs, bix)           \\\n  ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))\n#endif // SPIFFS_USE_MAGIC_LENGTH\n#endif // SPIFFS_USE_MAGIC\n\n#define SPIFFS_CONFIG_MAGIC             (0x20090315)\n\n#if SPIFFS_SINGLETON == 0\n#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \\\n  ((fs)->cfg.log_page_size)\n#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \\\n  ((fs)->cfg.log_block_size)\n#define SPIFFS_CFG_PHYS_SZ(fs) \\\n  ((fs)->cfg.phys_size)\n#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \\\n  ((fs)->cfg.phys_erase_block)\n#define SPIFFS_CFG_PHYS_ADDR(fs) \\\n  ((fs)->cfg.phys_addr)\n#endif\n\n// total number of pages\n#define SPIFFS_MAX_PAGES(fs) \\\n  ( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// total number of pages per block, including object lookup pages\n#define SPIFFS_PAGES_PER_BLOCK(fs) \\\n  ( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// number of object lookup pages per block\n#define SPIFFS_OBJ_LOOKUP_PAGES(fs)     \\\n  (MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )\n// checks if page index belongs to object lookup\n#define SPIFFS_IS_LOOKUP_PAGE(fs,pix)     \\\n  (((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))\n// number of object lookup entries in all object lookup pages\n#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \\\n  (SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))\n// converts a block to physical address\n#define SPIFFS_BLOCK_TO_PADDR(fs, block) \\\n  ( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )\n// converts a object lookup entry to page index\n#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \\\n  ((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))\n// converts a object lookup entry to physical address of corresponding page\n#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \\\n  (SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// converts a page to physical address\n#define SPIFFS_PAGE_TO_PADDR(fs, page) \\\n  ( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// converts a physical address to page\n#define SPIFFS_PADDR_TO_PAGE(fs, addr) \\\n  ( ((addr) -  SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// gives index in page for a physical address\n#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \\\n  ( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// returns containing block for given page\n#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \\\n  ( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )\n// returns starting page for block\n#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \\\n  ( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )\n// converts page to entry in object lookup page\n#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \\\n  ( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )\n// returns data size in a data page\n#define SPIFFS_DATA_PAGE_SIZE(fs) \\\n    ( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )\n// returns physical address for block's erase count,\n// always in the physical last entry of the last object lookup page\n#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \\\n  ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )\n// returns physical address for block's magic,\n// always in the physical second last entry of the last object lookup page\n#define SPIFFS_MAGIC_PADDR(fs, bix) \\\n  ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )\n// checks if there is any room for magic in the object luts\n#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \\\n  ( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \\\n    <= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )\n\n// define helpers object\n\n// entries in an object header page index\n#define SPIFFS_OBJ_HDR_IX_LEN(fs) \\\n  ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))\n// entries in an object page index\n#define SPIFFS_OBJ_IX_LEN(fs) \\\n  ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))\n// object index entry for given data span index\n#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \\\n  ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))\n// object index span index number for given data span index or entry\n#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \\\n  ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))\n// get data span index for object index span index\n#define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \\\n  ( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )\n\n#define SPIFFS_OP_T_OBJ_LU    (0<<0)\n#define SPIFFS_OP_T_OBJ_LU2   (1<<0)\n#define SPIFFS_OP_T_OBJ_IX    (2<<0)\n#define SPIFFS_OP_T_OBJ_DA    (3<<0)\n#define SPIFFS_OP_C_DELE      (0<<2)\n#define SPIFFS_OP_C_UPDT      (1<<2)\n#define SPIFFS_OP_C_MOVS      (2<<2)\n#define SPIFFS_OP_C_MOVD      (3<<2)\n#define SPIFFS_OP_C_FLSH      (4<<2)\n#define SPIFFS_OP_C_READ      (5<<2)\n#define SPIFFS_OP_C_WRTHRU    (6<<2)\n\n#define SPIFFS_OP_TYPE_MASK (3<<0)\n#define SPIFFS_OP_COM_MASK  (7<<2)\n\n\n// if 0, this page is written to, else clean\n#define SPIFFS_PH_FLAG_USED   (1<<0)\n// if 0, writing is finalized, else under modification\n#define SPIFFS_PH_FLAG_FINAL  (1<<1)\n// if 0, this is an index page, else a data page\n#define SPIFFS_PH_FLAG_INDEX  (1<<2)\n// if 0, page is deleted, else valid\n#define SPIFFS_PH_FLAG_DELET  (1<<7)\n// if 0, this index header is being deleted\n#define SPIFFS_PH_FLAG_IXDELE (1<<6)\n\n\n#define SPIFFS_CHECK_MOUNT(fs) \\\n  ((fs)->mounted != 0)\n\n#define SPIFFS_CHECK_CFG(fs) \\\n  ((fs)->config_magic == SPIFFS_CONFIG_MAGIC)\n\n#define SPIFFS_CHECK_RES(res) \\\n  do { \\\n    if ((res) < SPIFFS_OK) return (res); \\\n  } while (0);\n\n#define SPIFFS_API_CHECK_MOUNT(fs) \\\n  if (!SPIFFS_CHECK_MOUNT((fs))) { \\\n    (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \\\n    return SPIFFS_ERR_NOT_MOUNTED; \\\n  }\n\n#define SPIFFS_API_CHECK_CFG(fs) \\\n  if (!SPIFFS_CHECK_CFG((fs))) { \\\n    (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \\\n    return SPIFFS_ERR_NOT_CONFIGURED; \\\n  }\n\n#define SPIFFS_API_CHECK_RES(fs, res) \\\n  if ((res) < SPIFFS_OK) { \\\n    (fs)->err_code = (res); \\\n    return (res); \\\n  }\n\n#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \\\n  if ((res) < SPIFFS_OK) { \\\n    (fs)->err_code = (res); \\\n    SPIFFS_UNLOCK(fs); \\\n    return (res); \\\n  }\n\n#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \\\n    if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \\\n    if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \\\n    if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;\n    //if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;\n\n#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \\\n    if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \\\n    if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \\\n    if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;\n\n\n// check id, only visit matching objec ids\n#define SPIFFS_VIS_CHECK_ID     (1<<0)\n// report argument object id to visitor - else object lookup id is reported\n#define SPIFFS_VIS_CHECK_PH     (1<<1)\n// stop searching at end of all look up pages\n#define SPIFFS_VIS_NO_WRAP      (1<<2)\n\n#if SPIFFS_HAL_CALLBACK_EXTRA\n\n#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \\\n  (_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))\n#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \\\n  (_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))\n#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \\\n  (_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))\n\n#else // SPIFFS_HAL_CALLBACK_EXTRA\n\n#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \\\n  (_fs)->cfg.hal_write_f((_paddr), (_len), (_src))\n#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \\\n  (_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))\n#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \\\n  (_fs)->cfg.hal_erase_f((_paddr), (_len))\n\n#endif // SPIFFS_HAL_CALLBACK_EXTRA\n\n#if SPIFFS_CACHE\n\n#define SPIFFS_CACHE_FLAG_DIRTY       (1<<0)\n#define SPIFFS_CACHE_FLAG_WRTHRU      (1<<1)\n#define SPIFFS_CACHE_FLAG_OBJLU       (1<<2)\n#define SPIFFS_CACHE_FLAG_OBJIX       (1<<3)\n#define SPIFFS_CACHE_FLAG_DATA        (1<<4)\n#define SPIFFS_CACHE_FLAG_TYPE_WR     (1<<7)\n\n#define SPIFFS_CACHE_PAGE_SIZE(fs) \\\n  (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))\n\n#define spiffs_get_cache(fs) \\\n  ((spiffs_cache *)((fs)->cache))\n\n#define spiffs_get_cache_page_hdr(fs, c, ix) \\\n  ((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))\n\n#define spiffs_get_cache_page(fs, c, ix) \\\n  ((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))\n\n// cache page struct\ntypedef struct {\n  // cache flags\n  u8_t flags;\n  // cache page index\n  u8_t ix;\n  // last access of this cache page\n  u32_t last_access;\n  union {\n    // type read cache\n    struct {\n      // read cache page index\n      spiffs_page_ix pix;\n    };\n#if SPIFFS_CACHE_WR\n    // type write cache\n    struct {\n      // write cache\n      spiffs_obj_id obj_id;\n      // offset in cache page\n      u32_t offset;\n      // size of cache page\n      u16_t size;\n    };\n#endif\n  };\n} spiffs_cache_page;\n\n// cache struct\ntypedef struct {\n  u8_t cpage_count;\n  u32_t last_access;\n  u32_t cpage_use_map;\n  u32_t cpage_use_mask;\n  u8_t *cpages;\n} spiffs_cache;\n\n#endif\n\n\n// spiffs nucleus file descriptor\ntypedef struct {\n  // the filesystem of this descriptor\n  spiffs *fs;\n  // number of file descriptor - if 0, the file descriptor is closed\n  spiffs_file file_nbr;\n  // object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted\n  spiffs_obj_id obj_id;\n  // size of the file\n  u32_t size;\n  // cached object index header page index\n  spiffs_page_ix objix_hdr_pix;\n  // cached offset object index page index\n  spiffs_page_ix cursor_objix_pix;\n  // cached offset object index span index\n  spiffs_span_ix cursor_objix_spix;\n  // current absolute offset\n  u32_t offset;\n  // current file descriptor offset\n  u32_t fdoffset;\n  // fd flags\n  spiffs_flags flags;\n#if SPIFFS_CACHE_WR\n  spiffs_cache_page *cache_page;\n#endif\n#if SPIFFS_TEMPORAL_FD_CACHE\n  // djb2 hash of filename\n  u32_t name_hash;\n  // hit score (score == 0 indicates never used fd)\n  u16_t score;\n#endif\n#if SPIFFS_IX_MAP\n  // spiffs index map, if 0 it means unmapped\n  spiffs_ix_map *ix_map;\n#endif\n} spiffs_fd;\n\n\n// object structs\n\n// page header, part of each page except object lookup pages\n// NB: this is always aligned when the data page is an object index,\n// as in this case struct spiffs_page_object_ix is used\ntypedef struct __attribute(( packed )) {\n  // object id\n  spiffs_obj_id obj_id;\n  // object span index\n  spiffs_span_ix span_ix;\n  // flags\n  u8_t flags;\n} spiffs_page_header;\n\n// object index header page header\ntypedef struct __attribute(( packed ))\n#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES\n                __attribute(( aligned(sizeof(spiffs_page_ix)) ))\n#endif\n{\n  // common page header\n  spiffs_page_header p_hdr;\n  // alignment\n  u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];\n  // size of object\n  u32_t size;\n  // type of object\n  spiffs_obj_type type;\n  // name of object\n  u8_t name[SPIFFS_OBJ_NAME_LEN];\n#if SPIFFS_OBJ_META_LEN\n  // metadata. not interpreted by SPIFFS in any way.\n  u8_t meta[SPIFFS_OBJ_META_LEN];\n#endif\n} spiffs_page_object_ix_header;\n\n// object index page header\ntypedef struct __attribute(( packed )) {\n spiffs_page_header p_hdr;\n u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];\n} spiffs_page_object_ix;\n\n// callback func for object lookup visitor\ntypedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,\n    const void *user_const_p, void *user_var_p);\n\n\n#if SPIFFS_CACHE\n#define _spiffs_rd(fs, op, fh, addr, len, dst) \\\n    spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))\n#define _spiffs_wr(fs, op, fh, addr, len, src) \\\n    spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))\n#else\n#define _spiffs_rd(fs, op, fh, addr, len, dst) \\\n    spiffs_phys_rd((fs), (addr), (len), (dst))\n#define _spiffs_wr(fs, op, fh, addr, len, src) \\\n    spiffs_phys_wr((fs), (addr), (len), (src))\n#endif\n\n#ifndef MIN\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#endif\n#ifndef MAX\n#define MAX(a,b) ((a) > (b) ? (a) : (b))\n#endif\n\n// ---------------\n\ns32_t spiffs_phys_rd(\n    spiffs *fs,\n#if SPIFFS_CACHE\n    u8_t op,\n    spiffs_file fh,\n#endif\n    u32_t addr,\n    u32_t len,\n    u8_t *dst);\n\ns32_t spiffs_phys_wr(\n    spiffs *fs,\n#if SPIFFS_CACHE\n    u8_t op,\n    spiffs_file fh,\n#endif\n    u32_t addr,\n    u32_t len,\n    u8_t *src);\n\ns32_t spiffs_phys_cpy(\n    spiffs *fs,\n    spiffs_file fh,\n    u32_t dst,\n    u32_t src,\n    u32_t len);\n\ns32_t spiffs_phys_count_free_blocks(\n    spiffs *fs);\n\ns32_t spiffs_obj_lu_find_entry_visitor(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    u8_t flags,\n    spiffs_obj_id obj_id,\n    spiffs_visitor_f v,\n    const void *user_const_p,\n    void *user_var_p,\n    spiffs_block_ix *block_ix,\n    int *lu_entry);\n\ns32_t spiffs_erase_block(\n    spiffs *fs,\n    spiffs_block_ix bix);\n\n#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH\ns32_t spiffs_probe(\n    spiffs_config *cfg);\n#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH\n\n// ---------------\n\ns32_t spiffs_obj_lu_scan(\n    spiffs *fs);\n\ns32_t spiffs_obj_lu_find_free_obj_id(\n    spiffs *fs,\n    spiffs_obj_id *obj_id,\n    const u8_t *conflicting_name);\n\ns32_t spiffs_obj_lu_find_free(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    spiffs_block_ix *block_ix,\n    int *lu_entry);\n\ns32_t spiffs_obj_lu_find_id(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix *block_ix,\n    int *lu_entry);\n\ns32_t spiffs_obj_lu_find_id_and_span(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix exclusion_pix,\n    spiffs_page_ix *pix);\n\ns32_t spiffs_obj_lu_find_id_and_span_by_phdr(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix exclusion_pix,\n    spiffs_page_ix *pix);\n\n// ---------------\n\ns32_t spiffs_page_allocate_data(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_page_header *ph,\n    u8_t *data,\n    u32_t len,\n    u32_t page_offs,\n    u8_t finalize,\n    spiffs_page_ix *pix);\n\ns32_t spiffs_page_move(\n    spiffs *fs,\n    spiffs_file fh,\n    u8_t *page_data,\n    spiffs_obj_id obj_id,\n    spiffs_page_header *page_hdr,\n    spiffs_page_ix src_pix,\n    spiffs_page_ix *dst_pix);\n\ns32_t spiffs_page_delete(\n    spiffs *fs,\n    spiffs_page_ix pix);\n\n// ---------------\n\ns32_t spiffs_object_create(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    const u8_t name[],\n    const u8_t meta[],\n    spiffs_obj_type type,\n    spiffs_page_ix *objix_hdr_pix);\n\ns32_t spiffs_object_update_index_hdr(\n    spiffs *fs,\n    spiffs_fd *fd,\n    spiffs_obj_id obj_id,\n    spiffs_page_ix objix_hdr_pix,\n    u8_t *new_objix_hdr_data,\n    const u8_t name[],\n    const u8_t meta[],\n    u32_t size,\n    spiffs_page_ix *new_pix);\n\n#if SPIFFS_IX_MAP\n\ns32_t spiffs_populate_ix_map(\n    spiffs *fs,\n    spiffs_fd *fd,\n    u32_t vec_entry_start,\n    u32_t vec_entry_end);\n\n#endif\n\nvoid spiffs_cb_object_event(\n    spiffs *fs,\n    spiffs_page_object_ix *objix,\n    int ev,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix new_pix,\n    u32_t new_size);\n\ns32_t spiffs_object_open_by_id(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_fd *f,\n    spiffs_flags flags,\n    spiffs_mode mode);\n\ns32_t spiffs_object_open_by_page(\n    spiffs *fs,\n    spiffs_page_ix pix,\n    spiffs_fd *f,\n    spiffs_flags flags,\n    spiffs_mode mode);\n\ns32_t spiffs_object_append(\n    spiffs_fd *fd,\n    u32_t offset,\n    u8_t *data,\n    u32_t len);\n\ns32_t spiffs_object_modify(\n    spiffs_fd *fd,\n    u32_t offset,\n    u8_t *data,\n    u32_t len);\n\ns32_t spiffs_object_read(\n    spiffs_fd *fd,\n    u32_t offset,\n    u32_t len,\n    u8_t *dst);\n\ns32_t spiffs_object_truncate(\n    spiffs_fd *fd,\n    u32_t new_len,\n    u8_t remove_object);\n\ns32_t spiffs_object_find_object_index_header_by_name(\n    spiffs *fs,\n    const u8_t name[SPIFFS_OBJ_NAME_LEN],\n    spiffs_page_ix *pix);\n\n// ---------------\n\ns32_t spiffs_gc_check(\n    spiffs *fs,\n    u32_t len);\n\ns32_t spiffs_gc_erase_page_stats(\n    spiffs *fs,\n    spiffs_block_ix bix);\n\ns32_t spiffs_gc_find_candidate(\n    spiffs *fs,\n    spiffs_block_ix **block_candidate,\n    int *candidate_count,\n    char fs_crammed);\n\ns32_t spiffs_gc_clean(\n    spiffs *fs,\n    spiffs_block_ix bix);\n\ns32_t spiffs_gc_quick(\n    spiffs *fs, u16_t max_free_pages);\n\n// ---------------\n\ns32_t spiffs_fd_find_new(\n    spiffs *fs,\n    spiffs_fd **fd,\n    const char *name);\n\ns32_t spiffs_fd_return(\n    spiffs *fs,\n    spiffs_file f);\n\ns32_t spiffs_fd_get(\n    spiffs *fs,\n    spiffs_file f,\n    spiffs_fd **fd);\n\n#if SPIFFS_TEMPORAL_FD_CACHE\nvoid spiffs_fd_temporal_cache_rehash(\n    spiffs *fs,\n    const char *old_path,\n    const char *new_path);\n#endif\n\n#if SPIFFS_CACHE\nvoid spiffs_cache_init(\n    spiffs *fs);\n\nvoid spiffs_cache_drop_page(\n    spiffs *fs,\n    spiffs_page_ix pix);\n\n#if SPIFFS_CACHE_WR\nspiffs_cache_page *spiffs_cache_page_allocate_by_fd(\n    spiffs *fs,\n    spiffs_fd *fd);\n\nvoid spiffs_cache_fd_release(\n    spiffs *fs,\n    spiffs_cache_page *cp);\n\nspiffs_cache_page *spiffs_cache_page_get_by_fd(\n    spiffs *fs,\n    spiffs_fd *fd);\n#endif\n#endif\n\ns32_t spiffs_lookup_consistency_check(\n    spiffs *fs,\n    u8_t check_all_objects);\n\ns32_t spiffs_page_consistency_check(\n    spiffs *fs);\n\ns32_t spiffs_object_index_consistency_check(\n    spiffs *fs);\n\n#endif /* SPIFFS_NUCLEUS_H_ */\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/Arg.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/******************************************************************************\n *\n *  file:  Arg.h\n *\n *  Copyright (c) 2003, Michael E. Smoot .\n *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno .\n *  All rights reverved.\n *\n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *\n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS\n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n *  DEALINGS IN THE SOFTWARE.\n *\n *****************************************************************************/\n\n\n#ifndef TCLAP_ARGUMENT_H\n#define TCLAP_ARGUMENT_H\n\n#ifdef HAVE_CONFIG_H\n#include <config.h>\n#else\n#define HAVE_SSTREAM\n#endif\n\n#include <string>\n#include <vector>\n#include <list>\n#include <iostream>\n#include <iomanip>\n#include <cstdio>\n\n#if defined(HAVE_SSTREAM)\n#include <sstream>\ntypedef std::istringstream istringstream;\n#elif defined(HAVE_STRSTREAM)\n#include <strstream>\ntypedef std::istrstream istringstream;\n#else\n#error \"Need a stringstream (sstream or strstream) to compile!\"\n#endif\n\n#include \"ArgException.h\"\n#include \"Visitor.h\"\n#include \"CmdLineInterface.h\"\n#include \"ArgTraits.h\"\n#include \"StandardTraits.h\"\n\nnamespace TCLAP {\n\n/**\n * A virtual base class that defines the essential data for all arguments.\n * This class, or one of its existing children, must be subclassed to do\n * anything.\n */\nclass Arg\n{\n\tprivate:\n\t\t/**\n\t\t * Prevent accidental copying.\n\t\t */\n\t\tArg(const Arg& rhs);\n\n\t\t/**\n\t\t * Prevent accidental copying.\n\t\t */\n\t\tArg& operator=(const Arg& rhs);\n\n\t\t/**\n\t\t * Indicates whether the rest of the arguments should be ignored.\n\t\t */\n\t\tstatic bool& ignoreRestRef() { static bool ign = false; return ign; }\n\n\t\t/**\n\t\t * The delimiter that separates an argument flag/name from the\n\t\t * value.\n\t\t */\n\t\tstatic char& delimiterRef() { static char delim = ' '; return delim; }\n\n\tprotected:\n\n\t\t/**\n\t\t * The single char flag used to identify the argument.\n\t\t * This value (preceded by a dash {-}), can be used to identify\n\t\t * an argument on the command line.  The _flag can be blank,\n\t\t * in fact this is how unlabeled args work.  Unlabeled args must\n\t\t * override appropriate functions to get correct handling. Note\n\t\t * that the _flag does NOT include the dash as part of the flag.\n\t\t */\n\t\tstd::string _flag;\n\n\t\t/**\n\t\t * A single work namd indentifying the argument.\n\t\t * This value (preceded by two dashed {--}) can also be used\n\t\t * to identify an argument on the command line.  Note that the\n\t\t * _name does NOT include the two dashes as part of the _name. The\n\t\t * _name cannot be blank.\n\t\t */\n\t\tstd::string _name;\n\n\t\t/**\n\t\t * Description of the argument.\n\t\t */\n\t\tstd::string _description;\n\n\t\t/**\n\t\t * Indicating whether the argument is required.\n\t\t */\n\t\tbool _required;\n\n\t\t/**\n\t\t * Label to be used in usage description.  Normally set to\n\t\t * \"required\", but can be changed when necessary.\n\t\t */\n\t\tstd::string _requireLabel;\n\n\t\t/**\n\t\t * Indicates whether a value is required for the argument.\n\t\t * Note that the value may be required but the argument/value\n\t\t * combination may not be, as specified by _required.\n\t\t */\n\t\tbool _valueRequired;\n\n\t\t/**\n\t\t * Indicates whether the argument has been set.\n\t\t * Indicates that a value on the command line has matched the\n\t\t * name/flag of this argument and the values have been set accordingly.\n\t\t */\n\t\tbool _alreadySet;\n\n\t\t/**\n\t\t * A pointer to a vistitor object.\n\t\t * The visitor allows special handling to occur as soon as the\n\t\t * argument is matched.  This defaults to NULL and should not\n\t\t * be used unless absolutely necessary.\n\t\t */\n\t\tVisitor* _visitor;\n\n\t\t/**\n\t\t * Whether this argument can be ignored, if desired.\n\t\t */\n\t\tbool _ignoreable;\n\n\t\t/**\n\t\t * Indicates that the arg was set as part of an XOR and not on the\n\t\t * command line.\n\t\t */\n\t\tbool _xorSet;\n\n\t\tbool _acceptsMultipleValues;\n\n\t\t/**\n\t\t * Performs the special handling described by the Vistitor.\n\t\t */\n\t\tvoid _checkWithVisitor() const;\n\n\t\t/**\n\t\t * Primary constructor. YOU (yes you) should NEVER construct an Arg\n\t\t * directly, this is a base class that is extended by various children\n\t\t * that are meant to be used.  Use SwitchArg, ValueArg, MultiArg,\n\t\t * UnlabeledValueArg, or UnlabeledMultiArg instead.\n\t\t *\n\t\t * \\param flag - The flag identifying the argument.\n\t\t * \\param name - The name identifying the argument.\n\t\t * \\param desc - The description of the argument, used in the usage.\n\t\t * \\param req - Whether the argument is required.\n\t\t * \\param valreq - Whether the a value is required for the argument.\n\t\t * \\param v - The visitor checked by the argument. Defaults to NULL.\n\t\t */\n \t\tArg( const std::string& flag,\n\t\t\t const std::string& name,\n\t\t\t const std::string& desc,\n\t\t\t bool req,\n\t\t\t bool valreq,\n\t\t\t Visitor* v = NULL );\n\n\tpublic:\n\t\t/**\n\t\t * Destructor.\n\t\t */\n\t\tvirtual ~Arg();\n\n\t\t/**\n\t\t * Adds this to the specified list of Args.\n\t\t * \\param argList - The list to add this to.\n\t\t */\n\t\tvirtual void addToList( std::list<Arg*>& argList ) const;\n\n\t\t/**\n\t\t * Begin ignoring arguments since the \"--\" argument was specified.\n\t\t */\n\t\tstatic void beginIgnoring() { ignoreRestRef() = true; }\n\n\t\t/**\n\t\t * Whether to ignore the rest.\n\t\t */\n\t\tstatic bool ignoreRest() { return ignoreRestRef(); }\n\n\t\t/**\n\t\t * The delimiter that separates an argument flag/name from the\n\t\t * value.\n\t\t */\n\t\tstatic char delimiter() { return delimiterRef(); }\n\n\t\t/**\n\t\t * The char used as a place holder when SwitchArgs are combined.\n\t\t * Currently set to the bell char (ASCII 7).\n\t\t */\n\t\tstatic char blankChar() { return (char)7; }\n\n\t\t/**\n\t\t * The char that indicates the beginning of a flag.  Defaults to '-', but\n\t\t * clients can define TCLAP_FLAGSTARTCHAR to override.\n\t\t */\n#ifndef TCLAP_FLAGSTARTCHAR\n#define TCLAP_FLAGSTARTCHAR '-'\n#endif\n\t\tstatic char flagStartChar() { return TCLAP_FLAGSTARTCHAR; }\n\n\t\t/**\n\t\t * The sting that indicates the beginning of a flag.  Defaults to \"-\", but\n\t\t * clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same\n\t\t * as TCLAP_FLAGSTARTCHAR.\n\t\t */\n#ifndef TCLAP_FLAGSTARTSTRING\n#define TCLAP_FLAGSTARTSTRING \"-\"\n#endif\n\t\tstatic const std::string flagStartString() { return TCLAP_FLAGSTARTSTRING; }\n\n\t\t/**\n\t\t * The sting that indicates the beginning of a name.  Defaults to \"--\", but\n\t\t *  clients can define TCLAP_NAMESTARTSTRING to override.\n\t\t */\n#ifndef TCLAP_NAMESTARTSTRING\n#define TCLAP_NAMESTARTSTRING \"--\"\n#endif\n\t\tstatic const std::string nameStartString() { return TCLAP_NAMESTARTSTRING; }\n\n\t\t/**\n\t\t * The name used to identify the ignore rest argument.\n\t\t */\n\t\tstatic const std::string ignoreNameString() { return \"ignore_rest\"; }\n\n\t\t/**\n\t\t * Sets the delimiter for all arguments.\n\t\t * \\param c - The character that delimits flags/names from values.\n\t\t */\n\t\tstatic void setDelimiter( char c ) { delimiterRef() = c; }\n\n\t\t/**\n\t\t * Pure virtual method meant to handle the parsing and value assignment\n\t\t * of the string on the command line.\n\t\t * \\param i - Pointer the the current argument in the list.\n\t\t * \\param args - Mutable list of strings. What is\n\t\t * passed in from main.\n\t\t */\n\t\tvirtual bool processArg(int *i, std::vector<std::string>& args) = 0;\n\n\t\t/**\n\t\t * Operator ==.\n\t\t * Equality operator. Must be virtual to handle unlabeled args.\n\t\t * \\param a - The Arg to be compared to this.\n\t\t */\n\t\tvirtual bool operator==(const Arg& a) const;\n\n\t\t/**\n\t\t * Returns the argument flag.\n\t\t */\n\t\tconst std::string& getFlag() const;\n\n\t\t/**\n\t\t * Returns the argument name.\n\t\t */\n\t\tconst std::string& getName() const;\n\n\t\t/**\n\t\t * Returns the argument description.\n\t\t */\n\t\tstd::string getDescription() const;\n\n\t\t/**\n\t\t * Indicates whether the argument is required.\n\t\t */\n\t\tvirtual bool isRequired() const;\n\n\t\t/**\n\t\t * Sets _required to true. This is used by the XorHandler.\n\t\t * You really have no reason to ever use it.\n\t\t */\n\t\tvoid forceRequired();\n\n\t\t/**\n\t\t * Sets the _alreadySet value to true.  This is used by the XorHandler.\n\t\t * You really have no reason to ever use it.\n\t\t */\n\t\tvoid xorSet();\n\n\t\t/**\n\t\t * Indicates whether a value must be specified for argument.\n\t\t */\n\t\tbool isValueRequired() const;\n\n\t\t/**\n\t\t * Indicates whether the argument has already been set.  Only true\n\t\t * if the arg has been matched on the command line.\n\t\t */\n\t\tbool isSet() const;\n\n\t\t/**\n\t\t * Indicates whether the argument can be ignored, if desired.\n\t\t */\n\t\tbool isIgnoreable() const;\n\n\t\t/**\n\t\t * A method that tests whether a string matches this argument.\n\t\t * This is generally called by the processArg() method.  This\n\t\t * method could be re-implemented by a child to change how\n\t\t * arguments are specified on the command line.\n\t\t * \\param s - The string to be compared to the flag/name to determine\n\t\t * whether the arg matches.\n\t\t */\n\t\tvirtual bool argMatches( const std::string& s ) const;\n\n\t\t/**\n\t\t * Returns a simple string representation of the argument.\n\t\t * Primarily for debugging.\n\t\t */\n\t\tvirtual std::string toString() const;\n\n\t\t/**\n\t\t * Returns a short ID for the usage.\n\t\t * \\param valueId - The value used in the id.\n\t\t */\n\t\tvirtual std::string shortID( const std::string& valueId = \"val\" ) const;\n\n\t\t/**\n\t\t * Returns a long ID for the usage.\n\t\t * \\param valueId - The value used in the id.\n\t\t */\n\t\tvirtual std::string longID( const std::string& valueId = \"val\" ) const;\n\n\t\t/**\n\t\t * Trims a value off of the flag.\n\t\t * \\param flag - The string from which the flag and value will be\n\t\t * trimmed. Contains the flag once the value has been trimmed.\n\t\t * \\param value - Where the value trimmed from the string will\n\t\t * be stored.\n\t\t */\n\t\tvirtual void trimFlag( std::string& flag, std::string& value ) const;\n\n\t\t/**\n\t\t * Checks whether a given string has blank chars, indicating that\n\t\t * it is a combined SwitchArg.  If so, return true, otherwise return\n\t\t * false.\n\t\t * \\param s - string to be checked.\n\t\t */\n\t\tbool _hasBlanks( const std::string& s ) const;\n\n\t\t/**\n\t\t * Sets the requireLabel. Used by XorHandler.  You shouldn't ever\n\t\t * use this.\n\t\t * \\param s - Set the requireLabel to this value.\n\t\t */\n\t\tvoid setRequireLabel( const std::string& s );\n\n\t\t/**\n\t\t * Used for MultiArgs and XorHandler to determine whether args\n\t\t * can still be set.\n\t\t */\n\t\tvirtual bool allowMore();\n\n\t\t/**\n\t\t * Use by output classes to determine whether an Arg accepts\n\t\t * multiple values.\n\t\t */\n\t\tvirtual bool acceptsMultipleValues();\n\n\t\t/**\n\t\t * Clears the Arg object and allows it to be reused by new\n\t\t * command lines.\n\t\t */\n\t\t virtual void reset();\n};\n\n/**\n * Typedef of an Arg list iterator.\n */\ntypedef std::list<Arg*>::iterator ArgListIterator;\n\n/**\n * Typedef of an Arg vector iterator.\n */\ntypedef std::vector<Arg*>::iterator ArgVectorIterator;\n\n/**\n * Typedef of a Visitor list iterator.\n */\ntypedef std::list<Visitor*>::iterator VisitorListIterator;\n\n/*\n * Extract a value of type T from it's string representation contained\n * in strVal. The ValueLike parameter used to select the correct\n * specialization of ExtractValue depending on the value traits of T.\n * ValueLike traits use operator>> to assign the value from strVal.\n */\ntemplate<typename T> void\nExtractValue(T &destVal, const std::string& strVal, ValueLike vl)\n{\n    static_cast<void>(vl); // Avoid warning about unused vl\n    std::istringstream is(strVal);\n\n    int valuesRead = 0;\n    while ( is.good() ) {\n\tif ( is.peek() != EOF )\n#ifdef TCLAP_SETBASE_ZERO\n\t    is >> std::setbase(0) >> destVal;\n#else\n\t    is >> destVal;\n#endif\n\telse\n\t    break;\n\n\tvaluesRead++;\n    }\n\n    if ( is.fail() )\n\tthrow( ArgParseException(\"Couldn't read argument value \"\n\t\t\t\t \"from string '\" + strVal + \"'\"));\n\n\n    if ( valuesRead > 1 )\n\tthrow( ArgParseException(\"More than one valid value parsed from \"\n\t\t\t\t \"string '\" + strVal + \"'\"));\n\n}\n\n/*\n * Extract a value of type T from it's string representation contained\n * in strVal. The ValueLike parameter used to select the correct\n * specialization of ExtractValue depending on the value traits of T.\n * StringLike uses assignment (operator=) to assign from strVal.\n */\ntemplate<typename T> void\nExtractValue(T &destVal, const std::string& strVal, StringLike sl)\n{\n    static_cast<void>(sl); // Avoid warning about unused sl\n    SetString(destVal, strVal);\n}\n\n//////////////////////////////////////////////////////////////////////\n//BEGIN Arg.cpp\n//////////////////////////////////////////////////////////////////////\n\ninline Arg::Arg(const std::string& flag,\n         const std::string& name,\n         const std::string& desc,\n         bool req,\n         bool valreq,\n         Visitor* v) :\n  _flag(flag),\n  _name(name),\n  _description(desc),\n  _required(req),\n  _requireLabel(\"required\"),\n  _valueRequired(valreq),\n  _alreadySet(false),\n  _visitor( v ),\n  _ignoreable(true),\n  _xorSet(false),\n  _acceptsMultipleValues(false)\n{\n\tif ( _flag.length() > 1 )\n\t\tthrow(SpecificationException(\n\t\t\t\t\"Argument flag can only be one character long\", toString() ) );\n\n\tif ( _name != ignoreNameString() &&\n\t\t ( _flag == Arg::flagStartString() ||\n\t\t   _flag == Arg::nameStartString() ||\n\t\t   _flag == \" \" ) )\n\t\tthrow(SpecificationException(\"Argument flag cannot be either '\" +\n\t\t\t\t\t\t\tArg::flagStartString() + \"' or '\" +\n\t\t\t\t\t\t\tArg::nameStartString() + \"' or a space.\",\n\t\t\t\t\t\t\ttoString() ) );\n\n\tif ( ( _name.substr( 0, Arg::flagStartString().length() ) == Arg::flagStartString() ) ||\n\t\t ( _name.substr( 0, Arg::nameStartString().length() ) == Arg::nameStartString() ) ||\n\t\t ( _name.find( \" \", 0 ) != std::string::npos ) )\n\t\tthrow(SpecificationException(\"Argument name begin with either '\" +\n\t\t\t\t\t\t\tArg::flagStartString() + \"' or '\" +\n\t\t\t\t\t\t\tArg::nameStartString() + \"' or space.\",\n\t\t\t\t\t\t\ttoString() ) );\n\n}\n\ninline Arg::~Arg() { }\n\ninline std::string Arg::shortID( const std::string& valueId ) const\n{\n\tstd::string id = \"\";\n\n\tif ( _flag != \"\" )\n\t\tid = Arg::flagStartString() + _flag;\n\telse\n\t\tid = Arg::nameStartString() + _name;\n\n\tif ( _valueRequired )\n\t\tid += std::string( 1, Arg::delimiter() ) + \"<\" + valueId  + \">\";\n\n\tif ( !_required )\n\t\tid = \"[\" + id + \"]\";\n\n\treturn id;\n}\n\ninline std::string Arg::longID( const std::string& valueId ) const\n{\n\tstd::string id = \"\";\n\n\tif ( _flag != \"\" )\n\t{\n\t\tid += Arg::flagStartString() + _flag;\n\n\t\tif ( _valueRequired )\n\t\t\tid += std::string( 1, Arg::delimiter() ) + \"<\" + valueId + \">\";\n\n\t\tid += \",  \";\n\t}\n\n\tid += Arg::nameStartString() + _name;\n\n\tif ( _valueRequired )\n\t\tid += std::string( 1, Arg::delimiter() ) + \"<\" + valueId + \">\";\n\n\treturn id;\n\n}\n\ninline bool Arg::operator==(const Arg& a) const\n{\n\tif ( ( _flag != \"\" && _flag == a._flag ) || _name == a._name)\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\ninline std::string Arg::getDescription() const\n{\n\tstd::string desc = \"\";\n\tif ( _required )\n\t\tdesc = \"(\" + _requireLabel + \")  \";\n\n//\tif ( _valueRequired )\n//\t\tdesc += \"(value required)  \";\n\n\tdesc += _description;\n\treturn desc;\n}\n\ninline const std::string& Arg::getFlag() const { return _flag; }\n\ninline const std::string& Arg::getName() const { return _name; }\n\ninline bool Arg::isRequired() const { return _required; }\n\ninline bool Arg::isValueRequired() const { return _valueRequired; }\n\ninline bool Arg::isSet() const\n{\n\tif ( _alreadySet && !_xorSet )\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\ninline bool Arg::isIgnoreable() const { return _ignoreable; }\n\ninline void Arg::setRequireLabel( const std::string& s)\n{\n\t_requireLabel = s;\n}\n\ninline bool Arg::argMatches( const std::string& argFlag ) const\n{\n\tif ( ( argFlag == Arg::flagStartString() + _flag && _flag != \"\" ) ||\n\t       argFlag == Arg::nameStartString() + _name )\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\ninline std::string Arg::toString() const\n{\n\tstd::string s = \"\";\n\n\tif ( _flag != \"\" )\n\t\ts += Arg::flagStartString() + _flag + \" \";\n\n\ts += \"(\" + Arg::nameStartString() + _name + \")\";\n\n\treturn s;\n}\n\ninline void Arg::_checkWithVisitor() const\n{\n\tif ( _visitor != NULL )\n\t\t_visitor->visit();\n}\n\n/**\n * Implementation of trimFlag.\n */\ninline void Arg::trimFlag(std::string& flag, std::string& value) const\n{\n\tint stop = 0;\n\tfor ( int i = 0; static_cast<unsigned int>(i) < flag.length(); i++ )\n\t\tif ( flag[i] == Arg::delimiter() )\n\t\t{\n\t\t\tstop = i;\n\t\t\tbreak;\n\t\t}\n\n\tif ( stop > 1 )\n\t{\n\t\tvalue = flag.substr(stop+1);\n\t\tflag = flag.substr(0,stop);\n\t}\n\n}\n\n/**\n * Implementation of _hasBlanks.\n */\ninline bool Arg::_hasBlanks( const std::string& s ) const\n{\n\tfor ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )\n\t\tif ( s[i] == Arg::blankChar() )\n\t\t\treturn true;\n\n\treturn false;\n}\n\ninline void Arg::forceRequired()\n{\n\t_required = true;\n}\n\ninline void Arg::xorSet()\n{\n\t_alreadySet = true;\n\t_xorSet = true;\n}\n\n/**\n * Overridden by Args that need to added to the end of the list.\n */\ninline void Arg::addToList( std::list<Arg*>& argList ) const\n{\n\targList.push_front( const_cast<Arg*>(this) );\n}\n\ninline bool Arg::allowMore()\n{\n\treturn false;\n}\n\ninline bool Arg::acceptsMultipleValues()\n{\n\treturn _acceptsMultipleValues;\n}\n\ninline void Arg::reset()\n{\n\t_xorSet = false;\n\t_alreadySet = false;\n}\n\n//////////////////////////////////////////////////////////////////////\n//END Arg.cpp\n//////////////////////////////////////////////////////////////////////\n\n} //namespace TCLAP\n\n#endif\n\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/ArgException.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/****************************************************************************** \n * \n *  file:  ArgException.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_ARG_EXCEPTION_H\n#define TCLAP_ARG_EXCEPTION_H\n\n#include <string>\n#include <exception>\n\nnamespace TCLAP {\n\n/**\n * A simple class that defines and argument exception.  Should be caught\n * whenever a CmdLine is created and parsed.\n */\nclass ArgException : public std::exception\n{\n\tpublic:\n\t\n\t\t/**\n\t\t * Constructor.\n\t\t * \\param text - The text of the exception.\n\t\t * \\param id - The text identifying the argument source.\n\t\t * \\param td - Text describing the type of ArgException it is.\n\t\t * of the exception.\n\t\t */\n\t\tArgException( const std::string& text = \"undefined exception\", \n\t\t\t\t\t  const std::string& id = \"undefined\",\n\t\t\t\t\t  const std::string& td = \"Generic ArgException\")\n\t\t\t: std::exception(), \n\t\t\t  _errorText(text), \n\t\t\t  _argId( id ), \n\t\t\t  _typeDescription(td)\n\t\t{ } \n\t\t\n\t\t/**\n\t\t * Destructor.\n\t\t */\n\t\tvirtual ~ArgException() throw() { }\n\n\t\t/**\n\t\t * Returns the error text.\n\t\t */\n\t\tstd::string error() const { return ( _errorText ); }\n\n\t\t/**\n\t\t * Returns the argument id.\n\t\t */\n\t\tstd::string argId() const  \n\t\t{ \n\t\t\tif ( _argId == \"undefined\" )\n\t\t\t\treturn \" \";\n\t\t\telse\n\t\t\t\treturn ( \"Argument: \" + _argId ); \n\t\t}\n\n\t\t/**\n\t\t * Returns the arg id and error text. \n\t\t */\n\t\tconst char* what() const throw() \n\t\t{\n\t\t\tstatic std::string ex; \n\t\t\tex = _argId + \" -- \" + _errorText;\n\t\t\treturn ex.c_str();\n\t\t}\n\n\t\t/**\n\t\t * Returns the type of the exception.  Used to explain and distinguish\n\t\t * between different child exceptions.\n\t\t */\n\t\tstd::string typeDescription() const\n\t\t{\n\t\t\treturn _typeDescription; \n\t\t}\n\n\n\tprivate:\n\n\t\t/**\n\t\t * The text of the exception message.\n\t\t */\n\t\tstd::string _errorText;\n\n\t\t/**\n\t\t * The argument related to this exception.\n\t\t */\n\t\tstd::string _argId;\n\n\t\t/**\n\t\t * Describes the type of the exception.  Used to distinguish\n\t\t * between different child exceptions.\n\t\t */\n\t\tstd::string _typeDescription;\n\n};\n\n/**\n * Thrown from within the child Arg classes when it fails to properly\n * parse the argument it has been passed.\n */\nclass ArgParseException : public ArgException\n{ \n\tpublic:\n\t\t/**\n\t\t * Constructor.\n\t\t * \\param text - The text of the exception.\n\t\t * \\param id - The text identifying the argument source \n\t\t * of the exception.\n\t\t */\n\t\tArgParseException( const std::string& text = \"undefined exception\", \n\t\t\t\t\t       const std::string& id = \"undefined\" )\n\t\t\t: ArgException( text, \n\t\t\t                id, \n\t\t\t\t\t\t\tstd::string( \"Exception found while parsing \" ) + \n\t\t\t\t\t\t\tstd::string( \"the value the Arg has been passed.\" ))\n\t\t\t{ }\n};\n\n/**\n * Thrown from CmdLine when the arguments on the command line are not\n * properly specified, e.g. too many arguments, required argument missing, etc.\n */\nclass CmdLineParseException : public ArgException\n{\n\tpublic:\n\t\t/**\n\t\t * Constructor.\n\t\t * \\param text - The text of the exception.\n\t\t * \\param id - The text identifying the argument source \n\t\t * of the exception.\n\t\t */\n\t\tCmdLineParseException( const std::string& text = \"undefined exception\", \n\t\t\t\t\t           const std::string& id = \"undefined\" )\n\t\t\t: ArgException( text, \n\t\t\t                id,\n\t\t\t\t\t\t\tstd::string( \"Exception found when the values \") +\n\t\t\t\t\t\t\tstd::string( \"on the command line do not meet \") +\n\t\t\t\t\t\t\tstd::string( \"the requirements of the defined \") +\n\t\t\t\t\t\t\tstd::string( \"Args.\" ))\n\t\t{ }\n};\n\n/**\n * Thrown from Arg and CmdLine when an Arg is improperly specified, e.g. \n * same flag as another Arg, same name, etc.\n */\nclass SpecificationException : public ArgException\n{\n\tpublic:\n\t\t/**\n\t\t * Constructor.\n\t\t * \\param text - The text of the exception.\n\t\t * \\param id - The text identifying the argument source \n\t\t * of the exception.\n\t\t */\n\t\tSpecificationException( const std::string& text = \"undefined exception\",\n\t\t\t\t\t            const std::string& id = \"undefined\" )\n\t\t\t: ArgException( text, \n\t\t\t                id,\n\t\t\t\t\t\t\tstd::string(\"Exception found when an Arg object \")+\n\t\t\t\t\t\t\tstd::string(\"is improperly defined by the \") +\n\t\t\t\t\t\t\tstd::string(\"developer.\" )) \n\t\t{ }\n\n};\n\nclass ExitException {\npublic:\n\tExitException(int estat) : _estat(estat) {}\n\n\tint getExitStatus() const { return _estat; }\n\nprivate:\n\tint _estat;\n};\n\n} // namespace TCLAP\n\n#endif\n\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/ArgTraits.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/******************************************************************************\n *\n *  file:  ArgTraits.h\n *\n *  Copyright (c) 2007, Daniel Aarno, Michael E. Smoot .\n *  All rights reverved.\n *\n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *\n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS\n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n *  DEALINGS IN THE SOFTWARE.\n *\n *****************************************************************************/\n\n// This is an internal tclap file, you should probably not have to\n// include this directly\n\n#ifndef TCLAP_ARGTRAITS_H\n#define TCLAP_ARGTRAITS_H\n\nnamespace TCLAP {\n\n// We use two empty structs to get compile type specialization\n// function to work\n\n/**\n * A value like argument value type is a value that can be set using\n * operator>>. This is the default value type.\n */\nstruct ValueLike {\n    typedef ValueLike ValueCategory;\n\tvirtual ~ValueLike() {}\n};\n\n/**\n * A string like argument value type is a value that can be set using\n * operator=(string). Usefull if the value type contains spaces which\n * will be broken up into individual tokens by operator>>.\n */\nstruct StringLike {\n\tvirtual ~StringLike() {}\n};\n\n/**\n * A class can inherit from this object to make it have string like\n * traits. This is a compile time thing and does not add any overhead\n * to the inherenting class.\n */\nstruct StringLikeTrait {\n    typedef StringLike ValueCategory;\n\tvirtual ~StringLikeTrait() {}\n};\n\n/**\n * A class can inherit from this object to make it have value like\n * traits. This is a compile time thing and does not add any overhead\n * to the inherenting class.\n */\nstruct ValueLikeTrait {\n    typedef ValueLike ValueCategory;\n\tvirtual ~ValueLikeTrait() {}\n};\n\n/**\n * Arg traits are used to get compile type specialization when parsing\n * argument values. Using an ArgTraits you can specify the way that\n * values gets assigned to any particular type during parsing. The two\n * supported types are StringLike and ValueLike.\n */\ntemplate<typename T>\nstruct ArgTraits {\n    typedef typename T::ValueCategory ValueCategory;\n\tvirtual ~ArgTraits() {}\n    //typedef ValueLike ValueCategory;\n};\n\n#endif\n\n} // namespace\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/COPYING",
    "content": "\n\nCopyright (c) 2003 Michael E. Smoot \n\nPermission is hereby granted, free of charge, to any person \nobtaining a copy of this software and associated documentation \nfiles (the \"Software\"), to deal in the Software without restriction, \nincluding without limitation the rights to use, copy, modify, merge, \npublish, distribute, sublicense, and/or sell copies of the Software, \nand to permit persons to whom the Software is furnished to do so, \nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be \nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, \nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES \nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS \nBE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN \nAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR \nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN \nTHE SOFTWARE.\n\n\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/CmdLine.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/******************************************************************************\n *\n *  file:  CmdLine.h\n *\n *  Copyright (c) 2003, Michael E. Smoot .\n *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.\n *  All rights reverved.\n *\n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *\n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS\n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n *  DEALINGS IN THE SOFTWARE.\n *\n *****************************************************************************/\n\n#ifndef TCLAP_CMDLINE_H\n#define TCLAP_CMDLINE_H\n\n#include \"SwitchArg.h\"\n#include \"MultiSwitchArg.h\"\n#include \"UnlabeledValueArg.h\"\n#include \"UnlabeledMultiArg.h\"\n\n#include \"XorHandler.h\"\n#include \"HelpVisitor.h\"\n#include \"VersionVisitor.h\"\n#include \"IgnoreRestVisitor.h\"\n\n#include \"CmdLineOutput.h\"\n#include \"StdOutput.h\"\n\n#include \"Constraint.h\"\n#include \"ValuesConstraint.h\"\n\n#include <string>\n#include <vector>\n#include <list>\n#include <iostream>\n#include <iomanip>\n#include <algorithm>\n#include <stdlib.h> // Needed for exit(), which isn't defined in some envs.\n\nnamespace TCLAP {\n\ntemplate<typename T> void DelPtr(T ptr)\n{\n\tdelete ptr;\n}\n\ntemplate<typename C> void ClearContainer(C &c)\n{\n\ttypedef typename C::value_type value_type;\n\tstd::for_each(c.begin(), c.end(), DelPtr<value_type>);\n\tc.clear();\n}\n\n\n/**\n * The base class that manages the command line definition and passes\n * along the parsing to the appropriate Arg classes.\n */\nclass CmdLine : public CmdLineInterface\n{\n\tprotected:\n\n\t\t/**\n\t\t * The list of arguments that will be tested against the\n\t\t * command line.\n\t\t */\n\t\tstd::list<Arg*> _argList;\n\n\t\t/**\n\t\t * The name of the program.  Set to argv[0].\n\t\t */\n\t\tstd::string _progName;\n\n\t\t/**\n\t\t * A message used to describe the program.  Used in the usage output.\n\t\t */\n\t\tstd::string _message;\n\n\t\t/**\n\t\t * The version to be displayed with the --version switch.\n\t\t */\n\t\tstd::string _version;\n\n\t\t/**\n\t\t * The number of arguments that are required to be present on\n\t\t * the command line. This is set dynamically, based on the\n\t\t * Args added to the CmdLine object.\n\t\t */\n\t\tint _numRequired;\n\n\t\t/**\n\t\t * The character that is used to separate the argument flag/name\n\t\t * from the value.  Defaults to ' ' (space).\n\t\t */\n\t\tchar _delimiter;\n\n\t\t/**\n\t\t * The handler that manages xoring lists of args.\n\t\t */\n\t\tXorHandler _xorHandler;\n\n\t\t/**\n\t\t * A list of Args to be explicitly deleted when the destructor\n\t\t * is called.  At the moment, this only includes the three default\n\t\t * Args.\n\t\t */\n\t\tstd::list<Arg*> _argDeleteOnExitList;\n\n\t\t/**\n\t\t * A list of Visitors to be explicitly deleted when the destructor\n\t\t * is called.  At the moment, these are the Vistors created for the\n\t\t * default Args.\n\t\t */\n\t\tstd::list<Visitor*> _visitorDeleteOnExitList;\n\n\t\t/**\n\t\t * Object that handles all output for the CmdLine.\n\t\t */\n\t\tCmdLineOutput* _output;\n\n\t\t/**\n\t\t * Should CmdLine handle parsing exceptions internally?\n\t\t */\n\t\tbool _handleExceptions;\n\n\t\t/**\n\t\t * Throws an exception listing the missing args.\n\t\t */\n\t\tvoid missingArgsException();\n\n\t\t/**\n\t\t * Checks whether a name/flag string matches entirely matches\n\t\t * the Arg::blankChar.  Used when multiple switches are combined\n\t\t * into a single argument.\n\t\t * \\param s - The message to be used in the usage.\n\t\t */\n\t\tbool _emptyCombined(const std::string& s);\n\n\t\t/**\n\t\t * Perform a delete ptr; operation on ptr when this object is deleted.\n\t\t */\n\t\tvoid deleteOnExit(Arg* ptr);\n\n\t\t/**\n\t\t * Perform a delete ptr; operation on ptr when this object is deleted.\n\t\t */\n\t\tvoid deleteOnExit(Visitor* ptr);\n\nprivate:\n\n\t\t/**\n\t\t * Prevent accidental copying.\n\t\t */\n\t\tCmdLine(const CmdLine& rhs);\n\t\tCmdLine& operator=(const CmdLine& rhs);\n\n\t\t/**\n\t\t * Encapsulates the code common to the constructors\n\t\t * (which is all of it).\n\t\t */\n\t\tvoid _constructor();\n\n\n\t\t/**\n\t\t * Is set to true when a user sets the output object. We use this so\n\t\t * that we don't delete objects that are created outside of this lib.\n\t\t */\n\t\tbool _userSetOutput;\n\n\t\t/**\n\t\t * Whether or not to automatically create help and version switches.\n\t\t */\n\t\tbool _helpAndVersion;\n\n\tpublic:\n\n\t\t/**\n\t\t * Command line constructor. Defines how the arguments will be\n\t\t * parsed.\n\t\t * \\param message - The message to be used in the usage\n\t\t * output.\n\t\t * \\param delimiter - The character that is used to separate\n\t\t * the argument flag/name from the value.  Defaults to ' ' (space).\n\t\t * \\param version - The version number to be used in the\n\t\t * --version switch.\n\t\t * \\param helpAndVersion - Whether or not to create the Help and\n\t\t * Version switches. Defaults to true.\n\t\t */\n\t\tCmdLine(const std::string& message,\n\t\t\t\tconst char delimiter = ' ',\n\t\t\t\tconst std::string& version = \"none\",\n\t\t\t\tbool helpAndVersion = true);\n\n\t\t/**\n\t\t * Deletes any resources allocated by a CmdLine object.\n\t\t */\n\t\tvirtual ~CmdLine();\n\n\t\t/**\n\t\t * Adds an argument to the list of arguments to be parsed.\n\t\t * \\param a - Argument to be added.\n\t\t */\n\t\tvoid add( Arg& a );\n\n\t\t/**\n\t\t * An alternative add.  Functionally identical.\n\t\t * \\param a - Argument to be added.\n\t\t */\n\t\tvoid add( Arg* a );\n\n\t\t/**\n\t\t * Add two Args that will be xor'd.  If this method is used, add does\n\t\t * not need to be called.\n\t\t * \\param a - Argument to be added and xor'd.\n\t\t * \\param b - Argument to be added and xor'd.\n\t\t */\n\t\tvoid xorAdd( Arg& a, Arg& b );\n\n\t\t/**\n\t\t * Add a list of Args that will be xor'd.  If this method is used,\n\t\t * add does not need to be called.\n\t\t * \\param xors - List of Args to be added and xor'd.\n\t\t */\n\t\tvoid xorAdd( std::vector<Arg*>& xors );\n\n\t\t/**\n\t\t * Parses the command line.\n\t\t * \\param argc - Number of arguments.\n\t\t * \\param argv - Array of arguments.\n\t\t */\n\t\tvoid parse(int argc, const char * const * argv);\n\n\t\t/**\n\t\t * Parses the command line.\n\t\t * \\param args - A vector of strings representing the args.\n\t\t * args[0] is still the program name.\n\t\t */\n\t\tvoid parse(std::vector<std::string>& args);\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tCmdLineOutput* getOutput();\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tvoid setOutput(CmdLineOutput* co);\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tstd::string& getVersion();\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tstd::string& getProgramName();\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tstd::list<Arg*>& getArgList();\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tXorHandler& getXorHandler();\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tchar getDelimiter();\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tstd::string& getMessage();\n\n\t\t/**\n\t\t *\n\t\t */\n\t\tbool hasHelpAndVersion();\n\n\t\t/**\n\t\t * Disables or enables CmdLine's internal parsing exception handling.\n\t\t *\n\t\t * @param state Should CmdLine handle parsing exceptions internally?\n\t\t */\n\t\tvoid setExceptionHandling(const bool state);\n\n\t\t/**\n\t\t * Returns the current state of the internal exception handling.\n\t\t *\n\t\t * @retval true Parsing exceptions are handled internally.\n\t\t * @retval false Parsing exceptions are propagated to the caller.\n\t\t */\n\t\tbool getExceptionHandling() const;\n\n\t\t/**\n\t\t * Allows the CmdLine object to be reused.\n\t\t */\n\t\tvoid reset();\n\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n//Begin CmdLine.cpp\n///////////////////////////////////////////////////////////////////////////////\n\ninline CmdLine::CmdLine(const std::string& m,\n                        char delim,\n                        const std::string& v,\n                        bool help )\n    :\n  _argList(std::list<Arg*>()),\n  _progName(\"not_set_yet\"),\n  _message(m),\n  _version(v),\n  _numRequired(0),\n  _delimiter(delim),\n  _xorHandler(XorHandler()),\n  _argDeleteOnExitList(std::list<Arg*>()),\n  _visitorDeleteOnExitList(std::list<Visitor*>()),\n  _output(0),\n  _handleExceptions(true),\n  _userSetOutput(false),\n  _helpAndVersion(help)\n{\n\t_constructor();\n}\n\ninline CmdLine::~CmdLine()\n{\n\tClearContainer(_argDeleteOnExitList);\n\tClearContainer(_visitorDeleteOnExitList);\n\n\tif ( !_userSetOutput ) {\n\t\tdelete _output;\n\t\t_output = 0;\n\t}\n}\n\ninline void CmdLine::_constructor()\n{\n\t_output = new StdOutput;\n\n\tArg::setDelimiter( _delimiter );\n\n\tVisitor* v;\n\n\tif ( _helpAndVersion )\n\t{\n\t\tv = new HelpVisitor( this, &_output );\n\t\tSwitchArg* help = new SwitchArg(\"h\",\"help\",\n\t\t                      \"Displays usage information and exits.\",\n\t\t                      false, v);\n\t\tadd( help );\n\t\tdeleteOnExit(help);\n\t\tdeleteOnExit(v);\n\n\t\tv = new VersionVisitor( this, &_output );\n\t\tSwitchArg* vers = new SwitchArg(\"\",\"version\",\n\t\t                      \"Displays version information and exits.\",\n\t\t                      false, v);\n\t\tadd( vers );\n\t\tdeleteOnExit(vers);\n\t\tdeleteOnExit(v);\n\t}\n\n\tv = new IgnoreRestVisitor();\n\tSwitchArg* ignore  = new SwitchArg(Arg::flagStartString(),\n\t          Arg::ignoreNameString(),\n\t          \"Ignores the rest of the labeled arguments following this flag.\",\n\t          false, v);\n\tadd( ignore );\n\tdeleteOnExit(ignore);\n\tdeleteOnExit(v);\n}\n\ninline void CmdLine::xorAdd( std::vector<Arg*>& ors )\n{\n\t_xorHandler.add( ors );\n\n\tfor (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)\n\t{\n\t\t(*it)->forceRequired();\n\t\t(*it)->setRequireLabel( \"OR required\" );\n\t\tadd( *it );\n\t}\n}\n\ninline void CmdLine::xorAdd( Arg& a, Arg& b )\n{\n\tstd::vector<Arg*> ors;\n\tors.push_back( &a );\n\tors.push_back( &b );\n\txorAdd( ors );\n}\n\ninline void CmdLine::add( Arg& a )\n{\n\tadd( &a );\n}\n\ninline void CmdLine::add( Arg* a )\n{\n\tfor( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )\n\t\tif ( *a == *(*it) )\n\t\t\tthrow( SpecificationException(\n\t\t\t        \"Argument with same flag/name already exists!\",\n\t\t\t        a->longID() ) );\n\n\ta->addToList( _argList );\n\n\tif ( a->isRequired() )\n\t\t_numRequired++;\n}\n\n\ninline void CmdLine::parse(int argc, const char * const * argv)\n{\n\t\t// this step is necessary so that we have easy access to\n\t\t// mutable strings.\n\t\tstd::vector<std::string> args;\n\t\tfor (int i = 0; i < argc; i++)\n\t\t\targs.push_back(argv[i]);\n\n\t\tparse(args);\n}\n\ninline void CmdLine::parse(std::vector<std::string>& args)\n{\n\tbool shouldExit = false;\n\tint estat = 0;\n\n\ttry {\n\t\t_progName = args.front();\n\t\targs.erase(args.begin());\n\n\t\tint requiredCount = 0;\n\n\t\tfor (int i = 0; static_cast<unsigned int>(i) < args.size(); i++) \n\t\t{\n\t\t\tbool matched = false;\n\t\t\tfor (ArgListIterator it = _argList.begin();\n\t\t\t     it != _argList.end(); it++) {\n\t\t\t\tif ( (*it)->processArg( &i, args ) )\n\t\t\t\t{\n\t\t\t\t\trequiredCount += _xorHandler.check( *it );\n\t\t\t\t\tmatched = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// checks to see if the argument is an empty combined\n\t\t\t// switch and if so, then we've actually matched it\n\t\t\tif ( !matched && _emptyCombined( args[i] ) )\n\t\t\t\tmatched = true;\n\n\t\t\tif ( !matched && !Arg::ignoreRest() )\n\t\t\t\tthrow(CmdLineParseException(\"Couldn't find match \"\n\t\t\t\t                            \"for argument\",\n\t\t\t\t                            args[i]));\n\t\t}\n\n\t\tif ( requiredCount < _numRequired )\n\t\t\tmissingArgsException();\n\n\t\tif ( requiredCount > _numRequired )\n\t\t\tthrow(CmdLineParseException(\"Too many arguments!\"));\n\n\t} catch ( ArgException& e ) {\n\t\t// If we're not handling the exceptions, rethrow.\n\t\tif ( !_handleExceptions) {\n\t\t\tthrow;\n\t\t}\n\n\t\ttry {\n\t\t\t_output->failure(*this,e);\n\t\t} catch ( ExitException &ee ) {\n\t\t\testat = ee.getExitStatus();\n\t\t\tshouldExit = true;\n\t\t}\n\t} catch (ExitException &ee) {\n\t\t// If we're not handling the exceptions, rethrow.\n\t\tif ( !_handleExceptions) {\n\t\t\tthrow;\n\t\t}\n\n\t\testat = ee.getExitStatus();\n\t\tshouldExit = true;\n\t}\n\n\tif (shouldExit)\n\t\texit(estat);\n}\n\ninline bool CmdLine::_emptyCombined(const std::string& s)\n{\n\tif ( s.length() > 0 && s[0] != Arg::flagStartChar() )\n\t\treturn false;\n\n\tfor ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )\n\t\tif ( s[i] != Arg::blankChar() )\n\t\t\treturn false;\n\n\treturn true;\n}\n\ninline void CmdLine::missingArgsException()\n{\n\t\tint count = 0;\n\n\t\tstd::string missingArgList;\n\t\tfor (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)\n\t\t{\n\t\t\tif ( (*it)->isRequired() && !(*it)->isSet() )\n\t\t\t{\n\t\t\t\tmissingArgList += (*it)->getName();\n\t\t\t\tmissingArgList += \", \";\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\tmissingArgList = missingArgList.substr(0,missingArgList.length()-2);\n\n\t\tstd::string msg;\n\t\tif ( count > 1 )\n\t\t\tmsg = \"Required arguments missing: \";\n\t\telse\n\t\t\tmsg = \"Required argument missing: \";\n\n\t\tmsg += missingArgList;\n\n\t\tthrow(CmdLineParseException(msg));\n}\n\ninline void CmdLine::deleteOnExit(Arg* ptr)\n{\n\t_argDeleteOnExitList.push_back(ptr);\n}\n\ninline void CmdLine::deleteOnExit(Visitor* ptr)\n{\n\t_visitorDeleteOnExitList.push_back(ptr);\n}\n\ninline CmdLineOutput* CmdLine::getOutput()\n{\n\treturn _output;\n}\n\ninline void CmdLine::setOutput(CmdLineOutput* co)\n{\n\tif ( !_userSetOutput )\n\t\tdelete _output;\n\t_userSetOutput = true;\n\t_output = co;\n}\n\ninline std::string& CmdLine::getVersion()\n{\n\treturn _version;\n}\n\ninline std::string& CmdLine::getProgramName()\n{\n\treturn _progName;\n}\n\ninline std::list<Arg*>& CmdLine::getArgList()\n{\n\treturn _argList;\n}\n\ninline XorHandler& CmdLine::getXorHandler()\n{\n\treturn _xorHandler;\n}\n\ninline char CmdLine::getDelimiter()\n{\n\treturn _delimiter;\n}\n\ninline std::string& CmdLine::getMessage()\n{\n\treturn _message;\n}\n\ninline bool CmdLine::hasHelpAndVersion()\n{\n\treturn _helpAndVersion;\n}\n\ninline void CmdLine::setExceptionHandling(const bool state)\n{\n\t_handleExceptions = state;\n}\n\ninline bool CmdLine::getExceptionHandling() const\n{\n\treturn _handleExceptions;\n}\n\ninline void CmdLine::reset()\n{\n\tfor( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )\n\t\t(*it)->reset();\n\t\n\t_progName.clear();\n}\n\n///////////////////////////////////////////////////////////////////////////////\n//End CmdLine.cpp\n///////////////////////////////////////////////////////////////////////////////\n\n\n\n} //namespace TCLAP\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/CmdLineInterface.h",
    "content": "\n/****************************************************************************** \n * \n *  file:  CmdLineInterface.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.\n *  All rights reverved.\n *\n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n#ifndef TCLAP_COMMANDLINE_INTERFACE_H\n#define TCLAP_COMMANDLINE_INTERFACE_H\n\n#include <string>\n#include <vector>\n#include <list>\n#include <iostream>\n#include <algorithm>\n\n\nnamespace TCLAP {\n     \nclass Arg;\nclass CmdLineOutput;\nclass XorHandler;\n\n/**\n * The base class that manages the command line definition and passes\n * along the parsing to the appropriate Arg classes.\n */\nclass CmdLineInterface\n{\n\tpublic:\n\n\t\t/**\n\t\t * Destructor\n\t\t */\n\t\tvirtual ~CmdLineInterface() {}\n\n\t\t/**\n\t\t * Adds an argument to the list of arguments to be parsed.\n\t\t * \\param a - Argument to be added. \n\t\t */\n\t\tvirtual void add( Arg& a )=0;\n\n\t\t/**\n\t\t * An alternative add.  Functionally identical.\n\t\t * \\param a - Argument to be added. \n\t\t */\n\t\tvirtual void add( Arg* a )=0;\n\n\t\t/**\n\t\t * Add two Args that will be xor'd.  \n\t\t * If this method is used, add does\n\t\t * not need to be called.\n\t\t * \\param a - Argument to be added and xor'd. \n\t\t * \\param b - Argument to be added and xor'd. \n\t\t */\n\t\tvirtual void xorAdd( Arg& a, Arg& b )=0;\n\n\t\t/**\n\t\t * Add a list of Args that will be xor'd.  If this method is used, \n\t\t * add does not need to be called.\n\t\t * \\param xors - List of Args to be added and xor'd. \n\t\t */\n\t\tvirtual void xorAdd( std::vector<Arg*>& xors )=0;\n\n\t\t/**\n\t\t * Parses the command line.\n\t\t * \\param argc - Number of arguments.\n\t\t * \\param argv - Array of arguments.\n\t\t */\n\t\tvirtual void parse(int argc, const char * const * argv)=0;\n\n        /**\n         * Parses the command line.\n         * \\param args - A vector of strings representing the args. \n         * args[0] is still the program name.\n         */\n        void parse(std::vector<std::string>& args);\n\n\t\t/**\n\t\t * Returns the CmdLineOutput object.\n\t\t */\n\t\tvirtual CmdLineOutput* getOutput()=0;\n\n\t\t/**\n\t\t * \\param co - CmdLineOutput object that we want to use instead. \n\t\t */\n\t\tvirtual void setOutput(CmdLineOutput* co)=0;\n\n\t\t/**\n\t\t * Returns the version string.\n\t\t */\n\t\tvirtual std::string& getVersion()=0;\n\n\t\t/**\n\t\t * Returns the program name string.\n\t\t */\n\t\tvirtual std::string& getProgramName()=0;\n\n\t\t/**\n\t\t * Returns the argList. \n\t\t */\n\t\tvirtual std::list<Arg*>& getArgList()=0;\n\n\t\t/**\n\t\t * Returns the XorHandler. \n\t\t */\n\t\tvirtual XorHandler& getXorHandler()=0;\n\n\t\t/**\n\t\t * Returns the delimiter string.\n\t\t */\n\t\tvirtual char getDelimiter()=0;\n\n\t\t/**\n\t\t * Returns the message string.\n\t\t */\n\t\tvirtual std::string& getMessage()=0;\n\n\t\t/**\n\t\t * Indicates whether or not the help and version switches were created\n\t\t * automatically.\n\t\t */\n\t\tvirtual bool hasHelpAndVersion()=0;\n\n\t\t/** \n\t\t * Resets the instance as if it had just been constructed so that the\n\t\t * instance can be reused. \n\t\t */\n\t\tvirtual void reset()=0;\n};\n\n} //namespace\n\n\n#endif \n"
  },
  {
    "path": "components/mkspiffs/src/tclap/CmdLineOutput.h",
    "content": "\n\n/****************************************************************************** \n * \n *  file:  CmdLineOutput.h\n * \n *  Copyright (c) 2004, Michael E. Smoot\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n#ifndef TCLAP_CMDLINEOUTPUT_H\n#define TCLAP_CMDLINEOUTPUT_H\n\n#include <string>\n#include <vector>\n#include <list>\n#include <iostream>\n#include <iomanip>\n#include <algorithm>\n\nnamespace TCLAP {\n\nclass CmdLineInterface;\nclass ArgException;\n\n/**\n * The interface that any output object must implement.\n */\nclass CmdLineOutput \n{\n\n\tpublic:\n\n\t\t/**\n\t\t * Virtual destructor.\n\t\t */\n\t\tvirtual ~CmdLineOutput() {}\n\n\t\t/**\n\t\t * Generates some sort of output for the USAGE. \n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t */\n\t\tvirtual void usage(CmdLineInterface& c)=0;\n\n\t\t/**\n\t\t * Generates some sort of output for the version. \n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t */\n\t\tvirtual void version(CmdLineInterface& c)=0;\n\n\t\t/**\n\t\t * Generates some sort of output for a failure. \n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t * \\param e - The ArgException that caused the failure. \n\t\t */\n\t\tvirtual void failure( CmdLineInterface& c, \n\t\t\t\t\t\t      ArgException& e )=0;\n\n};\n\n} //namespace TCLAP\n#endif \n"
  },
  {
    "path": "components/mkspiffs/src/tclap/Constraint.h",
    "content": "\n/******************************************************************************\n *\n *  file:  Constraint.h\n *\n *  Copyright (c) 2005, Michael E. Smoot\n *  All rights reverved.\n *\n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *\n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS\n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n *  DEALINGS IN THE SOFTWARE.\n *\n *****************************************************************************/\n\n#ifndef TCLAP_CONSTRAINT_H\n#define TCLAP_CONSTRAINT_H\n\n#include <string>\n#include <vector>\n#include <list>\n#include <iostream>\n#include <iomanip>\n#include <algorithm>\n\nnamespace TCLAP {\n\n/**\n * The interface that defines the interaction between the Arg and Constraint.\n */\ntemplate<class T>\nclass Constraint\n{\n\n\tpublic:\n\t\t/**\n\t\t * Returns a description of the Constraint.\n\t\t */\n\t\tvirtual std::string description() const =0;\n\n\t\t/**\n\t\t * Returns the short ID for the Constraint.\n\t\t */\n\t\tvirtual std::string shortID() const =0;\n\n\t\t/**\n\t\t * The method used to verify that the value parsed from the command\n\t\t * line meets the constraint.\n\t\t * \\param value - The value that will be checked.\n\t\t */\n\t\tvirtual bool check(const T& value) const =0;\n\n\t\t/**\n\t\t * Destructor.\n\t\t * Silences warnings about Constraint being a base class with virtual\n\t\t * functions but without a virtual destructor.\n\t\t */\n\t\tvirtual ~Constraint() { ; }\n};\n\n} //namespace TCLAP\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/DocBookOutput.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/****************************************************************************** \n * \n *  file:  DocBookOutput.h\n * \n *  Copyright (c) 2004, Michael E. Smoot\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n#ifndef TCLAP_DOCBOOKOUTPUT_H\n#define TCLAP_DOCBOOKOUTPUT_H\n\n#include <string>\n#include <vector>\n#include <list>\n#include <iostream>\n#include <algorithm>\n\n#include \"CmdLineInterface.h\"\n#include \"CmdLineOutput.h\"\n#include \"XorHandler.h\"\n#include \"Arg.h\"\n\nnamespace TCLAP {\n\n/**\n * A class that generates DocBook output for usage() method for the \n * given CmdLine and its Args.\n */\nclass DocBookOutput : public CmdLineOutput\n{\n\n\tpublic:\n\n\t\t/**\n\t\t * Prints the usage to stdout.  Can be overridden to \n\t\t * produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t */\n\t\tvirtual void usage(CmdLineInterface& c);\n\n\t\t/**\n\t\t * Prints the version to stdout. Can be overridden \n\t\t * to produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t */\n\t\tvirtual void version(CmdLineInterface& c);\n\n\t\t/**\n\t\t * Prints (to stderr) an error message, short usage \n\t\t * Can be overridden to produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t * \\param e - The ArgException that caused the failure. \n\t\t */\n\t\tvirtual void failure(CmdLineInterface& c, \n\t\t\t\t\t\t     ArgException& e );\n\n\tprotected:\n\n\t\t/**\n\t\t * Substitutes the char r for string x in string s.\n\t\t * \\param s - The string to operate on. \n\t\t * \\param r - The char to replace. \n\t\t * \\param x - What to replace r with. \n\t\t */\n\t\tvoid substituteSpecialChars( std::string& s, char r, std::string& x );\n\t\tvoid removeChar( std::string& s, char r);\n\t\tvoid basename( std::string& s );\n\n\t\tvoid printShortArg(Arg* it);\n\t\tvoid printLongArg(Arg* it);\n\n\t\tchar theDelimiter;\n};\n\n\ninline void DocBookOutput::version(CmdLineInterface& _cmd) \n{ \n\tstd::cout << _cmd.getVersion() << std::endl;\n}\n\ninline void DocBookOutput::usage(CmdLineInterface& _cmd ) \n{\n\tstd::list<Arg*> argList = _cmd.getArgList();\n\tstd::string progName = _cmd.getProgramName();\n\tstd::string xversion = _cmd.getVersion();\n\ttheDelimiter = _cmd.getDelimiter();\n\tXorHandler xorHandler = _cmd.getXorHandler();\n\tstd::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();\n\tbasename(progName);\n\n\tstd::cout << \"<?xml version='1.0'?>\" << std::endl;\n\tstd::cout << \"<!DOCTYPE refentry PUBLIC \\\"-//OASIS//DTD DocBook XML V4.2//EN\\\"\" << std::endl;\n\tstd::cout << \"\\t\\\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\\\">\" << std::endl << std::endl;\n\n\tstd::cout << \"<refentry>\" << std::endl;\n\n\tstd::cout << \"<refmeta>\" << std::endl;\n\tstd::cout << \"<refentrytitle>\" << progName << \"</refentrytitle>\" << std::endl;\n\tstd::cout << \"<manvolnum>1</manvolnum>\" << std::endl;\n\tstd::cout << \"</refmeta>\" << std::endl;\n\n\tstd::cout << \"<refnamediv>\" << std::endl;\n\tstd::cout << \"<refname>\" << progName << \"</refname>\" << std::endl;\n\tstd::cout << \"<refpurpose>\" << _cmd.getMessage() << \"</refpurpose>\" << std::endl;\n\tstd::cout << \"</refnamediv>\" << std::endl;\n\n\tstd::cout << \"<refsynopsisdiv>\" << std::endl;\n\tstd::cout << \"<cmdsynopsis>\" << std::endl;\n\n\tstd::cout << \"<command>\" << progName << \"</command>\" << std::endl;\n\n\t// xor\n\tfor ( int i = 0; (unsigned int)i < xorList.size(); i++ )\n\t{\n\t\tstd::cout << \"<group choice='req'>\" << std::endl;\n\t\tfor ( ArgVectorIterator it = xorList[i].begin(); \n\t\t\t\t\t\tit != xorList[i].end(); it++ )\n\t\t\tprintShortArg((*it));\n\n\t\tstd::cout << \"</group>\" << std::endl;\n\t}\n\t\n\t// rest of args\n\tfor (ArgListIterator it = argList.begin(); it != argList.end(); it++)\n\t\tif ( !xorHandler.contains( (*it) ) )\n\t\t\tprintShortArg((*it));\n\n \tstd::cout << \"</cmdsynopsis>\" << std::endl;\n\tstd::cout << \"</refsynopsisdiv>\" << std::endl;\n\n\tstd::cout << \"<refsect1>\" << std::endl;\n\tstd::cout << \"<title>Description</title>\" << std::endl;\n\tstd::cout << \"<para>\" << std::endl;\n\tstd::cout << _cmd.getMessage() << std::endl; \n\tstd::cout << \"</para>\" << std::endl;\n\tstd::cout << \"</refsect1>\" << std::endl;\n\n\tstd::cout << \"<refsect1>\" << std::endl;\n\tstd::cout << \"<title>Options</title>\" << std::endl;\n\n\tstd::cout << \"<variablelist>\" << std::endl;\n\t\n\tfor (ArgListIterator it = argList.begin(); it != argList.end(); it++)\n\t\tprintLongArg((*it));\n\n\tstd::cout << \"</variablelist>\" << std::endl;\n\tstd::cout << \"</refsect1>\" << std::endl;\n\n\tstd::cout << \"<refsect1>\" << std::endl;\n\tstd::cout << \"<title>Version</title>\" << std::endl;\n\tstd::cout << \"<para>\" << std::endl;\n\tstd::cout << xversion << std::endl; \n\tstd::cout << \"</para>\" << std::endl;\n\tstd::cout << \"</refsect1>\" << std::endl;\n\t\n\tstd::cout << \"</refentry>\" << std::endl;\n\n}\n\ninline void DocBookOutput::failure( CmdLineInterface& _cmd,\n\t\t\t\t    ArgException& e ) \n{ \n\tstatic_cast<void>(_cmd); // unused\n\tstd::cout << e.what() << std::endl;\n\tthrow ExitException(1);\n}\n\ninline void DocBookOutput::substituteSpecialChars( std::string& s,\n\t\t\t\t                                   char r,\n\t\t\t\t\t\t\t\t\t\t\t\t   std::string& x )\n{\n\tsize_t p;\n\twhile ( (p = s.find_first_of(r)) != std::string::npos )\n\t{\n\t\ts.erase(p,1);\n\t\ts.insert(p,x);\n\t}\n}\n\ninline void DocBookOutput::removeChar( std::string& s, char r)\n{\n\tsize_t p;\n\twhile ( (p = s.find_first_of(r)) != std::string::npos )\n\t{\n\t\ts.erase(p,1);\n\t}\n}\n\ninline void DocBookOutput::basename( std::string& s )\n{\n\tsize_t p = s.find_last_of('/');\n\tif ( p != std::string::npos )\n\t{\n\t\ts.erase(0, p + 1);\n\t}\n}\n\ninline void DocBookOutput::printShortArg(Arg* a)\n{\n\tstd::string lt = \"&lt;\"; \n\tstd::string gt = \"&gt;\"; \n\n\tstd::string id = a->shortID();\n\tsubstituteSpecialChars(id,'<',lt);\n\tsubstituteSpecialChars(id,'>',gt);\n\tremoveChar(id,'[');\n\tremoveChar(id,']');\n\t\n\tstd::string choice = \"opt\";\n\tif ( a->isRequired() )\n\t\tchoice = \"plain\";\n\n\tstd::cout << \"<arg choice='\" << choice << '\\'';\n\tif ( a->acceptsMultipleValues() )\n\t\tstd::cout << \" rep='repeat'\";\n\n\n\tstd::cout << '>';\n\tif ( !a->getFlag().empty() )\n\t\tstd::cout << a->flagStartChar() << a->getFlag();\n\telse\n\t\tstd::cout << a->nameStartString() << a->getName();\n\tif ( a->isValueRequired() )\n\t{\n\t\tstd::string arg = a->shortID();\n\t\tremoveChar(arg,'[');\n\t\tremoveChar(arg,']');\n\t\tremoveChar(arg,'<');\n\t\tremoveChar(arg,'>');\n\t\targ.erase(0, arg.find_last_of(theDelimiter) + 1);\n\t\tstd::cout << theDelimiter;\n\t\tstd::cout << \"<replaceable>\" << arg << \"</replaceable>\";\n\t}\n\tstd::cout << \"</arg>\" << std::endl;\n\n}\n\ninline void DocBookOutput::printLongArg(Arg* a)\n{\n\tstd::string lt = \"&lt;\"; \n\tstd::string gt = \"&gt;\"; \n\n\tstd::string desc = a->getDescription();\n\tsubstituteSpecialChars(desc,'<',lt);\n\tsubstituteSpecialChars(desc,'>',gt);\n\n\tstd::cout << \"<varlistentry>\" << std::endl;\n\n\tif ( !a->getFlag().empty() )\n\t{\n\t\tstd::cout << \"<term>\" << std::endl;\n\t\tstd::cout << \"<option>\";\n\t\tstd::cout << a->flagStartChar() << a->getFlag();\n\t\tstd::cout << \"</option>\" << std::endl;\n\t\tstd::cout << \"</term>\" << std::endl;\n\t}\n\n\tstd::cout << \"<term>\" << std::endl;\n\tstd::cout << \"<option>\";\n\tstd::cout << a->nameStartString() << a->getName();\n\tif ( a->isValueRequired() )\n\t{\n\t\tstd::string arg = a->shortID();\n\t\tremoveChar(arg,'[');\n\t\tremoveChar(arg,']');\n\t\tremoveChar(arg,'<');\n\t\tremoveChar(arg,'>');\n\t\targ.erase(0, arg.find_last_of(theDelimiter) + 1);\n\t\tstd::cout << theDelimiter;\n\t\tstd::cout << \"<replaceable>\" << arg << \"</replaceable>\";\n\t}\n\tstd::cout << \"</option>\" << std::endl;\n\tstd::cout << \"</term>\" << std::endl;\n\n\tstd::cout << \"<listitem>\" << std::endl;\n\tstd::cout << \"<para>\" << std::endl;\n\tstd::cout << desc << std::endl;\n\tstd::cout << \"</para>\" << std::endl;\n\tstd::cout << \"</listitem>\" << std::endl;\n\n\tstd::cout << \"</varlistentry>\" << std::endl;\n}\n\n} //namespace TCLAP\n#endif \n"
  },
  {
    "path": "components/mkspiffs/src/tclap/HelpVisitor.h",
    "content": "\n/****************************************************************************** \n * \n *  file:  HelpVisitor.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n#ifndef TCLAP_HELP_VISITOR_H\n#define TCLAP_HELP_VISITOR_H\n\n#include \"CmdLineInterface.h\"\n#include \"CmdLineOutput.h\"\n#include \"Visitor.h\"\n\nnamespace TCLAP {\n\n/**\n * A Visitor object that calls the usage method of the given CmdLineOutput\n * object for the specified CmdLine object.\n */\nclass HelpVisitor: public Visitor\n{\n\tprivate:\n\t\t/**\n\t\t * Prevent accidental copying.\n\t\t */\n\t\tHelpVisitor(const HelpVisitor& rhs);\n\t\tHelpVisitor& operator=(const HelpVisitor& rhs);\n\n\tprotected:\n\n\t\t/**\n\t\t * The CmdLine the output will be generated for. \n\t\t */\n\t\tCmdLineInterface* _cmd;\n\n\t\t/**\n\t\t * The output object. \n\t\t */\n\t\tCmdLineOutput** _out;\n\n\tpublic:\n\n\t\t/**\n\t\t * Constructor.\n\t\t * \\param cmd - The CmdLine the output will be generated for.\n\t\t * \\param out - The type of output. \n\t\t */\n\t\tHelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) \n\t\t\t\t: Visitor(), _cmd( cmd ), _out( out ) { }\n\n\t\t/**\n\t\t * Calls the usage method of the CmdLineOutput for the \n\t\t * specified CmdLine.\n\t\t */\n\t\tvoid visit() { (*_out)->usage(*_cmd); throw ExitException(0); }\n\t\t\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/IgnoreRestVisitor.h",
    "content": "\n/****************************************************************************** \n * \n *  file:  IgnoreRestVisitor.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_IGNORE_REST_VISITOR_H\n#define TCLAP_IGNORE_REST_VISITOR_H\n\n#include \"Visitor.h\"\n#include \"Arg.h\"\n\nnamespace TCLAP {\n\n/**\n * A Vistor that tells the CmdLine to begin ignoring arguments after\n * this one is parsed.\n */\nclass IgnoreRestVisitor: public Visitor\n{\n\tpublic:\n\n\t\t/**\n\t\t * Constructor.\n\t\t */\n\t\tIgnoreRestVisitor() : Visitor() {}\n\n\t\t/**\n\t\t * Sets Arg::_ignoreRest.\n\t\t */\n\t\tvoid visit() { Arg::beginIgnoring();  }\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/MultiArg.h",
    "content": "/****************************************************************************** \n * \n *  file:  MultiArg.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/\n\n\n#ifndef TCLAP_MULTIPLE_ARGUMENT_H\n#define TCLAP_MULTIPLE_ARGUMENT_H\n\n#include <string>\n#include <vector>\n\n#include \"Arg.h\"\n#include \"Constraint.h\"\n\nnamespace TCLAP {\n/**\n * An argument that allows multiple values of type T to be specified.  Very\n * similar to a ValueArg, except a vector of values will be returned\n * instead of just one.\n */\ntemplate<class T>\nclass MultiArg : public Arg\n{\npublic:\n\ttypedef std::vector<T> container_type;\t\n\ttypedef typename container_type::iterator iterator;\n\ttypedef typename container_type::const_iterator const_iterator;\n\nprotected:\n\n\t/**\n\t * The list of values parsed from the CmdLine.\n\t */\n\tstd::vector<T> _values;\n\n\t/**\n\t * The description of type T to be used in the usage.\n\t */\n\tstd::string _typeDesc;\n\n\t/**\n\t * A list of constraint on this Arg. \n\t */\n\tConstraint<T>* _constraint;\n\n\t/**\n\t * Extracts the value from the string.\n\t * Attempts to parse string as type T, if this fails an exception\n\t * is thrown.\n\t * \\param val - The string to be read.\n\t */\n\tvoid _extractValue( const std::string& val );\n\n\t/**\n\t * Used by XorHandler to decide whether to keep parsing for this arg.\n\t */\n\tbool _allowMore;\n\npublic:\n\n\t/**\n\t * Constructor.\n\t * \\param flag - The one character flag that identifies this\n\t * argument on the command line.\n\t * \\param name - A one word name for the argument.  Can be\n\t * used as a long flag on the command line.\n\t * \\param desc - A description of what the argument is for or\n\t * does.\n\t * \\param req - Whether the argument is required on the command\n\t * line.\n\t * \\param typeDesc - A short, human readable description of the\n\t * type that this object expects.  This is used in the generation\n\t * of the USAGE statement.  The goal is to be helpful to the end user\n\t * of the program.\n\t * \\param v - An optional visitor.  You probably should not\n\t * use this unless you have a very good reason.\n\t */\n\tMultiArg( const std::string& flag,\n                  const std::string& name,\n                  const std::string& desc,\n                  bool req,\n                  const std::string& typeDesc,\n                  Visitor* v = NULL);\n\n\t/**\n\t * Constructor.\n\t * \\param flag - The one character flag that identifies this\n\t * argument on the command line.\n\t * \\param name - A one word name for the argument.  Can be\n\t * used as a long flag on the command line.\n\t * \\param desc - A description of what the argument is for or\n\t * does.\n\t * \\param req - Whether the argument is required on the command\n\t * line.\n\t * \\param typeDesc - A short, human readable description of the\n\t * type that this object expects.  This is used in the generation\n\t * of the USAGE statement.  The goal is to be helpful to the end user\n\t * of the program.\n\t * \\param parser - A CmdLine parser object to add this Arg to\n\t * \\param v - An optional visitor.  You probably should not\n\t * use this unless you have a very good reason.\n\t */\n\tMultiArg( const std::string& flag, \n                  const std::string& name,\n                  const std::string& desc,\n                  bool req,\n                  const std::string& typeDesc,\n                  CmdLineInterface& parser,\n                  Visitor* v = NULL );\n\n\t/**\n\t * Constructor.\n\t * \\param flag - The one character flag that identifies this\n\t * argument on the command line.\n\t * \\param name - A one word name for the argument.  Can be\n\t * used as a long flag on the command line.\n\t * \\param desc - A description of what the argument is for or\n\t * does.\n\t * \\param req - Whether the argument is required on the command\n\t * line.\n\t * \\param constraint - A pointer to a Constraint object used\n\t * to constrain this Arg.\n\t * \\param v - An optional visitor.  You probably should not\n\t * use this unless you have a very good reason.\n\t */\n\tMultiArg( const std::string& flag,\n                  const std::string& name,\n                  const std::string& desc,\n                  bool req,\n                  Constraint<T>* constraint,\n                  Visitor* v = NULL );\n\t\t  \n\t/**\n\t * Constructor.\n\t * \\param flag - The one character flag that identifies this\n\t * argument on the command line.\n\t * \\param name - A one word name for the argument.  Can be\n\t * used as a long flag on the command line.\n\t * \\param desc - A description of what the argument is for or\n\t * does.\n\t * \\param req - Whether the argument is required on the command\n\t * line.\n\t * \\param constraint - A pointer to a Constraint object used\n\t * to constrain this Arg.\n\t * \\param parser - A CmdLine parser object to add this Arg to\n\t * \\param v - An optional visitor.  You probably should not\n\t * use this unless you have a very good reason.\n\t */\n\tMultiArg( const std::string& flag, \n                  const std::string& name,\n                  const std::string& desc,\n                  bool req,\n                  Constraint<T>* constraint,\n                  CmdLineInterface& parser,\n                  Visitor* v = NULL );\n\t\t  \n\t/**\n\t * Handles the processing of the argument.\n\t * This re-implements the Arg version of this method to set the\n\t * _value of the argument appropriately.  It knows the difference\n\t * between labeled and unlabeled.\n\t * \\param i - Pointer the the current argument in the list.\n\t * \\param args - Mutable list of strings. Passed from main().\n\t */\n\tvirtual bool processArg(int* i, std::vector<std::string>& args); \n\n\t/**\n\t * Returns a vector of type T containing the values parsed from\n\t * the command line.\n\t */\n\tconst std::vector<T>& getValue();\n\n\t/**\n\t * Returns an iterator over the values parsed from the command\n\t * line.\n\t */\n\tconst_iterator begin() const { return _values.begin(); }\n\n\t/**\n\t * Returns the end of the values parsed from the command\n\t * line.\n\t */\n\tconst_iterator end() const { return _values.end(); }\n\n\t/**\n\t * Returns the a short id string.  Used in the usage. \n\t * \\param val - value to be used.\n\t */\n\tvirtual std::string shortID(const std::string& val=\"val\") const;\n\n\t/**\n\t * Returns the a long id string.  Used in the usage. \n\t * \\param val - value to be used.\n\t */\n\tvirtual std::string longID(const std::string& val=\"val\") const;\n\n\t/**\n\t * Once we've matched the first value, then the arg is no longer\n\t * required.\n\t */\n\tvirtual bool isRequired() const;\n\n\tvirtual bool allowMore();\n\t\n\tvirtual void reset();\n\nprivate:\n\t/**\n\t * Prevent accidental copying\n\t */\n\tMultiArg<T>(const MultiArg<T>& rhs);\n\tMultiArg<T>& operator=(const MultiArg<T>& rhs);\n\n};\n\ntemplate<class T>\nMultiArg<T>::MultiArg(const std::string& flag, \n                      const std::string& name,\n                      const std::string& desc,\n                      bool req,\n                      const std::string& typeDesc,\n                      Visitor* v) :\n   Arg( flag, name, desc, req, true, v ),\n  _values(std::vector<T>()),\n  _typeDesc( typeDesc ),\n  _constraint( NULL ),\n  _allowMore(false)\n{ \n\t_acceptsMultipleValues = true;\n}\n\ntemplate<class T>\nMultiArg<T>::MultiArg(const std::string& flag, \n                      const std::string& name,\n                      const std::string& desc,\n                      bool req,\n                      const std::string& typeDesc,\n                      CmdLineInterface& parser,\n                      Visitor* v)\n: Arg( flag, name, desc, req, true, v ),\n  _values(std::vector<T>()),\n  _typeDesc( typeDesc ),\n  _constraint( NULL ),\n  _allowMore(false)\n{ \n\tparser.add( this );\n\t_acceptsMultipleValues = true;\n}\n\n/**\n *\n */\ntemplate<class T>\nMultiArg<T>::MultiArg(const std::string& flag, \n                      const std::string& name,\n                      const std::string& desc,\n                      bool req,\n                      Constraint<T>* constraint,\n                      Visitor* v)\n: Arg( flag, name, desc, req, true, v ),\n  _values(std::vector<T>()),\n  _typeDesc( constraint->shortID() ),\n  _constraint( constraint ),\n  _allowMore(false)\n{ \n\t_acceptsMultipleValues = true;\n}\n\ntemplate<class T>\nMultiArg<T>::MultiArg(const std::string& flag, \n                      const std::string& name,\n                      const std::string& desc,\n                      bool req,\n                      Constraint<T>* constraint,\n                      CmdLineInterface& parser,\n                      Visitor* v)\n: Arg( flag, name, desc, req, true, v ),\n  _values(std::vector<T>()),\n  _typeDesc( constraint->shortID() ),\n  _constraint( constraint ),\n  _allowMore(false)\n{ \n\tparser.add( this );\n\t_acceptsMultipleValues = true;\n}\n\ntemplate<class T>\nconst std::vector<T>& MultiArg<T>::getValue() { return _values; }\n\ntemplate<class T>\nbool MultiArg<T>::processArg(int *i, std::vector<std::string>& args) \n{\n \tif ( _ignoreable && Arg::ignoreRest() )\n\t\treturn false;\n\n\tif ( _hasBlanks( args[*i] ) )\n\t\treturn false;\n\n\tstd::string flag = args[*i];\n\tstd::string value = \"\";\n\n   \ttrimFlag( flag, value );\n\n   \tif ( argMatches( flag ) )\n   \t{\n   \t\tif ( Arg::delimiter() != ' ' && value == \"\" )\n\t\t\tthrow( ArgParseException( \n\t\t\t           \"Couldn't find delimiter for this argument!\",\n\t\t\t\t\t   toString() ) );\n\n\t\t// always take the first one, regardless of start string\n\t\tif ( value == \"\" )\n\t\t{\n\t\t\t(*i)++;\n\t\t\tif ( static_cast<unsigned int>(*i) < args.size() )\n\t\t\t\t_extractValue( args[*i] );\n\t\t\telse\n\t\t\t\tthrow( ArgParseException(\"Missing a value for this argument!\",\n                                         toString() ) );\n\t\t} \n\t\telse\n\t\t\t_extractValue( value );\n\n\t\t/*\n\t\t// continuing taking the args until we hit one with a start string \n\t\twhile ( (unsigned int)(*i)+1 < args.size() &&\n\t\t\t\targs[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&\n\t\t        args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) \n\t\t\t\t_extractValue( args[++(*i)] );\n\t\t*/\n\n\t\t_alreadySet = true;\n\t\t_checkWithVisitor();\n\n\t\treturn true;\n\t}\n\telse\n\t\treturn false;\n}\n\n/**\n *\n */\ntemplate<class T>\nstd::string MultiArg<T>::shortID(const std::string& val) const\n{\n\tstatic_cast<void>(val); // Ignore input, don't warn\n\treturn Arg::shortID(_typeDesc) + \" ... \";\n}\n\n/**\n *\n */\ntemplate<class T>\nstd::string MultiArg<T>::longID(const std::string& val) const\n{\n\tstatic_cast<void>(val); // Ignore input, don't warn\n\treturn Arg::longID(_typeDesc) + \"  (accepted multiple times)\";\n}\n\n/**\n * Once we've matched the first value, then the arg is no longer\n * required.\n */\ntemplate<class T>\nbool MultiArg<T>::isRequired() const\n{\n\tif ( _required )\n\t{\n\t\tif ( _values.size() > 1 )\n\t\t\treturn false;\n\t\telse\n\t\t\treturn true;\n   \t}\n   \telse\n\t\treturn false;\n\n}\n\ntemplate<class T>\nvoid MultiArg<T>::_extractValue( const std::string& val ) \n{\n    try {\n\tT tmp;\n\tExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory());\n\t_values.push_back(tmp);\n    } catch( ArgParseException &e) {\n\tthrow ArgParseException(e.error(), toString());\n    }\n\n    if ( _constraint != NULL )\n\tif ( ! _constraint->check( _values.back() ) )\n\t    throw( CmdLineParseException( \"Value '\" + val +\n\t\t\t\t\t  \"' does not meet constraint: \" +\n\t\t\t\t\t  _constraint->description(), \n\t\t\t\t\t  toString() ) );\n}\n\t\t\ntemplate<class T>\nbool MultiArg<T>::allowMore()\n{\n\tbool am = _allowMore;\n\t_allowMore = true;\n\treturn am;\n}\n\ntemplate<class T>\nvoid MultiArg<T>::reset()\n{\n\tArg::reset();\n\t_values.clear();\n}\n\n} // namespace TCLAP\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/MultiSwitchArg.h",
    "content": "\n/****************************************************************************** \n*\n*  file:  MultiSwitchArg.h\n*\n*  Copyright (c) 2003, Michael E. Smoot .\n*  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.\n*  Copyright (c) 2005, Michael E. Smoot, Daniel Aarno, Erik Zeek.\n*  All rights reverved.\n*\n*  See the file COPYING in the top directory of this distribution for\n*  more information.\n*\n*  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS\n*  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n*  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n*  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n*  DEALINGS IN THE SOFTWARE.\n*\n*****************************************************************************/\n\n\n#ifndef TCLAP_MULTI_SWITCH_ARG_H\n#define TCLAP_MULTI_SWITCH_ARG_H\n\n#include <string>\n#include <vector>\n\n#include \"SwitchArg.h\"\n\nnamespace TCLAP {\n\n/**\n* A multiple switch argument.  If the switch is set on the command line, then\n* the getValue method will return the number of times the switch appears.\n*/\nclass MultiSwitchArg : public SwitchArg\n{\n\tprotected:\n\n\t\t/**\n\t\t * The value of the switch.\n\t\t */\n\t\tint _value;\n\n\t\t/**\n\t\t * Used to support the reset() method so that ValueArg can be\n\t\t * reset to their constructed value.\n\t\t */\n\t\tint _default;\n\n\tpublic:\n\n\t\t/**\n\t\t * MultiSwitchArg constructor.\n\t\t * \\param flag - The one character flag that identifies this\n\t\t * argument on the command line.\n\t\t * \\param name - A one word name for the argument.  Can be\n\t\t * used as a long flag on the command line.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param init - Optional. The initial/default value of this Arg. \n\t\t * Defaults to 0.\n\t\t * \\param v - An optional visitor.  You probably should not\n\t\t * use this unless you have a very good reason.\n\t\t */\n\t\tMultiSwitchArg(const std::string& flag, \n\t\t\t\tconst std::string& name,\n\t\t\t\tconst std::string& desc,\n\t\t\t\tint init = 0,\n\t\t\t\tVisitor* v = NULL);\n\n\n\t\t/**\n\t\t * MultiSwitchArg constructor.\n\t\t * \\param flag - The one character flag that identifies this\n\t\t * argument on the command line.\n\t\t * \\param name - A one word name for the argument.  Can be\n\t\t * used as a long flag on the command line.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param parser - A CmdLine parser object to add this Arg to\n\t\t * \\param init - Optional. The initial/default value of this Arg. \n\t\t * Defaults to 0.\n\t\t * \\param v - An optional visitor.  You probably should not\n\t\t * use this unless you have a very good reason.\n\t\t */\n\t\tMultiSwitchArg(const std::string& flag, \n\t\t\t\tconst std::string& name,\n\t\t\t\tconst std::string& desc,\n\t\t\t\tCmdLineInterface& parser,\n\t\t\t\tint init = 0,\n\t\t\t\tVisitor* v = NULL);\n\n\n\t\t/**\n\t\t * Handles the processing of the argument.\n\t\t * This re-implements the SwitchArg version of this method to set the\n\t\t * _value of the argument appropriately.\n\t\t * \\param i - Pointer the the current argument in the list.\n\t\t * \\param args - Mutable list of strings. Passed\n\t\t * in from main().\n\t\t */\n\t\tvirtual bool processArg(int* i, std::vector<std::string>& args); \n\n\t\t/**\n\t\t * Returns int, the number of times the switch has been set.\n\t\t */\n\t\tint getValue();\n\n\t\t/**\n\t\t * Returns the shortID for this Arg.\n\t\t */\n\t\tstd::string shortID(const std::string& val) const;\n\n\t\t/**\n\t\t * Returns the longID for this Arg.\n\t\t */\n\t\tstd::string longID(const std::string& val) const;\n\t\t\n\t\tvoid reset();\n\n};\n\n//////////////////////////////////////////////////////////////////////\n//BEGIN MultiSwitchArg.cpp\n//////////////////////////////////////////////////////////////////////\ninline MultiSwitchArg::MultiSwitchArg(const std::string& flag,\n\t\t\t\t\tconst std::string& name,\n\t\t\t\t\tconst std::string& desc,\n\t\t\t\t\tint init,\n\t\t\t\t\tVisitor* v )\n: SwitchArg(flag, name, desc, false, v),\n_value( init ),\n_default( init )\n{ }\n\ninline MultiSwitchArg::MultiSwitchArg(const std::string& flag,\n\t\t\t\t\tconst std::string& name, \n\t\t\t\t\tconst std::string& desc, \n\t\t\t\t\tCmdLineInterface& parser,\n\t\t\t\t\tint init,\n\t\t\t\t\tVisitor* v )\n: SwitchArg(flag, name, desc, false, v),\n_value( init ),\n_default( init )\n{ \n\tparser.add( this );\n}\n\ninline int MultiSwitchArg::getValue() { return _value; }\n\ninline bool MultiSwitchArg::processArg(int *i, std::vector<std::string>& args)\n{\n\tif ( _ignoreable && Arg::ignoreRest() )\n\t\treturn false;\n\n\tif ( argMatches( args[*i] ))\n\t{\n\t\t// so the isSet() method will work\n\t\t_alreadySet = true;\n\n\t\t// Matched argument: increment value.\n\t\t++_value;\n\n\t\t_checkWithVisitor();\n\n\t\treturn true;\n\t}\n\telse if ( combinedSwitchesMatch( args[*i] ) )\n\t{\n\t\t// so the isSet() method will work\n\t\t_alreadySet = true;\n\n\t\t// Matched argument: increment value.\n\t\t++_value;\n\n\t\t// Check for more in argument and increment value.\n\t\twhile ( combinedSwitchesMatch( args[*i] ) ) \n\t\t\t++_value;\n\n\t\t_checkWithVisitor();\n\n\t\treturn false;\n\t}\n\telse\n\t\treturn false;\n}\n\ninline std::string \nMultiSwitchArg::shortID(const std::string& val) const\n{\n\treturn Arg::shortID(val) + \" ... \";\n}\n\ninline std::string \nMultiSwitchArg::longID(const std::string& val) const\n{\n\treturn Arg::longID(val) + \"  (accepted multiple times)\";\n}\n\ninline void\nMultiSwitchArg::reset()\n{\n\tMultiSwitchArg::_value = MultiSwitchArg::_default;\n}\n\n//////////////////////////////////////////////////////////////////////\n//END MultiSwitchArg.cpp\n//////////////////////////////////////////////////////////////////////\n\n} //namespace TCLAP\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/OptionalUnlabeledTracker.h",
    "content": "\n\n/****************************************************************************** \n * \n *  file:  OptionalUnlabeledTracker.h\n * \n *  Copyright (c) 2005, Michael E. Smoot .\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H\n#define TCLAP_OPTIONAL_UNLABELED_TRACKER_H\n\n#include <string>\n\nnamespace TCLAP {\n\nclass OptionalUnlabeledTracker\n{\n\n\tpublic:\n\n\t\tstatic void check( bool req, const std::string& argName );\n\n\t\tstatic void gotOptional() { alreadyOptionalRef() = true; }\n\n\t\tstatic bool& alreadyOptional() { return alreadyOptionalRef(); } \n\n\tprivate:\n\n\t\tstatic bool& alreadyOptionalRef() { static bool ct = false; return ct; }\n};\n\n\ninline void OptionalUnlabeledTracker::check( bool req, const std::string& argName )\n{\n    if ( OptionalUnlabeledTracker::alreadyOptional() )\n        throw( SpecificationException(\n\t\"You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg\",\n\t                argName ) );\n\n    if ( !req )\n        OptionalUnlabeledTracker::gotOptional();\n}\n\n\n} // namespace TCLAP\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/StandardTraits.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/******************************************************************************\n *\n *  file:  StandardTraits.h\n *\n *  Copyright (c) 2007, Daniel Aarno, Michael E. Smoot .\n *  All rights reverved.\n *\n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *\n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS\n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n *  DEALINGS IN THE SOFTWARE.\n *\n *****************************************************************************/\n\n// This is an internal tclap file, you should probably not have to\n// include this directly\n\n#ifndef TCLAP_STANDARD_TRAITS_H\n#define TCLAP_STANDARD_TRAITS_H\n\n#ifdef HAVE_CONFIG_H\n#include <config.h> // To check for long long\n#endif\n\n// If Microsoft has already typedef'd wchar_t as an unsigned \n// short, then compiles will break because it's as if we're\n// creating ArgTraits twice for unsigned short. Thus...\n#ifdef _MSC_VER\n#ifndef _NATIVE_WCHAR_T_DEFINED\n#define TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS\n#endif\n#endif\n\nnamespace TCLAP {\n\n// ======================================================================\n// Integer types\n// ======================================================================\n\n/**\n * longs have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<long> {\n    typedef ValueLike ValueCategory;\n};\n\n/**\n * ints have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<int> {\n    typedef ValueLike ValueCategory;\n};\n\n/**\n * shorts have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<short> {\n    typedef ValueLike ValueCategory;\n};\n\n/**\n * chars have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<char> {\n    typedef ValueLike ValueCategory;\n};\n\n#ifdef HAVE_LONG_LONG\n/**\n * long longs have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<long long> {\n    typedef ValueLike ValueCategory;\n};\n#endif\n\n// ======================================================================\n// Unsigned integer types\n// ======================================================================\n\n/**\n * unsigned longs have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<unsigned long> {\n    typedef ValueLike ValueCategory;\n};\n\n/**\n * unsigned ints have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<unsigned int> {\n    typedef ValueLike ValueCategory;\n};\n\n/**\n * unsigned shorts have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<unsigned short> {\n    typedef ValueLike ValueCategory;\n};\n\n/**\n * unsigned chars have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<unsigned char> {\n    typedef ValueLike ValueCategory;\n};\n\n// Microsoft implements size_t awkwardly. \n#if defined(_MSC_VER) && defined(_M_X64)\n/**\n * size_ts have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<size_t> {\n    typedef ValueLike ValueCategory;\n};\n#endif\n\n\n#ifdef HAVE_LONG_LONG\n/**\n * unsigned long longs have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<unsigned long long> {\n    typedef ValueLike ValueCategory;\n};\n#endif\n\n// ======================================================================\n// Float types\n// ======================================================================\n\n/**\n * floats have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<float> {\n    typedef ValueLike ValueCategory;\n};\n\n/**\n * doubles have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<double> {\n    typedef ValueLike ValueCategory;\n};\n\n// ======================================================================\n// Other types\n// ======================================================================\n\n/**\n * bools have value-like semantics.\n */\ntemplate<>\nstruct ArgTraits<bool> {\n    typedef ValueLike ValueCategory;\n};\n\n\n/**\n * wchar_ts have value-like semantics.\n */\n#ifndef TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS\ntemplate<>\nstruct ArgTraits<wchar_t> {\n    typedef ValueLike ValueCategory;\n};\n#endif\n\n/**\n * Strings have string like argument traits.\n */\ntemplate<>\nstruct ArgTraits<std::string> {\n    typedef StringLike ValueCategory;\n};\n\ntemplate<typename T>\nvoid SetString(T &dst, const std::string &src)\n{\n    dst = src;\n}\n\n} // namespace\n\n#endif\n\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/StdOutput.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/****************************************************************************** \n * \n *  file:  StdOutput.h\n * \n *  Copyright (c) 2004, Michael E. Smoot\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n#ifndef TCLAP_STDCMDLINEOUTPUT_H\n#define TCLAP_STDCMDLINEOUTPUT_H\n\n#include <string>\n#include <vector>\n#include <list>\n#include <iostream>\n#include <algorithm>\n\n#include \"CmdLineInterface.h\"\n#include \"CmdLineOutput.h\"\n#include \"XorHandler.h\"\n#include \"Arg.h\"\n\nnamespace TCLAP {\n\n/**\n * A class that isolates any output from the CmdLine object so that it\n * may be easily modified.\n */\nclass StdOutput : public CmdLineOutput\n{\n\n\tpublic:\n\n\t\t/**\n\t\t * Prints the usage to stdout.  Can be overridden to \n\t\t * produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t */\n\t\tvirtual void usage(CmdLineInterface& c);\n\n\t\t/**\n\t\t * Prints the version to stdout. Can be overridden \n\t\t * to produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t */\n\t\tvirtual void version(CmdLineInterface& c);\n\n\t\t/**\n\t\t * Prints (to stderr) an error message, short usage \n\t\t * Can be overridden to produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t * \\param e - The ArgException that caused the failure. \n\t\t */\n\t\tvirtual void failure(CmdLineInterface& c, \n\t\t\t\t     ArgException& e );\n\n\tprotected:\n\n        /**\n         * Writes a brief usage message with short args.\n\t\t * \\param c - The CmdLine object the output is generated for. \n         * \\param os - The stream to write the message to.\n         */\n        void _shortUsage( CmdLineInterface& c, std::ostream& os ) const;\n\n        /**\n\t\t * Writes a longer usage message with long and short args, \n\t\t * provides descriptions and prints message.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t * \\param os - The stream to write the message to.\n\t\t */\n\t\tvoid _longUsage( CmdLineInterface& c, std::ostream& os ) const;\n\n\t\t/**\n\t\t * This function inserts line breaks and indents long strings \n\t\t * according the  params input. It will only break lines at spaces, \n\t\t * commas and pipes.\n\t\t * \\param os - The stream to be printed to.\n\t\t * \\param s - The string to be printed.\n\t\t * \\param maxWidth - The maxWidth allowed for the output line. \n\t\t * \\param indentSpaces - The number of spaces to indent the first line. \n\t\t * \\param secondLineOffset - The number of spaces to indent the second\n\t\t * and all subsequent lines in addition to indentSpaces.\n\t\t */\n\t\tvoid spacePrint( std::ostream& os, \n\t\t\t\t\t\t const std::string& s, \n\t\t\t\t\t\t int maxWidth, \n\t\t\t\t\t\t int indentSpaces, \n\t\t\t\t\t\t int secondLineOffset ) const;\n\n};\n\n\ninline void StdOutput::version(CmdLineInterface& _cmd) \n{\n\tstd::string progName = _cmd.getProgramName();\n\tstd::string xversion = _cmd.getVersion();\n\n\tstd::cout << std::endl << progName << \"  version: \" \n\t\t\t  << xversion << std::endl << std::endl;\n}\n\ninline void StdOutput::usage(CmdLineInterface& _cmd ) \n{\n\tstd::cout << std::endl << \"USAGE: \" << std::endl << std::endl; \n\n\t_shortUsage( _cmd, std::cout );\n\n\tstd::cout << std::endl << std::endl << \"Where: \" << std::endl << std::endl;\n\n\t_longUsage( _cmd, std::cout );\n\n\tstd::cout << std::endl; \n\n}\n\ninline void StdOutput::failure( CmdLineInterface& _cmd,\n\t\t\t\t\t\t\t\tArgException& e ) \n{\n\tstd::string progName = _cmd.getProgramName();\n\n\tstd::cerr << \"PARSE ERROR: \" << e.argId() << std::endl\n\t\t      << \"             \" << e.error() << std::endl << std::endl;\n\n\tif ( _cmd.hasHelpAndVersion() )\n\t\t{\n\t\t\tstd::cerr << \"Brief USAGE: \" << std::endl;\n\n\t\t\t_shortUsage( _cmd, std::cerr );\t\n\n\t\t\tstd::cerr << std::endl << \"For complete USAGE and HELP type: \" \n\t\t\t\t\t  << std::endl << \"   \" << progName << \" --help\" \n\t\t\t\t\t  << std::endl << std::endl;\n\t\t}\n\telse\n\t\tusage(_cmd);\n\n\tthrow ExitException(1);\n}\n\ninline void \nStdOutput::_shortUsage( CmdLineInterface& _cmd, \n\t\t\t\t\t\tstd::ostream& os ) const\n{\n\tstd::list<Arg*> argList = _cmd.getArgList();\n\tstd::string progName = _cmd.getProgramName();\n\tXorHandler xorHandler = _cmd.getXorHandler();\n\tstd::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();\n\n\tstd::string s = progName + \" \";\n\n\t// first the xor\n\tfor ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )\n\t\t{\n\t\t\ts += \" {\";\n\t\t\tfor ( ArgVectorIterator it = xorList[i].begin(); \n\t\t\t\t  it != xorList[i].end(); it++ )\n\t\t\t\ts += (*it)->shortID() + \"|\";\n\n\t\t\ts[s.length()-1] = '}';\n\t\t}\n\n\t// then the rest\n\tfor (ArgListIterator it = argList.begin(); it != argList.end(); it++)\n\t\tif ( !xorHandler.contains( (*it) ) )\n\t\t\ts += \" \" + (*it)->shortID();\n\n\t// if the program name is too long, then adjust the second line offset \n\tint secondLineOffset = static_cast<int>(progName.length()) + 2;\n\tif ( secondLineOffset > 75/2 )\n\t\tsecondLineOffset = static_cast<int>(75/2);\n\n\tspacePrint( os, s, 75, 3, secondLineOffset );\n}\n\ninline void \nStdOutput::_longUsage( CmdLineInterface& _cmd, \n\t\t\t\t\t   std::ostream& os ) const\n{\n\tstd::list<Arg*> argList = _cmd.getArgList();\n\tstd::string message = _cmd.getMessage();\n\tXorHandler xorHandler = _cmd.getXorHandler();\n\tstd::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();\n\n\t// first the xor \n\tfor ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )\n\t\t{\n\t\t\tfor ( ArgVectorIterator it = xorList[i].begin(); \n\t\t\t\t  it != xorList[i].end(); \n\t\t\t\t  it++ )\n\t\t\t\t{\n\t\t\t\t\tspacePrint( os, (*it)->longID(), 75, 3, 3 );\n\t\t\t\t\tspacePrint( os, (*it)->getDescription(), 75, 5, 0 );\n\n\t\t\t\t\tif ( it+1 != xorList[i].end() )\n\t\t\t\t\t\tspacePrint(os, \"-- OR --\", 75, 9, 0);\n\t\t\t\t}\n\t\t\tos << std::endl << std::endl;\n\t\t}\n\n\t// then the rest\n\tfor (ArgListIterator it = argList.begin(); it != argList.end(); it++)\n\t\tif ( !xorHandler.contains( (*it) ) )\n\t\t\t{\n\t\t\t\tspacePrint( os, (*it)->longID(), 75, 3, 3 ); \n\t\t\t\tspacePrint( os, (*it)->getDescription(), 75, 5, 0 ); \n\t\t\t\tos << std::endl;\n\t\t\t}\n\n\tos << std::endl;\n\n\tspacePrint( os, message, 75, 3, 0 );\n}\n\ninline void StdOutput::spacePrint( std::ostream& os, \n\t\t\t\t\t\t           const std::string& s, \n\t\t\t\t\t\t           int maxWidth, \n\t\t\t\t\t\t           int indentSpaces, \n\t\t\t\t\t\t           int secondLineOffset ) const\n{\n\tint len = static_cast<int>(s.length());\n\n\tif ( (len + indentSpaces > maxWidth) && maxWidth > 0 )\n\t\t{\n\t\t\tint allowedLen = maxWidth - indentSpaces;\n\t\t\tint start = 0;\n\t\t\twhile ( start < len )\n\t\t\t\t{\n\t\t\t\t\t// find the substring length\n\t\t\t\t\t// int stringLen = std::min<int>( len - start, allowedLen );\n\t\t\t\t\t// doing it this way to support a VisualC++ 2005 bug \n\t\t\t\t\tusing namespace std; \n\t\t\t\t\tint stringLen = min<int>( len - start, allowedLen );\n\n\t\t\t\t\t// trim the length so it doesn't end in middle of a word\n\t\t\t\t\tif ( stringLen == allowedLen )\n\t\t\t\t\t\twhile ( stringLen >= 0 &&\n\t\t\t\t\t\t\t\ts[stringLen+start] != ' ' && \n\t\t\t\t\t\t\t\ts[stringLen+start] != ',' &&\n\t\t\t\t\t\t\t\ts[stringLen+start] != '|' ) \n\t\t\t\t\t\t\tstringLen--;\n\t\n\t\t\t\t\t// ok, the word is longer than the line, so just split \n\t\t\t\t\t// wherever the line ends\n\t\t\t\t\tif ( stringLen <= 0 )\n\t\t\t\t\t\tstringLen = allowedLen;\n\n\t\t\t\t\t// check for newlines\n\t\t\t\t\tfor ( int i = 0; i < stringLen; i++ )\n\t\t\t\t\t\tif ( s[start+i] == '\\n' )\n\t\t\t\t\t\t\tstringLen = i+1;\n\n\t\t\t\t\t// print the indent\t\n\t\t\t\t\tfor ( int i = 0; i < indentSpaces; i++ )\n\t\t\t\t\t\tos << \" \";\n\n\t\t\t\t\tif ( start == 0 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// handle second line offsets\n\t\t\t\t\t\t\tindentSpaces += secondLineOffset;\n\n\t\t\t\t\t\t\t// adjust allowed len\n\t\t\t\t\t\t\tallowedLen -= secondLineOffset;\n\t\t\t\t\t\t}\n\n\t\t\t\t\tos << s.substr(start,stringLen) << std::endl;\n\n\t\t\t\t\t// so we don't start a line with a space\n\t\t\t\t\twhile ( s[stringLen+start] == ' ' && start < len )\n\t\t\t\t\t\tstart++;\n\t\t\t\n\t\t\t\t\tstart += stringLen;\n\t\t\t\t}\n\t\t}\n\telse\n\t\t{\n\t\t\tfor ( int i = 0; i < indentSpaces; i++ )\n\t\t\t\tos << \" \";\n\t\t\tos << s << std::endl;\n\t\t}\n}\n\n} //namespace TCLAP\n#endif \n"
  },
  {
    "path": "components/mkspiffs/src/tclap/SwitchArg.h",
    "content": "\n/****************************************************************************** \n * \n *  file:  SwitchArg.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_SWITCH_ARG_H\n#define TCLAP_SWITCH_ARG_H\n\n#include <string>\n#include <vector>\n\n#include \"Arg.h\"\n\nnamespace TCLAP {\n\n/**\n * A simple switch argument.  If the switch is set on the command line, then\n * the getValue method will return the opposite of the default value for the\n * switch.\n */\nclass SwitchArg : public Arg\n{\n\tprotected:\n\n\t\t/**\n\t\t * The value of the switch.\n\t\t */\n\t\tbool _value;\n\n\t\t/**\n\t\t * Used to support the reset() method so that ValueArg can be\n\t\t * reset to their constructed value.\n\t\t */\n        bool _default;\n\n\tpublic:\n\n        /**\n\t\t * SwitchArg constructor.\n\t\t * \\param flag - The one character flag that identifies this\n\t\t * argument on the command line.\n\t\t * \\param name - A one word name for the argument.  Can be\n\t\t * used as a long flag on the command line.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param def - The default value for this Switch. \n\t\t * \\param v - An optional visitor.  You probably should not\n\t\t * use this unless you have a very good reason.\n\t\t */\n\t\tSwitchArg(const std::string& flag, \n\t\t\t      const std::string& name, \n\t\t\t      const std::string& desc,\n\t\t\t      bool def = false,\n\t\t\t\t  Visitor* v = NULL);\n\n\t\t\t\t  \n\t\t/**\n\t\t * SwitchArg constructor.\n\t\t * \\param flag - The one character flag that identifies this\n\t\t * argument on the command line.\n\t\t * \\param name - A one word name for the argument.  Can be\n\t\t * used as a long flag on the command line.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param parser - A CmdLine parser object to add this Arg to\n\t\t * \\param def - The default value for this Switch.\n\t\t * \\param v - An optional visitor.  You probably should not\n\t\t * use this unless you have a very good reason.\n\t\t */\n\t\tSwitchArg(const std::string& flag, \n\t\t\t      const std::string& name, \n\t\t\t      const std::string& desc,\n\t\t\t\t  CmdLineInterface& parser,\n\t\t\t      bool def = false,\n\t\t\t\t  Visitor* v = NULL);\n\t\t\t\t  \n\t\t\t\t  \n        /**\n\t\t * Handles the processing of the argument.\n\t\t * This re-implements the Arg version of this method to set the\n\t\t * _value of the argument appropriately.\n\t\t * \\param i - Pointer the the current argument in the list.\n\t\t * \\param args - Mutable list of strings. Passed\n\t\t * in from main().\n\t\t */\n\t\tvirtual bool processArg(int* i, std::vector<std::string>& args); \n\n\t\t/**\n\t\t * Checks a string to see if any of the chars in the string\n\t\t * match the flag for this Switch.\n\t\t */\n\t\tbool combinedSwitchesMatch(std::string& combined);\n\n\t\t/**\n\t\t * Returns bool, whether or not the switch has been set.\n\t\t */\n\t\tbool getValue();\n\t\t\n\t\tvirtual void reset();\n\n\tprivate:\n\t\t/**\n\t\t * Checks to see if we've found the last match in\n\t\t * a combined string.\n\t\t */\n\t\tbool lastCombined(std::string& combined);\n\n\t\t/**\n\t\t * Does the common processing of processArg.\n\t\t */\n\t\tvoid commonProcessing();\n};\n\n//////////////////////////////////////////////////////////////////////\n//BEGIN SwitchArg.cpp\n//////////////////////////////////////////////////////////////////////\ninline SwitchArg::SwitchArg(const std::string& flag, \n                            const std::string& name, \n                            const std::string& desc, \n                            bool default_val,\n                            Visitor* v )\n: Arg(flag, name, desc, false, false, v),\n  _value( default_val ),\n  _default( default_val )\n{ }\n\ninline SwitchArg::SwitchArg(const std::string& flag, \n                            const std::string& name, \n                            const std::string& desc, \n                            CmdLineInterface& parser,\n                            bool default_val,\n                            Visitor* v )\n: Arg(flag, name, desc, false, false, v),\n  _value( default_val ),\n  _default(default_val)\n{ \n\tparser.add( this );\n}\n\ninline bool SwitchArg::getValue() { return _value; }\n\ninline bool SwitchArg::lastCombined(std::string& combinedSwitches ) \n{\n\tfor ( unsigned int i = 1; i < combinedSwitches.length(); i++ )\n\t\tif ( combinedSwitches[i] != Arg::blankChar() )\n\t\t\treturn false;\n\t\n\treturn true;\n}\n\ninline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches )\n{\n\t// make sure this is actually a combined switch\n\tif ( combinedSwitches.length() > 0 &&\n\t     combinedSwitches[0] != Arg::flagStartString()[0] )\n\t\treturn false;\n\n\t// make sure it isn't a long name \n\tif ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) == \n\t     Arg::nameStartString() )\n\t\treturn false;\n\n\t// make sure the delimiter isn't in the string \n\tif ( combinedSwitches.find_first_of( Arg::delimiter() ) != std::string::npos )\n\t\treturn false;\n\n\t// ok, we're not specifying a ValueArg, so we know that we have\n\t// a combined switch list.  \n\tfor ( unsigned int i = 1; i < combinedSwitches.length(); i++ )\n\t\tif ( _flag.length() > 0 && \n\t\t     combinedSwitches[i] == _flag[0] &&\n\t\t     _flag[0] != Arg::flagStartString()[0] ) \n\t\t{\n\t\t\t// update the combined switches so this one is no longer present\n\t\t\t// this is necessary so that no unlabeled args are matched\n\t\t\t// later in the processing.\n\t\t\t//combinedSwitches.erase(i,1);\n\t\t\tcombinedSwitches[i] = Arg::blankChar(); \n\t\t\treturn true;\n\t\t}\n\n\t// none of the switches passed in the list match. \n\treturn false;\t\n}\n\ninline void SwitchArg::commonProcessing()\n{\n\tif ( _xorSet )\n\t\tthrow(CmdLineParseException(\n\t\t      \"Mutually exclusive argument already set!\", toString()));\n\n\tif ( _alreadySet ) \n\t\tthrow(CmdLineParseException(\"Argument already set!\", toString()));\n\n\t_alreadySet = true;\n\n\tif ( _value == true )\n\t\t_value = false;\n\telse\n\t\t_value = true;\n\n\t_checkWithVisitor();\n}\n\ninline bool SwitchArg::processArg(int *i, std::vector<std::string>& args)\n{\n\tif ( _ignoreable && Arg::ignoreRest() )\n\t\treturn false;\n\n\t// if the whole string matches the flag or name string\n\tif ( argMatches( args[*i] ) )\n\t{\n\t\tcommonProcessing();\n\n\t\treturn true;\n\t}\n\t// if a substring matches the flag as part of a combination\n\telse if ( combinedSwitchesMatch( args[*i] ) )\n\t{\n\t\t// check again to ensure we don't misinterpret \n\t\t// this as a MultiSwitchArg \n\t\tif ( combinedSwitchesMatch( args[*i] ) )\n\t\t\tthrow(CmdLineParseException(\"Argument already set!\", \n\t\t\t                            toString()));\n\n\t\tcommonProcessing();\n\n\t\t// We only want to return true if we've found the last combined\n\t\t// match in the string, otherwise we return true so that other \n\t\t// switches in the combination will have a chance to match.\n\t\treturn lastCombined( args[*i] );\n\t}\n\telse\n\t\treturn false;\n}\n\ninline void SwitchArg::reset()\n{\n\tArg::reset();\n\t_value = _default;  \n}\n//////////////////////////////////////////////////////////////////////\n//End SwitchArg.cpp\n//////////////////////////////////////////////////////////////////////\n\n} //namespace TCLAP\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/UnlabeledMultiArg.h",
    "content": "\n/****************************************************************************** \n * \n *  file:  UnlabeledMultiArg.h\n * \n *  Copyright (c) 2003, Michael E. Smoot.\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H\n#define TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H\n\n#include <string>\n#include <vector>\n\n#include \"MultiArg.h\"\n#include \"OptionalUnlabeledTracker.h\"\n\nnamespace TCLAP {\n\n/**\n * Just like a MultiArg, except that the arguments are unlabeled.  Basically,\n * this Arg will slurp up everything that hasn't been matched to another \n * Arg.\n */\ntemplate<class T>\nclass UnlabeledMultiArg : public MultiArg<T>\n{\n\n\t// If compiler has two stage name lookup (as gcc >= 3.4 does)\n\t// this is requried to prevent undef. symbols\n\tusing MultiArg<T>::_ignoreable;\n\tusing MultiArg<T>::_hasBlanks;\n\tusing MultiArg<T>::_extractValue;\n\tusing MultiArg<T>::_typeDesc;\n\tusing MultiArg<T>::_name;\n\tusing MultiArg<T>::_description;\n\tusing MultiArg<T>::_alreadySet;\n\tusing MultiArg<T>::toString;\n\n\tpublic:\n\t\t\n\t\t/**\n\t\t * Constructor.  \n\t\t * \\param name - The name of the Arg. Note that this is used for\n\t\t * identification, not as a long flag.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param req - Whether the argument is required on the command\n\t\t *  line.\n\t\t * \\param typeDesc - A short, human readable description of the\n\t\t * type that this object expects.  This is used in the generation\n\t\t * of the USAGE statement.  The goal is to be helpful to the end user\n\t\t * of the program.\n\t\t * \\param ignoreable - Whether or not this argument can be ignored\n\t\t * using the \"--\" flag.\n\t\t * \\param v - An optional visitor.  You probably should not\n\t\t * use this unless you have a very good reason.\n\t\t */\n\t\tUnlabeledMultiArg( const std::string& name,\n\t\t\t\t           const std::string& desc,\n\t\t\t\t\t\t   bool req,\n\t\t\t\t           const std::string& typeDesc,\n\t\t\t\t\t\t   bool ignoreable = false,\n\t\t\t\t           Visitor* v = NULL );\n\t\t/**\n\t\t * Constructor.  \n\t\t * \\param name - The name of the Arg. Note that this is used for\n\t\t * identification, not as a long flag.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param req - Whether the argument is required on the command\n\t\t *  line.\n\t\t * \\param typeDesc - A short, human readable description of the\n\t\t * type that this object expects.  This is used in the generation\n\t\t * of the USAGE statement.  The goal is to be helpful to the end user\n\t\t * of the program.\n\t\t * \\param parser - A CmdLine parser object to add this Arg to\n\t\t * \\param ignoreable - Whether or not this argument can be ignored\n\t\t * using the \"--\" flag.\n\t\t * \\param v - An optional visitor.  You probably should not\n\t\t * use this unless you have a very good reason.\n\t\t */\n\t\tUnlabeledMultiArg( const std::string& name,\n\t\t\t\t           const std::string& desc,\n\t\t\t\t\t\t   bool req,\n\t\t\t\t           const std::string& typeDesc,\n\t\t\t\t\t\t   CmdLineInterface& parser,\n\t\t\t\t\t\t   bool ignoreable = false,\n\t\t\t\t           Visitor* v = NULL );\n\t\t\t\t\t\t \n\t\t/**\n\t\t * Constructor.  \n\t\t * \\param name - The name of the Arg. Note that this is used for\n\t\t * identification, not as a long flag.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param req - Whether the argument is required on the command\n\t\t *  line.\n\t\t * \\param constraint - A pointer to a Constraint object used\n\t\t * to constrain this Arg.\n\t\t * \\param ignoreable - Whether or not this argument can be ignored\n\t\t * using the \"--\" flag.\n\t\t * \\param v - An optional visitor.  You probably should not\n\t\t * use this unless you have a very good reason.\n\t\t */\n\t\tUnlabeledMultiArg( const std::string& name,\n\t\t\t\t\t\t   const std::string& desc,\n\t\t\t\t\t\t   bool req,\n\t\t\t\t\t\t   Constraint<T>* constraint,\n\t\t\t\t\t\t   bool ignoreable = false,\n\t\t\t\t\t\t   Visitor* v = NULL );\n\n\t\t/**\n\t\t * Constructor.  \n\t\t * \\param name - The name of the Arg. Note that this is used for\n\t\t * identification, not as a long flag.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param req - Whether the argument is required on the command\n\t\t *  line.\n\t\t * \\param constraint - A pointer to a Constraint object used\n\t\t * to constrain this Arg.\n\t\t * \\param parser - A CmdLine parser object to add this Arg to\n\t\t * \\param ignoreable - Whether or not this argument can be ignored\n\t\t * using the \"--\" flag.\n\t\t * \\param v - An optional visitor.  You probably should not\n\t\t * use this unless you have a very good reason.\n\t\t */\n\t\tUnlabeledMultiArg( const std::string& name, \n\t\t\t\t\t\t   const std::string& desc, \n\t\t\t\t\t\t   bool req,\n\t\t\t\t\t\t   Constraint<T>* constraint,\n\t\t\t\t\t\t   CmdLineInterface& parser,\n\t\t\t\t\t\t   bool ignoreable = false,\n\t\t\t\t\t\t   Visitor* v = NULL );\n\t\t\t\t\t\t \n\t\t/**\n\t\t * Handles the processing of the argument.\n\t\t * This re-implements the Arg version of this method to set the\n\t\t * _value of the argument appropriately.  It knows the difference\n\t\t * between labeled and unlabeled.\n\t\t * \\param i - Pointer the the current argument in the list.\n\t\t * \\param args - Mutable list of strings. Passed from main().\n\t\t */\n\t\tvirtual bool processArg(int* i, std::vector<std::string>& args); \n\n\t\t/**\n\t\t * Returns the a short id string.  Used in the usage.\n\t\t * \\param val - value to be used.\n\t\t */\n\t\tvirtual std::string shortID(const std::string& val=\"val\") const;\n\n\t\t/**\n\t\t * Returns the a long id string.  Used in the usage.\n\t\t * \\param val - value to be used.\n\t\t */\n\t\tvirtual std::string longID(const std::string& val=\"val\") const;\n\n\t\t/**\n\t\t * Opertor ==.\n\t\t * \\param a - The Arg to be compared to this.\n\t\t */\n\t\tvirtual bool operator==(const Arg& a) const;\n\n\t\t/**\n\t\t * Pushes this to back of list rather than front.\n\t\t * \\param argList - The list this should be added to.\n\t\t */\n\t\tvirtual void addToList( std::list<Arg*>& argList ) const;\n};\n\ntemplate<class T>\nUnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, \n\t\t\t\t                        const std::string& desc, \n\t\t\t\t\t\t\t\t\t\tbool req,\n\t\t\t\t\t                    const std::string& typeDesc,\n\t\t\t\t\t\t\t\t\t\tbool ignoreable,\n\t\t\t\t\t                    Visitor* v)\n: MultiArg<T>(\"\", name, desc,  req, typeDesc, v)\n{ \n\t_ignoreable = ignoreable;\n\tOptionalUnlabeledTracker::check(true, toString());\n}\n\ntemplate<class T>\nUnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, \n\t\t\t\t                        const std::string& desc, \n\t\t\t\t\t\t\t\t\t\tbool req,\n\t\t\t\t\t                    const std::string& typeDesc,\n\t\t\t\t\t\t\t\t\t\tCmdLineInterface& parser,\n\t\t\t\t\t\t\t\t\t\tbool ignoreable,\n\t\t\t\t\t                    Visitor* v)\n: MultiArg<T>(\"\", name, desc,  req, typeDesc, v)\n{ \n\t_ignoreable = ignoreable;\n\tOptionalUnlabeledTracker::check(true, toString());\n\tparser.add( this );\n}\n\n\ntemplate<class T>\nUnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, \n\t\t\t\t                        const std::string& desc, \n\t\t\t\t\t\t\t\t\t\tbool req,\n\t\t\t\t\t                    Constraint<T>* constraint,\n\t\t\t\t\t\t\t\t\t\tbool ignoreable,\n\t\t\t\t\t                    Visitor* v)\n: MultiArg<T>(\"\", name, desc,  req, constraint, v)\n{ \n\t_ignoreable = ignoreable;\n\tOptionalUnlabeledTracker::check(true, toString());\n}\n\ntemplate<class T>\nUnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, \n\t\t\t\t                        const std::string& desc, \n\t\t\t\t\t\t\t\t\t\tbool req,\n\t\t\t\t\t                    Constraint<T>* constraint,\n\t\t\t\t\t\t\t\t\t\tCmdLineInterface& parser,\n\t\t\t\t\t\t\t\t\t\tbool ignoreable,\n\t\t\t\t\t                    Visitor* v)\n: MultiArg<T>(\"\", name, desc,  req, constraint, v)\n{ \n\t_ignoreable = ignoreable;\n\tOptionalUnlabeledTracker::check(true, toString());\n\tparser.add( this );\n}\n\n\ntemplate<class T>\nbool UnlabeledMultiArg<T>::processArg(int *i, std::vector<std::string>& args) \n{\n\n\tif ( _hasBlanks( args[*i] ) )\n\t\treturn false;\n\n\t// never ignore an unlabeled multi arg\n\n\n\t// always take the first value, regardless of the start string \n\t_extractValue( args[(*i)] );\n\n\t/*\n\t// continue taking args until we hit the end or a start string \n\twhile ( (unsigned int)(*i)+1 < args.size() &&\n\t\t\targs[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&\n            args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) \n\t\t_extractValue( args[++(*i)] );\n\t*/\n\n\t_alreadySet = true;\n\n\treturn true;\n}\n\ntemplate<class T>\nstd::string UnlabeledMultiArg<T>::shortID(const std::string& val) const\n{\n\tstatic_cast<void>(val); // Ignore input, don't warn\n\treturn std::string(\"<\") + _typeDesc + \"> ...\";\n}\n\ntemplate<class T>\nstd::string UnlabeledMultiArg<T>::longID(const std::string& val) const\n{\n\tstatic_cast<void>(val); // Ignore input, don't warn\n\treturn std::string(\"<\") + _typeDesc + \">  (accepted multiple times)\";\n}\n\ntemplate<class T>\nbool UnlabeledMultiArg<T>::operator==(const Arg& a) const\n{\n\tif ( _name == a.getName() || _description == a.getDescription() )\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\ntemplate<class T>\nvoid UnlabeledMultiArg<T>::addToList( std::list<Arg*>& argList ) const\n{\n\targList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/UnlabeledValueArg.h",
    "content": "\n/****************************************************************************** \n * \n *  file:  UnlabeledValueArg.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_UNLABELED_VALUE_ARGUMENT_H\n#define TCLAP_UNLABELED_VALUE_ARGUMENT_H\n\n#include <string>\n#include <vector>\n\n#include \"ValueArg.h\"\n#include \"OptionalUnlabeledTracker.h\"\n\n\nnamespace TCLAP {\n\n/**\n * The basic unlabeled argument that parses a value.\n * This is a template class, which means the type T defines the type\n * that a given object will attempt to parse when an UnlabeledValueArg\n * is reached in the list of args that the CmdLine iterates over.\n */\ntemplate<class T>\nclass UnlabeledValueArg : public ValueArg<T>\n{\n\n\t// If compiler has two stage name lookup (as gcc >= 3.4 does)\n\t// this is requried to prevent undef. symbols\n\tusing ValueArg<T>::_ignoreable;\n\tusing ValueArg<T>::_hasBlanks;\n\tusing ValueArg<T>::_extractValue;\n\tusing ValueArg<T>::_typeDesc;\n\tusing ValueArg<T>::_name;\n\tusing ValueArg<T>::_description;\n\tusing ValueArg<T>::_alreadySet;\n\tusing ValueArg<T>::toString;\n\n\tpublic:\n\n\t\t/**\n\t\t * UnlabeledValueArg constructor.\n\t\t * \\param name - A one word name for the argument.  Note that this is used for\n\t\t * identification, not as a long flag.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param req - Whether the argument is required on the command\n\t\t * line.\n\t\t * \\param value - The default value assigned to this argument if it\n\t\t * is not present on the command line.\n\t\t * \\param typeDesc - A short, human readable description of the\n\t\t * type that this object expects.  This is used in the generation\n\t\t * of the USAGE statement.  The goal is to be helpful to the end user\n\t\t * of the program.\n\t\t * \\param ignoreable - Allows you to specify that this argument can be\n\t\t * ignored if the '--' flag is set.  This defaults to false (cannot\n\t\t * be ignored) and should  generally stay that way unless you have \n\t\t * some special need for certain arguments to be ignored.\n\t\t * \\param v - Optional Vistor.  You should leave this blank unless\n\t\t * you have a very good reason.\n\t\t */\n\t\tUnlabeledValueArg( const std::string& name, \n\t\t\t               const std::string& desc, \n\t\t\t\t\t\t   bool req,\n\t\t\t\t           T value,\n\t\t\t\t           const std::string& typeDesc,\n\t\t\t\t\t\t   bool ignoreable = false,\n\t\t\t\t           Visitor* v = NULL); \n\n\t\t/**\n\t\t * UnlabeledValueArg constructor.\n\t\t * \\param name - A one word name for the argument.  Note that this is used for\n\t\t * identification, not as a long flag.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param req - Whether the argument is required on the command\n\t\t * line.\n\t\t * \\param value - The default value assigned to this argument if it\n\t\t * is not present on the command line.\n\t\t * \\param typeDesc - A short, human readable description of the\n\t\t * type that this object expects.  This is used in the generation\n\t\t * of the USAGE statement.  The goal is to be helpful to the end user\n\t\t * of the program.\n\t\t * \\param parser - A CmdLine parser object to add this Arg to\n\t\t * \\param ignoreable - Allows you to specify that this argument can be\n\t\t * ignored if the '--' flag is set.  This defaults to false (cannot\n\t\t * be ignored) and should  generally stay that way unless you have \n\t\t * some special need for certain arguments to be ignored.\n\t\t * \\param v - Optional Vistor.  You should leave this blank unless\n\t\t * you have a very good reason.\n\t\t */\n\t\tUnlabeledValueArg( const std::string& name, \n\t\t\t               const std::string& desc, \n\t\t\t\t\t\t   bool req,\n\t\t\t\t           T value,\n\t\t\t\t           const std::string& typeDesc,\n\t\t\t\t\t\t   CmdLineInterface& parser,\n\t\t\t\t\t\t   bool ignoreable = false,\n\t\t\t\t           Visitor* v = NULL ); \t\t\t\t\t\n\t\t\t\t\t\t\n\t\t/**\n\t\t * UnlabeledValueArg constructor.\n\t\t * \\param name - A one word name for the argument.  Note that this is used for\n\t\t * identification, not as a long flag.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param req - Whether the argument is required on the command\n\t\t * line.\n\t\t * \\param value - The default value assigned to this argument if it\n\t\t * is not present on the command line.\n\t\t * \\param constraint - A pointer to a Constraint object used\n\t\t * to constrain this Arg.\n\t\t * \\param ignoreable - Allows you to specify that this argument can be\n\t\t * ignored if the '--' flag is set.  This defaults to false (cannot\n\t\t * be ignored) and should  generally stay that way unless you have \n\t\t * some special need for certain arguments to be ignored.\n\t\t * \\param v - Optional Vistor.  You should leave this blank unless\n\t\t * you have a very good reason.\n\t\t */\n\t\tUnlabeledValueArg( const std::string& name, \n\t\t\t               const std::string& desc, \n\t\t\t\t\t\t   bool req,\n\t\t\t\t           T value,\n\t\t\t\t           Constraint<T>* constraint,\n\t\t\t\t\t\t   bool ignoreable = false,\n\t\t\t\t           Visitor* v = NULL ); \n\n\t\t\n\t\t/**\n\t\t * UnlabeledValueArg constructor.\n\t\t * \\param name - A one word name for the argument.  Note that this is used for\n\t\t * identification, not as a long flag.\n\t\t * \\param desc - A description of what the argument is for or\n\t\t * does.\n\t\t * \\param req - Whether the argument is required on the command\n\t\t * line.\n\t\t * \\param value - The default value assigned to this argument if it\n\t\t * is not present on the command line.\n\t\t * \\param constraint - A pointer to a Constraint object used\n\t\t * to constrain this Arg.\n\t\t * \\param parser - A CmdLine parser object to add this Arg to\n\t\t * \\param ignoreable - Allows you to specify that this argument can be\n\t\t * ignored if the '--' flag is set.  This defaults to false (cannot\n\t\t * be ignored) and should  generally stay that way unless you have \n\t\t * some special need for certain arguments to be ignored.\n\t\t * \\param v - Optional Vistor.  You should leave this blank unless\n\t\t * you have a very good reason.\n\t\t */\n\t\tUnlabeledValueArg( const std::string& name, \n\t\t\t               const std::string& desc, \n\t\t\t\t\t\t   bool req,\n\t\t\t\t           T value,\n\t\t\t\t           Constraint<T>* constraint,\n\t\t\t\t\t\t   CmdLineInterface& parser,\n\t\t\t\t\t\t   bool ignoreable = false,\n\t\t\t\t           Visitor* v = NULL);\n\t\t\t\t\t\t\n\t\t/**\n\t\t * Handles the processing of the argument.\n\t\t * This re-implements the Arg version of this method to set the\n\t\t * _value of the argument appropriately.  Handling specific to\n\t\t * unlabled arguments.\n\t\t * \\param i - Pointer the the current argument in the list.\n\t\t * \\param args - Mutable list of strings. \n\t\t */\n\t\tvirtual bool processArg(int* i, std::vector<std::string>& args); \n\n\t\t/**\n\t\t * Overrides shortID for specific behavior.\n\t\t */\n\t\tvirtual std::string shortID(const std::string& val=\"val\") const;\n\n\t\t/**\n\t\t * Overrides longID for specific behavior.\n\t\t */\n\t\tvirtual std::string longID(const std::string& val=\"val\") const;\n\n\t\t/**\n\t\t * Overrides operator== for specific behavior.\n\t\t */\n\t\tvirtual bool operator==(const Arg& a ) const;\n\n\t\t/**\n\t\t * Instead of pushing to the front of list, push to the back.\n\t\t * \\param argList - The list to add this to.\n\t\t */\n\t\tvirtual void addToList( std::list<Arg*>& argList ) const;\n\n};\n\n/**\n * Constructor implemenation.\n */\ntemplate<class T>\nUnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, \n\t\t\t\t\t                    const std::string& desc, \n\t\t\t\t\t\t\t\t\t\tbool req,\n\t\t\t\t\t                    T val,\n\t\t\t\t\t                    const std::string& typeDesc,\n\t\t\t\t\t                    bool ignoreable,\n\t\t\t\t\t                    Visitor* v)\n: ValueArg<T>(\"\", name, desc, req, val, typeDesc, v)\n{ \n\t_ignoreable = ignoreable;\n\n\tOptionalUnlabeledTracker::check(req, toString());\n\n}\n\ntemplate<class T>\nUnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, \n\t\t\t\t\t                    const std::string& desc, \n\t\t\t\t\t\t\t\t\t\tbool req,\n\t\t\t\t\t                    T val,\n\t\t\t\t\t                    const std::string& typeDesc,\n\t\t\t\t\t                    CmdLineInterface& parser,\n\t\t\t\t\t                    bool ignoreable,\n\t\t\t\t\t                    Visitor* v)\n: ValueArg<T>(\"\", name, desc, req, val, typeDesc, v)\n{ \n\t_ignoreable = ignoreable;\n\tOptionalUnlabeledTracker::check(req, toString());\n\tparser.add( this );\n}\n\n/**\n * Constructor implemenation.\n */\ntemplate<class T>\nUnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, \n                                        const std::string& desc, \n\t\t\t\t\t\t\t\t\t\tbool req,\n                                        T val,\n                                        Constraint<T>* constraint,\n                                        bool ignoreable,\n                                        Visitor* v)\n: ValueArg<T>(\"\", name, desc, req, val, constraint, v)\n{ \n\t_ignoreable = ignoreable;\n\tOptionalUnlabeledTracker::check(req, toString());\n}\n\ntemplate<class T>\nUnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, \n\t\t\t\t\t                    const std::string& desc, \n\t\t\t\t\t\t\t\t\t\tbool req,\n\t\t\t\t\t                    T val,\n\t\t\t\t\t                    Constraint<T>* constraint,\n\t\t\t\t\t                    CmdLineInterface& parser,\n\t\t\t\t\t                    bool ignoreable,\n\t\t\t\t\t                    Visitor* v)\n: ValueArg<T>(\"\", name, desc, req, val, constraint,  v)\n{ \n\t_ignoreable = ignoreable;\n\tOptionalUnlabeledTracker::check(req, toString());\n\tparser.add( this );\n}\n\n/**\n * Implementation of processArg().\n */\ntemplate<class T>\nbool UnlabeledValueArg<T>::processArg(int *i, std::vector<std::string>& args) \n{\n\t\n\tif ( _alreadySet )\n\t\treturn false;\n\t\n\tif ( _hasBlanks( args[*i] ) )\n\t\treturn false;\n\n\t// never ignore an unlabeled arg\n\t\n\t_extractValue( args[*i] );\n\t_alreadySet = true;\n\treturn true;\n}\n\n/**\n * Overriding shortID for specific output.\n */\ntemplate<class T>\nstd::string UnlabeledValueArg<T>::shortID(const std::string& val) const\n{\n\tstatic_cast<void>(val); // Ignore input, don't warn\n\treturn std::string(\"<\") + _typeDesc + \">\";\n}\n\n/**\n * Overriding longID for specific output.\n */\ntemplate<class T>\nstd::string UnlabeledValueArg<T>::longID(const std::string& val) const\n{\n\tstatic_cast<void>(val); // Ignore input, don't warn\n\n\t// Ideally we would like to be able to use RTTI to return the name\n\t// of the type required for this argument.  However, g++ at least, \n\t// doesn't appear to return terribly useful \"names\" of the types.  \n\treturn std::string(\"<\") + _typeDesc + \">\";\n}\n\n/**\n * Overriding operator== for specific behavior.\n */\ntemplate<class T>\nbool UnlabeledValueArg<T>::operator==(const Arg& a ) const\n{\n\tif ( _name == a.getName() || _description == a.getDescription() )\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\ntemplate<class T>\nvoid UnlabeledValueArg<T>::addToList( std::list<Arg*>& argList ) const\n{\n\targList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );\n}\n\n}\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/ValueArg.h",
    "content": "/****************************************************************************** \n * \n *  file:  ValueArg.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_VALUE_ARGUMENT_H\n#define TCLAP_VALUE_ARGUMENT_H\n\n#include <string>\n#include <vector>\n\n#include \"Arg.h\"\n#include \"Constraint.h\"\n\nnamespace TCLAP {\n\n/**\n * The basic labeled argument that parses a value.\n * This is a template class, which means the type T defines the type\n * that a given object will attempt to parse when the flag/name is matched\n * on the command line.  While there is nothing stopping you from creating\n * an unflagged ValueArg, it is unwise and would cause significant problems.\n * Instead use an UnlabeledValueArg.\n */\ntemplate<class T>\nclass ValueArg : public Arg \n{\n    protected:\n\n        /**\n         * The value parsed from the command line.\n         * Can be of any type, as long as the >> operator for the type\n         * is defined.\n         */\n        T _value;\n\n\t\t/**\n\t\t * Used to support the reset() method so that ValueArg can be\n\t\t * reset to their constructed value.\n\t\t */\n        T _default;\n\n        /**\n         * A human readable description of the type to be parsed.\n         * This is a hack, plain and simple.  Ideally we would use RTTI to\n         * return the name of type T, but until there is some sort of\n         * consistent support for human readable names, we are left to our\n         * own devices.\n         */\n        std::string _typeDesc;\n\n        /**\n         * A Constraint this Arg must conform to. \n         */\n        Constraint<T>* _constraint;\n\n        /**\n         * Extracts the value from the string.\n         * Attempts to parse string as type T, if this fails an exception\n         * is thrown.\n         * \\param val - value to be parsed. \n         */\n        void _extractValue( const std::string& val );\n\n\tpublic:\n\n        /**\n         * Labeled ValueArg constructor.\n         * You could conceivably call this constructor with a blank flag, \n         * but that would make you a bad person.  It would also cause\n         * an exception to be thrown.   If you want an unlabeled argument, \n         * use the other constructor.\n         * \\param flag - The one character flag that identifies this\n         * argument on the command line.\n         * \\param name - A one word name for the argument.  Can be\n         * used as a long flag on the command line.\n         * \\param desc - A description of what the argument is for or\n         * does.\n         * \\param req - Whether the argument is required on the command\n         * line.\n         * \\param value - The default value assigned to this argument if it\n         * is not present on the command line.\n         * \\param typeDesc - A short, human readable description of the\n         * type that this object expects.  This is used in the generation\n         * of the USAGE statement.  The goal is to be helpful to the end user\n         * of the program.\n         * \\param v - An optional visitor.  You probably should not\n         * use this unless you have a very good reason.\n         */\n        ValueArg( const std::string& flag, \n                  const std::string& name, \n                  const std::string& desc, \n                  bool req, \n                  T value,\n                  const std::string& typeDesc,\n                  Visitor* v = NULL);\n\t\t\t\t \n\t\t\t\t \n        /**\n         * Labeled ValueArg constructor.\n         * You could conceivably call this constructor with a blank flag, \n         * but that would make you a bad person.  It would also cause\n         * an exception to be thrown.   If you want an unlabeled argument, \n         * use the other constructor.\n         * \\param flag - The one character flag that identifies this\n         * argument on the command line.\n         * \\param name - A one word name for the argument.  Can be\n         * used as a long flag on the command line.\n         * \\param desc - A description of what the argument is for or\n         * does.\n         * \\param req - Whether the argument is required on the command\n         * line.\n         * \\param value - The default value assigned to this argument if it\n         * is not present on the command line.\n         * \\param typeDesc - A short, human readable description of the\n         * type that this object expects.  This is used in the generation\n         * of the USAGE statement.  The goal is to be helpful to the end user\n         * of the program.\n         * \\param parser - A CmdLine parser object to add this Arg to\n         * \\param v - An optional visitor.  You probably should not\n         * use this unless you have a very good reason.\n         */\n        ValueArg( const std::string& flag, \n                  const std::string& name, \n                  const std::string& desc, \n                  bool req, \n                  T value,\n                  const std::string& typeDesc,\n                  CmdLineInterface& parser,\n                  Visitor* v = NULL );\n \n        /**\n         * Labeled ValueArg constructor.\n         * You could conceivably call this constructor with a blank flag, \n         * but that would make you a bad person.  It would also cause\n         * an exception to be thrown.   If you want an unlabeled argument, \n         * use the other constructor.\n         * \\param flag - The one character flag that identifies this\n         * argument on the command line.\n         * \\param name - A one word name for the argument.  Can be\n         * used as a long flag on the command line.\n         * \\param desc - A description of what the argument is for or\n         * does.\n         * \\param req - Whether the argument is required on the command\n         * line.\n         * \\param value - The default value assigned to this argument if it\n         * is not present on the command line.\n         * \\param constraint - A pointer to a Constraint object used\n\t\t * to constrain this Arg.\n         * \\param parser - A CmdLine parser object to add this Arg to.\n         * \\param v - An optional visitor.  You probably should not\n         * use this unless you have a very good reason.\n         */\n        ValueArg( const std::string& flag, \n                  const std::string& name, \n                  const std::string& desc, \n                  bool req, \n                  T value,\n                  Constraint<T>* constraint,\n                  CmdLineInterface& parser,\n                  Visitor* v = NULL );\n\t  \n        /**\n         * Labeled ValueArg constructor.\n         * You could conceivably call this constructor with a blank flag, \n         * but that would make you a bad person.  It would also cause\n         * an exception to be thrown.   If you want an unlabeled argument, \n         * use the other constructor.\n         * \\param flag - The one character flag that identifies this\n         * argument on the command line.\n         * \\param name - A one word name for the argument.  Can be\n         * used as a long flag on the command line.\n         * \\param desc - A description of what the argument is for or\n         * does.\n         * \\param req - Whether the argument is required on the command\n         * line.\n         * \\param value - The default value assigned to this argument if it\n         * is not present on the command line.\n         * \\param constraint - A pointer to a Constraint object used\n\t\t * to constrain this Arg.\n         * \\param v - An optional visitor.  You probably should not\n         * use this unless you have a very good reason.\n         */\n        ValueArg( const std::string& flag, \n                  const std::string& name, \n                  const std::string& desc, \n                  bool req, \n                  T value,\n                  Constraint<T>* constraint,\n                  Visitor* v = NULL );\n\n        /**\n         * Handles the processing of the argument.\n         * This re-implements the Arg version of this method to set the\n         * _value of the argument appropriately.  It knows the difference\n         * between labeled and unlabeled.\n         * \\param i - Pointer the the current argument in the list.\n         * \\param args - Mutable list of strings. Passed \n         * in from main().\n         */\n        virtual bool processArg(int* i, std::vector<std::string>& args); \n\n        /**\n         * Returns the value of the argument.\n         */\n        T& getValue() ;\n\n        /**\n         * Specialization of shortID.\n         * \\param val - value to be used.\n         */\n        virtual std::string shortID(const std::string& val = \"val\") const;\n\n        /**\n         * Specialization of longID.\n         * \\param val - value to be used.\n         */\n        virtual std::string longID(const std::string& val = \"val\") const;\n        \n        virtual void reset() ;\n\nprivate:\n       /**\n        * Prevent accidental copying\n        */\n       ValueArg<T>(const ValueArg<T>& rhs);\n       ValueArg<T>& operator=(const ValueArg<T>& rhs);\n};\n\n\n/**\n * Constructor implementation.\n */\ntemplate<class T>\nValueArg<T>::ValueArg(const std::string& flag, \n                      const std::string& name, \n                      const std::string& desc, \n                      bool req, \n                      T val,\n                      const std::string& typeDesc,\n                      Visitor* v)\n: Arg(flag, name, desc, req, true, v),\n  _value( val ),\n  _default( val ),\n  _typeDesc( typeDesc ),\n  _constraint( NULL )\n{ }\n\ntemplate<class T>\nValueArg<T>::ValueArg(const std::string& flag, \n                      const std::string& name, \n                      const std::string& desc, \n                      bool req, \n                      T val,\n                      const std::string& typeDesc,\n                      CmdLineInterface& parser,\n                      Visitor* v)\n: Arg(flag, name, desc, req, true, v),\n  _value( val ),\n  _default( val ),\n  _typeDesc( typeDesc ),\n  _constraint( NULL )\n{ \n    parser.add( this );\n}\n\ntemplate<class T>\nValueArg<T>::ValueArg(const std::string& flag, \n                      const std::string& name, \n                      const std::string& desc, \n                      bool req, \n                      T val,\n                      Constraint<T>* constraint,\n                      Visitor* v)\n: Arg(flag, name, desc, req, true, v),\n  _value( val ),\n  _default( val ),\n  _typeDesc( constraint->shortID() ),\n  _constraint( constraint )\n{ }\n\ntemplate<class T>\nValueArg<T>::ValueArg(const std::string& flag, \n                      const std::string& name, \n                      const std::string& desc, \n                      bool req, \n                      T val,\n                      Constraint<T>* constraint,\n                      CmdLineInterface& parser,\n                      Visitor* v)\n: Arg(flag, name, desc, req, true, v),\n  _value( val ),\n  _default( val ),\n  _typeDesc( constraint->shortID() ),\n  _constraint( constraint )\n{ \n    parser.add( this );\n}\n\n\n/**\n * Implementation of getValue().\n */\ntemplate<class T>\nT& ValueArg<T>::getValue() { return _value; }\n\n/**\n * Implementation of processArg().\n */\ntemplate<class T>\nbool ValueArg<T>::processArg(int *i, std::vector<std::string>& args)\n{\n    if ( _ignoreable && Arg::ignoreRest() )\n\t\treturn false;\n\n    if ( _hasBlanks( args[*i] ) )\n\t\treturn false;\n\n    std::string flag = args[*i];\n\n    std::string value = \"\";\n    trimFlag( flag, value );\n\n    if ( argMatches( flag ) )\n    {\n        if ( _alreadySet )\n\t\t{\n\t\t\tif ( _xorSet )\n\t\t\t\tthrow( CmdLineParseException(\n\t\t\t\t       \"Mutually exclusive argument already set!\", \n\t\t\t\t                             toString()) );\n\t\t\telse\n\t\t\t\tthrow( CmdLineParseException(\"Argument already set!\", \n\t\t\t\t                             toString()) );\n\t\t}\n\n        if ( Arg::delimiter() != ' ' && value == \"\" )\n\t\t\tthrow( ArgParseException( \n\t\t\t\t\t\t\t\"Couldn't find delimiter for this argument!\",\n                             toString() ) );\n\n        if ( value == \"\" )\n        {\n            (*i)++;\n            if ( static_cast<unsigned int>(*i) < args.size() ) \n\t\t\t\t_extractValue( args[*i] );\n            else\n\t\t\t\tthrow( ArgParseException(\"Missing a value for this argument!\",\n                                                    toString() ) );\n        }\n        else\n\t\t\t_extractValue( value );\n\t\t\t\t\n        _alreadySet = true;\n        _checkWithVisitor();\n        return true;\n    }\t\n    else\n\t\treturn false;\n}\n\n/**\n * Implementation of shortID.\n */\ntemplate<class T>\nstd::string ValueArg<T>::shortID(const std::string& val) const\n{\n\tstatic_cast<void>(val); // Ignore input, don't warn\n\treturn Arg::shortID( _typeDesc ); \n}\n\n/**\n * Implementation of longID.\n */\ntemplate<class T>\nstd::string ValueArg<T>::longID(const std::string& val) const\n{\n\tstatic_cast<void>(val); // Ignore input, don't warn\n\treturn Arg::longID( _typeDesc ); \n}\n\ntemplate<class T>\nvoid ValueArg<T>::_extractValue( const std::string& val ) \n{\n    try {\n\tExtractValue(_value, val, typename ArgTraits<T>::ValueCategory());\n    } catch( ArgParseException &e) {\n\tthrow ArgParseException(e.error(), toString());\n    }\n    \n    if ( _constraint != NULL )\n\tif ( ! _constraint->check( _value ) )\n\t    throw( CmdLineParseException( \"Value '\" + val + \n\t\t\t\t\t  + \"' does not meet constraint: \" \n\t\t\t\t\t  + _constraint->description(),\n\t\t\t\t\t  toString() ) );\n}\n\ntemplate<class T>\nvoid ValueArg<T>::reset()\n{\n\tArg::reset();\n\t_value = _default;\n}\n\n} // namespace TCLAP\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/ValuesConstraint.h",
    "content": "\n\n/****************************************************************************** \n * \n *  file:  ValuesConstraint.h\n * \n *  Copyright (c) 2005, Michael E. Smoot\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n#ifndef TCLAP_VALUESCONSTRAINT_H\n#define TCLAP_VALUESCONSTRAINT_H\n\n#include <string>\n#include <vector>\n#include \"Constraint.h\"\n\n#ifdef HAVE_CONFIG_H\n#include <config.h>\n#else\n#define HAVE_SSTREAM\n#endif\n\n#if defined(HAVE_SSTREAM)\n#include <sstream>\n#elif defined(HAVE_STRSTREAM)\n#include <strstream>\n#else\n#error \"Need a stringstream (sstream or strstream) to compile!\"\n#endif\n\nnamespace TCLAP {\n\n/**\n * A Constraint that constrains the Arg to only those values specified\n * in the constraint.\n */\ntemplate<class T>\nclass ValuesConstraint : public Constraint<T>\n{\n\n\tpublic:\n\n\t\t/**\n\t\t * Constructor. \n\t\t * \\param allowed - vector of allowed values. \n\t\t */\n\t\tValuesConstraint(std::vector<T>& allowed);\t\n\n\t\t/**\n\t\t * Virtual destructor.\n\t\t */\n\t\tvirtual ~ValuesConstraint() {}\n\n\t\t/**\n\t\t * Returns a description of the Constraint. \n\t\t */\n\t\tvirtual std::string description() const;\n\n\t\t/**\n\t\t * Returns the short ID for the Constraint.\n\t\t */\n\t\tvirtual std::string shortID() const;\n\n\t\t/**\n\t\t * The method used to verify that the value parsed from the command\n\t\t * line meets the constraint.\n\t\t * \\param value - The value that will be checked. \n\t\t */\n\t\tvirtual bool check(const T& value) const;\n\t\n\tprotected:\n\n\t\t/**\n\t\t * The list of valid values. \n\t\t */\n\t\tstd::vector<T> _allowed;\n\n\t\t/**\n\t\t * The string used to describe the allowed values of this constraint.\n\t\t */\n\t\tstd::string _typeDesc;\n\n};\n\ntemplate<class T>\nValuesConstraint<T>::ValuesConstraint(std::vector<T>& allowed)\n: _allowed(allowed),\n  _typeDesc(\"\")\n{ \n    for ( unsigned int i = 0; i < _allowed.size(); i++ )\n    {\n\n#if defined(HAVE_SSTREAM)\n        std::ostringstream os;\n#elif defined(HAVE_STRSTREAM)\n        std::ostrstream os;\n#else\n#error \"Need a stringstream (sstream or strstream) to compile!\"\n#endif\n\n        os << _allowed[i];\n\n        std::string temp( os.str() ); \n\n        if ( i > 0 )\n\t\t\t_typeDesc += \"|\";\n        _typeDesc += temp;\n    }\n}\n\ntemplate<class T>\nbool ValuesConstraint<T>::check( const T& val ) const\n{\n\tif ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() )\n\t\treturn false;\n\telse \n\t\treturn true;\n}\n\ntemplate<class T>\nstd::string ValuesConstraint<T>::shortID() const\n{\n    return _typeDesc;\t\n}\n\ntemplate<class T>\nstd::string ValuesConstraint<T>::description() const\n{\n    return _typeDesc;\t\n}\n\n\n} //namespace TCLAP\n#endif \n\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/VersionVisitor.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/****************************************************************************** \n * \n *  file:  VersionVisitor.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_VERSION_VISITOR_H\n#define TCLAP_VERSION_VISITOR_H\n\n#include \"CmdLineInterface.h\"\n#include \"CmdLineOutput.h\"\n#include \"Visitor.h\"\n\nnamespace TCLAP {\n\n/**\n * A Vistor that will call the version method of the given CmdLineOutput\n * for the specified CmdLine object and then exit.\n */\nclass VersionVisitor: public Visitor\n{\n\tprivate:\n\t\t/**\n\t\t * Prevent accidental copying\n\t\t */\n\t\tVersionVisitor(const VersionVisitor& rhs);\n\t\tVersionVisitor& operator=(const VersionVisitor& rhs);\n\n\tprotected:\n\n\t\t/**\n\t\t * The CmdLine of interest.\n\t\t */\n\t\tCmdLineInterface* _cmd;\n\n\t\t/**\n\t\t * The output object. \n\t\t */\n\t\tCmdLineOutput** _out;\n\n\tpublic:\n\n\t\t/**\n\t\t * Constructor.\n\t\t * \\param cmd - The CmdLine the output is generated for. \n\t\t * \\param out - The type of output. \n\t\t */\n\t\tVersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out ) \n\t\t\t\t: Visitor(), _cmd( cmd ), _out( out ) { }\n\n\t\t/**\n\t\t * Calls the version method of the output object using the\n\t\t * specified CmdLine.\n\t\t */\n\t\tvoid visit() { \n\t\t    (*_out)->version(*_cmd); \n\t\t    throw ExitException(0); \n\t\t}\n\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/Visitor.h",
    "content": "\n/****************************************************************************** \n * \n *  file:  Visitor.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n\n#ifndef TCLAP_VISITOR_H\n#define TCLAP_VISITOR_H\n\nnamespace TCLAP {\n\n/**\n * A base class that defines the interface for visitors.\n */\nclass Visitor\n{\n\tpublic:\n\n\t\t/**\n\t\t * Constructor. Does nothing.\n\t\t */\n\t\tVisitor() { }\n\n\t\t/**\n\t\t * Destructor. Does nothing.\n\t\t */\n\t\tvirtual ~Visitor() { }\n\n\t\t/**\n\t\t * Does nothing. Should be overridden by child.\n\t\t */\n\t\tvirtual void visit() { }\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "components/mkspiffs/src/tclap/XorHandler.h",
    "content": "\n/****************************************************************************** \n * \n *  file:  XorHandler.h\n * \n *  Copyright (c) 2003, Michael E. Smoot .\n *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.  \n *  \n *****************************************************************************/ \n\n#ifndef TCLAP_XORHANDLER_H\n#define TCLAP_XORHANDLER_H\n\n#include \"Arg.h\"\n#include <string>\n#include <vector>\n#include <algorithm>\n#include <iostream>\n\nnamespace TCLAP {\n\n/**\n * This class handles lists of Arg's that are to be XOR'd on the command\n * line.  This is used by CmdLine and you shouldn't ever use it.\n */\nclass XorHandler\n{\n\tprotected:\n\n\t\t/**\n\t\t * The list of of lists of Arg's to be or'd together.\n\t\t */\n\t\tstd::vector< std::vector<Arg*> > _orList;\n\n\tpublic:\n\n\t\t/**\n\t\t * Constructor.  Does nothing.\n\t\t */\n\t\tXorHandler( ) : _orList(std::vector< std::vector<Arg*> >()) {}\n\n\t\t/**\n\t\t * Add a list of Arg*'s that will be orred together.\n\t\t * \\param ors - list of Arg* that will be xor'd.\n\t\t */\n\t\tvoid add( std::vector<Arg*>& ors );\n\t\t\t\n\t\t/**\n\t\t * Checks whether the specified Arg is in one of the xor lists and\n\t\t * if it does match one, returns the size of the xor list that the\n\t\t * Arg matched.  If the Arg matches, then it also sets the rest of\n\t\t * the Arg's in the list. You shouldn't use this.  \n\t\t * \\param a - The Arg to be checked.\n\t\t */\n\t\tint check( const Arg* a );\n\n\t\t/**\n\t\t * Returns the XOR specific short usage.\n\t\t */\n\t\tstd::string shortUsage();\n\n\t\t/**\n\t\t * Prints the XOR specific long usage.\n\t\t * \\param os - Stream to print to.\n\t\t */\n\t\tvoid printLongUsage(std::ostream& os);\n\n\t\t/**\n\t\t * Simply checks whether the Arg is contained in one of the arg\n\t\t * lists.\n\t\t * \\param a - The Arg to be checked.\n\t\t */\n\t\tbool contains( const Arg* a );\n\n\t\tstd::vector< std::vector<Arg*> >& getXorList(); \n\n};\n\n\n//////////////////////////////////////////////////////////////////////\n//BEGIN XOR.cpp\n//////////////////////////////////////////////////////////////////////\ninline void XorHandler::add( std::vector<Arg*>& ors )\n{ \n\t_orList.push_back( ors );\n}\n\ninline int XorHandler::check( const Arg* a ) \n{\n\t// iterate over each XOR list\n\tfor ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )\n\t{\n\t\t// if the XOR list contains the arg..\n\t\tArgVectorIterator ait = std::find( _orList[i].begin(), \n\t\t                                   _orList[i].end(), a );\n\t\tif ( ait != _orList[i].end() )\n\t\t{\n\t\t\t// first check to see if a mutually exclusive switch\n\t\t\t// has not already been set\n\t\t\tfor ( ArgVectorIterator it = _orList[i].begin(); \n\t\t\t\t  it != _orList[i].end(); \n\t\t\t\t  it++ )\n\t\t\t\tif ( a != (*it) && (*it)->isSet() )\n\t\t\t\t\tthrow(CmdLineParseException(\n\t\t\t\t\t      \"Mutually exclusive argument already set!\",\n\t\t\t\t\t      (*it)->toString()));\n\n\t\t\t// go through and set each arg that is not a\n\t\t\tfor ( ArgVectorIterator it = _orList[i].begin(); \n\t\t\t\t  it != _orList[i].end(); \n\t\t\t\t  it++ )\n\t\t\t\tif ( a != (*it) )\n\t\t\t\t\t(*it)->xorSet();\n\n\t\t\t// return the number of required args that have now been set\n\t\t\tif ( (*ait)->allowMore() )\n\t\t\t\treturn 0;\n\t\t\telse\n\t\t\t\treturn static_cast<int>(_orList[i].size());\n\t\t}\n\t}\n\n\tif ( a->isRequired() )\n\t\treturn 1;\n\telse\n\t\treturn 0;\n}\n\ninline bool XorHandler::contains( const Arg* a )\n{\n\tfor ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )\n\t\tfor ( ArgVectorIterator it = _orList[i].begin(); \n\t\t\t  it != _orList[i].end(); \n\t\t\t  it++ )\t\n\t\t\tif ( a == (*it) )\n\t\t\t\treturn true;\n\n\treturn false;\n}\n\ninline std::vector< std::vector<Arg*> >& XorHandler::getXorList() \n{\n\treturn _orList;\n}\n\n\n\n//////////////////////////////////////////////////////////////////////\n//END XOR.cpp\n//////////////////////////////////////////////////////////////////////\n\n} //namespace TCLAP\n\n#endif \n"
  },
  {
    "path": "components/mkspiffs/src/tclap/ZshCompletionOutput.h",
    "content": "// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-\n\n/****************************************************************************** \n * \n *  file:  ZshCompletionOutput.h\n * \n *  Copyright (c) 2006, Oliver Kiddle\n *  All rights reverved.\n * \n *  See the file COPYING in the top directory of this distribution for\n *  more information.\n *  \n *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS \n *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \n *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n *  DEALINGS IN THE SOFTWARE.\n *  \n *****************************************************************************/ \n\n#ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H\n#define TCLAP_ZSHCOMPLETIONOUTPUT_H\n\n#include <string>\n#include <vector>\n#include <list>\n#include <iostream>\n#include <map>\n\n#include \"CmdLineInterface.h\"\n#include \"CmdLineOutput.h\"\n#include \"XorHandler.h\"\n#include \"Arg.h\"\n\nnamespace TCLAP {\n\n/**\n * A class that generates a Zsh completion function as output from the usage()\n * method for the given CmdLine and its Args.\n */\nclass ZshCompletionOutput : public CmdLineOutput\n{\n\n\tpublic:\n\n\t\tZshCompletionOutput();\n\n\t\t/**\n\t\t * Prints the usage to stdout.  Can be overridden to \n\t\t * produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t */\n\t\tvirtual void usage(CmdLineInterface& c);\n\n\t\t/**\n\t\t * Prints the version to stdout. Can be overridden \n\t\t * to produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t */\n\t\tvirtual void version(CmdLineInterface& c);\n\n\t\t/**\n\t\t * Prints (to stderr) an error message, short usage \n\t\t * Can be overridden to produce alternative behavior.\n\t\t * \\param c - The CmdLine object the output is generated for. \n\t\t * \\param e - The ArgException that caused the failure. \n\t\t */\n\t\tvirtual void failure(CmdLineInterface& c,\n\t\t\t\t\t\t     ArgException& e );\n\n\tprotected:\n\n\t\tvoid basename( std::string& s );\n\t\tvoid quoteSpecialChars( std::string& s );\n\n\t\tstd::string getMutexList( CmdLineInterface& _cmd, Arg* a );\n\t\tvoid printOption( Arg* it, std::string mutex );\n\t\tvoid printArg( Arg* it );\n\n\t\tstd::map<std::string, std::string> common;\n\t\tchar theDelimiter;\n};\n\nZshCompletionOutput::ZshCompletionOutput()\n: common(std::map<std::string, std::string>()),\n  theDelimiter('=')\n{\n\tcommon[\"host\"] = \"_hosts\";\n\tcommon[\"hostname\"] = \"_hosts\";\n\tcommon[\"file\"] = \"_files\";\n\tcommon[\"filename\"] = \"_files\";\n\tcommon[\"user\"] = \"_users\";\n\tcommon[\"username\"] = \"_users\";\n\tcommon[\"directory\"] = \"_directories\";\n\tcommon[\"path\"] = \"_directories\";\n\tcommon[\"url\"] = \"_urls\";\n}\n\ninline void ZshCompletionOutput::version(CmdLineInterface& _cmd)\n{\n\tstd::cout << _cmd.getVersion() << std::endl;\n}\n\ninline void ZshCompletionOutput::usage(CmdLineInterface& _cmd )\n{\n\tstd::list<Arg*> argList = _cmd.getArgList();\n\tstd::string progName = _cmd.getProgramName();\n\tstd::string xversion = _cmd.getVersion();\n\ttheDelimiter = _cmd.getDelimiter();\n\tbasename(progName);\n\n\tstd::cout << \"#compdef \" << progName << std::endl << std::endl <<\n\t\t\"# \" << progName << \" version \" << _cmd.getVersion() << std::endl << std::endl <<\n\t\t\"_arguments -s -S\";\n\n\tfor (ArgListIterator it = argList.begin(); it != argList.end(); it++)\n\t{\n\t\tif ( (*it)->shortID().at(0) == '<' )\n\t\t\tprintArg((*it));\n\t\telse if ( (*it)->getFlag() != \"-\" )\n\t\t\tprintOption((*it), getMutexList(_cmd, *it));\n\t}\n\n\tstd::cout << std::endl;\n}\n\ninline void ZshCompletionOutput::failure( CmdLineInterface& _cmd,\n\t\t\t\t                ArgException& e )\n{\n\tstatic_cast<void>(_cmd); // unused\n\tstd::cout << e.what() << std::endl;\n}\n\ninline void ZshCompletionOutput::quoteSpecialChars( std::string& s )\n{\n\tsize_t idx = s.find_last_of(':');\n\twhile ( idx != std::string::npos )\n\t{\n\t\ts.insert(idx, 1, '\\\\');\n\t\tidx = s.find_last_of(':', idx);\n\t}\n\tidx = s.find_last_of('\\'');\n\twhile ( idx != std::string::npos )\n\t{\n\t\ts.insert(idx, \"'\\\\'\");\n\t\tif (idx == 0)\n\t\t\tidx = std::string::npos;\n\t\telse\n\t\t\tidx = s.find_last_of('\\'', --idx);\n\t}\n}\n\ninline void ZshCompletionOutput::basename( std::string& s )\n{\n\tsize_t p = s.find_last_of('/');\n\tif ( p != std::string::npos )\n\t{\n\t\ts.erase(0, p + 1);\n\t}\n}\n\ninline void ZshCompletionOutput::printArg(Arg* a)\n{\n\tstatic int count = 1;\n\n\tstd::cout << \" \\\\\" << std::endl << \"  '\";\n\tif ( a->acceptsMultipleValues() )\n\t\tstd::cout << '*';\n\telse\n\t\tstd::cout << count++;\n\tstd::cout << ':';\n\tif ( !a->isRequired() )\n\t\tstd::cout << ':';\n\n\tstd::cout << a->getName() << ':';\n\tstd::map<std::string, std::string>::iterator compArg = common.find(a->getName());\n\tif ( compArg != common.end() )\n\t{\n\t\tstd::cout << compArg->second;\n\t}\n\telse\n\t{\n\t\tstd::cout << \"_guard \\\"^-*\\\" \" << a->getName();\n\t}\n\tstd::cout << '\\'';\n}\n\ninline void ZshCompletionOutput::printOption(Arg* a, std::string mutex)\n{\n\tstd::string flag = a->flagStartChar() + a->getFlag();\n\tstd::string name = a->nameStartString() + a->getName();\n\tstd::string desc = a->getDescription();\n\n\t// remove full stop and capitalisation from description as\n\t// this is the convention for zsh function\n\tif (!desc.compare(0, 12, \"(required)  \"))\n\t{\n\t\tdesc.erase(0, 12);\n\t}\n\tif (!desc.compare(0, 15, \"(OR required)  \"))\n\t{\n\t\tdesc.erase(0, 15);\n\t}\n\tsize_t len = desc.length();\n\tif (len && desc.at(--len) == '.')\n\t{\n\t\tdesc.erase(len);\n\t}\n\tif (len)\n\t{\n\t\tdesc.replace(0, 1, 1, tolower(desc.at(0)));\n\t}\n\n\tstd::cout << \" \\\\\" << std::endl << \"  '\" << mutex;\n\n\tif ( a->getFlag().empty() )\n\t{\n\t\tstd::cout << name;\n\t}\n\telse\n\t{\n\t\tstd::cout << \"'{\" << flag << ',' << name << \"}'\";\n\t}\n\tif ( theDelimiter == '=' && a->isValueRequired() )\n\t\tstd::cout << \"=-\";\n\tquoteSpecialChars(desc);\n\tstd::cout << '[' << desc << ']';\n\n\tif ( a->isValueRequired() )\n\t{\n\t\tstd::string arg = a->shortID();\n\t\targ.erase(0, arg.find_last_of(theDelimiter) + 1);\n\t\tif ( arg.at(arg.length()-1) == ']' )\n\t\t\targ.erase(arg.length()-1);\n\t\tif ( arg.at(arg.length()-1) == ']' )\n\t\t{\n\t\t\targ.erase(arg.length()-1);\n\t\t}\n\t\tif ( arg.at(0) == '<' )\n\t\t{\n\t\t\targ.erase(arg.length()-1);\n\t\t\targ.erase(0, 1);\n\t\t}\n\t\tsize_t p = arg.find('|');\n\t\tif ( p != std::string::npos )\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\targ.replace(p, 1, 1, ' ');\n\t\t\t}\n\t\t\twhile ( (p = arg.find_first_of('|', p)) != std::string::npos );\n\t\t\tquoteSpecialChars(arg);\n\t\t\tstd::cout << \": :(\" << arg << ')';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::cout << ':' << arg;\n\t\t\tstd::map<std::string, std::string>::iterator compArg = common.find(arg);\n\t\t\tif ( compArg != common.end() )\n\t\t\t{\n\t\t\t\tstd::cout << ':' << compArg->second;\n\t\t\t}\n\t\t}\n\t}\n\n\tstd::cout << '\\'';\n}\n\ninline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a)\n{\n\tXorHandler xorHandler = _cmd.getXorHandler();\n\tstd::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();\n\t\n\tif (a->getName() == \"help\" || a->getName() == \"version\")\n\t{\n\t\treturn \"(-)\";\n\t}\n\n\tstd::ostringstream list;\n\tif ( a->acceptsMultipleValues() )\n\t{\n\t\tlist << '*';\n\t}\n\n\tfor ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )\n\t{\n\t\tfor ( ArgVectorIterator it = xorList[i].begin();\n\t\t\tit != xorList[i].end();\n\t\t\tit++)\n\t\tif ( a == (*it) )\n\t\t{\n\t\t\tlist << '(';\n\t\t\tfor ( ArgVectorIterator iu = xorList[i].begin();\n\t\t\t\tiu != xorList[i].end();\n\t\t\t\tiu++ )\n\t\t\t{\n\t\t\t\tbool notCur = (*iu) != a;\n\t\t\t\tbool hasFlag = !(*iu)->getFlag().empty();\n\t\t\t\tif ( iu != xorList[i].begin() && (notCur || hasFlag) )\n\t\t\t\t\tlist << ' ';\n\t\t\t\tif (hasFlag)\n\t\t\t\t\tlist << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';\n\t\t\t\tif ( notCur || hasFlag )\n\t\t\t\t\tlist << (*iu)->nameStartString() << (*iu)->getName();\n\t\t\t}\n\t\t\tlist << ')';\n\t\t\treturn list.str();\n\t\t}\n\t}\n\t\n\t// wasn't found in xor list\n\tif (!a->getFlag().empty()) {\n\t\tlist << \"(\" << a->flagStartChar() << a->getFlag() << ' ' <<\n\t\t\ta->nameStartString() << a->getName() << ')';\n\t}\n\t\n\treturn list.str();\n}\n\n} //namespace TCLAP\n#endif\n"
  },
  {
    "path": "components/spidriver/component.mk",
    "content": "#\n# Main Makefile. This is basically the same as a component makefile.\n#\n# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)\n\nCOMPONENT_SRCDIRS := . \nCOMPONENT_ADD_INCLUDEDIRS := .\n"
  },
  {
    "path": "components/spidriver/spi_master_lobo.c",
    "content": "// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n/*\n----------------------------------------\nNon DMA version of the spi_master driver\n----------------------------------------\n------------------------------------------------------------------------------------\nBased on esp-idf 'spi_master', modified by LoBo (https://github.com/loboris) 03/2017\n------------------------------------------------------------------------------------\n\n* Transfers data to SPI device in direct mode, not using DMA\n* All configuration options (bus, device, transaction) are the same as in spi_master driver\n* Transfers uses the semaphore (taken in select function & given in deselect function) to protect the transfer\n* Number of the devices attached to the bus which uses hardware CS can be 3 ('NO_CS')\n* Additional devices which uses software CS can be attached to the bus, up to 'NO_DEV'\n* 'spi_bus_initialize' & 'spi_bus_remove' functions are removed, spi bus is initiated/removed in spi_lobo_bus_add_device/spi_lobo_bus_remove_device when needed\n* 'spi_lobo_bus_add_device' function has added parameter 'bus_config' and automatically initializes spi bus device if not already initialized\n* 'spi_lobo_bus_remove_device' automatically removes spi bus device if no other devices are attached to it.\n* Devices can have individual bus_configs, so different mosi, miso, sck pins can be configured for each device\n    Reconfiguring the bus is done automaticaly in 'spi_lobo_device_select' function\n* 'spi_lobo_device_select' & 'spi_lobo_device_deselect' functions handles devices configuration changes and software CS\n* Some helper functions are added ('spi_lobo_get_speed', 'spi_lobo_set_speed', ...)\n* All structures are available in header file for easy creation of user low level spi functions. See **tftfunc.c** source for examples.\n* Transimt and receive lenghts are limited only by available memory\n\n\nMain driver's function is 'spi_lobo_transfer_data()'\n\n * TRANSMIT 8-bit data to spi device from 'trans->tx_buffer' or 'trans->tx_data' (trans->lenght/8 bytes)\n * and RECEIVE data to 'trans->rx_buffer' or 'trans->rx_data' (trans->rx_length/8 bytes)\n * Lengths must be 8-bit multiples!\n * If trans->rx_buffer is NULL or trans->rx_length is 0, only transmits data\n * If trans->tx_buffer is NULL or trans->length is 0, only receives data\n * If the device is in duplex mode (SPI_DEVICE_HALFDUPLEX flag NOT set), data are transmitted and received simultaneously.\n * If the device is in half duplex mode (SPI_DEVICE_HALFDUPLEX flag IS set), data are received after transmission\n * 'address', 'command' and 'dummy bits' are transmitted before data phase IF set in device's configuration\n *   and IF 'trans->length' and 'trans->rx_length' are NOT both 0\n * If configured, devices 'pre_cb' callback is called before and 'post_cb' after the transmission\n * If device was not previously selected, it will be selected before transmission and deselected after transmission.\n\n*/\n\n/*\n Replace this include with\n #include \"driver/spi_master_lobo.h\"\n if the driver is located in esp-isf/components\n*/\n#include \"freertos/FreeRTOS.h\"\n#include <string.h>\n#include <stdio.h>\n#include \"soc/gpio_sig_map.h\"\n#include \"soc/spi_reg.h\"\n#include \"soc/dport_reg.h\"\n#include \"soc/rtc_cntl_reg.h\"\n#include \"rom/ets_sys.h\"\n#include \"esp_types.h\"\n#include \"esp_attr.h\"\n#include \"esp_log.h\"\n#include \"esp_err.h\"\n#include \"freertos/semphr.h\"\n#include \"freertos/xtensa_api.h\"\n#include \"freertos/task.h\"\n#include \"freertos/ringbuf.h\"\n#include \"soc/soc.h\"\n#include \"soc/dport_reg.h\"\n#include \"soc/uart_struct.h\"\n#include \"driver/uart.h\"\n#include \"driver/gpio.h\"\n#include \"driver/periph_ctrl.h\"\n#include \"esp_heap_caps.h\"\n#include \"driver/periph_ctrl.h\"\n#include \"spi_master_lobo.h\"\n\n\nstatic spi_lobo_host_t *spihost[3] = {NULL};\n\n\nstatic const char *SPI_TAG = \"spi_lobo_master\";\n#define SPI_CHECK(a, str, ret_val) \\\n    if (!(a)) { \\\n        ESP_LOGE(SPI_TAG,\"%s(%d): %s\", __FUNCTION__, __LINE__, str); \\\n        return (ret_val); \\\n    }\n\n/*\n Stores a bunch of per-spi-peripheral data.\n*/\ntypedef struct {\n    const uint8_t spiclk_out;       //GPIO mux output signals\n    const uint8_t spid_out;\n    const uint8_t spiq_out;\n    const uint8_t spiwp_out;\n    const uint8_t spihd_out;\n    const uint8_t spid_in;          //GPIO mux input signals\n    const uint8_t spiq_in;\n    const uint8_t spiwp_in;\n    const uint8_t spihd_in;\n    const uint8_t spics_out[3];     // /CS GPIO output mux signals\n    const uint8_t spiclk_native;    //IO pins of IO_MUX muxed signals\n    const uint8_t spid_native;\n    const uint8_t spiq_native;\n    const uint8_t spiwp_native;\n    const uint8_t spihd_native;\n    const uint8_t spics0_native;\n    const uint8_t irq;              //irq source for interrupt mux\n    const uint8_t irq_dma;          //dma irq source for interrupt mux\n    const periph_module_t module;   //peripheral module, for enabling clock etc\n    spi_dev_t *hw;                  //Pointer to the hardware registers\n} spi_signal_conn_t;\n\n/*\n Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc\n*/\nstatic const spi_signal_conn_t io_signal[3]={\n    {\n        .spiclk_out=SPICLK_OUT_IDX,\n        .spid_out=SPID_OUT_IDX,\n        .spiq_out=SPIQ_OUT_IDX,\n        .spiwp_out=SPIWP_OUT_IDX,\n        .spihd_out=SPIHD_OUT_IDX,\n        .spid_in=SPID_IN_IDX,\n        .spiq_in=SPIQ_IN_IDX,\n        .spiwp_in=SPIWP_IN_IDX,\n        .spihd_in=SPIHD_IN_IDX,\n        .spics_out={SPICS0_OUT_IDX, SPICS1_OUT_IDX, SPICS2_OUT_IDX},\n        .spiclk_native=6,\n        .spid_native=8,\n        .spiq_native=7,\n        .spiwp_native=10,\n        .spihd_native=9,\n        .spics0_native=11,\n        .irq=ETS_SPI1_INTR_SOURCE,\n        .irq_dma=ETS_SPI1_DMA_INTR_SOURCE,\n        .module=PERIPH_SPI_MODULE,\n        .hw=&SPI1\n    }, {\n        .spiclk_out=HSPICLK_OUT_IDX,\n        .spid_out=HSPID_OUT_IDX,\n        .spiq_out=HSPIQ_OUT_IDX,\n        .spiwp_out=HSPIWP_OUT_IDX,\n        .spihd_out=HSPIHD_OUT_IDX,\n        .spid_in=HSPID_IN_IDX,\n        .spiq_in=HSPIQ_IN_IDX,\n        .spiwp_in=HSPIWP_IN_IDX,\n        .spihd_in=HSPIHD_IN_IDX,\n        .spics_out={HSPICS0_OUT_IDX, HSPICS1_OUT_IDX, HSPICS2_OUT_IDX},\n        .spiclk_native=14,\n        .spid_native=13,\n        .spiq_native=12,\n        .spiwp_native=2,\n        .spihd_native=4,\n        .spics0_native=15,\n        .irq=ETS_SPI2_INTR_SOURCE,\n        .irq_dma=ETS_SPI2_DMA_INTR_SOURCE,\n        .module=PERIPH_HSPI_MODULE,\n        .hw=&SPI2\n    }, {\n        .spiclk_out=VSPICLK_OUT_IDX,\n        .spid_out=VSPID_OUT_IDX,\n        .spiq_out=VSPIQ_OUT_IDX,\n        .spiwp_out=VSPIWP_OUT_IDX,\n        .spihd_out=VSPIHD_OUT_IDX,\n        .spid_in=VSPID_IN_IDX,\n        .spiq_in=VSPIQ_IN_IDX,\n        .spiwp_in=VSPIWP_IN_IDX,\n        .spihd_in=VSPIHD_IN_IDX,\n        .spics_out={VSPICS0_OUT_IDX, VSPICS1_OUT_IDX, VSPICS2_OUT_IDX},\n        .spiclk_native=18,\n        .spid_native=23,\n        .spiq_native=19,\n        .spiwp_native=22,\n        .spihd_native=21,\n        .spics0_native=5,\n        .irq=ETS_SPI3_INTR_SOURCE,\n        .irq_dma=ETS_SPI3_DMA_INTR_SOURCE,\n        .module=PERIPH_VSPI_MODULE,\n        .hw=&SPI3\n    }\n};\n\n\n//======================================================================================================\n\n#define DMA_CHANNEL_ENABLED(dma_chan)    (BIT(dma_chan-1))\n\ntypedef void(*dmaworkaround_cb_t)(void *arg);\n\n//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to.\n//--------------------------------------------------------------------------------------------\nvoid spi_lobo_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)\n{\n    int n = 0;\n    while (len) {\n        int dmachunklen = len;\n        if (dmachunklen > SPI_MAX_DMA_LEN) dmachunklen = SPI_MAX_DMA_LEN;\n        if (isrx) {\n            //Receive needs DMA length rounded to next 32-bit boundary\n            dmadesc[n].size = (dmachunklen + 3) & (~3);\n            dmadesc[n].length = (dmachunklen + 3) & (~3);\n        } else {\n            dmadesc[n].size = dmachunklen;\n            dmadesc[n].length = dmachunklen;\n        }\n        dmadesc[n].buf = (uint8_t *)data;\n        dmadesc[n].eof = 0;\n        dmadesc[n].sosf = 0;\n        dmadesc[n].owner = 1;\n        dmadesc[n].qe.stqe_next = &dmadesc[n + 1];\n        len -= dmachunklen;\n        data += dmachunklen;\n        n++;\n    }\n    dmadesc[n - 1].eof = 1; //Mark last DMA desc as end of stream.\n    dmadesc[n - 1].qe.stqe_next = NULL;\n}\n\n\n/*\nCode for workaround for DMA issue in ESP32 v0/v1 silicon\n*/\n\n\nstatic volatile int dmaworkaround_channels_busy[2] = {0, 0};\nstatic dmaworkaround_cb_t dmaworkaround_cb;\nstatic void *dmaworkaround_cb_arg;\nstatic portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;\nstatic int dmaworkaround_waiting_for_chan = 0;\nstatic bool spi_periph_claimed[3] = {true, false, false};\nstatic uint8_t spi_dma_chan_enabled = 0;\nstatic portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;\n\n//--------------------------------------------------------------------------------------------\nbool IRAM_ATTR spi_lobo_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)\n{\n    int otherchan = (dmachan == 1) ? 2 : 1;\n    bool ret;\n    portENTER_CRITICAL(&dmaworkaround_mux);\n    if (dmaworkaround_channels_busy[otherchan-1]) {\n        //Other channel is busy. Call back when it's done.\n        dmaworkaround_cb = cb;\n        dmaworkaround_cb_arg = arg;\n        dmaworkaround_waiting_for_chan = otherchan;\n        ret = false;\n    } else {\n        //Reset DMA\n        DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);\n        DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);\n        ret = true;\n    }\n    portEXIT_CRITICAL(&dmaworkaround_mux);\n    return ret;\n}\n\n//-------------------------------------------------------\nbool IRAM_ATTR spi_lobo_dmaworkaround_reset_in_progress()\n{\n    return (dmaworkaround_waiting_for_chan != 0);\n}\n\n//-----------------------------------------------------\nvoid IRAM_ATTR spi_lobo_dmaworkaround_idle(int dmachan)\n{\n    portENTER_CRITICAL(&dmaworkaround_mux);\n    dmaworkaround_channels_busy[dmachan-1] = 0;\n    if (dmaworkaround_waiting_for_chan == dmachan) {\n        //Reset DMA\n        DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);\n        DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);\n        dmaworkaround_waiting_for_chan = 0;\n        //Call callback\n        dmaworkaround_cb(dmaworkaround_cb_arg);\n\n    }\n    portEXIT_CRITICAL(&dmaworkaround_mux);\n}\n\n//----------------------------------------------------------------\nvoid IRAM_ATTR spi_lobo_dmaworkaround_transfer_active(int dmachan)\n{\n    portENTER_CRITICAL(&dmaworkaround_mux);\n    dmaworkaround_channels_busy[dmachan-1] = 1;\n    portEXIT_CRITICAL(&dmaworkaround_mux);\n}\n\n//Returns true if this peripheral is successfully claimed, false if otherwise.\n//-----------------------------------------------------\nbool spi_lobo_periph_claim(spi_lobo_host_device_t host)\n{\n    bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], false, true);\n    if (ret) periph_module_enable(io_signal[host].module);\n    return ret;\n}\n\n//Returns true if this peripheral is successfully freed, false if otherwise.\n//-----------------------------------------------\nbool spi_lobo_periph_free(spi_lobo_host_device_t host)\n{\n    bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], true, false);\n    if (ret) periph_module_disable(io_signal[host].module);\n    return ret;\n}\n\n//-----------------------------------------\nbool spi_lobo_dma_chan_claim (int dma_chan)\n{\n    bool ret = false;\n    assert( dma_chan == 1 || dma_chan == 2 );\n\n    portENTER_CRITICAL(&spi_dma_spinlock);\n    if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) {\n        // get the channel only when it's not claimed yet.\n        spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan);\n        ret = true;\n    }\n    periph_module_enable( PERIPH_SPI_DMA_MODULE );\n    portEXIT_CRITICAL(&spi_dma_spinlock);\n\n    return ret;\n}\n\n//---------------------------------------\nbool spi_lobo_dma_chan_free(int dma_chan)\n{\n    assert( dma_chan == 1 || dma_chan == 2 );\n    assert( spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan) );\n\n    portENTER_CRITICAL(&spi_dma_spinlock);\n    spi_dma_chan_enabled &= ~DMA_CHANNEL_ENABLED(dma_chan);\n    if ( spi_dma_chan_enabled == 0 ) {\n        //disable the DMA only when all the channels are freed.\n        periph_module_disable( PERIPH_SPI_DMA_MODULE );\n    }\n    portEXIT_CRITICAL(&spi_dma_spinlock);\n\n    return true;\n}\n\n\n//======================================================================================================\n\n\n//----------------------------------------------------------------------------------------------------------------\nstatic esp_err_t spi_lobo_bus_initialize(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, int init)\n{\n    bool native=true, spi_chan_claimed, dma_chan_claimed;\n\n    if (init > 0) {\n        /* ToDo: remove this when we have flash operations cooperating with this */\n        SPI_CHECK(host!=SPI_HOST, \"SPI1 is not supported\", ESP_ERR_NOT_SUPPORTED);\n\n        SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, \"invalid host\", ESP_ERR_INVALID_ARG);\n        SPI_CHECK(spihost[host]==NULL, \"host already in use\", ESP_ERR_INVALID_STATE);\n    }\n    else {\n        SPI_CHECK(spihost[host]!=NULL, \"host not in use\", ESP_ERR_INVALID_STATE);\n    }\n    \n    SPI_CHECK(bus_config->mosi_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), \"spid pin invalid\", ESP_ERR_INVALID_ARG);\n    SPI_CHECK(bus_config->sclk_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->sclk_io_num), \"spiclk pin invalid\", ESP_ERR_INVALID_ARG);\n    SPI_CHECK(bus_config->miso_io_num<0 || GPIO_IS_VALID_GPIO(bus_config->miso_io_num), \"spiq pin invalid\", ESP_ERR_INVALID_ARG);\n    SPI_CHECK(bus_config->quadwp_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadwp_io_num), \"spiwp pin invalid\", ESP_ERR_INVALID_ARG);\n    SPI_CHECK(bus_config->quadhd_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadhd_io_num), \"spihd pin invalid\", ESP_ERR_INVALID_ARG);\n\n    if (init > 0) {\n        spi_chan_claimed=spi_lobo_periph_claim(host);\n        SPI_CHECK(spi_chan_claimed, \"host already in use\", ESP_ERR_INVALID_STATE);\n\n        //spihost[host]=malloc(sizeof(spi_lobo_host_t));\n\t\tspihost[host]=heap_caps_malloc(sizeof(spi_lobo_host_t), MALLOC_CAP_DMA);\n\t\tif (spihost[host]==NULL) return ESP_ERR_NO_MEM;\n\t\tmemset(spihost[host], 0, sizeof(spi_lobo_host_t));\n\t\t// Create semaphore\n\t\tspihost[host]->spi_lobo_bus_mutex = xSemaphoreCreateMutex();\n\t\tif (!spihost[host]->spi_lobo_bus_mutex) return ESP_ERR_NO_MEM;\n    }\n\n    spihost[host]->cur_device = -1;\n    memcpy(&spihost[host]->cur_bus_config, bus_config, sizeof(spi_lobo_bus_config_t));\n\n    //Check if the selected pins correspond to the native pins of the peripheral\n    if (bus_config->mosi_io_num >= 0 && bus_config->mosi_io_num!=io_signal[host].spid_native) native=false;\n    if (bus_config->miso_io_num >= 0 && bus_config->miso_io_num!=io_signal[host].spiq_native) native=false;\n    if (bus_config->sclk_io_num >= 0 && bus_config->sclk_io_num!=io_signal[host].spiclk_native) native=false;\n    if (bus_config->quadwp_io_num >= 0 && bus_config->quadwp_io_num!=io_signal[host].spiwp_native) native=false;\n    if (bus_config->quadhd_io_num >= 0 && bus_config->quadhd_io_num!=io_signal[host].spihd_native) native=false;\n    \n    spihost[host]->no_gpio_matrix=native;\n    if (native) {\n        //All SPI native pin selections resolve to 1, so we put that here instead of trying to figure\n        //out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.\n        if (bus_config->mosi_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], 1);\n        if (bus_config->miso_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], 1);\n        if (bus_config->quadwp_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], 1);\n        if (bus_config->quadhd_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], 1);\n        if (bus_config->sclk_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], 1);\n    } else {\n        //Use GPIO \n        if (bus_config->mosi_io_num>0) {\n            PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], PIN_FUNC_GPIO);\n            gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_OUTPUT);\n            gpio_matrix_out(bus_config->mosi_io_num, io_signal[host].spid_out, false, false);\n            gpio_matrix_in(bus_config->mosi_io_num, io_signal[host].spid_in, false);\n        }\n        if (bus_config->miso_io_num>0) {\n            PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], PIN_FUNC_GPIO);\n            gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT);\n            gpio_matrix_out(bus_config->miso_io_num, io_signal[host].spiq_out, false, false);\n            gpio_matrix_in(bus_config->miso_io_num, io_signal[host].spiq_in, false);\n        }\n        if (bus_config->quadwp_io_num>0) {\n            PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], PIN_FUNC_GPIO);\n            gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_OUTPUT);\n            gpio_matrix_out(bus_config->quadwp_io_num, io_signal[host].spiwp_out, false, false);\n            gpio_matrix_in(bus_config->quadwp_io_num, io_signal[host].spiwp_in, false);\n        }\n        if (bus_config->quadhd_io_num>0) {\n            PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], PIN_FUNC_GPIO);\n            gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_OUTPUT);\n            gpio_matrix_out(bus_config->quadhd_io_num, io_signal[host].spihd_out, false, false);\n            gpio_matrix_in(bus_config->quadhd_io_num, io_signal[host].spihd_in, false);\n        }\n        if (bus_config->sclk_io_num>0) {\n            PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], PIN_FUNC_GPIO);\n            gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_OUTPUT);\n            gpio_matrix_out(bus_config->sclk_io_num, io_signal[host].spiclk_out, false, false);\n        }\n    }\n\tperiph_module_enable(io_signal[host].module);\n\tspihost[host]->hw=io_signal[host].hw;\n\n\tif (init > 0) {\n        dma_chan_claimed=spi_lobo_dma_chan_claim(init);\n        if ( !dma_chan_claimed ) {\n        \tspi_lobo_periph_free( host );\n            SPI_CHECK(dma_chan_claimed, \"dma channel already in use\", ESP_ERR_INVALID_STATE);\n        }\n\t    spihost[host]->dma_chan = init;\n        //See how many dma descriptors we need and allocate them\n        int dma_desc_ct=(bus_config->max_transfer_sz+SPI_MAX_DMA_LEN-1)/SPI_MAX_DMA_LEN;\n        if (dma_desc_ct==0) dma_desc_ct=1; //default to 4k when max is not given\n        spihost[host]->max_transfer_sz = dma_desc_ct*SPI_MAX_DMA_LEN;\n\n        spihost[host]->dmadesc_tx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA);\n        spihost[host]->dmadesc_rx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA);\n        if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) goto nomem;\n\n        //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.\n        spi_lobo_dmaworkaround_idle(spihost[host]->dma_chan);\n\n        // Reset DMA\n        spihost[host]->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;\n        spihost[host]->hw->dma_out_link.start=0;\n        spihost[host]->hw->dma_in_link.start=0;\n        spihost[host]->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);\n        spihost[host]->hw->dma_conf.out_data_burst_en=1;\n\n        //Reset timing\n        spihost[host]->hw->ctrl2.val=0;\n\n        //Disable unneeded ints\n        spihost[host]->hw->slave.rd_buf_done=0;\n        spihost[host]->hw->slave.wr_buf_done=0;\n        spihost[host]->hw->slave.rd_sta_done=0;\n        spihost[host]->hw->slave.wr_sta_done=0;\n        spihost[host]->hw->slave.rd_buf_inten=0;\n        spihost[host]->hw->slave.wr_buf_inten=0;\n        spihost[host]->hw->slave.rd_sta_inten=0;\n        spihost[host]->hw->slave.wr_sta_inten=0;\n\n        //Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as\n        //disabled.  This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling\n        //any transactions that are queued.\n        spihost[host]->hw->slave.trans_inten=1;\n        spihost[host]->hw->slave.trans_done=1;\n\n\t\t//Select DMA channel.\n\t\tDPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, init, (host * 2));\n    }\n    return ESP_OK;\n\nnomem:\n\tif (spihost[host]) {\n\t\tfree(spihost[host]->dmadesc_tx);\n\t\tfree(spihost[host]->dmadesc_rx);\n\t}\n\tfree(spihost[host]);\n    spi_lobo_periph_free(host);\n\treturn ESP_ERR_NO_MEM;\n}\n\n//---------------------------------------------------------------------------\nstatic esp_err_t spi_lobo_bus_free(spi_lobo_host_device_t host, int dofree)\n{\n\tif ((host == SPI_HOST) || (host >VSPI_HOST)) return ESP_ERR_NOT_SUPPORTED;  // invalid host\n\n\tif (spihost[host] == NULL) return ESP_ERR_INVALID_STATE;  // host not in use\n\n    if (dofree) {\n\t\tfor (int x=0; x<NO_DEV; x++) {\n\t\t\tif (spihost[host]->device[x] != NULL) return ESP_ERR_INVALID_STATE;  // not all devices freed\n\t\t}\n    }\n    if ( spihost[host]->dma_chan > 0 ) {\n        spi_lobo_dma_chan_free ( spihost[host]->dma_chan );\n    }\n    spihost[host]->hw->slave.trans_inten=0;\n    spihost[host]->hw->slave.trans_done=0;\n    spi_lobo_periph_free(host);\n\n    if (dofree) {\n\t\tvSemaphoreDelete(spihost[host]->spi_lobo_bus_mutex);\n\t    free(spihost[host]->dmadesc_tx);\n\t    free(spihost[host]->dmadesc_rx);\n\t\tfree(spihost[host]);\n\t\tspihost[host] = NULL;\n    }\n    return ESP_OK;\n}\n\n//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nesp_err_t spi_lobo_bus_add_device(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, spi_lobo_device_interface_config_t *dev_config, spi_lobo_device_handle_t *handle)\n{\n\tif ((host == SPI_HOST) || (host >VSPI_HOST)) return ESP_ERR_NOT_SUPPORTED;  // invalid host\n\t\n\tif (spihost[host] == NULL) {\n\t\tesp_err_t ret = spi_lobo_bus_initialize(host, bus_config, 1);\n\t\tif (ret) return ret;\n\t}\n\t\n\tint freecs, maxdev;\n    int apbclk=APB_CLK_FREQ;\n\n\tif (spihost[host] == NULL) return ESP_ERR_INVALID_STATE;\n\n    if (dev_config->spics_io_num >= 0) {\n\t\tif (!GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_io_num)) return  ESP_ERR_INVALID_ARG;\n\t\tif (dev_config->spics_ext_io_num > 0) dev_config->spics_ext_io_num = -1;\n\t}\n\telse {\n\t\t//if ((dev_config->spics_ext_io_num <= 0) || (!GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_ext_io_num))) return ESP_ERR_INVALID_ARG;\n\t}\n\n    //ToDo: Check if some other device uses the same 'spics_ext_io_num'\n\n    if (dev_config->clock_speed_hz == 0) return ESP_ERR_INVALID_ARG;\n\tif (dev_config->spics_io_num > 0) maxdev = NO_CS;\n\telse maxdev = NO_DEV;\n\n    for (freecs=0; freecs<maxdev; freecs++) {\n        //See if this slot is free; reserve if it is by putting a dummy pointer in the slot. We use an atomic compare&swap to make this thread-safe.\n        if (__sync_bool_compare_and_swap(&spihost[host]->device[freecs], NULL, (spi_lobo_device_t *)1)) break;\n    }\n    if (freecs == maxdev) return ESP_ERR_NOT_FOUND;\n\n    // The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full\n    // duplex mode does absolutely nothing on the ESP32.\n    if ((dev_config->cs_ena_pretrans != 0) && (dev_config->flags & SPI_DEVICE_HALFDUPLEX)) return ESP_ERR_INVALID_ARG;\n\n    // Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections.\n    if (((dev_config->flags & SPI_DEVICE_HALFDUPLEX)==0) && (dev_config->clock_speed_hz > ((apbclk*2)/5)) && (!spihost[host]->no_gpio_matrix)) return ESP_ERR_INVALID_ARG;\n\n    //Allocate memory for device\n    spi_lobo_device_t *dev=malloc(sizeof(spi_lobo_device_t));\n    if (dev==NULL) return ESP_ERR_NO_MEM;\n\n    memset(dev, 0, sizeof(spi_lobo_device_t));\n    spihost[host]->device[freecs]=dev;\n\n    if (dev_config->duty_cycle_pos==0) dev_config->duty_cycle_pos=128;\n    dev->host=spihost[host];\n\tdev->host_dev = host;\n\n    //We want to save a copy of the dev config in the dev struct.\n    memcpy(&dev->cfg, dev_config, sizeof(spi_lobo_device_interface_config_t));\n    //We want to save a copy of the bus config in the dev struct.\n    memcpy(&dev->bus_config, bus_config, sizeof(spi_lobo_bus_config_t));\n\n    //Set CS pin, CS options\n    if (dev_config->spics_io_num > 0) {\n        if (spihost[host]->no_gpio_matrix &&dev_config->spics_io_num == io_signal[host].spics0_native && freecs==0) {\n            //Again, the cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.\n            PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], 1);\n        } else {\n            //Use GPIO matrix\n            PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], PIN_FUNC_GPIO);\n            gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT);\n            gpio_matrix_out(dev_config->spics_io_num, io_signal[host].spics_out[freecs], false, false);\n        }\n    }\n    else if (dev_config->spics_ext_io_num >= 0) {\n\t\tgpio_set_direction(dev_config->spics_ext_io_num, GPIO_MODE_OUTPUT);\n\t\tgpio_set_level(dev_config->spics_ext_io_num, 1);\n\t}\n    if (dev_config->flags & SPI_DEVICE_CLK_AS_CS) {\n        spihost[host]->hw->pin.master_ck_sel |= (1<<freecs);\n    } else {\n        spihost[host]->hw->pin.master_ck_sel &= (1<<freecs);\n    }\n    if (dev_config->flags & SPI_DEVICE_POSITIVE_CS) {\n        spihost[host]->hw->pin.master_cs_pol |= (1<<freecs);\n    } else {\n        spihost[host]->hw->pin.master_cs_pol &= (1<<freecs);\n    }\n\n    *handle = dev;\n    return ESP_OK;\n}\n\n//-------------------------------------------------------------------\nesp_err_t spi_lobo_bus_remove_device(spi_lobo_device_handle_t handle)\n{\n    int x;\n    if (handle == NULL) return ESP_ERR_INVALID_ARG;\n\n    //Remove device from list of csses and free memory\n    for (x=0; x<NO_DEV; x++) {\n        if (handle->host->device[x] == handle) handle->host->device[x]=NULL;\n    }\n\t\n\t// Check if all devices are removed from this host and free the bus if yes\n\tfor (x=0; x<NO_DEV; x++) {\n\t\tif (spihost[handle->host_dev]->device[x] !=NULL) break;\n\t}\n\tif (x == NO_DEV) {\n\t\tfree(handle);\n\t\tspi_lobo_bus_free(handle->host_dev, 1);\n\t}\n\telse free(handle);\n\n\treturn ESP_OK;\n}\n\n//-----------------------------------------------------------------\nstatic int IRAM_ATTR spi_freq_for_pre_n(int fapb, int pre, int n) {\n    return (fapb / (pre * n));\n}\n\n/*\n * Set the SPI clock to a certain frequency. Returns the effective frequency set, which may be slightly\n * different from the requested frequency.\n */\n//-----------------------------------------------------------------------------------\nstatic int IRAM_ATTR spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) {\n   int pre, n, h, l, eff_clk;\n\n    //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.\n    if (hz>((fapb/4)*3)) {\n        //Using Fapb directly will give us the best result here.\n        hw->clock.clkcnt_l=0;\n        hw->clock.clkcnt_h=0;\n        hw->clock.clkcnt_n=0;\n        hw->clock.clkdiv_pre=0;\n        hw->clock.clk_equ_sysclk=1;\n        eff_clk=fapb;\n    } else {\n        //For best duty cycle resolution, we want n to be as close to 32 as possible, but\n        //we also need a pre/n combo that gets us as close as possible to the intended freq.\n        //To do this, we bruteforce n and calculate the best pre to go along with that.\n        //If there's a choice between pre/n combos that give the same result, use the one\n        //with the higher n.\n        int bestn=-1;\n        int bestpre=-1;\n        int besterr=0;\n        int errval;\n        for (n=1; n<=64; n++) {\n            //Effectively, this does pre=round((fapb/n)/hz).\n            pre=((fapb/n)+(hz/2))/hz;\n            if (pre<=0) pre=1;\n            if (pre>8192) pre=8192;\n            errval=abs(spi_freq_for_pre_n(fapb, pre, n)-hz);\n            if (bestn==-1 || errval<=besterr) {\n                besterr=errval;\n                bestn=n;\n                bestpre=pre;\n            }\n        }\n\n        n=bestn;\n        pre=bestpre;\n        l=n;\n        //This effectively does round((duty_cycle*n)/256)\n        h=(duty_cycle*n+127)/256;\n        if (h<=0) h=1;\n\n        hw->clock.clk_equ_sysclk=0;\n        hw->clock.clkcnt_n=n-1;\n        hw->clock.clkdiv_pre=pre-1;\n        hw->clock.clkcnt_h=h-1;\n        hw->clock.clkcnt_l=l-1;\n        eff_clk=spi_freq_for_pre_n(fapb, pre, n);\n    }\n    return eff_clk;\n}\n\n\n\n//------------------------------------------------------------------------------------\nesp_err_t IRAM_ATTR spi_lobo_device_select(spi_lobo_device_handle_t handle, int force)\n{\n\tif (handle == NULL) return ESP_ERR_INVALID_ARG;\n\n\tif ((handle->cfg.selected == 1) && (!force)) return ESP_OK;  // already selected\n\n\tint i;\n\tspi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;\n\n\t// find device's host bus\n\tfor (i=0; i<NO_DEV; i++) {\n\t\tif (host->device[i] == handle) break;\n\t}\n\tif (i == NO_DEV) return ESP_ERR_INVALID_ARG;\n\n\tif (!(xSemaphoreTake(host->spi_lobo_bus_mutex, SPI_SEMAPHORE_WAIT))) return ESP_ERR_INVALID_STATE;\n\n\t// Check if previously used device's bus device is the same\n\tif (memcmp(&host->cur_bus_config, &handle->bus_config, sizeof(spi_lobo_bus_config_t)) != 0) {\n\t\t// device has different bus configuration, we need to reconfigure the bus\n\t\tesp_err_t err = spi_lobo_bus_free(1, 0);\n\t\tif (err) {\n\t\t\txSemaphoreGive(host->spi_lobo_bus_mutex);\n\t\t\treturn err;\n\t\t}\n\t\terr = spi_lobo_bus_initialize(i, &handle->bus_config, -1);\n\t\tif (err) {\n\t\t\txSemaphoreGive(host->spi_lobo_bus_mutex);\n\t\t\treturn err;\n\t\t}\n\t}\n\n\t//Reconfigure according to device settings, but only if the device changed or forced.\n\tif ((force) || (host->device[host->cur_device] != handle)) {\n\t    //Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have clock scaling working.\n\t\tint apbclk=APB_CLK_FREQ;\n\n\t    //Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections.\n\t    if (((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) == 0) && (handle->cfg.clock_speed_hz > ((apbclk*2)/5)) && (!host->no_gpio_matrix)) {\n\t    \t// set speed to 32 MHz\n\t    \thandle->cfg.clock_speed_hz = (apbclk*2)/5;\n\t    }\n\n\t\tint effclk=spi_set_clock(host->hw, apbclk, handle->cfg.clock_speed_hz, handle->cfg.duty_cycle_pos);\n\t\t//Configure bit order\n\t\thost->hw->ctrl.rd_bit_order=(handle->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0;\n\t\thost->hw->ctrl.wr_bit_order=(handle->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0;\n\t\t\n\t\t//Configure polarity\n        //SPI iface needs to be configured for a delay in some cases.\n\t\tint nodelay=0;\n        int extra_dummy=0;\n        if (host->no_gpio_matrix) {\n            if (effclk >= apbclk/2) {\n                nodelay=1;\n            }\n        } else {\n            if (effclk >= apbclk/2) {\n                nodelay=1;\n                extra_dummy=1;          //Note: This only works on half-duplex connections. spi_lobo_bus_add_device checks for this.\n            } else if (effclk >= apbclk/4) {\n                nodelay=1;\n            }\n        }\n\t\tif (handle->cfg.mode==0) {\n\t\t\thost->hw->pin.ck_idle_edge=0;\n\t\t\thost->hw->user.ck_out_edge=0;\n\t\t\thost->hw->ctrl2.miso_delay_mode=nodelay?0:2;\n\t\t} else if (handle->cfg.mode==1) {\n\t\t\thost->hw->pin.ck_idle_edge=0;\n\t\t\thost->hw->user.ck_out_edge=1;\n\t\t\thost->hw->ctrl2.miso_delay_mode=nodelay?0:1;\n\t\t} else if (handle->cfg.mode==2) {\n\t\t\thost->hw->pin.ck_idle_edge=1;\n\t\t\thost->hw->user.ck_out_edge=1;\n\t\t\thost->hw->ctrl2.miso_delay_mode=nodelay?0:1;\n\t\t} else if (handle->cfg.mode==3) {\n\t\t\thost->hw->pin.ck_idle_edge=1;\n\t\t\thost->hw->user.ck_out_edge=0;\n\t\t\thost->hw->ctrl2.miso_delay_mode=nodelay?0:2;\n\t\t}\n\n\t\t//Configure bit sizes, load addr and command\n\t\thost->hw->user.usr_dummy=(handle->cfg.dummy_bits+extra_dummy)?1:0;\n\t\thost->hw->user.usr_addr=(handle->cfg.address_bits)?1:0;\n\t\thost->hw->user.usr_command=(handle->cfg.command_bits)?1:0;\n\t\thost->hw->user1.usr_addr_bitlen=handle->cfg.address_bits-1;\n\t\thost->hw->user1.usr_dummy_cyclelen=handle->cfg.dummy_bits+extra_dummy-1;\n\t\thost->hw->user2.usr_command_bitlen=handle->cfg.command_bits-1;\n\t\t//Configure misc stuff\n\t\thost->hw->user.doutdin=(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX)?0:1;\n\t\thost->hw->user.sio=(handle->cfg.flags & SPI_DEVICE_3WIRE)?1:0;\n\n\t\thost->hw->ctrl2.setup_time=handle->cfg.cs_ena_pretrans-1;\n\t\thost->hw->user.cs_setup=handle->cfg.cs_ena_pretrans?1:0;\n\t\thost->hw->ctrl2.hold_time=handle->cfg.cs_ena_posttrans-1;\n\t\thost->hw->user.cs_hold=(handle->cfg.cs_ena_posttrans)?1:0;\n\n\t\t//Configure CS pin\n\t\thost->hw->pin.cs0_dis=(i==0)?0:1;\n\t\thost->hw->pin.cs1_dis=(i==1)?0:1;\n\t\thost->hw->pin.cs2_dis=(i==2)?0:1;\n\t\t\n\t\thost->cur_device = i;\n\t}\n\n\tif ((handle->cfg.spics_io_num < 0) && (handle->cfg.spics_ext_io_num > 0)) {\n\t\tgpio_set_level(handle->cfg.spics_ext_io_num, 0);\n\t}\n\n\thandle->cfg.selected = 1;\n\n\treturn ESP_OK;\n}\n\n//---------------------------------------------------------------------------\nesp_err_t IRAM_ATTR spi_lobo_device_deselect(spi_lobo_device_handle_t handle)\n{\n\tif (handle == NULL) return ESP_ERR_INVALID_ARG;\n\n\tif (handle->cfg.selected == 0) return ESP_OK;  // already deselected\n\n\tint i;\n\tspi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;\n\n\tfor (i=0; i<NO_DEV; i++) {\n\t\tif (host->device[i] == handle) break;\n\t}\n\tif (i == NO_DEV) return ESP_ERR_INVALID_ARG;\n\t\n\tif (host->device[host->cur_device] == handle) {\n\t\tif ((handle->cfg.spics_io_num < 0) && (handle->cfg.spics_ext_io_num > 0)) {\n\t\t\tgpio_set_level(handle->cfg.spics_ext_io_num, 1);\n\t\t}\n\t}\n\n\thandle->cfg.selected = 0;\n\txSemaphoreGive(host->spi_lobo_bus_mutex);\n\n\treturn ESP_OK;\n}\n\n//--------------------------------------------------------------------------------\nesp_err_t IRAM_ATTR spi_lobo_device_TakeSemaphore(spi_lobo_device_handle_t handle)\n{\n\tif (!(xSemaphoreTake(handle->host->spi_lobo_bus_mutex, SPI_SEMAPHORE_WAIT))) return ESP_ERR_INVALID_STATE;\n\telse return ESP_OK;\n}\n\n//---------------------------------------------------------------------------\nvoid IRAM_ATTR spi_lobo_device_GiveSemaphore(spi_lobo_device_handle_t handle)\n{\n\txSemaphoreTake(handle->host->spi_lobo_bus_mutex, portMAX_DELAY);\n}\n\n//----------------------------------------------------------\nuint32_t spi_lobo_get_speed(spi_lobo_device_handle_t handle)\n{\n\tspi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;\n\tuint32_t speed = 0;\n\tif (spi_lobo_device_select(handle, 0) == ESP_OK) {\n\t\tif (host->hw->clock.clk_equ_sysclk == 1) speed = 80000000;\n\t\telse speed =  80000000/(host->hw->clock.clkdiv_pre+1)/(host->hw->clock.clkcnt_n+1);\n\t}\n\tspi_lobo_device_deselect(handle);\n\treturn speed;\n}\n\n//--------------------------------------------------------------------------\nuint32_t spi_lobo_set_speed(spi_lobo_device_handle_t handle, uint32_t speed)\n{\n\tspi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;\n\tuint32_t newspeed = 0;\n\tif (spi_lobo_device_select(handle, 0) == ESP_OK) {\n\t\tspi_lobo_device_deselect(handle);\n\t\thandle->cfg.clock_speed_hz = speed;\n\t\tif (spi_lobo_device_select(handle, 1) == ESP_OK) {\n\t\t\tif (host->hw->clock.clk_equ_sysclk == 1) newspeed = 80000000;\n\t\t\telse newspeed =  80000000/(host->hw->clock.clkdiv_pre+1)/(host->hw->clock.clkcnt_n+1);\n\t\t}\n\t}\n\tspi_lobo_device_deselect(handle);\n\t\n\treturn newspeed;\n}\n\n//-------------------------------------------------------------\nbool spi_lobo_uses_native_pins(spi_lobo_device_handle_t handle)\n{\n\treturn handle->host->no_gpio_matrix;\n}\n\n//-------------------------------------------------------------------\nvoid spi_lobo_get_native_pins(int host, int *sdi, int *sdo, int *sck)\n{\n\t*sdo = io_signal[host].spid_native;\n\t*sdi = io_signal[host].spiq_native;\n\t*sck = io_signal[host].spiclk_native;\n}\n\n/*\nWhen using  'spi_lobo_transfer_data' function we can have several scenarios:\n\nA: Send only      (trans->rxlength = 0)\nB: Receive only   (trans->txlength = 0)\nC: Send & receive (trans->txlength > 0 & trans->rxlength > 0)\nD: No operation   (trans->txlength = 0 & trans->rxlength = 0)\n\n*/\n//----------------------------------------------------------------------------------------------------------\nesp_err_t IRAM_ATTR spi_lobo_transfer_data(spi_lobo_device_handle_t handle, spi_lobo_transaction_t *trans) {\n\tif (!handle) return ESP_ERR_INVALID_ARG;\n\n\t// *** For now we can only handle 8-bit bytes transmission\n\tif (((trans->length % 8) != 0) || ((trans->rxlength % 8) != 0)) return ESP_ERR_INVALID_ARG;\n\n\tspi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;\n\tesp_err_t ret;\n\tuint8_t do_deselect = 0;\n    const uint8_t *txbuffer = NULL;\n\tuint8_t *rxbuffer = NULL;\n\n\tif (trans->flags & SPI_TRANS_USE_TXDATA) {\n        // Send data from 'trans->tx_data'\n\t\ttxbuffer=(uint8_t*)&trans->tx_data[0];\n\t} else {\n        // Send data from 'trans->tx_buffer'\n\t\ttxbuffer=(uint8_t*)trans->tx_buffer;\n\t}\n\tif (trans->flags & SPI_TRANS_USE_RXDATA) {\n        // Receive data to 'trans->rx_data'\n\t\trxbuffer=(uint8_t*)&trans->rx_data[0];\n\t} else {\n        // Receive data to 'trans->rx_buffer'\n\t\trxbuffer=(uint8_t*)trans->rx_buffer;\n\t}\n\n\t// ** Set transmit & receive length in bytes\n\tuint32_t txlen = trans->length / 8;\n\tuint32_t rxlen = trans->rxlength / 8;\n\n\tif (txbuffer == NULL) txlen = 0;\n\tif (rxbuffer == NULL) rxlen = 0;\n\tif ((rxlen == 0) && (txlen == 0)) {\n        // ** NOTHING TO SEND or RECEIVE, return\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    // If using 'trans->tx_data' and/or 'trans->rx_data', maximum 4 bytes can be sent/received\n\tif ((txbuffer == &trans->tx_data[0]) && (txlen > 4)) return ESP_ERR_INVALID_ARG;\n\tif ((rxbuffer == &trans->rx_data[0]) && (rxlen > 4)) return ESP_ERR_INVALID_ARG;\n\n\t// --- Wait for SPI bus ready ---\n\twhile (host->hw->cmd.usr);\n\n    // ** If the device was not selected, select it\n\tif (handle->cfg.selected == 0) {\n\t\tret = spi_lobo_device_select(handle, 0);\n\t\tif (ret) return ret;\n\t\tdo_deselect = 1;     // We will deselect the device after the operation !\n\t}\n\n\t// ** Call pre-transmission callback, if any\n\tif (handle->cfg.pre_cb) handle->cfg.pre_cb(trans);\n\n    // Test if operating in full duplex mode\n\tuint8_t duplex = 1;\n\tif (handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) duplex = 0; // Half duplex mode !\n\n    uint32_t bits, rdbits;\n\tuint32_t wd;\n\tuint8_t bc, rdidx;\n\tuint32_t rdcount = rxlen;\t// Total number of bytes to read\n\tuint32_t count = 0;\t\t\t// number of bytes transmitted\n\tuint32_t rd_read = 0;\t\t// Number of bytes read so far\n\n\thost->hw->user.usr_mosi_highpart = 0; // use the whole spi buffer\n\n    // ** Check if address phase will be used\n\thost->hw->user2.usr_command_value=trans->command;\n\tif (handle->cfg.address_bits>32) {\n\t\thost->hw->addr=trans->address >> 32;\n\t\thost->hw->slv_wr_status=trans->address & 0xffffffff;\n\t} else {\n\t\thost->hw->addr=trans->address & 0xffffffff;\n\t}\n\n\t// Check if we have to transmit some data\n\tif (txlen > 0) {\n\t\thost->hw->user.usr_mosi = 1;\n\t\tuint8_t idx;\n\t\tbits = 0;\t\t\t\t// remaining bits to send\n\t\tidx = 0;\t\t\t\t// index to spi hw data_buf (16 32-bit words, 64 bytes, 512 bits)\n\n        // ** Transmit 'txlen' bytes\n\t\twhile (count < txlen) {\n\t\t\twd = 0;\n\t\t\tfor (bc=0;bc<32;bc+=8) {\n\t\t\t\twd |= (uint32_t)txbuffer[count] << bc;\n\t\t\t\tcount++;                    // Increment sent data count\n\t\t\t\tbits += 8;                  // Increment bits count\n\t\t\t\tif (count == txlen) break;  // If all transmit data pushed to hw spi buffer break from the loop\n\t\t\t}\n\t\t\thost->hw->data_buf[idx] = wd;\n\t\t\tidx++;\n\t\t\tif (idx == 16) {\n\t\t\t\t// hw SPI buffer full (all 64 bytes filled, START THE TRANSSACTION\n\t\t\t\thost->hw->mosi_dlen.usr_mosi_dbitlen=bits-1;            // Set mosi dbitlen\n\n\t\t\t\tif ((duplex) && (rdcount > 0)) {\n                    // In full duplex mode we are receiving while sending !\n\t\t\t\t\thost->hw->miso_dlen.usr_miso_dbitlen = bits-1;      // Set miso dbitlen\n\t\t\t\t\thost->hw->user.usr_miso = 1;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\thost->hw->miso_dlen.usr_miso_dbitlen = 0;           // In half duplex mode nothing will be received\n\t\t\t\t\thost->hw->user.usr_miso = 0;\n\t\t\t\t}\n\n\t\t\t\t// ** Start the transaction ***\n\t\t\t\thost->hw->cmd.usr=1;\n                // Wait the transaction to finish\n\t\t\t\twhile (host->hw->cmd.usr);\n\n\t\t\t\tif ((duplex) && (rdcount > 0)) {\n\t\t\t\t\t// *** in full duplex mode transfer received data to input buffer ***\n\t\t\t\t\trdidx = 0;\n\t\t\t    \twhile (bits > 0) {\n\t\t\t\t\t\twd = host->hw->data_buf[rdidx];\n\t\t\t\t\t\trdidx++;\n\t\t\t\t\t\tfor (bc=0;bc<32;bc+=8) { // get max 4 bytes\n\t\t\t\t\t\t\trxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);\n\t\t\t\t\t\t\trdcount--;\n\t\t\t\t\t\t\tbits -= 8;\n\t\t\t\t\t\t\tif (rdcount == 0) {\n\t\t\t\t\t\t\t\tbits = 0;\n\t\t\t\t\t\t\t\tbreak; // Finished reading data\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t    \t}\n\t\t\t\t}\n\t\t\t\tbits = 0;   // nothing in hw spi buffer yet\n\t\t\t\tidx = 0;    // start from the beginning of the hw spi buffer\n\t\t\t}\n\t\t}\n\t\t// *** All transmit data are sent or pushed to hw spi buffer\n\t\t// bits > 0  IF THERE ARE SOME DATA STILL WAITING IN THE HW SPI TRANSMIT BUFFER\n\t\tif (bits > 0) {\n\t\t\t// ** WE HAVE SOME DATA IN THE HW SPI TRANSMIT BUFFER\n\t\t\thost->hw->mosi_dlen.usr_mosi_dbitlen = bits-1;          // Set mosi dbitlen\n\n\t\t\tif ((duplex) && (rdcount > 0)) {\n                // In full duplex mode we are receiving while sending !\n\t\t\t\thost->hw->miso_dlen.usr_miso_dbitlen = bits-1;      // Set miso dbitlen\n\t\t\t\thost->hw->user.usr_miso = 1;\n\t\t\t}\n\t\t\telse {\n\t\t\t\thost->hw->miso_dlen.usr_miso_dbitlen = 0;           // In half duplex mode nothing will be received\n\t\t\t\thost->hw->user.usr_miso = 0;\n\t\t\t}\n\n\t\t\t// ** Start the transaction ***\n\t\t\thost->hw->cmd.usr=1;\n            // Wait the transaction to finish\n\t\t\twhile (host->hw->cmd.usr);\n\n\t\t\tif ((duplex) && (rdcount > 0)) {\n                // *** in full duplex mode transfer received data to input buffer ***\n\t\t\t\trdidx = 0;\n\t\t    \twhile (bits > 0) {\n\t\t\t\t\twd = host->hw->data_buf[rdidx];\n\t\t\t\t\trdidx++;\n\t\t\t\t\tfor (bc=0;bc<32;bc+=8) { // get max 4 bytes\n\t\t\t\t\t\trxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);\n\t\t\t\t\t\trdcount--;\n\t\t\t\t\t\tbits -= 8;\n\t\t\t\t\t\tif (bits == 0) break;\n\t\t\t\t\t\tif (rdcount == 0) {\n\t\t\t\t\t\t\tbits = 0;\n\t\t\t\t\t\t\tbreak; // Finished reading data\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t    \t}\n\t\t\t}\n\t\t}\n\t\t//if (duplex) rdcount = 0;  // In duplex mode receive only as many bytes as was transmitted\n\t}\n\n\t// ------------------------------------------------------------------------\n\t// *** If rdcount = 0 we have nothing to receive and we exit the function\n    //     This is true if no data receive was requested,\n    //     or all the data was received in Full duplex mode during the transmission\n\t// ------------------------------------------------------------------------\n\tif (rdcount > 0) {\n\t\t// ----------------------------------------------------------------------------------------------------------------\n\t\t// *** rdcount > 0, we have to receive some data\n\t\t//     This is true if we operate in Half duplex mode when receiving after transmission is done,\n\t\t//     or not all data was received in Full duplex mode during the transmission (trans->rxlength > trans->txlength)\n\t\t// ----------------------------------------------------------------------------------------------------------------\n\t\thost->hw->user.usr_mosi = 0;  // do not send\n\t\thost->hw->user.usr_miso = 1;  // do receive\n\t\twhile (rdcount > 0) {\n\t\t\tif (rdcount <= 64) rdbits = rdcount * 8;\n\t\t\telse rdbits = 64 * 8;\n\n\t\t\t// Load receive buffer\n\t\t\thost->hw->mosi_dlen.usr_mosi_dbitlen=0;\n\t\t\thost->hw->miso_dlen.usr_miso_dbitlen=rdbits-1;\n\n\t\t\t// ** Start the transaction ***\n\t\t\thost->hw->cmd.usr=1;\n\t\t\t// Wait the transaction to finish\n\t\t\twhile (host->hw->cmd.usr);\n\n\t\t\t// *** transfer received data to input buffer ***\n\t\t\trdidx = 0;\n\t\t\twhile (rdbits > 0) {\n\t\t\t\twd = host->hw->data_buf[rdidx];\n\t\t\t\trdidx++;\n\t\t\t\tfor (bc=0;bc<32;bc+=8) {\n\t\t\t\t\trxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);\n\t\t\t\t\trdcount--;\n\t\t\t\t\trdbits -= 8;\n\t\t\t\t\tif (rdcount == 0) {\n\t\t\t\t\t\trdbits = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ** Call post-transmission callback, if any\n\tif (handle->cfg.post_cb) handle->cfg.post_cb(trans);\n\n\tif (do_deselect) {\n        // Spi device was selected in this function, we have to deselect it now\n\t\tret = spi_lobo_device_deselect(handle);\n\t\tif (ret) return ret;\n\t}\n\n\treturn ESP_OK;\n}\n"
  },
  {
    "path": "components/spidriver/spi_master_lobo.h",
    "content": "// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n#ifndef _DRIVER_SPI_MASTER_LOBO_H_\n#define _DRIVER_SPI_MASTER_LOBO_H_\n\n#include \"esp_err.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"soc/spi_struct.h\"\n\n#include \"esp_intr.h\"\n#include \"esp_intr_alloc.h\"\n#include \"rom/lldesc.h\"\n\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n\n//Maximum amount of bytes that can be put in one DMA descriptor\n#define SPI_MAX_DMA_LEN (4096-4)\n\n/**\n * @brief Enum with the three SPI peripherals that are software-accessible in it\n */\ntypedef enum {\n    SPI_HOST=0,                     ///< SPI1, SPI; Cannot be used in this driver!\n    HSPI_HOST=1,                    ///< SPI2, HSPI\n    VSPI_HOST=2                     ///< SPI3, VSPI\n} spi_lobo_host_device_t;\n\n\n/**\n * @brief This is a configuration structure for a SPI bus.\n *\n * You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the\n * GPIO matrix to route the signals. An exception is made when all signals either can be routed through \n * the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.\n */\ntypedef struct {\n    int mosi_io_num;                ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.\n    int miso_io_num;                ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.\n    int sclk_io_num;                ///< GPIO pin for Spi CLocK signal, or -1 if not used.\n    int quadwp_io_num;              ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.\n    int quadhd_io_num;              ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.\n    int max_transfer_sz;            ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.\n} spi_lobo_bus_config_t;\n\n\n#define SPI_DEVICE_TXBIT_LSBFIRST          (1<<0)  ///< Transmit command/address/data LSB first instead of the default MSB first\n#define SPI_DEVICE_RXBIT_LSBFIRST          (1<<1)  ///< Receive data LSB first instead of the default MSB first\n#define SPI_DEVICE_BIT_LSBFIRST            (SPI_TXBIT_LSBFIRST|SPI_RXBIT_LSBFIRST); ///< Transmit and receive LSB first\n#define SPI_DEVICE_3WIRE                   (1<<2)  ///< Use spiq for both sending and receiving data\n#define SPI_DEVICE_POSITIVE_CS             (1<<3)  ///< Make CS positive during a transaction instead of negative\n#define SPI_DEVICE_HALFDUPLEX              (1<<4)  ///< Transmit data before receiving it, instead of simultaneously\n#define SPI_DEVICE_CLK_AS_CS               (1<<5)  ///< Output clock on CS line if CS is active\n\n#define SPI_ERR_OTHER_CONFIG 7001\n\ntypedef struct spi_lobo_transaction_t spi_lobo_transaction_t;\ntypedef void(*transaction_cb_t)(spi_lobo_transaction_t *trans);\n\n/**\n * @brief This is a configuration for a SPI slave device that is connected to one of the SPI buses.\n */\ntypedef struct {\n    uint8_t command_bits;           ///< Amount of bits in command phase (0-16)\n    uint8_t address_bits;           ///< Amount of bits in address phase (0-64)\n    uint8_t dummy_bits;             ///< Amount of dummy bits to insert between address and data phase\n    uint8_t mode;                   ///< SPI mode (0-3)\n    uint8_t duty_cycle_pos;         ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.\n    uint8_t cs_ena_pretrans;        ///< Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions.\n    uint8_t cs_ena_posttrans;       ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16)\n    int clock_speed_hz;             ///< Clock speed, in Hz\n    int spics_io_num;               ///< CS GPIO pin for this device, handled by hardware; set to -1 if not used\n    int spics_ext_io_num;           ///< CS GPIO pin for this device, handled by software (spi_lobo_device_select/spi_lobo_device_deselect); only used if spics_io_num=-1\n    uint32_t flags;                 ///< Bitwise OR of SPI_DEVICE_* flags\n    transaction_cb_t pre_cb;        ///< Callback to be called before a transmission is started. This callback from 'spi_lobo_transfer_data' function.\n    transaction_cb_t post_cb;       ///< Callback to be called after a transmission has completed. This callback from 'spi_lobo_transfer_data' function.\n    uint8_t selected;               ///< **INTERNAL** 1 if the device's CS pin is active\n} spi_lobo_device_interface_config_t;\n\n\n#define SPI_TRANS_MODE_DIO            (1<<0)  ///< Transmit/receive data in 2-bit mode\n#define SPI_TRANS_MODE_QIO            (1<<1)  ///< Transmit/receive data in 4-bit mode\n#define SPI_TRANS_MODE_DIOQIO_ADDR    (1<<2)  ///< Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO\n#define SPI_TRANS_USE_RXDATA          (1<<3)  ///< Receive into rx_data member of spi_lobo_transaction_t instead into memory at rx_buffer.\n#define SPI_TRANS_USE_TXDATA          (1<<4)  ///< Transmit tx_data member of spi_lobo_transaction_t instead of data at tx_buffer. Do not set tx_buffer when using this.\n\n/**\n * This structure describes one SPI transmission\n */\nstruct spi_lobo_transaction_t {\n    uint32_t flags;                 ///< Bitwise OR of SPI_TRANS_* flags\n    uint16_t command;               ///< Command data. Specific length was given when device was added to the bus.\n    uint64_t address;               ///< Address. Specific length was given when device was added to the bus.\n    size_t length;                  ///< Total data length to be transmitted to the device, in bits; if 0, no data is transmitted\n    size_t rxlength;                ///< Total data length to be received from the device, in bits; if 0, no data is received\n    void *user;                     ///< User-defined variable. Can be used to store eg transaction ID or data to be used by pre_cb and/or post_cb callbacks.\n    union {\n        const void *tx_buffer;      ///< Pointer to transmit buffer, or NULL for no MOSI phase\n        uint8_t tx_data[4];         ///< If SPI_USE_TXDATA is set, data set here is sent directly from this variable.\n    };\n    union {\n        void *rx_buffer;            ///< Pointer to receive buffer, or NULL for no MISO phase\n        uint8_t rx_data[4];         ///< If SPI_USE_RXDATA is set, data is received directly to this variable\n    };\n};\n\n#define NO_CS 3\t\t\t\t\t    // Number of CS pins per SPI host\n#define NO_DEV 6\t\t\t\t    // Number of spi devices per SPI host; more than 3 devices can be attached to the same bus if using software CS's\n#define SPI_SEMAPHORE_WAIT 2000     // Time in ms to wait for SPI mutex\n\ntypedef struct spi_lobo_device_t spi_lobo_device_t;\n\ntypedef struct {\n    spi_lobo_device_t *device[NO_DEV];\n    intr_handle_t intr;\n    spi_dev_t *hw;\n    //spi_lobo_transaction_t *cur_trans;\n    int cur_device;\n    lldesc_t *dmadesc_tx;\n    lldesc_t *dmadesc_rx;\n    bool no_gpio_matrix;\n    int dma_chan;\n    int max_transfer_sz;\n    QueueHandle_t spi_lobo_bus_mutex;\n    spi_lobo_bus_config_t cur_bus_config;\n} spi_lobo_host_t;\n\nstruct spi_lobo_device_t {\n    spi_lobo_device_interface_config_t cfg;\n    spi_lobo_host_t *host;\n    spi_lobo_bus_config_t bus_config;\n\tspi_lobo_host_device_t host_dev;\n};\n\ntypedef spi_lobo_device_t* spi_lobo_device_handle_t;  ///< Handle for a device on a SPI bus\ntypedef spi_lobo_host_t* spi_lobo_host_handle_t;\ntypedef spi_lobo_device_interface_config_t* spi_lobo_device_interface_config_handle_t;\n\n\n/**\n * @brief Add a device. This allocates a CS line for the device, allocates memory for the device structure and hooks\n *        up the CS pin to whatever is specified.\n *\n * This initializes the internal structures for a device, plus allocates a CS pin on the indicated SPI master\n * peripheral and routes it to the indicated GPIO. All SPI master devices have three hw CS pins and can thus control\n * up to three devices. Software handled CS pin can also be used for additional devices on the same SPI bus.\n * \n * ### If selected SPI host device bus is not yet initialized, it is initialized first with 'bus_config' function ###\n *\n * @note While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are\n *       supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz.\n *\n * @param host SPI peripheral to allocate device on (HSPI or VSPI)\n * @param dev_config SPI interface protocol config for the device\n * @param bus_config Pointer to a spi_lobo_bus_config_t struct specifying how the host device bus should be initialized\n * @param handle Pointer to variable to hold the device handle\n * @return\n *         - ESP_ERR_INVALID_ARG   if parameter is invalid\n *         - ESP_ERR_NOT_FOUND     if host doesn't have any free CS slots\n *         - ESP_ERR_NO_MEM        if out of memory\n *         - ESP_OK                on success\n */\nesp_err_t spi_lobo_bus_add_device(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, spi_lobo_device_interface_config_t *dev_config, spi_lobo_device_handle_t *handle);\n\n/**\n * @brief Remove a device from the SPI bus. If after removal no other device is attached to the spi bus device, it is freed.\n *\n * @param handle Device handle to free\n * @return\n *         - ESP_ERR_INVALID_ARG   if parameter is invalid\n *         - ESP_ERR_INVALID_STATE if device already is freed\n *         - ESP_OK                on success\n */\nesp_err_t spi_lobo_bus_remove_device(spi_lobo_device_handle_t handle);\n\n\n/**\n * @brief Return the actuall SPI bus speed for the spi device in Hz\n *\n * Some frequencies cannot be set, for example 30000000 will actually set SPI clock to 26666666 Hz\n *\n * @param handle Device handle obtained using spi_lobo_bus_add_device\n * \n * @return \n *         - actuall SPI clock\n */\nuint32_t spi_lobo_get_speed(spi_lobo_device_handle_t handle);\n\n/**\n * @brief Set the new clock speed for the device, return the actuall SPI bus speed set, in Hz\n *        This function can be used after the device is initialized\n *\n * Some frequencies cannot be set, for example 30000000 will actually set SPI clock to 26666666 Hz\n *\n * @param handle Device handle obtained using spi_lobo_bus_add_device\n * @param speed  New device spi clock to be set in Hz\n * \n * @return \n *         - actuall SPI clock\n *         - 0 if speed cannot be set\n */\nuint32_t spi_lobo_set_speed(spi_lobo_device_handle_t handle, uint32_t speed);\n\n/**\n * @brief Select spi device for transmission\n *\n * It configures spi bus with selected spi device parameters if previously selected device was different than the current\n * If device's spics_io_num=-1 and spics_ext_io_num > 0 'spics_ext_io_num' pin is set to active state (low)\n * \n * spi bus device's semaphore is taken before selecting the device\n *\n * @param handle Device handle obtained using spi_lobo_bus_add_device\n * @param force  configure spi bus even if the previous device was the same\n * \n * @return \n *         - ESP_ERR_INVALID_ARG   if parameter is invalid\n *         - ESP_OK                on success\n */\nesp_err_t spi_lobo_device_select(spi_lobo_device_handle_t handle, int force);\n\n/**\n * @brief De-select spi device\n *\n * If device's spics_io_num=-1 and spics_ext_io_num > 0 'spics_ext_io_num' pin is set to inactive state (high)\n * \n * spi bus device's semaphore is given after selecting the device\n * \n * @param handle Device handle obtained using spi_lobo_bus_add_device\n * \n * @return \n *         - ESP_ERR_INVALID_ARG   if parameter is invalid\n *         - ESP_OK                on success\n */\nesp_err_t spi_lobo_device_deselect(spi_lobo_device_handle_t handle);\n\n\n/**\n * @brief Check if spi bus uses native spi pins\n *\n * @param handle Device handle obtained using spi_lobo_bus_add_device\n * \n * @return \n *         - true        if native spi pins are used\n *         - false       if spi pins are routed through gpio matrix\n */\nbool spi_lobo_uses_native_pins(spi_lobo_device_handle_t handle);\n\n/**\n * @brief Get spi bus native spi pins\n *\n * @param handle Device handle obtained using spi_lobo_bus_add_device\n * \n * @return \n *         places spi bus native pins in provided pointers\n */\nvoid spi_lobo_get_native_pins(int host, int *sdi, int *sdo, int *sck);\n\n/**\n * @brief Transimit and receive data to/from spi device based on transaction data\n * \n * TRANSMIT 8-bit data to spi device from 'trans->tx_buffer' or 'trans->tx_data' (trans->lenght/8 bytes)\n * and RECEIVE data to 'trans->rx_buffer' or 'trans->rx_data' (trans->rx_length/8 bytes)\n * Lengths must be 8-bit multiples!\n * If trans->rx_buffer is NULL or trans->rx_length is 0, only transmits data\n * If trans->tx_buffer is NULL or trans->length is 0, only receives data\n * If the device is in duplex mode (SPI_DEVICE_HALFDUPLEX flag NOT set), data are transmitted and received simultaneously.\n * If the device is in half duplex mode (SPI_DEVICE_HALFDUPLEX flag IS set), data are received after transmission\n * 'address', 'command' and 'dummy bits' are transmitted before data phase IF set in device's configuration\n *   and IF 'trans->length' and 'trans->rx_length' are NOT both 0\n * If device was not previously selected, it will be selected before transmission and deselected after transmission.\n *\n * @param handle Device handle obtained using spi_lobo_bus_add_device\n * \n * @param trans Pointer to variable containing the description of the transaction that is executed\n *\n * @return\n *         - ESP_ERR_INVALID_ARG   if parameter is invalid\n *         - ESP error code        if device cannot be selected\n *         - ESP_OK                on success\n *\n */\nesp_err_t spi_lobo_transfer_data(spi_lobo_device_handle_t handle, spi_lobo_transaction_t *trans);\n\n\n/*\n * SPI transactions uses the semaphore (taken in select function) to protect the transfer\n */\nesp_err_t spi_lobo_device_TakeSemaphore(spi_lobo_device_handle_t handle);\nvoid spi_lobo_device_GiveSemaphore(spi_lobo_device_handle_t handle);\n\n\n/**\n * @brief Setup a DMA link chain\n *\n * This routine will set up a chain of linked DMA descriptors in the array pointed to by\n * ``dmadesc``. Enough DMA descriptors will be used to fit the buffer of ``len`` bytes in, and the\n * descriptors will point to the corresponding positions in ``buffer`` and linked together. The\n * end result is that feeding ``dmadesc[0]`` into DMA hardware results in the entirety ``len`` bytes\n * of ``data`` being read or written.\n *\n * @param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ``len`` bytes\n * @param len Length of buffer\n * @param data Data buffer to use for DMA transfer\n * @param isrx True if data is to be written into ``data``, false if it's to be read from ``data``.\n */\nvoid spi_lobo_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx);\n\n/**\n * @brief Check if a DMA reset is requested but has not completed yet\n *\n * @return True when a DMA reset is requested but hasn't completed yet. False otherwise.\n */\nbool spi_lobo_dmaworkaround_reset_in_progress();\n\n\n/**\n * @brief Mark a DMA channel as idle.\n *\n * A call to this function tells the workaround logic that this channel will\n * not be affected by a global SPI DMA reset.\n */\nvoid spi_lobo_dmaworkaround_idle(int dmachan);\n\n/**\n * @brief Mark a DMA channel as active.\n *\n * A call to this function tells the workaround logic that this channel will\n * be affected by a global SPI DMA reset, and a reset like that should not be attempted.\n */\nvoid spi_lobo_dmaworkaround_transfer_active(int dmachan);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "components/spiffs/component.mk",
    "content": "#\n# Component Makefile\n#\n\nCOMPONENT_SRCDIRS := .\nCOMPONENT_ADD_INCLUDEDIRS := .\nCOMPONENT_PRIV_INCLUDEDIRS := "
  },
  {
    "path": "components/spiffs/esp_spiffs.c",
    "content": "/*\n * Lua RTOS, SPIFFS low access\n *\n * Copyright (C) 2015 - 2017\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * \n * Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n * \n * All rights reserved.  \n *\n * Permission to use, copy, modify, and distribute this software\n * and its documentation for any purpose and without fee is hereby\n * granted, provided that the above copyright notice appear in all\n * copies and that both that the copyright notice and this\n * permission notice and warranty disclaimer appear in supporting\n * documentation, and that the name of the author not be used in\n * advertising or publicity pertaining to distribution of the\n * software without specific, written prior permission.\n *\n * The author disclaim all warranties with regard to this\n * software, including all implied warranties of merchantability\n * and fitness.  In no event shall the author be liable for any\n * special, indirect or consequential damages or any damages\n * whatsoever resulting from loss of use, data or profits, whether\n * in an action of contract, negligence or other tortious action,\n * arising out of or in connection with the use or performance of\n * this software.\n */\n\n#include <stdlib.h>\n\n#include \"esp_spiffs.h\"\n#include \"esp_attr.h\"\n\n#include \"spiffs.h\"\n\n#include <esp_spi_flash.h>\n\ns32_t IRAM_ATTR esp32_spi_flash_read(u32_t addr, u32_t size, u8_t *dst) {\n\tu32_t aaddr;\n\tu8_t *buff = NULL;\n\tu8_t *abuff = NULL;\n\tu32_t asize;\n\n\tasize = size;\n\t\n\t// Align address to 4 byte\n\taaddr = (addr + (4 - 1)) & (u32_t)-4;\n\tif (aaddr != addr) {\n\t\taaddr -= 4;\n\t\tasize += (addr - aaddr);\n\t}\n\n\t// Align size to 4 byte\n\tasize = (asize + (4 - 1)) & (u32_t)-4;\n\n\tif ((aaddr != addr) || (asize != size)) {\n\t\t// Align buffer\n\t\tbuff = malloc(asize + 4);\n\t\tif (!buff) {\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tabuff = (u8_t *)(((ptrdiff_t)buff + (4 - 1)) & (u32_t)-4);\n\n\t\tif (spi_flash_read(aaddr, (void *)abuff, asize) != 0) {\n\t\t\tfree(buff);\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tmemcpy(dst, abuff + (addr - aaddr), size);\n\n\t\tfree(buff);\n\t} else {\n\t\tif (spi_flash_read(addr, (void *)dst, size) != 0) {\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\t}\n\t\n    return SPIFFS_OK;\n}\n\ns32_t IRAM_ATTR esp32_spi_flash_write(u32_t addr, u32_t size, const u8_t *src) {\n\tu32_t aaddr;\n\tu8_t *buff = NULL;\n\tu8_t *abuff = NULL;\n\tu32_t asize;\n\n\tasize = size;\n\t\n\t// Align address to 4 byte\n\taaddr = (addr + (4 - 1)) & -4;\n\tif (aaddr != addr) {\n\t\taaddr -= 4;\n\t\tasize += (addr - aaddr);\n\t}\n\n\t// Align size to 4 byte\n\tasize = (asize + (4 - 1)) & -4; \n\n\tif ((aaddr != addr) || (asize != size)) {\n\t\t// Align buffer\n\t\tbuff = malloc(asize + 4);\n\t\tif (!buff) {\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tabuff = (u8_t *)(((ptrdiff_t)buff + (4 - 1)) & -4);\n\n\t\tif (spi_flash_read(aaddr, (void *)abuff, asize) != 0) {\n\t\t\tfree(buff);\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tmemcpy(abuff + (addr - aaddr), src, size);\n\n\t\tif (spi_flash_write(aaddr, (uint32_t *)abuff, asize) != 0) {\n\t\t\tfree(buff);\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\n\t\tfree(buff);\n\t} else {\n\t\tif (spi_flash_write(addr, (uint32_t *)src, size) != 0) {\n\t\t\treturn SPIFFS_ERR_INTERNAL;\n\t\t}\n\t}\n\t\n    return SPIFFS_OK;\n}\n\ns32_t IRAM_ATTR esp32_spi_flash_erase(u32_t addr, u32_t size) {\n\tif (spi_flash_erase_sector(addr >> 12) != 0) {\n\t\treturn SPIFFS_ERR_INTERNAL;\n\t}\n\t\n    return SPIFFS_OK;\n}\n"
  },
  {
    "path": "components/spiffs/esp_spiffs.h",
    "content": "/*\n * Lua RTOS, write syscall implementation\n *\n * Copyright (C) 2015 - 2017\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * \n * Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n * \n * All rights reserved.  \n *\n * Permission to use, copy, modify, and distribute this software\n * and its documentation for any purpose and without fee is hereby\n * granted, provided that the above copyright notice appear in all\n * copies and that both that the copyright notice and this\n * permission notice and warranty disclaimer appear in supporting\n * documentation, and that the name of the author not be used in\n * advertising or publicity pertaining to distribution of the\n * software without specific, written prior permission.\n *\n * The author disclaim all warranties with regard to this\n * software, including all implied warranties of merchantability\n * and fitness.  In no event shall the author be liable for any\n * special, indirect or consequential damages or any damages\n * whatsoever resulting from loss of use, data or profits, whether\n * in an action of contract, negligence or other tortious action,\n * arising out of or in connection with the use or performance of\n * this software.\n */\n\n#ifndef __ESP_SPIFFS_H__\n#define __ESP_SPIFFS_H__\n\n#include \"spiffs.h\"\n\ns32_t esp32_spi_flash_read(u32_t addr, u32_t size, u8_t *dst);\ns32_t esp32_spi_flash_write(u32_t addr, u32_t size, const u8_t *src);\ns32_t esp32_spi_flash_erase(u32_t addr, u32_t size);\n\n#define low_spiffs_read  (spiffs_read *)esp32_spi_flash_read\n#define low_spiffs_write (spiffs_write *)esp32_spi_flash_write\n#define low_spiffs_erase (spiffs_erase *)esp32_spi_flash_erase\n\n#endif  // __ESP_SPIFFS_H__\n"
  },
  {
    "path": "components/spiffs/list.c",
    "content": "/*\n * Lua RTOS, list data structure\n *\n * Copyright (C) 2015 - 2017\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * \n * Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n * \n * All rights reserved.  \n *\n * Permission to use, copy, modify, and distribute this software\n * and its documentation for any purpose and without fee is hereby\n * granted, provided that the above copyright notice appear in all\n * copies and that both that the copyright notice and this\n * permission notice and warranty disclaimer appear in supporting\n * documentation, and that the name of the author not be used in\n * advertising or publicity pertaining to distribution of the\n * software without specific, written prior permission.\n *\n * The author disclaim all warranties with regard to this\n * software, including all implied warranties of merchantability\n * and fitness.  In no event shall the author be liable for any\n * special, indirect or consequential damages or any damages\n * whatsoever resulting from loss of use, data or profits, whether\n * in an action of contract, negligence or other tortious action,\n * arising out of or in connection with the use or performance of\n * this software.\n */\n\n#include \"esp_attr.h\"\n\n#include <errno.h>\n#include <string.h>\n#include <stdlib.h>\n\n#include \"list.h\"\n#include \"mutex.h\"\n\nvoid list_init(struct list *list, int first_index) {\n    // Create the mutex\n    mtx_init(&list->mutex, NULL, NULL, 0);\n    \n    mtx_lock(&list->mutex);\n    \n    list->indexes =  0;\n    list->free = NULL;\n    list->index = NULL;\n    list->first_index = first_index;\n    \n    mtx_unlock(&list->mutex);    \n}\n\nint list_add(struct list *list, void *item, int *item_index) {\n    struct list_index *index = NULL;\n    struct list_index *indexa = NULL;\n    int grow = 0;\n        \n    mtx_lock(&list->mutex);\n    \n    // Get an index\n    if (list->free) {\n        // Get first free element\n        index = list->free;\n        list->free = index->next;\n    } else {\n        // Must grow index array\n        grow = 1;\n    }\n    \n    if (grow) {        \n        // Increment index count\n        list->indexes++;\n\n        // Create a new index array for allocate new index\n        indexa = (struct list_index *)malloc(sizeof(struct list_index) * list->indexes);     \n        if (!indexa) {\n            mtx_unlock(&list->mutex);\n            return ENOMEM;            \n        }\n        \n        if (list->index) {\n            // Copy current index array to new created\n            bcopy(list->index, indexa, sizeof(struct list_index) * (list->indexes - 1));\n\n            // Free current index array\n            free(list->index);\n        }\n\n        // Store new index array\n        list->index = indexa;\n\n        // Current index\n        index = list->index + list->indexes - 1;\n        \n        // Initialize new index\n        index->index = list->indexes - 1;\n        \n    }\n    \n    index->next = NULL;\n    index->item = item;        \n    index->deleted = 0;\n    \n    // Return index\n    *item_index = index->index + list->first_index;\n            \n    mtx_unlock(&list->mutex);\n    \n    return 0;\n}\n\nint IRAM_ATTR list_get(struct list *list, int index, void **item) {\n    struct list_index *cindex = NULL;\n    int iindex;\n\n    mtx_lock(&list->mutex);\n\n    if (!list->indexes) {\n        mtx_unlock(&list->mutex);\n        return EINVAL;\n    }\n\n    // Check index\n    if (index < list->first_index) {\n        mtx_unlock(&list->mutex);\n        return EINVAL;\n    }\n\n    // Get new internal index\n    iindex = index - list->first_index;\n    \n    // Test for a valid index\n    if (iindex > list->indexes) {\n        mtx_unlock(&list->mutex);\n        return EINVAL;\n    }\n\n    cindex = list->index + iindex;\n\n    if (cindex->deleted) {\n        mtx_unlock(&list->mutex);\n        return EINVAL;\n    }\n    \n    *item = cindex->item;\n    \n    mtx_unlock(&list->mutex);\n\n    return 0;\n}\n\nint list_remove(struct list *list, int index, int destroy) {\n    struct list_index *cindex = NULL;\n    int iindex;\n\n    mtx_lock(&list->mutex);\n\n    // Check index\n    if (index < list->first_index) {\n        mtx_unlock(&list->mutex);\n        return EINVAL;\n    }\n    \n    // Get new internal index\n    iindex = index - list->first_index;\n    \n    // Test for a valid index\n    if ((iindex < 0) || (iindex > list->indexes)) {\n        mtx_unlock(&list->mutex);\n        return EINVAL;\n    }\n    \n    cindex = &list->index[iindex];\n    \n    if (destroy) {\n    \tfree(cindex->item);\n    }\n    \n    cindex->next = list->free;\n    cindex->deleted = 1;\n    list->free = cindex;\n    \n    mtx_unlock(&list->mutex);\n    \n    return 0;\n}\n\nint IRAM_ATTR list_first(struct list *list) {\n    int index;\n    int res = -1;\n    \n    mtx_lock(&list->mutex);\n    \n    for(index=0;index < list->indexes;index++) {\n        if (!list->index[index].deleted) {\n            res = index + list->first_index;\n            break;\n        }\n    }\n    \n    mtx_unlock(&list->mutex);\n\n    return res;\n}\n\nint IRAM_ATTR list_next(struct list *list, int index) {\n    int res = -1;\n    int iindex;\n    \n    mtx_lock(&list->mutex);\n\n    // Check index\n    if (index < list->first_index) {\n        mtx_unlock(&list->mutex);    \n        return -1;\n    }\n    \n    // Get new internal index\n    iindex = index - list->first_index + 1;\n\n    // Get next non deleted item on list\n    for(;iindex < list->indexes;iindex++) {\n        if (!list->index[iindex].deleted) {\n           res = iindex + list->first_index;\n           break;\n        }\n    }\n    \n    mtx_unlock(&list->mutex);\n    \n    return res;\n}\n\nvoid list_destroy(struct list *list, int items) {\n    int index;\n    \n    mtx_lock(&list->mutex);\n    \n    if (items) {\n        for(index=0;index < list->indexes;index++) {\n            if (!list->index[index].deleted) {\n                free(list->index[index].item);\n            }\n        }        \n    }\n    \n    free(list->index);\n    \n    mtx_unlock(&list->mutex);    \n    mtx_destroy(&list->mutex);\n}\n"
  },
  {
    "path": "components/spiffs/list.h",
    "content": "/*\n * Lua RTOS, list data structure\n *\n * Copyright (C) 2015 - 2017\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * \n * Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n * \n * All rights reserved.  \n *\n * Permission to use, copy, modify, and distribute this software\n * and its documentation for any purpose and without fee is hereby\n * granted, provided that the above copyright notice appear in all\n * copies and that both that the copyright notice and this\n * permission notice and warranty disclaimer appear in supporting\n * documentation, and that the name of the author not be used in\n * advertising or publicity pertaining to distribution of the\n * software without specific, written prior permission.\n *\n * The author disclaim all warranties with regard to this\n * software, including all implied warranties of merchantability\n * and fitness.  In no event shall the author be liable for any\n * special, indirect or consequential damages or any damages\n * whatsoever resulting from loss of use, data or profits, whether\n * in an action of contract, negligence or other tortious action,\n * arising out of or in connection with the use or performance of\n * this software.\n */\n\n#ifndef _LIST_H\n#define\t_LIST_H\n\n#include <stdint.h>\n#include \"mutex.h\"\n\nstruct list {\n    struct mtx mutex;\n    struct list_index *index;\n    struct list_index *free;\n    uint8_t indexes;\n    uint8_t first_index;\n};\n\nstruct list_index {\n    void *item;\n    uint8_t index;\n    uint8_t deleted;\n    struct list_index *next;\n};\n\nvoid list_init(struct list *list, int first_index);\nint list_add(struct list *list, void *item, int *item_index);\nint list_get(struct list *list, int index, void **item);\nint list_remove(struct list *list, int index, int destroy);\nint list_first(struct list *list);\nint list_next(struct list *list, int index);\nvoid list_destroy(struct list *list, int items);\n\n#endif\t/* LIST_H */\n\n"
  },
  {
    "path": "components/spiffs/mutex.c",
    "content": "/*\n * Lua RTOS, mutex api implementation over FreeRTOS\n *\n * Copyright (C) 2015 - 2017\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * \n * Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n * \n * All rights reserved.  \n *\n * Permission to use, copy, modify, and distribute this software\n * and its documentation for any purpose and without fee is hereby\n * granted, provided that the above copyright notice appear in all\n * copies and that both that the copyright notice and this\n * permission notice and warranty disclaimer appear in supporting\n * documentation, and that the name of the author not be used in\n * advertising or publicity pertaining to distribution of the\n * software without specific, written prior permission.\n *\n * The author disclaim all warranties with regard to this\n * software, including all implied warranties of merchantability\n * and fitness.  In no event shall the author be liable for any\n * special, indirect or consequential damages or any damages\n * whatsoever resulting from loss of use, data or profits, whether\n * in an action of contract, negligence or other tortious action,\n * arising out of or in connection with the use or performance of\n * this software.\n *\n * Modified by: LoBo (loboris@gmail.com / https://github.com/loboris)\n *\n */\n\n#include \"freertos/FreeRTOS.h\"\n#include \"esp_attr.h\"\n#include \"mutex.h\"\n\n\n#define portEND_SWITCHING_ISR(xSwitchRequired) \\\nif (xSwitchRequired) {\t  \\\n\t_frxt_setup_switch(); \\\n}\n\nextern unsigned port_interruptNesting[portNUM_PROCESSORS];\n\nvoid _mtx_init() {\n}\n\nvoid mtx_init(struct mtx *mutex, const char *name, const char *type, int opts) {    \n    mutex->sem = xSemaphoreCreateBinary();\n\n    if (mutex->sem) {\n        if (port_interruptNesting[xPortGetCoreID()] != 0) {\n            BaseType_t xHigherPriorityTaskWoken = pdFALSE;\n            xSemaphoreGiveFromISR( mutex->sem, &xHigherPriorityTaskWoken); \n            portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\n        } else {\n            xSemaphoreGive( mutex->sem );            \n        }\n    }    \n}\n\nvoid IRAM_ATTR mtx_lock(struct mtx *mutex) {\n    if (port_interruptNesting[xPortGetCoreID()] != 0) {\n        BaseType_t xHigherPriorityTaskWoken = pdFALSE;        \n        xSemaphoreTakeFromISR( mutex->sem, &xHigherPriorityTaskWoken );\n        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\n    } else {\n        xSemaphoreTake( mutex->sem, portMAX_DELAY );\n    }\n}\n\nint mtx_trylock(struct\tmtx *mutex) {\n    if (xSemaphoreTake( mutex->sem, 0 ) == pdTRUE) {\n        return 1;\n    } else {\n        return 0;\n    }\n}\n\nvoid IRAM_ATTR mtx_unlock(struct mtx *mutex) {\n    if (port_interruptNesting[xPortGetCoreID()] != 0) {\n        BaseType_t xHigherPriorityTaskWoken = pdFALSE;  \n        xSemaphoreGiveFromISR( mutex->sem, &xHigherPriorityTaskWoken );  \n        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\n    } else {\n        xSemaphoreGive( mutex->sem );    \n    }\n}\n\nvoid mtx_destroy(struct\tmtx *mutex) {\n    if (port_interruptNesting[xPortGetCoreID()] != 0) {\n        BaseType_t xHigherPriorityTaskWoken = pdFALSE;  \n        xSemaphoreGiveFromISR( mutex->sem, &xHigherPriorityTaskWoken );  \n        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\n    } else {\n        xSemaphoreGive( mutex->sem );        \n    }\n    \n    vSemaphoreDelete( mutex->sem );\n    \n    mutex->sem = 0;\n}\n"
  },
  {
    "path": "components/spiffs/mutex.h",
    "content": "/*\n * Lua RTOS, mutex api implementation over FreeRTOS\n *\n * Copyright (C) 2015 - 2017\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * \n * Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n * \n * All rights reserved.  \n *\n * Permission to use, copy, modify, and distribute this software\n * and its documentation for any purpose and without fee is hereby\n * granted, provided that the above copyright notice appear in all\n * copies and that both that the copyright notice and this\n * permission notice and warranty disclaimer appear in supporting\n * documentation, and that the name of the author not be used in\n * advertising or publicity pertaining to distribution of the\n * software without specific, written prior permission.\n *\n * The author disclaim all warranties with regard to this\n * software, including all implied warranties of merchantability\n * and fitness.  In no event shall the author be liable for any\n * special, indirect or consequential damages or any damages\n * whatsoever resulting from loss of use, data or profits, whether\n * in an action of contract, negligence or other tortious action,\n * arising out of or in connection with the use or performance of\n * this software.\n *\n * Modified by: LoBo (loboris@gmail.com / https://github.com/loboris)\n *\n */\n\n#ifndef MUTEX_H_H\n#define\tMUTEX_H_H\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n\n#define MUTEX_INITIALIZER {.sem = 0}\n\nstruct mtx {\n    SemaphoreHandle_t sem;\n};\n\n\nvoid mtx_init(struct mtx *mutex, const char *name, const char *type, int opts);\nvoid mtx_lock(struct mtx *mutex);\nint  mtx_trylock(struct\tmtx *mutex);\nvoid mtx_unlock(struct mtx *mutex);\nvoid mtx_destroy(struct\tmtx *mutex);\n\n#endif\t/* MUTEX_H_H */\n\n"
  },
  {
    "path": "components/spiffs/spiffs.h",
    "content": "/*\n * spiffs.h\n *\n *  Created on: May 26, 2013\n *      Author: petera\n */\n\n#ifndef SPIFFS_H_\n#define SPIFFS_H_\n#if defined(__cplusplus)\nextern \"C\" {\n#endif\n\n#include \"spiffs_config.h\"\n\n#define SPIFFS_OK                       0\n#define SPIFFS_ERR_NOT_MOUNTED          -10000\n#define SPIFFS_ERR_FULL                 -10001\n#define SPIFFS_ERR_NOT_FOUND            -10002\n#define SPIFFS_ERR_END_OF_OBJECT        -10003\n#define SPIFFS_ERR_DELETED              -10004\n#define SPIFFS_ERR_NOT_FINALIZED        -10005\n#define SPIFFS_ERR_NOT_INDEX            -10006\n#define SPIFFS_ERR_OUT_OF_FILE_DESCS    -10007\n#define SPIFFS_ERR_FILE_CLOSED          -10008\n#define SPIFFS_ERR_FILE_DELETED         -10009\n#define SPIFFS_ERR_BAD_DESCRIPTOR       -10010\n#define SPIFFS_ERR_IS_INDEX             -10011\n#define SPIFFS_ERR_IS_FREE              -10012\n#define SPIFFS_ERR_INDEX_SPAN_MISMATCH  -10013\n#define SPIFFS_ERR_DATA_SPAN_MISMATCH   -10014\n#define SPIFFS_ERR_INDEX_REF_FREE       -10015\n#define SPIFFS_ERR_INDEX_REF_LU         -10016\n#define SPIFFS_ERR_INDEX_REF_INVALID    -10017\n#define SPIFFS_ERR_INDEX_FREE           -10018\n#define SPIFFS_ERR_INDEX_LU             -10019\n#define SPIFFS_ERR_INDEX_INVALID        -10020\n#define SPIFFS_ERR_NOT_WRITABLE         -10021\n#define SPIFFS_ERR_NOT_READABLE         -10022\n#define SPIFFS_ERR_CONFLICTING_NAME     -10023\n#define SPIFFS_ERR_NOT_CONFIGURED       -10024\n\n#define SPIFFS_ERR_NOT_A_FS             -10025\n#define SPIFFS_ERR_MOUNTED              -10026\n#define SPIFFS_ERR_ERASE_FAIL           -10027\n#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE   -10028\n\n#define SPIFFS_ERR_NO_DELETED_BLOCKS    -10029\n\n#define SPIFFS_ERR_FILE_EXISTS          -10030\n\n#define SPIFFS_ERR_NOT_A_FILE           -10031\n#define SPIFFS_ERR_RO_NOT_IMPL          -10032\n#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033\n#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034\n#define SPIFFS_ERR_PROBE_NOT_A_FS       -10035\n#define SPIFFS_ERR_NAME_TOO_LONG        -10036\n\n#define SPIFFS_ERR_IX_MAP_UNMAPPED      -10037\n#define SPIFFS_ERR_IX_MAP_MAPPED        -10038\n#define SPIFFS_ERR_IX_MAP_BAD_RANGE     -10039\n\n#define SPIFFS_ERR_INTERNAL             -10050\n\n#define SPIFFS_ERR_TEST                 -10100\n\n\n// spiffs file descriptor index type. must be signed\ntypedef s16_t spiffs_file;\n// spiffs file descriptor flags\ntypedef u16_t spiffs_flags;\n// spiffs file mode\ntypedef u16_t spiffs_mode;\n// object type\ntypedef u8_t spiffs_obj_type;\n\nstruct spiffs_t;\n\n#if SPIFFS_HAL_CALLBACK_EXTRA\n\n/* spi read call function type */\ntypedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);\n/* spi write call function type */\ntypedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);\n/* spi erase call function type */\ntypedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);\n\n#else // SPIFFS_HAL_CALLBACK_EXTRA\n\n/* spi read call function type */\ntypedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);\n/* spi write call function type */\ntypedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);\n/* spi erase call function type */\ntypedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);\n#endif // SPIFFS_HAL_CALLBACK_EXTRA\n\n/* file system check callback report operation */\ntypedef enum {\n  SPIFFS_CHECK_LOOKUP = 0,\n  SPIFFS_CHECK_INDEX,\n  SPIFFS_CHECK_PAGE\n} spiffs_check_type;\n\n/* file system check callback report type */\ntypedef enum {\n  SPIFFS_CHECK_PROGRESS = 0,\n  SPIFFS_CHECK_ERROR,\n  SPIFFS_CHECK_FIX_INDEX,\n  SPIFFS_CHECK_FIX_LOOKUP,\n  SPIFFS_CHECK_DELETE_ORPHANED_INDEX,\n  SPIFFS_CHECK_DELETE_PAGE,\n  SPIFFS_CHECK_DELETE_BAD_FILE\n} spiffs_check_report;\n\n/* file system check callback function */\n#if SPIFFS_HAL_CALLBACK_EXTRA\ntypedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,\n    u32_t arg1, u32_t arg2);\n#else // SPIFFS_HAL_CALLBACK_EXTRA\ntypedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,\n    u32_t arg1, u32_t arg2);\n#endif // SPIFFS_HAL_CALLBACK_EXTRA\n\n/* file system listener callback operation */\ntypedef enum {\n  /* the file has been created */\n  SPIFFS_CB_CREATED = 0,\n  /* the file has been updated or moved to another page */\n  SPIFFS_CB_UPDATED,\n  /* the file has been deleted */\n  SPIFFS_CB_DELETED\n} spiffs_fileop_type;\n\n/* file system listener callback function */\ntypedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix);\n\n#ifndef SPIFFS_DBG\n#define SPIFFS_DBG(...) \\\n    printf(__VA_ARGS__)\n#endif\n#ifndef SPIFFS_GC_DBG\n#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)\n#endif\n#ifndef SPIFFS_CACHE_DBG\n#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)\n#endif\n#ifndef SPIFFS_CHECK_DBG\n#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)\n#endif\n\n/* Any write to the filehandle is appended to end of the file */\n#define SPIFFS_APPEND                   (1<<0)\n#define SPIFFS_O_APPEND                 SPIFFS_APPEND\n/* If the opened file exists, it will be truncated to zero length before opened */\n#define SPIFFS_TRUNC                    (1<<1)\n#define SPIFFS_O_TRUNC                  SPIFFS_TRUNC\n/* If the opened file does not exist, it will be created before opened */\n#define SPIFFS_CREAT                    (1<<2)\n#define SPIFFS_O_CREAT                  SPIFFS_CREAT\n/* The opened file may only be read */\n#define SPIFFS_RDONLY                   (1<<3)\n#define SPIFFS_O_RDONLY                 SPIFFS_RDONLY\n/* The opened file may only be written */\n#define SPIFFS_WRONLY                   (1<<4)\n#define SPIFFS_O_WRONLY                 SPIFFS_WRONLY\n/* The opened file may be both read and written */\n#define SPIFFS_RDWR                     (SPIFFS_RDONLY | SPIFFS_WRONLY)\n#define SPIFFS_O_RDWR                   SPIFFS_RDWR\n/* Any writes to the filehandle will never be cached but flushed directly */\n#define SPIFFS_DIRECT                   (1<<5)\n#define SPIFFS_O_DIRECT                 SPIFFS_DIRECT\n/* If SPIFFS_O_CREAT and SPIFFS_O_EXCL are set, SPIFFS_open() shall fail if the file exists */\n#define SPIFFS_EXCL                     (1<<6)\n#define SPIFFS_O_EXCL                   SPIFFS_EXCL\n\n#define SPIFFS_SEEK_SET                 (0)\n#define SPIFFS_SEEK_CUR                 (1)\n#define SPIFFS_SEEK_END                 (2)\n\n#define SPIFFS_TYPE_FILE                (1)\n#define SPIFFS_TYPE_DIR                 (2)\n#define SPIFFS_TYPE_HARD_LINK           (3)\n#define SPIFFS_TYPE_SOFT_LINK           (4)\n\n#ifndef SPIFFS_LOCK\n#define SPIFFS_LOCK(fs)\n#endif\n\n#ifndef SPIFFS_UNLOCK\n#define SPIFFS_UNLOCK(fs)\n#endif\n\n// phys structs\n\n// spiffs spi configuration struct\ntypedef struct {\n  // physical read function\n  spiffs_read hal_read_f;\n  // physical write function\n  spiffs_write hal_write_f;\n  // physical erase function\n  spiffs_erase hal_erase_f;\n#if SPIFFS_SINGLETON == 0\n  // physical size of the spi flash\n  u32_t phys_size;\n  // physical offset in spi flash used for spiffs,\n  // must be on block boundary\n  u32_t phys_addr;\n  // physical size when erasing a block\n  u32_t phys_erase_block;\n\n  // logical size of a block, must be on physical\n  // block size boundary and must never be less than\n  // a physical block\n  u32_t log_block_size;\n  // logical size of a page, must be at least\n  // log_block_size / 8\n  u32_t log_page_size;\n\n#endif\n#if SPIFFS_FILEHDL_OFFSET\n  // an integer offset added to each file handle\n  u16_t fh_ix_offset;\n#endif\n} spiffs_config;\n\ntypedef struct spiffs_t {\n  // file system configuration\n  spiffs_config cfg;\n  // number of logical blocks\n  u32_t block_count;\n\n  // cursor for free blocks, block index\n  spiffs_block_ix free_cursor_block_ix;\n  // cursor for free blocks, entry index\n  int free_cursor_obj_lu_entry;\n  // cursor when searching, block index\n  spiffs_block_ix cursor_block_ix;\n  // cursor when searching, entry index\n  int cursor_obj_lu_entry;\n\n  // primary work buffer, size of a logical page\n  u8_t *lu_work;\n  // secondary work buffer, size of a logical page\n  u8_t *work;\n  // file descriptor memory area\n  u8_t *fd_space;\n  // available file descriptors\n  u32_t fd_count;\n\n  // last error\n  s32_t err_code;\n\n  // current number of free blocks\n  u32_t free_blocks;\n  // current number of busy pages\n  u32_t stats_p_allocated;\n  // current number of deleted pages\n  u32_t stats_p_deleted;\n  // flag indicating that garbage collector is cleaning\n  u8_t cleaning;\n  // max erase count amongst all blocks\n  spiffs_obj_id max_erase_count;\n\n#if SPIFFS_GC_STATS\n  u32_t stats_gc_runs;\n#endif\n\n#if SPIFFS_CACHE\n  // cache memory\n  void *cache;\n  // cache size\n  u32_t cache_size;\n#if SPIFFS_CACHE_STATS\n  u32_t cache_hits;\n  u32_t cache_misses;\n#endif\n#endif\n\n  // check callback function\n  spiffs_check_callback check_cb_f;\n  // file callback function\n  spiffs_file_callback file_cb_f;\n  // mounted flag\n  u8_t mounted;\n  // user data\n  void *user_data;\n  // config magic\n  u32_t config_magic;\n} spiffs;\n\n/* spiffs file status struct */\ntypedef struct {\n  spiffs_obj_id obj_id;\n  u32_t size;\n  spiffs_obj_type type;\n  spiffs_page_ix pix;\n  u8_t name[SPIFFS_OBJ_NAME_LEN];\n#if SPIFFS_OBJ_META_LEN\n  u8_t meta[SPIFFS_OBJ_META_LEN];\n#endif\n} spiffs_stat;\n\nstruct spiffs_dirent {\n  spiffs_obj_id obj_id;\n  u8_t name[SPIFFS_OBJ_NAME_LEN];\n  spiffs_obj_type type;\n  u32_t size;\n  spiffs_page_ix pix;\n#if SPIFFS_OBJ_META_LEN\n  u8_t meta[SPIFFS_OBJ_META_LEN];\n#endif\n};\n\ntypedef struct {\n  spiffs *fs;\n  spiffs_block_ix block;\n  int entry;\n} spiffs_DIR;\n\n#if SPIFFS_IX_MAP\n\ntypedef struct {\n  // buffer with looked up data pixes\n  spiffs_page_ix *map_buf;\n  // precise file byte offset\n  u32_t offset;\n  // start data span index of lookup buffer\n  spiffs_span_ix start_spix;\n  // end data span index of lookup buffer\n  spiffs_span_ix end_spix;\n} spiffs_ix_map;\n\n#endif\n\n// functions\n\n#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n/**\n * Special function. This takes a spiffs config struct and returns the number\n * of blocks this file system was formatted with. This function relies on\n * that following info is set correctly in given config struct:\n *\n * phys_addr, log_page_size, and log_block_size.\n *\n * Also, hal_read_f must be set in the config struct.\n *\n * One must be sure of the correct page size and that the physical address is\n * correct in the probed file system when calling this function. It is not\n * checked if the phys_addr actually points to the start of the file system,\n * so one might get a false positive if entering a phys_addr somewhere in the\n * middle of the file system at block boundary. In addition, it is not checked\n * if the page size is actually correct. If it is not, weird file system sizes\n * will be returned.\n *\n * If this function detects a file system it returns the assumed file system\n * size, which can be used to set the phys_size.\n *\n * Otherwise, it returns an error indicating why it is not regarded as a file\n * system.\n *\n * Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK\n * macros. It returns the error code directly, instead of as read by\n * SPIFFS_errno.\n *\n * @param config        essential parts of the physical and logical\n *                      configuration of the file system.\n */\ns32_t SPIFFS_probe_fs(spiffs_config *config);\n#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n\n/**\n * Initializes the file system dynamic parameters and mounts the filesystem.\n * If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS\n * if the flash does not contain a recognizable file system.\n * In this case, SPIFFS_format must be called prior to remounting.\n * @param fs            the file system struct\n * @param config        the physical and logical configuration of the file system\n * @param work          a memory work buffer comprising 2*config->log_page_size\n *                      bytes used throughout all file system operations\n * @param fd_space      memory for file descriptors\n * @param fd_space_size memory size of file descriptors\n * @param cache         memory for cache, may be null\n * @param cache_size    memory size of cache\n * @param check_cb_f    callback function for reporting during consistency checks\n */\ns32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,\n    u8_t *fd_space, u32_t fd_space_size,\n    void *cache, u32_t cache_size,\n    spiffs_check_callback check_cb_f);\n\n/**\n * Unmounts the file system. All file handles will be flushed of any\n * cached writes and closed.\n * @param fs            the file system struct\n */\nvoid SPIFFS_unmount(spiffs *fs);\n\n/**\n * Creates a new file.\n * @param fs            the file system struct\n * @param path          the path of the new file\n * @param mode          ignored, for posix compliance\n */\ns32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);\n\n/**\n * Opens/creates a file.\n * @param fs            the file system struct\n * @param path          the path of the new file\n * @param flags         the flags for the open command, can be combinations of\n *                      SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,\n *                      SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL\n * @param mode          ignored, for posix compliance\n */\nspiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);\n\n/**\n * Opens a file by given dir entry.\n * Optimization purposes, when traversing a file system with SPIFFS_readdir\n * a normal SPIFFS_open would need to traverse the filesystem again to find\n * the file, whilst SPIFFS_open_by_dirent already knows where the file resides.\n * @param fs            the file system struct\n * @param e             the dir entry to the file\n * @param flags         the flags for the open command, can be combinations of\n *                      SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,\n *                      SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.\n *                      SPIFFS_CREAT will have no effect in this case.\n * @param mode          ignored, for posix compliance\n */\nspiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);\n\n/**\n * Opens a file by given page index.\n * Optimization purposes, opens a file by directly pointing to the page\n * index in the spi flash.\n * If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE\n * is returned.\n * @param fs            the file system struct\n * @param page_ix       the page index\n * @param flags         the flags for the open command, can be combinations of\n *                      SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,\n *                      SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.\n *                      SPIFFS_CREAT will have no effect in this case.\n * @param mode          ignored, for posix compliance\n */\nspiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);\n\n/**\n * Reads from given filehandle.\n * @param fs            the file system struct\n * @param fh            the filehandle\n * @param buf           where to put read data\n * @param len           how much to read\n * @returns number of bytes read, or -1 if error\n */\ns32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);\n\n/**\n * Writes to given filehandle.\n * @param fs            the file system struct\n * @param fh            the filehandle\n * @param buf           the data to write\n * @param len           how much to write\n * @returns number of bytes written, or -1 if error\n */\ns32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);\n\n/**\n * Moves the read/write file offset. Resulting offset is returned or negative if error.\n * lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.\n * @param fs            the file system struct\n * @param fh            the filehandle\n * @param offs          how much/where to move the offset\n * @param whence        if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes\n *                      if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset\n *                      if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative\n */\ns32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);\n\n/**\n * Removes a file by path\n * @param fs            the file system struct\n * @param path          the path of the file to remove\n */\ns32_t SPIFFS_remove(spiffs *fs, const char *path);\n\n/**\n * Removes a file by filehandle\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to remove\n */\ns32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);\n\n/**\n * Gets file status by path\n * @param fs            the file system struct\n * @param path          the path of the file to stat\n * @param s             the stat struct to populate\n */\ns32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);\n\n/**\n * Gets file status by filehandle\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to stat\n * @param s             the stat struct to populate\n */\ns32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);\n\n/**\n * Flushes all pending write operations from cache for given file\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to flush\n */\ns32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);\n\n/**\n * Closes a filehandle. If there are pending write operations, these are finalized before closing.\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to close\n */\ns32_t SPIFFS_close(spiffs *fs, spiffs_file fh);\n\n/**\n * Renames a file\n * @param fs            the file system struct\n * @param old           path of file to rename\n * @param newPath       new path of file\n */\ns32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);\n\n#if SPIFFS_OBJ_META_LEN\n/**\n * Updates file's metadata\n * @param fs            the file system struct\n * @param path          path to the file\n * @param meta          new metadata. must be SPIFFS_OBJ_META_LEN bytes long.\n */\ns32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta);\n\n/**\n * Updates file's metadata\n * @param fs            the file system struct\n * @param fh            file handle of the file\n * @param meta          new metadata. must be SPIFFS_OBJ_META_LEN bytes long.\n */\ns32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta);\n#endif\n\n/**\n * Returns last error of last file operation.\n * @param fs            the file system struct\n */\ns32_t SPIFFS_errno(spiffs *fs);\n\n/**\n * Clears last error.\n * @param fs            the file system struct\n */\nvoid SPIFFS_clearerr(spiffs *fs);\n\n/**\n * Opens a directory stream corresponding to the given name.\n * The stream is positioned at the first entry in the directory.\n * On hydrogen builds the name argument is ignored as hydrogen builds always correspond\n * to a flat file structure - no directories.\n * @param fs            the file system struct\n * @param name          the name of the directory\n * @param d             pointer the directory stream to be populated\n */\nspiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);\n\n/**\n * Closes a directory stream\n * @param d             the directory stream to close\n */\ns32_t SPIFFS_closedir(spiffs_DIR *d);\n\n/**\n * Reads a directory into given spifs_dirent struct.\n * @param d             pointer to the directory stream\n * @param e             the dirent struct to be populated\n * @returns null if error or end of stream, else given dirent is returned\n */\nstruct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);\n\n/**\n * Runs a consistency check on given filesystem.\n * @param fs            the file system struct\n */\ns32_t SPIFFS_check(spiffs *fs);\n\n/**\n * Returns number of total bytes available and number of used bytes.\n * This is an estimation, and depends on if there a many files with little\n * data or few files with much data.\n * NB: If used number of bytes exceeds total bytes, a SPIFFS_check should\n * run. This indicates a power loss in midst of things. In worst case\n * (repeated powerlosses in mending or gc) you might have to delete some files.\n *\n * @param fs            the file system struct\n * @param total         total number of bytes in filesystem\n * @param used          used number of bytes in filesystem\n */\ns32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);\n\n/**\n * Formats the entire file system. All data will be lost.\n * The filesystem must not be mounted when calling this.\n *\n * NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount\n * MUST be called prior to formatting in order to configure the filesystem.\n * If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling\n * SPIFFS_format.\n * If SPIFFS_mount fails, SPIFFS_format can be called directly without calling\n * SPIFFS_unmount first.\n *\n * @param fs            the file system struct\n */\ns32_t SPIFFS_format(spiffs *fs);\n\n/**\n * Returns nonzero if spiffs is mounted, or zero if unmounted.\n * @param fs            the file system struct\n */\nu8_t SPIFFS_mounted(spiffs *fs);\n\n/**\n * Tries to find a block where most or all pages are deleted, and erase that\n * block if found. Does not care for wear levelling. Will not move pages\n * around.\n * If parameter max_free_pages are set to 0, only blocks with only deleted\n * pages will be selected.\n *\n * NB: the garbage collector is automatically called when spiffs needs free\n * pages. The reason for this function is to give possibility to do background\n * tidying when user knows the system is idle.\n *\n * Use with care.\n *\n * Setting max_free_pages to anything larger than zero will eventually wear\n * flash more as a block containing free pages can be erased.\n *\n * Will set err_no to SPIFFS_OK if a block was found and erased,\n * SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,\n * or other error.\n *\n * @param fs             the file system struct\n * @param max_free_pages maximum number allowed free pages in block\n */\ns32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);\n\n/**\n * Will try to make room for given amount of bytes in the filesystem by moving\n * pages and erasing blocks.\n * If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If\n * there already is this amount (or more) of free space, SPIFFS_gc will\n * silently return. It is recommended to call SPIFFS_info before invoking\n * this method in order to determine what amount of bytes to give.\n *\n * NB: the garbage collector is automatically called when spiffs needs free\n * pages. The reason for this function is to give possibility to do background\n * tidying when user knows the system is idle.\n *\n * Use with care.\n *\n * @param fs            the file system struct\n * @param size          amount of bytes that should be freed\n */\ns32_t SPIFFS_gc(spiffs *fs, u32_t size);\n\n/**\n * Check if EOF reached.\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to check\n */\ns32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);\n\n/**\n * Get position in file.\n * @param fs            the file system struct\n * @param fh            the filehandle of the file to check\n */\ns32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);\n\n/**\n * Registers a callback function that keeps track on operations on file\n * headers. Do note, that this callback is called from within internal spiffs\n * mechanisms. Any operations on the actual file system being callbacked from\n * in this callback will mess things up for sure - do not do this.\n * This can be used to track where files are and move around during garbage\n * collection, which in turn can be used to build location tables in ram.\n * Used in conjuction with SPIFFS_open_by_page this may improve performance\n * when opening a lot of files.\n * Must be invoked after mount.\n *\n * @param fs            the file system struct\n * @param cb_func       the callback on file operations\n */\ns32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);\n\n#if SPIFFS_IX_MAP\n\n/**\n * Maps the first level index lookup to a given memory map.\n * This will make reading big files faster, as the memory map will be used for\n * looking up data pages instead of searching for the indices on the physical\n * medium. When mapping, all affected indicies are found and the information is\n * copied to the array.\n * Whole file or only parts of it may be mapped. The index map will cover file\n * contents from argument offset until and including arguments (offset+len).\n * It is valid to map a longer range than the current file size. The map will\n * then be populated when the file grows.\n * On garbage collections and file data page movements, the map array will be\n * automatically updated. Do not tamper with the map array, as this contains\n * the references to the data pages. Modifying it from outside will corrupt any\n * future readings using this file descriptor.\n * The map will no longer be used when the file descriptor closed or the file\n * is unmapped.\n * This can be useful to get faster and more deterministic timing when reading\n * large files, or when seeking and reading a lot within a file.\n * @param fs      the file system struct\n * @param fh      the file handle of the file to map\n * @param map     a spiffs_ix_map struct, describing the index map\n * @param offset  absolute file offset where to start the index map\n * @param len     length of the mapping in actual file bytes\n * @param map_buf the array buffer for the look up data - number of required\n *                elements in the array can be derived from function\n *                SPIFFS_bytes_to_ix_map_entries given the length\n */\ns32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,\n    u32_t offset, u32_t len, spiffs_page_ix *map_buf);\n\n/**\n * Unmaps the index lookup from this filehandle. All future readings will\n * proceed as normal, requiring reading of the first level indices from\n * physical media.\n * The map and map buffer given in function SPIFFS_ix_map will no longer be\n * referenced by spiffs.\n * It is not strictly necessary to unmap a file before closing it, as closing\n * a file will automatically unmap it.\n * @param fs      the file system struct\n * @param fh      the file handle of the file to unmap\n */\ns32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh);\n\n/**\n * Moves the offset for the index map given in function SPIFFS_ix_map. Parts or\n * all of the map buffer will repopulated.\n * @param fs      the file system struct\n * @param fh      the mapped file handle of the file to remap\n * @param offset  new absolute file offset where to start the index map\n */\ns32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs);\n\n/**\n * Utility function to get number of spiffs_page_ix entries a map buffer must\n * contain on order to map given amount of file data in bytes.\n * See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.\n * @param fs      the file system struct\n * @param bytes   number of file data bytes to map\n * @return        needed number of elements in a spiffs_page_ix array needed to\n *                map given amount of bytes in a file\n */\ns32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes);\n\n/**\n * Utility function to amount of file data bytes that can be mapped when\n * mapping a file with buffer having given number of spiffs_page_ix entries.\n * See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.\n * @param fs      the file system struct\n * @param map_page_ix_entries   number of entries in a spiffs_page_ix array\n * @return        amount of file data in bytes that can be mapped given a map\n *                buffer having given amount of spiffs_page_ix entries\n */\ns32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);\n\n#endif // SPIFFS_IX_MAP\n\n\n#if SPIFFS_TEST_VISUALISATION\n/**\n * Prints out a visualization of the filesystem.\n * @param fs            the file system struct\n */\ns32_t SPIFFS_vis(spiffs *fs);\n#endif\n\n#if SPIFFS_BUFFER_HELP\n/**\n * Returns number of bytes needed for the filedescriptor buffer given\n * amount of file descriptors.\n */\nu32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);\n\n#if SPIFFS_CACHE\n/**\n * Returns number of bytes needed for the cache buffer given\n * amount of cache pages.\n */\nu32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);\n#endif\n#endif\n\n#if SPIFFS_CACHE\n#endif\n#if defined(__cplusplus)\n}\n#endif\n\n#endif /* SPIFFS_H_ */\n"
  },
  {
    "path": "components/spiffs/spiffs_cache.c",
    "content": "/*\n * spiffs_cache.c\n *\n *  Created on: Jun 23, 2013\n *      Author: petera\n */\n\n#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\n#if SPIFFS_CACHE\n\n// returns cached page for give page index, or null if no such cached page\nstatic spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;\n  int i;\n  for (i = 0; i < cache->cpage_count; i++) {\n    spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);\n    if ((cache->cpage_use_map & (1<<i)) &&\n        (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&\n        cp->pix == pix ) {\n      SPIFFS_CACHE_DBG(\"CACHE_GET: have cache page \"_SPIPRIi\" for \"_SPIPRIpg\"\\n\", i, pix);\n      cp->last_access = cache->last_access;\n      return cp;\n    }\n  }\n  //SPIFFS_CACHE_DBG(\"CACHE_GET: no cache for \"_SPIPRIpg\"\\n\", pix);\n  return 0;\n}\n\n// frees cached page\nstatic s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {\n  s32_t res = SPIFFS_OK;\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);\n  if (cache->cpage_use_map & (1<<ix)) {\n    if (write_back &&\n        (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&\n        (cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {\n      u8_t *mem =  spiffs_get_cache_page(fs, cache, ix);\n      res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);\n    }\n\n    cp->flags = 0;\n    cache->cpage_use_map &= ~(1 << ix);\n\n    if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {\n      SPIFFS_CACHE_DBG(\"CACHE_FREE: free cache page \"_SPIPRIi\" objid \"_SPIPRIid\"\\n\", ix, cp->obj_id);\n    } else {\n      SPIFFS_CACHE_DBG(\"CACHE_FREE: free cache page \"_SPIPRIi\" pix \"_SPIPRIpg\"\\n\", ix, cp->pix);\n    }\n  }\n\n  return res;\n}\n\n// removes the oldest accessed cached page\nstatic s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {\n  s32_t res = SPIFFS_OK;\n  spiffs_cache *cache = spiffs_get_cache(fs);\n\n  if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {\n    // at least one free cpage\n    return SPIFFS_OK;\n  }\n\n  // all busy, scan thru all to find the cpage which has oldest access\n  int i;\n  int cand_ix = -1;\n  u32_t oldest_val = 0;\n  for (i = 0; i < cache->cpage_count; i++) {\n    spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);\n    if ((cache->last_access - cp->last_access) > oldest_val &&\n        (cp->flags & flag_mask) == flags) {\n      oldest_val = cache->last_access - cp->last_access;\n      cand_ix = i;\n    }\n  }\n\n  if (cand_ix >= 0) {\n    res = spiffs_cache_page_free(fs, cand_ix, 1);\n  }\n\n  return res;\n}\n\n// allocates a new cached page and returns it, or null if all cache pages are busy\nstatic spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  if (cache->cpage_use_map == 0xffffffff) {\n    // out of cache memory\n    return 0;\n  }\n  int i;\n  for (i = 0; i < cache->cpage_count; i++) {\n    if ((cache->cpage_use_map & (1<<i)) == 0) {\n      spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);\n      cache->cpage_use_map |= (1<<i);\n      cp->last_access = cache->last_access;\n      SPIFFS_CACHE_DBG(\"CACHE_ALLO: allocated cache page \"_SPIPRIi\"\\n\", i);\n      return cp;\n    }\n  }\n  // out of cache entries\n  return 0;\n}\n\n// drops the cache page for give page index\nvoid spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {\n  spiffs_cache_page *cp =  spiffs_cache_page_get(fs, pix);\n  if (cp) {\n    spiffs_cache_page_free(fs, cp->ix, 0);\n  }\n}\n\n// ------------------------------\n\n// reads from spi flash or the cache\ns32_t spiffs_phys_rd(\n    spiffs *fs,\n    u8_t op,\n    spiffs_file fh,\n    u32_t addr,\n    u32_t len,\n    u8_t *dst) {\n  (void)fh;\n  s32_t res = SPIFFS_OK;\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  spiffs_cache_page *cp =  spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));\n  cache->last_access++;\n  if (cp) {\n    // we've already got one, you see\n#if SPIFFS_CACHE_STATS\n    fs->cache_hits++;\n#endif\n    cp->last_access = cache->last_access;\n    u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);\n    memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);\n  } else {\n    if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {\n      // for second layer lookup functions, we do not cache in order to prevent shredding\n      return SPIFFS_HAL_READ(fs, addr, len, dst);\n    }\n#if SPIFFS_CACHE_STATS\n    fs->cache_misses++;\n#endif\n    // this operation will always free one cache page (unless all already free),\n    // the result code stems from the write operation of the possibly freed cache page\n    res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);\n\n    cp = spiffs_cache_page_allocate(fs);\n    if (cp) {\n      cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;\n      cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);\n\n      s32_t res2 = SPIFFS_HAL_READ(fs,\n          addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),\n          SPIFFS_CFG_LOG_PAGE_SZ(fs),\n          spiffs_get_cache_page(fs, cache, cp->ix));\n      if (res2 != SPIFFS_OK) {\n        // honor read failure before possible write failure (bad idea?)\n        res = res2;\n      }\n      u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);\n      memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);\n    } else {\n      // this will never happen, last resort for sake of symmetry\n      s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);\n      if (res2 != SPIFFS_OK) {\n        // honor read failure before possible write failure (bad idea?)\n        res = res2;\n      }\n    }\n  }\n  return res;\n}\n\n// writes to spi flash and/or the cache\ns32_t spiffs_phys_wr(\n    spiffs *fs,\n    u8_t op,\n    spiffs_file fh,\n    u32_t addr,\n    u32_t len,\n    u8_t *src) {\n  (void)fh;\n  spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);\n  spiffs_cache *cache = spiffs_get_cache(fs);\n  spiffs_cache_page *cp =  spiffs_cache_page_get(fs, pix);\n\n  if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {\n    // have a cache page\n    // copy in data to cache page\n\n    if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&\n        (op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {\n      // page is being deleted, wipe from cache - unless it is a lookup page\n      spiffs_cache_page_free(fs, cp->ix, 0);\n      return SPIFFS_HAL_WRITE(fs, addr, len, src);\n    }\n\n    u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);\n    memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);\n\n    cache->last_access++;\n    cp->last_access = cache->last_access;\n\n    if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {\n      // page is being updated, no write-cache, just pass thru\n      return SPIFFS_HAL_WRITE(fs, addr, len, src);\n    } else {\n      return SPIFFS_OK;\n    }\n  } else {\n    // no cache page, no write cache - just write thru\n    return SPIFFS_HAL_WRITE(fs, addr, len, src);\n  }\n}\n\n#if SPIFFS_CACHE_WR\n// returns the cache page that this fd refers, or null if no cache page\nspiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {\n  spiffs_cache *cache = spiffs_get_cache(fs);\n\n  if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {\n    // all cpages free, no cpage cannot be assigned to obj_id\n    return 0;\n  }\n\n  int i;\n  for (i = 0; i < cache->cpage_count; i++) {\n    spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);\n    if ((cache->cpage_use_map & (1<<i)) &&\n        (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&\n        cp->obj_id == fd->obj_id) {\n      return cp;\n    }\n  }\n\n  return 0;\n}\n\n// allocates a new cache page and refers this to given fd - flushes an old cache\n// page if all cache is busy\nspiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {\n  // before this function is called, it is ensured that there is no already existing\n  // cache page with same object id\n  spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);\n  spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);\n  if (cp == 0) {\n    // could not get cache page\n    return 0;\n  }\n\n  cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;\n  cp->obj_id = fd->obj_id;\n  fd->cache_page = cp;\n  return cp;\n}\n\n// unrefers all fds that this cache page refers to and releases the cache page\nvoid spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {\n  if (cp == 0) return;\n  u32_t i;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {\n      cur_fd->cache_page = 0;\n    }\n  }\n  spiffs_cache_page_free(fs, cp->ix, 0);\n\n  cp->obj_id = 0;\n}\n\n#endif\n\n// initializes the cache\nvoid spiffs_cache_init(spiffs *fs) {\n  if (fs->cache == 0) return;\n  u32_t sz = fs->cache_size;\n  u32_t cache_mask = 0;\n  int i;\n  int cache_entries =\n      (sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));\n  if (cache_entries <= 0) return;\n\n  for (i = 0; i < cache_entries; i++) {\n    cache_mask <<= 1;\n    cache_mask |= 1;\n  }\n\n  spiffs_cache cache;\n  memset(&cache, 0, sizeof(spiffs_cache));\n  cache.cpage_count = cache_entries;\n  cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));\n\n  cache.cpage_use_map = 0xffffffff;\n  cache.cpage_use_mask = cache_mask;\n  memcpy(fs->cache, &cache, sizeof(spiffs_cache));\n\n  spiffs_cache *c = spiffs_get_cache(fs);\n\n  memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));\n\n  c->cpage_use_map &= ~(c->cpage_use_mask);\n  for (i = 0; i < cache.cpage_count; i++) {\n    spiffs_get_cache_page_hdr(fs, c, i)->ix = i;\n  }\n}\n\n#endif // SPIFFS_CACHE\n"
  },
  {
    "path": "components/spiffs/spiffs_check.c",
    "content": "/*\n * spiffs_check.c\n *\n * Contains functionality for checking file system consistency\n * and mending problems.\n * Three levels of consistency checks are implemented:\n *\n * Look up consistency\n *   Checks if indices in lookup pages are coherent with page headers\n * Object index consistency\n *   Checks if there are any orphaned object indices (missing object index headers).\n *   If an object index is found but not its header, the object index is deleted.\n *   This is critical for the following page consistency check.\n * Page consistency\n *   Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed\n *\n *\n *  Created on: Jul 7, 2013\n *      Author: petera\n */\n\n\n#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\n#if !SPIFFS_READ_ONLY\n\n#if SPIFFS_HAL_CALLBACK_EXTRA\n#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \\\n  do { \\\n    if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \\\n  } while (0)\n#else\n#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \\\n  do { \\\n    if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \\\n  } while (0)\n#endif\n\n//---------------------------------------\n// Look up consistency\n\n// searches in the object indices and returns the referenced page index given\n// the object id and the data span index\n// destroys fs->lu_work\nstatic s32_t spiffs_object_get_data_page_index_reference(\n  spiffs *fs,\n  spiffs_obj_id obj_id,\n  spiffs_span_ix data_spix,\n  spiffs_page_ix *pix,\n  spiffs_page_ix *objix_pix) {\n  s32_t res;\n\n  // calculate object index span index for given data page span index\n  spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n\n  // find obj index for obj id and span index\n  res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix);\n  SPIFFS_CHECK_RES(res);\n\n  // load obj index entry\n  u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix);\n  if (objix_spix == 0) {\n    // get referenced page from object index header\n    addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix);\n  } else {\n    // get referenced page from object index\n    addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix);\n  }\n\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);\n\n  return res;\n}\n\n// copies page contents to a new page\nstatic s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) {\n  s32_t res;\n  res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix);\n  SPIFFS_CHECK_RES(res);\n  res = spiffs_phys_cpy(fs, 0,\n      SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header),\n      SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),\n      SPIFFS_DATA_PAGE_SIZE(fs));\n  SPIFFS_CHECK_RES(res);\n  return res;\n}\n\n// rewrites the object index for given object id and replaces the\n// data page index to a new page index\nstatic s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n  spiffs_page_ix free_pix;\n  obj_id |= SPIFFS_OBJ_ID_IX_FLAG;\n\n  // find free entry\n  res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);\n  SPIFFS_CHECK_RES(res);\n  free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n\n  // calculate object index span index for given data page span index\n  spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n  if (objix_spix == 0) {\n    // calc index in index header\n    entry = data_spix;\n  } else {\n    // calc entry in index\n    entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);\n\n  }\n  // load index\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n  SPIFFS_CHECK_RES(res);\n  spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;\n\n  // be ultra safe, double check header against provided data\n  if (objix_p_hdr->obj_id != obj_id) {\n    spiffs_page_delete(fs, free_pix);\n    return SPIFFS_ERR_CHECK_OBJ_ID_MISM;\n  }\n  if (objix_p_hdr->span_ix != objix_spix) {\n    spiffs_page_delete(fs, free_pix);\n    return SPIFFS_ERR_CHECK_SPIX_MISM;\n  }\n  if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX |\n                            SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) !=\n                                (SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) {\n    spiffs_page_delete(fs, free_pix);\n    return SPIFFS_ERR_CHECK_FLAGS_BAD;\n  }\n\n  // rewrite in mem\n  if (objix_spix == 0) {\n    ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;\n  } else {\n    ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;\n  }\n\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n  SPIFFS_CHECK_RES(res);\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),\n      sizeof(spiffs_obj_id),\n      (u8_t *)&obj_id);\n  SPIFFS_CHECK_RES(res);\n  res = spiffs_page_delete(fs, objix_pix);\n\n  return res;\n}\n\n// deletes an object just by marking object index header as deleted\nstatic s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {\n  spiffs_page_ix objix_hdr_pix;\n  s32_t res;\n  res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);\n  if (res == SPIFFS_ERR_NOT_FOUND) {\n    return SPIFFS_OK;\n  }\n  SPIFFS_CHECK_RES(res);\n  u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE;\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),\n      sizeof(u8_t),\n      (u8_t *)&flags);\n  return res;\n}\n\n// validates the given look up entry\nstatic s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,\n    spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {\n  (void)cur_block;\n  (void)cur_entry;\n  u8_t delete_page = 0;\n  s32_t res = SPIFFS_OK;\n  spiffs_page_ix objix_pix;\n  spiffs_page_ix ref_pix;\n  // check validity, take actions\n  if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||\n      ((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {\n    // look up entry deleted / free but used in page header\n    SPIFFS_CHECK_DBG(\"LU: pix \"_SPIPRIpg\" deleted/free in lu but not on page\\n\", cur_pix);\n    *reload_lu = 1;\n    delete_page = 1;\n    if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {\n      // header says data page\n      // data page can be removed if not referenced by some object index\n      res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        // no object with this id, so remove page safely\n        res = SPIFFS_OK;\n      } else {\n        SPIFFS_CHECK_RES(res);\n        if (ref_pix == cur_pix) {\n          // data page referenced by object index but deleted in lu\n          // copy page to new place and re-write the object index to new place\n          spiffs_page_ix new_pix;\n          res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: data page not found elsewhere, rewriting \"_SPIPRIpg\" to new page \"_SPIPRIpg\"\\n\", cur_pix, new_pix);\n          SPIFFS_CHECK_RES(res);\n          *reload_lu = 1;\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: \"_SPIPRIpg\" rewritten to \"_SPIPRIpg\", affected objix_pix \"_SPIPRIpg\"\\n\", cur_pix, new_pix, objix_pix);\n          res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);\n          if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n            // index bad also, cannot mend this file\n            SPIFFS_CHECK_DBG(\"LU: FIXUP: index bad \"_SPIPRIi\", cannot mend!\\n\", res);\n            res = spiffs_page_delete(fs, new_pix);\n            SPIFFS_CHECK_RES(res);\n            res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);\n            CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);\n          } else {\n            CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);\n          }\n          SPIFFS_CHECK_RES(res);\n        }\n      }\n    } else {\n      // header says index page\n      // index page can be removed if other index with same obj_id and spanix is found\n      res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        // no such index page found, check for a data page amongst page headers\n        // lu cannot be trusted\n        res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);\n        if (res == SPIFFS_OK) { // ignore other errors\n          // got a data page also, assume lu corruption only, rewrite to new page\n          spiffs_page_ix new_pix;\n          res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: ix page with data not found elsewhere, rewriting \"_SPIPRIpg\" to new page \"_SPIPRIpg\"\\n\", cur_pix, new_pix);\n          SPIFFS_CHECK_RES(res);\n          *reload_lu = 1;\n          CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);\n        }\n      } else {\n        SPIFFS_CHECK_RES(res);\n      }\n    }\n  }\n  if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {\n    // look up entry used\n    if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {\n      SPIFFS_CHECK_DBG(\"LU: pix \"_SPIPRIpg\" differ in obj_id lu:\"_SPIPRIid\" ph:\"_SPIPRIid\"\\n\", cur_pix, lu_obj_id, p_hdr->obj_id);\n      delete_page = 1;\n      if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||\n          (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||\n          (p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {\n        // page deleted or not finalized, just remove it\n      } else {\n        if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {\n          // if data page, check for reference to this page\n          res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);\n          if (res == SPIFFS_ERR_NOT_FOUND) {\n            // no object with this id, so remove page safely\n            res = SPIFFS_OK;\n          } else {\n            SPIFFS_CHECK_RES(res);\n            //   if found, rewrite page with object id, update index, and delete current\n            if (ref_pix == cur_pix) {\n              spiffs_page_ix new_pix;\n              res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);\n              SPIFFS_CHECK_RES(res);\n              res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);\n              if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n                // index bad also, cannot mend this file\n                SPIFFS_CHECK_DBG(\"LU: FIXUP: index bad \"_SPIPRIi\", cannot mend!\\n\", res);\n                res = spiffs_page_delete(fs, new_pix);\n                SPIFFS_CHECK_RES(res);\n                res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);\n                *reload_lu = 1;\n                CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);\n              }\n              SPIFFS_CHECK_RES(res);\n            }\n          }\n        } else {\n          // else if index, check for other pages with both obj_id's and spanix\n          spiffs_page_ix objix_pix_lu, objix_pix_ph;\n          // see if other object index page exists for lookup obj id and span index\n          res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu);\n          if (res == SPIFFS_ERR_NOT_FOUND) {\n            res = SPIFFS_OK;\n            objix_pix_lu = 0;\n          }\n          SPIFFS_CHECK_RES(res);\n          // see if other object index exists for page header obj id and span index\n          res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph);\n          if (res == SPIFFS_ERR_NOT_FOUND) {\n            res = SPIFFS_OK;\n            objix_pix_ph = 0;\n          }\n          SPIFFS_CHECK_RES(res);\n          //   if both obj_id's found, just delete current\n          if (objix_pix_ph == 0 || objix_pix_lu == 0) {\n            // otherwise try finding first corresponding data pages\n            spiffs_page_ix data_pix_lu, data_pix_ph;\n            // see if other data page exists for look up obj id and span index\n            res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);\n            if (res == SPIFFS_ERR_NOT_FOUND) {\n              res = SPIFFS_OK;\n              objix_pix_lu = 0;\n            }\n            SPIFFS_CHECK_RES(res);\n            // see if other data page exists for page header obj id and span index\n            res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);\n            if (res == SPIFFS_ERR_NOT_FOUND) {\n              res = SPIFFS_OK;\n              objix_pix_ph = 0;\n            }\n            SPIFFS_CHECK_RES(res);\n\n            spiffs_page_header new_ph;\n            new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);\n            new_ph.span_ix = p_hdr->span_ix;\n            spiffs_page_ix new_pix;\n            if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||\n                (objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {\n              //   got a data page for page header obj id\n              //   rewrite as obj_id_ph\n              new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n              res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);\n              SPIFFS_CHECK_DBG(\"LU: FIXUP: rewrite page \"_SPIPRIpg\" as \"_SPIPRIid\" to pix \"_SPIPRIpg\"\\n\", cur_pix, new_ph.obj_id, new_pix);\n              CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);\n              SPIFFS_CHECK_RES(res);\n              *reload_lu = 1;\n            } else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||\n                (objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {\n              //   got a data page for look up obj id\n              //   rewrite as obj_id_lu\n              new_ph.obj_id =  lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n              SPIFFS_CHECK_DBG(\"LU: FIXUP: rewrite page \"_SPIPRIpg\" as \"_SPIPRIid\"\\n\", cur_pix, new_ph.obj_id);\n              CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);\n              res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);\n              SPIFFS_CHECK_RES(res);\n              *reload_lu = 1;\n            } else {\n              // cannot safely do anything\n              SPIFFS_CHECK_DBG(\"LU: FIXUP: nothing to do, just delete\\n\");\n            }\n          }\n        }\n      }\n    } else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||\n        ((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {\n      SPIFFS_CHECK_DBG(\"LU: \"_SPIPRIpg\" lu/page index marking differ\\n\", cur_pix);\n      spiffs_page_ix data_pix, objix_pix_d;\n      // see if other data page exists for given obj id and span index\n      res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        res = SPIFFS_OK;\n        data_pix = 0;\n      }\n      SPIFFS_CHECK_RES(res);\n      // see if other object index exists for given obj id and span index\n      res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        res = SPIFFS_OK;\n        objix_pix_d = 0;\n      }\n      SPIFFS_CHECK_RES(res);\n\n      delete_page = 1;\n      // if other data page exists and object index exists, just delete page\n      if (data_pix && objix_pix_d) {\n        SPIFFS_CHECK_DBG(\"LU: FIXUP: other index and data page exists, simply remove\\n\");\n      } else\n      // if only data page exists, make this page index\n      if (data_pix && objix_pix_d == 0) {\n        SPIFFS_CHECK_DBG(\"LU: FIXUP: other data page exists, make this index\\n\");\n        CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);\n        spiffs_page_header new_ph;\n        spiffs_page_ix new_pix;\n        new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);\n        new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n        new_ph.span_ix = p_hdr->span_ix;\n        res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);\n        SPIFFS_CHECK_RES(res);\n        res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),\n            SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),\n            SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));\n        SPIFFS_CHECK_RES(res);\n      } else\n      // if only index exists, make data page\n      if (data_pix == 0 && objix_pix_d) {\n        SPIFFS_CHECK_DBG(\"LU: FIXUP: other index page exists, make this data\\n\");\n        CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);\n        spiffs_page_header new_ph;\n        spiffs_page_ix new_pix;\n        new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);\n        new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n        new_ph.span_ix = p_hdr->span_ix;\n        res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);\n        SPIFFS_CHECK_RES(res);\n        res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),\n            SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),\n            SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));\n        SPIFFS_CHECK_RES(res);\n      } else {\n        // if nothing exists, we cannot safely make a decision - delete\n      }\n    }\n    else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {\n      SPIFFS_CHECK_DBG(\"LU: pix \"_SPIPRIpg\" busy in lu but deleted on page\\n\", cur_pix);\n      delete_page = 1;\n    } else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {\n      SPIFFS_CHECK_DBG(\"LU: pix \"_SPIPRIpg\" busy but not final\\n\", cur_pix);\n      // page can be removed if not referenced by object index\n      *reload_lu = 1;\n      res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        // no object with this id, so remove page safely\n        res = SPIFFS_OK;\n        delete_page = 1;\n      } else {\n        SPIFFS_CHECK_RES(res);\n        if (ref_pix != cur_pix) {\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: other finalized page is referred, just delete\\n\");\n          delete_page = 1;\n        } else {\n          // page referenced by object index but not final\n          // just finalize\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: unfinalized page is referred, finalizing\\n\");\n          CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);\n          u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;\n          res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n              0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),\n              sizeof(u8_t), (u8_t*)&flags);\n        }\n      }\n    }\n  }\n\n  if (delete_page) {\n    SPIFFS_CHECK_DBG(\"LU: FIXUP: deleting page \"_SPIPRIpg\"\\n\", cur_pix);\n    CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);\n    res = spiffs_page_delete(fs, cur_pix);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  return res;\n}\n\nstatic s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,\n    const void *user_const_p, void *user_var_p) {\n  (void)user_const_p;\n  (void)user_var_p;\n  s32_t res = SPIFFS_OK;\n  spiffs_page_header p_hdr;\n  spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);\n\n  CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,\n      (cur_block * 256)/fs->block_count, 0);\n\n  // load header\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n  SPIFFS_CHECK_RES(res);\n\n  int reload_lu = 0;\n\n  res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);\n  SPIFFS_CHECK_RES(res);\n\n  if (res == SPIFFS_OK) {\n    return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;\n  }\n  return res;\n}\n\n\n// Scans all object look up. For each entry, corresponding page header is checked for validity.\n// If an object index header page is found, this is also checked\ns32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {\n  (void)check_all_objects;\n  s32_t res = SPIFFS_OK;\n\n  CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);\n\n  res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_OK;\n  }\n\n  if (res != SPIFFS_OK) {\n    CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);\n  }\n\n  CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);\n\n  return res;\n}\n\n//---------------------------------------\n// Page consistency\n\n// Scans all pages (except lu pages), reserves 4 bits in working memory for each page\n// bit 0: 0 == FREE|DELETED, 1 == USED\n// bit 1: 0 == UNREFERENCED, 1 == REFERENCED\n// bit 2: 0 == NOT_INDEX,    1 == INDEX\n// bit 3: unused\n// A consistent file system will have only pages being\n//  * x000 free, unreferenced, not index\n//  * x011 used, referenced only once, not index\n//  * x101 used, unreferenced, index\n// The working memory might not fit all pages so several scans might be needed\nstatic s32_t spiffs_page_consistency_check_i(spiffs *fs) {\n  const u32_t bits = 4;\n  const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;\n\n  s32_t res = SPIFFS_OK;\n  spiffs_page_ix pix_offset = 0;\n\n  // for each range of pages fitting into work memory\n  while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {\n    // set this flag to abort all checks and rescan the page range\n    u8_t restart = 0;\n    memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n\n    spiffs_block_ix cur_block = 0;\n    // build consistency bitmap for id range traversing all blocks\n    while (!restart && cur_block < fs->block_count) {\n      CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,\n          (pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +\n          ((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),\n          0);\n      // traverse each page except for lookup pages\n      spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;\n      while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {\n        //if ((cur_pix & 0xff) == 0)\n        //  SPIFFS_CHECK_DBG(\"PA: processing pix \"_SPIPRIpg\", block \"_SPIPRIbl\" of pix \"_SPIPRIpg\", block \"_SPIPRIbl\"\\n\",\n        //      cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);\n\n        // read header\n        spiffs_page_header p_hdr;\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n            0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n        SPIFFS_CHECK_RES(res);\n\n        u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);\n        const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits);\n        const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits;\n\n        if (within_range &&\n            (p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {\n          // used\n          fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0));\n        }\n        if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&\n            (p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&\n            (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {\n          // found non-deleted index\n          if (within_range) {\n            fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2));\n          }\n\n          // load non-deleted index\n          res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n              0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n          SPIFFS_CHECK_RES(res);\n\n          // traverse index for referenced pages\n          spiffs_page_ix *object_page_index;\n          spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;\n\n          int entries;\n          int i;\n          spiffs_span_ix data_spix_offset;\n          if (p_hdr.span_ix == 0) {\n            // object header page index\n            entries = SPIFFS_OBJ_HDR_IX_LEN(fs);\n            data_spix_offset = 0;\n            object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));\n          } else {\n            // object page index\n            entries = SPIFFS_OBJ_IX_LEN(fs);\n            data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);\n            object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));\n          }\n\n          // for all entries in index\n          for (i = 0; !restart && i < entries; i++) {\n            spiffs_page_ix rpix = object_page_index[i];\n            u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;\n\n            if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs))\n                || (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {\n\n              // bad reference\n              SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\"x bad pix / LU referenced from page \"_SPIPRIpg\"\\n\",\n                  rpix, cur_pix);\n              // check for data page elsewhere\n              spiffs_page_ix data_pix;\n              res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n                  data_spix_offset + i, 0, &data_pix);\n              if (res == SPIFFS_ERR_NOT_FOUND) {\n                res = SPIFFS_OK;\n                data_pix = 0;\n              }\n              SPIFFS_CHECK_RES(res);\n              if (data_pix == 0) {\n                // if not, allocate free page\n                spiffs_page_header new_ph;\n                new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);\n                new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n                new_ph.span_ix = data_spix_offset + i;\n                res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);\n                SPIFFS_CHECK_RES(res);\n                SPIFFS_CHECK_DBG(\"PA: FIXUP: found no existing data page, created new @ \"_SPIPRIpg\"\\n\", data_pix);\n              }\n              // remap index\n              SPIFFS_CHECK_DBG(\"PA: FIXUP: rewriting index pix \"_SPIPRIpg\"\\n\", cur_pix);\n              res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,\n                  data_spix_offset + i, data_pix, cur_pix);\n              if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n                // index bad also, cannot mend this file\n                SPIFFS_CHECK_DBG(\"PA: FIXUP: index bad \"_SPIPRIi\", cannot mend - delete object\\n\", res);\n                CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);\n                // delete file\n                res = spiffs_page_delete(fs, cur_pix);\n              } else {\n                CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);\n              }\n              SPIFFS_CHECK_RES(res);\n              restart = 1;\n\n            } else if (rpix_within_range) {\n\n              // valid reference\n              // read referenced page header\n              spiffs_page_header rp_hdr;\n              res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                  0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);\n              SPIFFS_CHECK_RES(res);\n\n              // cross reference page header check\n              if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||\n                  rp_hdr.span_ix != data_spix_offset + i ||\n                  (rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=\n                      (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {\n               SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" has inconsistent page header ix id/span:\"_SPIPRIid\"/\"_SPIPRIsp\", ref id/span:\"_SPIPRIid\"/\"_SPIPRIsp\" flags:\"_SPIPRIfl\"\\n\",\n                    rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,\n                    rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);\n               // try finding correct page\n               spiffs_page_ix data_pix;\n               res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n                   data_spix_offset + i, rpix, &data_pix);\n               if (res == SPIFFS_ERR_NOT_FOUND) {\n                 res = SPIFFS_OK;\n                 data_pix = 0;\n               }\n               SPIFFS_CHECK_RES(res);\n               if (data_pix == 0) {\n                 // not found, this index is badly borked\n                 SPIFFS_CHECK_DBG(\"PA: FIXUP: index bad, delete object id \"_SPIPRIid\"\\n\", p_hdr.obj_id);\n                 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);\n                 res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);\n                 SPIFFS_CHECK_RES(res);\n                 break;\n               } else {\n                 // found it, so rewrite index\n                 SPIFFS_CHECK_DBG(\"PA: FIXUP: found correct data pix \"_SPIPRIpg\", rewrite ix pix \"_SPIPRIpg\" id \"_SPIPRIid\"\\n\",\n                     data_pix, cur_pix, p_hdr.obj_id);\n                 res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);\n                 if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n                   // index bad also, cannot mend this file\n                   SPIFFS_CHECK_DBG(\"PA: FIXUP: index bad \"_SPIPRIi\", cannot mend!\\n\", res);\n                   CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);\n                   res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);\n                 } else {\n                   CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);\n                 }\n                 SPIFFS_CHECK_RES(res);\n                 restart = 1;\n               }\n              }\n              else {\n                // mark rpix as referenced\n                const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits);\n                const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits;\n                if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) {\n                  SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" multiple referenced from page \"_SPIPRIpg\"\\n\",\n                      rpix, cur_pix);\n                  // Here, we should have fixed all broken references - getting this means there\n                  // must be multiple files with same object id. Only solution is to delete\n                  // the object which is referring to this page\n                  SPIFFS_CHECK_DBG(\"PA: FIXUP: removing object \"_SPIPRIid\" and page \"_SPIPRIpg\"\\n\",\n                      p_hdr.obj_id, cur_pix);\n                  CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);\n                  res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);\n                  SPIFFS_CHECK_RES(res);\n                  // extra precaution, delete this page also\n                  res = spiffs_page_delete(fs, cur_pix);\n                  SPIFFS_CHECK_RES(res);\n                  restart = 1;\n                }\n                fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1));\n              }\n            }\n          } // for all index entries\n        } // found index\n\n        // next page\n        cur_pix++;\n      }\n      // next block\n      cur_block++;\n    }\n    // check consistency bitmap\n    if (!restart) {\n      spiffs_page_ix objix_pix;\n      spiffs_page_ix rpix;\n\n      u32_t byte_ix;\n      u8_t bit_ix;\n      for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {\n        for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) {\n          u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;\n          spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix;\n\n          // 000 ok - free, unreferenced, not index\n\n          if (bitmask == 0x1) {\n\n            // 001\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" USED, UNREFERENCED, not index\\n\", cur_pix);\n\n            u8_t rewrite_ix_to_this = 0;\n            u8_t delete_page = 0;\n            // check corresponding object index entry\n            spiffs_page_header p_hdr;\n            res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n            SPIFFS_CHECK_RES(res);\n\n            res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,\n                &rpix, &objix_pix);\n            if (res == SPIFFS_OK) {\n              if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {\n                // pointing to a bad page altogether, rewrite index to this\n                rewrite_ix_to_this = 1;\n                SPIFFS_CHECK_DBG(\"PA: corresponding ref is bad: \"_SPIPRIpg\", rewrite to this \"_SPIPRIpg\"\\n\", rpix, cur_pix);\n              } else {\n                // pointing to something else, check what\n                spiffs_page_header rp_hdr;\n                res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                    0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);\n                SPIFFS_CHECK_RES(res);\n                if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&\n                    ((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==\n                        (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {\n                  // pointing to something else valid, just delete this page then\n                  SPIFFS_CHECK_DBG(\"PA: corresponding ref is good but different: \"_SPIPRIpg\", delete this \"_SPIPRIpg\"\\n\", rpix, cur_pix);\n                  delete_page = 1;\n                } else {\n                  // pointing to something weird, update index to point to this page instead\n                  if (rpix != cur_pix) {\n                    SPIFFS_CHECK_DBG(\"PA: corresponding ref is weird: \"_SPIPRIpg\" %s%s%s%s, rewrite this \"_SPIPRIpg\"\\n\", rpix,\n                        (rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? \"\" : \"INDEX \",\n                            (rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? \"\" : \"DELETED \",\n                                (rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? \"NOTUSED \" : \"\",\n                                    (rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? \"NOTFINAL \" : \"\",\n                        cur_pix);\n                    rewrite_ix_to_this = 1;\n                  } else {\n                    // should not happen, destined for fubar\n                  }\n                }\n              }\n            } else if (res == SPIFFS_ERR_NOT_FOUND) {\n              SPIFFS_CHECK_DBG(\"PA: corresponding ref not found, delete \"_SPIPRIpg\"\\n\", cur_pix);\n              delete_page = 1;\n              res = SPIFFS_OK;\n            }\n\n            if (rewrite_ix_to_this) {\n              // if pointing to invalid page, redirect index to this page\n              SPIFFS_CHECK_DBG(\"PA: FIXUP: rewrite index id \"_SPIPRIid\" data spix \"_SPIPRIsp\" to point to this pix: \"_SPIPRIpg\"\\n\",\n                  p_hdr.obj_id, p_hdr.span_ix, cur_pix);\n              res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);\n              if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {\n                // index bad also, cannot mend this file\n                SPIFFS_CHECK_DBG(\"PA: FIXUP: index bad \"_SPIPRIi\", cannot mend!\\n\", res);\n                CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);\n                res = spiffs_page_delete(fs, cur_pix);\n                SPIFFS_CHECK_RES(res);\n                res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);\n              } else {\n                CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);\n              }\n              SPIFFS_CHECK_RES(res);\n              restart = 1;\n              continue;\n            } else if (delete_page) {\n              SPIFFS_CHECK_DBG(\"PA: FIXUP: deleting page \"_SPIPRIpg\"\\n\", cur_pix);\n              CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);\n              res = spiffs_page_delete(fs, cur_pix);\n            }\n            SPIFFS_CHECK_RES(res);\n          }\n          if (bitmask == 0x2) {\n\n            // 010\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" FREE, REFERENCED, not index\\n\", cur_pix);\n\n            // no op, this should be taken care of when checking valid references\n          }\n\n          // 011 ok - busy, referenced, not index\n\n          if (bitmask == 0x4) {\n\n            // 100\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" FREE, unreferenced, INDEX\\n\", cur_pix);\n\n            // this should never happen, major fubar\n          }\n\n          // 101 ok - busy, unreferenced, index\n\n          if (bitmask == 0x6) {\n\n            // 110\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" FREE, REFERENCED, INDEX\\n\", cur_pix);\n\n            // no op, this should be taken care of when checking valid references\n          }\n          if (bitmask == 0x7) {\n\n            // 111\n            SPIFFS_CHECK_DBG(\"PA: pix \"_SPIPRIpg\" USED, REFERENCED, INDEX\\n\", cur_pix);\n\n            // no op, this should be taken care of when checking valid references\n          }\n        }\n      }\n    }\n\n    SPIFFS_CHECK_DBG(\"PA: processed \"_SPIPRIpg\", restart \"_SPIPRIi\"\\n\", pix_offset, restart);\n    // next page range\n    if (!restart) {\n      pix_offset += pages_per_scan;\n    }\n  } // while page range not reached end\n  return res;\n}\n\n// Checks consistency amongst all pages and fixes irregularities\ns32_t spiffs_page_consistency_check(spiffs *fs) {\n  CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);\n  s32_t res = spiffs_page_consistency_check_i(fs);\n  if (res != SPIFFS_OK) {\n    CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);\n  }\n  CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);\n  return res;\n}\n\n//---------------------------------------\n// Object index consistency\n\n// searches for given object id in temporary object id index,\n// returns the index or -1\nstatic int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {\n  u32_t i;\n  spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;\n  obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n  for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {\n    if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {\n      return i;\n    }\n  }\n  return -1;\n}\n\nstatic s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,\n    int cur_entry, const void *user_const_p, void *user_var_p) {\n  (void)user_const_p;\n  s32_t res_c = SPIFFS_VIS_COUNTINUE;\n  s32_t res = SPIFFS_OK;\n  u32_t *log_ix = (u32_t*)user_var_p;\n  spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;\n\n  CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,\n      (cur_block * 256)/fs->block_count, 0);\n\n  if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {\n    spiffs_page_header p_hdr;\n    spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);\n\n    // load header\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n    SPIFFS_CHECK_RES(res);\n\n    if (p_hdr.span_ix == 0 &&\n        (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==\n        (SPIFFS_PH_FLAG_DELET)) {\n      SPIFFS_CHECK_DBG(\"IX: pix \"_SPIPRIpg\", obj id:\"_SPIPRIid\" spix:\"_SPIPRIsp\" header not fully deleted - deleting\\n\",\n          cur_pix, obj_id, p_hdr.span_ix);\n      CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);\n      res = spiffs_page_delete(fs, cur_pix);\n      SPIFFS_CHECK_RES(res);\n      return res_c;\n    }\n\n    if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==\n        (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {\n      return res_c;\n    }\n\n    if (p_hdr.span_ix == 0) {\n      // objix header page, register objid as reachable\n      int r = spiffs_object_index_search(fs, obj_id);\n      if (r == -1) {\n        // not registered, do it\n        obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n        (*log_ix)++;\n        if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {\n          *log_ix = 0;\n        }\n      }\n    } else { // span index\n      // objix page, see if header can be found\n      int r = spiffs_object_index_search(fs, obj_id);\n      u8_t delete = 0;\n      if (r == -1) {\n        // not in temporary index, try finding it\n        spiffs_page_ix objix_hdr_pix;\n        res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);\n        res_c = SPIFFS_VIS_COUNTINUE_RELOAD;\n        if (res == SPIFFS_OK) {\n          // found, register as reachable\n          obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n        } else if (res == SPIFFS_ERR_NOT_FOUND) {\n          // not found, register as unreachable\n          delete = 1;\n          obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n        } else {\n          SPIFFS_CHECK_RES(res);\n        }\n        (*log_ix)++;\n        if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {\n          *log_ix = 0;\n        }\n      } else {\n        // in temporary index, check reachable flag\n        if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {\n          // registered as unreachable\n          delete = 1;\n        }\n      }\n\n      if (delete) {\n        SPIFFS_CHECK_DBG(\"IX: FIXUP: pix \"_SPIPRIpg\", obj id:\"_SPIPRIid\" spix:\"_SPIPRIsp\" is orphan index - deleting\\n\",\n            cur_pix, obj_id, p_hdr.span_ix);\n        CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);\n        res = spiffs_page_delete(fs, cur_pix);\n        SPIFFS_CHECK_RES(res);\n      }\n    } // span index\n  } // valid object index id\n\n  return res_c;\n}\n\n// Removes orphaned and partially deleted index pages.\n// Scans for index pages. When an index page is found, corresponding index header is searched for.\n// If no such page exists, the index page cannot be reached as no index header exists and must be\n// deleted.\ns32_t spiffs_object_index_consistency_check(spiffs *fs) {\n  s32_t res = SPIFFS_OK;\n  // impl note:\n  // fs->work is used for a temporary object index memory, listing found object ids and\n  // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.\n  // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate\n  // a reachable/unreachable object id.\n  memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n  u32_t obj_id_log_ix = 0;\n  CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);\n  res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,\n        0, 0);\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_OK;\n  }\n  if (res != SPIFFS_OK) {\n    CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);\n  }\n  CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);\n  return res;\n}\n\n#endif // !SPIFFS_READ_ONLY\n"
  },
  {
    "path": "components/spiffs/spiffs_config.h",
    "content": "/*\n * spiffs_config.h\n *\n *  Created on: Jul 3, 2013\n *      Author: petera\n */\n\n#ifndef SPIFFS_CONFIG_H_\n#define SPIFFS_CONFIG_H_\n\n// ----------- 8< ------------\n// Following includes are for the linux test build of spiffs\n// These may/should/must be removed/altered/replaced in your target\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stddef.h>\n#include <unistd.h>\n#include <stdint.h>\n#include <ctype.h>\n// ----------- >8 ------------\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/queue.h\"\n#include \"freertos/semphr.h\"\n\ntypedef signed int s32_t;\ntypedef unsigned int u32_t;\ntypedef signed short s16_t;\ntypedef unsigned short u16_t;\ntypedef signed char s8_t;\ntypedef unsigned char u8_t;\n\nQueueHandle_t spiffs_mutex;\n\n// compile time switches\n\n// Set generic spiffs debug output call.\n#ifndef SPIFFS_DBG\n#define SPIFFS_DBG(...) //printf(__VA_ARGS__)\n#endif\n// Set spiffs debug output call for garbage collecting.\n#ifndef SPIFFS_GC_DBG\n#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)\n#endif\n// Set spiffs debug output call for caching.\n#ifndef SPIFFS_CACHE_DBG\n#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)\n#endif\n// Set spiffs debug output call for system consistency checks.\n#ifndef SPIFFS_CHECK_DBG\n#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)\n#endif\n\n\n// Defines spiffs debug print formatters\n// some general signed number\n#ifndef _SPIPRIi\n#define _SPIPRIi   \"%d\"\n#endif\n// address\n#ifndef _SPIPRIad\n#define _SPIPRIad  \"%08x\"\n#endif\n// block\n#ifndef _SPIPRIbl\n#define _SPIPRIbl  \"%04x\"\n#endif\n// page\n#ifndef _SPIPRIpg\n#define _SPIPRIpg  \"%04x\"\n#endif\n// span index\n#ifndef _SPIPRIsp\n#define _SPIPRIsp  \"%04x\"\n#endif\n// file descriptor\n#ifndef _SPIPRIfd\n#define _SPIPRIfd  \"%d\"\n#endif\n// file object id\n#ifndef _SPIPRIid\n#define _SPIPRIid  \"%04x\"\n#endif\n// file flags\n#ifndef _SPIPRIfl\n#define _SPIPRIfl  \"%02x\"\n#endif\n\n// Enable/disable API functions to determine exact number of bytes\n// for filedescriptor and cache buffers. Once decided for a configuration,\n// this can be disabled to reduce flash.\n#ifndef SPIFFS_BUFFER_HELP\n#define SPIFFS_BUFFER_HELP              0\n#endif\n\n// Enables/disable memory read caching of nucleus file system operations.\n// If enabled, memory area must be provided for cache in SPIFFS_mount.\n#ifndef  SPIFFS_CACHE\n#define SPIFFS_CACHE                    1\n#endif\n#if SPIFFS_CACHE\n// Enables memory write caching for file descriptors in hydrogen\n#ifndef  SPIFFS_CACHE_WR\n#define SPIFFS_CACHE_WR                 1\n#endif\n\n// Enable/disable statistics on caching. Debug/test purpose only.\n#ifndef  SPIFFS_CACHE_STATS\n#define SPIFFS_CACHE_STATS              0\n#endif\n#endif\n\n// Always check header of each accessed page to ensure consistent state.\n// If enabled it will increase number of reads, will increase flash.\n#ifndef SPIFFS_PAGE_CHECK\n#define SPIFFS_PAGE_CHECK               0\n#endif\n\n// Define maximum number of gc runs to perform to reach desired free pages.\n#ifndef SPIFFS_GC_MAX_RUNS\n#define SPIFFS_GC_MAX_RUNS              5\n#endif\n\n// Enable/disable statistics on gc. Debug/test purpose only.\n#ifndef SPIFFS_GC_STATS\n#define SPIFFS_GC_STATS                 0\n#endif\n\n// Garbage collecting examines all pages in a block which and sums up\n// to a block score. Deleted pages normally gives positive score and\n// used pages normally gives a negative score (as these must be moved).\n// To have a fair wear-leveling, the erase age is also included in score,\n// whose factor normally is the most positive.\n// The larger the score, the more likely it is that the block will\n// picked for garbage collection.\n\n// Garbage collecting heuristics - weight used for deleted pages.\n#ifndef SPIFFS_GC_HEUR_W_DELET\n#define SPIFFS_GC_HEUR_W_DELET          (5)\n#endif\n// Garbage collecting heuristics - weight used for used pages.\n#ifndef SPIFFS_GC_HEUR_W_USED\n#define SPIFFS_GC_HEUR_W_USED           (-1)\n#endif\n// Garbage collecting heuristics - weight used for time between\n// last erased and erase of this block.\n#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE\n#define SPIFFS_GC_HEUR_W_ERASE_AGE      (50)\n#endif\n\n// Object name maximum length. Note that this length include the\n// zero-termination character, meaning maximum string of characters\n// can at most be SPIFFS_OBJ_NAME_LEN - 1.\n#ifndef SPIFFS_OBJ_NAME_LEN\n#define SPIFFS_OBJ_NAME_LEN             (64)\n#endif\n\n// Maximum length of the metadata associated with an object.\n// Setting to non-zero value enables metadata-related API but also\n// changes the on-disk format, so the change is not backward-compatible.\n//\n// Do note: the meta length must never exceed\n// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64)\n//\n// This is derived from following:\n// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +\n// spiffs_object_ix_header fields + at least some LUT entries)\n#ifndef SPIFFS_OBJ_META_LEN\n#define SPIFFS_OBJ_META_LEN             (64)\n#endif\n\n// Size of buffer allocated on stack used when copying data.\n// Lower value generates more read/writes. No meaning having it bigger\n// than logical page size.\n#ifndef SPIFFS_COPY_BUFFER_STACK\n#define SPIFFS_COPY_BUFFER_STACK        (256)\n#endif\n\n// Enable this to have an identifiable spiffs filesystem. This will look for\n// a magic in all sectors to determine if this is a valid spiffs system or\n// not on mount point. If not, SPIFFS_format must be called prior to mounting\n// again.\n#ifndef SPIFFS_USE_MAGIC\n#define SPIFFS_USE_MAGIC                (1)\n#endif\n\n#if SPIFFS_USE_MAGIC\n// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is\n// enabled, the magic will also be dependent on the length of the filesystem.\n// For example, a filesystem configured and formatted for 4 megabytes will not\n// be accepted for mounting with a configuration defining the filesystem as 2\n// megabytes.\n#ifndef SPIFFS_USE_MAGIC_LENGTH\n#define SPIFFS_USE_MAGIC_LENGTH         (1)\n#endif\n#endif\n\n// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level\n// These should be defined on a multithreaded system\n\n// define this to enter a mutex if you're running on a multithreaded system\n#ifndef SPIFFS_LOCK\n#define SPIFFS_LOCK(fs) xSemaphoreTake(spiffs_mutex, portMAX_DELAY)\n#endif\n// define this to exit a mutex if you're running on a multithreaded system\n#ifndef SPIFFS_UNLOCK\n#define SPIFFS_UNLOCK(fs) xSemaphoreGive(spiffs_mutex)\n#endif\n\n// Enable if only one spiffs instance with constant configuration will exist\n// on the target. This will reduce calculations, flash and memory accesses.\n// Parts of configuration must be defined below instead of at time of mount.\n#ifndef SPIFFS_SINGLETON\n#define SPIFFS_SINGLETON 0\n#endif\n\n#if SPIFFS_SINGLETON\n// Instead of giving parameters in config struct, singleton build must\n// give parameters in defines below.\n#ifndef SPIFFS_CFG_PHYS_SZ\n#define SPIFFS_CFG_PHYS_SZ(ignore)        (1024*1024*2)\n#endif\n#ifndef SPIFFS_CFG_PHYS_ERASE_SZ\n#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore)  (65536)\n#endif\n#ifndef SPIFFS_CFG_PHYS_ADDR\n#define SPIFFS_CFG_PHYS_ADDR(ignore)      (0)\n#endif\n#ifndef SPIFFS_CFG_LOG_PAGE_SZ\n#define SPIFFS_CFG_LOG_PAGE_SZ(ignore)    (256)\n#endif\n#ifndef SPIFFS_CFG_LOG_BLOCK_SZ\n#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore)   (65536)\n#endif\n#endif\n\n// Enable this if your target needs aligned data for index tables\n#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES\n#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES       1\n#endif\n\n// Enable this if you want the HAL callbacks to be called with the spiffs struct\n#ifndef SPIFFS_HAL_CALLBACK_EXTRA\n#define SPIFFS_HAL_CALLBACK_EXTRA         0\n#endif\n\n// Enable this if you want to add an integer offset to all file handles\n// (spiffs_file). This is useful if running multiple instances of spiffs on\n// same target, in order to recognise to what spiffs instance a file handle\n// belongs.\n// NB: This adds config field fh_ix_offset in the configuration struct when\n// mounting, which must be defined.\n#ifndef SPIFFS_FILEHDL_OFFSET\n#define SPIFFS_FILEHDL_OFFSET                 0\n#endif\n\n// Enable this to compile a read only version of spiffs.\n// This will reduce binary size of spiffs. All code comprising modification\n// of the file system will not be compiled. Some config will be ignored.\n// HAL functions for erasing and writing to spi-flash may be null. Cache\n// can be disabled for even further binary size reduction (and ram savings).\n// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.\n// If the file system cannot be mounted due to aborted erase operation and\n// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be\n// returned.\n// Might be useful for e.g. bootloaders and such.\n#ifndef SPIFFS_READ_ONLY\n#define SPIFFS_READ_ONLY                      0\n#endif\n\n// Enable this to add a temporal file cache using the fd buffer.\n// The effects of the cache is that SPIFFS_open will find the file faster in\n// certain cases. It will make it a lot easier for spiffs to find files\n// opened frequently, reducing number of readings from the spi flash for\n// finding those files.\n// This will grow each fd by 6 bytes. If your files are opened in patterns\n// with a degree of temporal locality, the system is optimized.\n// Examples can be letting spiffs serve web content, where one file is the css.\n// The css is accessed for each html file that is opened, meaning it is\n// accessed almost every second time a file is opened. Another example could be\n// a log file that is often opened, written, and closed.\n// The size of the cache is number of given file descriptors, as it piggybacks\n// on the fd update mechanism. The cache lives in the closed file descriptors.\n// When closed, the fd know the whereabouts of the file. Instead of forgetting\n// this, the temporal cache will keep handling updates to that file even if the\n// fd is closed. If the file is opened again, the location of the file is found\n// directly. If all available descriptors become opened, all cache memory is\n// lost.\n#ifndef SPIFFS_TEMPORAL_FD_CACHE\n#define SPIFFS_TEMPORAL_FD_CACHE              1\n#endif\n\n// Temporal file cache hit score. Each time a file is opened, all cached files\n// will lose one point. If the opened file is found in cache, that entry will\n// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this\n// value for the specific access patterns of the application. However, it must\n// be between 1 (no gain for hitting a cached entry often) and 255.\n#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE\n#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE       8\n#endif\n\n// Enable to be able to map object indices to memory.\n// This allows for faster and more deterministic reading if cases of reading\n// large files and when changing file offset by seeking around a lot.\n// When mapping a file's index, the file system will be scanned for index pages\n// and the info will be put in memory provided by user. When reading, the\n// memory map can be looked up instead of searching for index pages on the\n// medium. This way, user can trade memory against performance.\n// Whole, parts of, or future parts not being written yet can be mapped. The\n// memory array will be owned by spiffs and updated accordingly during garbage\n// collecting or when modifying the indices. The latter is invoked by when the\n// file is modified in some way. The index buffer is tied to the file\n// descriptor.\n#ifndef SPIFFS_IX_MAP\n#define SPIFFS_IX_MAP                         1\n#endif\n\n// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function\n// in the api. This function will visualize all filesystem using given printf\n// function.\n#ifndef SPIFFS_TEST_VISUALISATION\n#define SPIFFS_TEST_VISUALISATION         0\n#endif\n#if SPIFFS_TEST_VISUALISATION\n#ifndef spiffs_printf\n#define spiffs_printf(...)                printf(__VA_ARGS__)\n#endif\n// spiffs_printf argument for a free page\n#ifndef SPIFFS_TEST_VIS_FREE_STR\n#define SPIFFS_TEST_VIS_FREE_STR          \"_\"\n#endif\n// spiffs_printf argument for a deleted page\n#ifndef SPIFFS_TEST_VIS_DELE_STR\n#define SPIFFS_TEST_VIS_DELE_STR          \"/\"\n#endif\n// spiffs_printf argument for an index page for given object id\n#ifndef SPIFFS_TEST_VIS_INDX_STR\n#define SPIFFS_TEST_VIS_INDX_STR(id)      \"i\"\n#endif\n// spiffs_printf argument for a data page for given object id\n#ifndef SPIFFS_TEST_VIS_DATA_STR\n#define SPIFFS_TEST_VIS_DATA_STR(id)      \"d\"\n#endif\n#endif\n\n// Types depending on configuration such as the amount of flash bytes\n// given to spiffs file system in total (spiffs_file_system_size),\n// the logical block size (log_block_size), and the logical page size\n// (log_page_size)\n\n// Block index type. Make sure the size of this type can hold\n// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size\ntypedef u16_t spiffs_block_ix;\n// Page index type. Make sure the size of this type can hold\n// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size\ntypedef u16_t spiffs_page_ix;\n// Object id type - most significant bit is reserved for index flag. Make sure the\n// size of this type can hold the highest object id on a full system,\n// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2\ntypedef u16_t spiffs_obj_id;\n// Object span index type. Make sure the size of this type can\n// hold the largest possible span index on the system -\n// i.e. (spiffs_file_system_size / log_page_size) - 1\ntypedef u16_t spiffs_span_ix;\n\n#endif /* SPIFFS_CONFIG_H_ */\n"
  },
  {
    "path": "components/spiffs/spiffs_gc.c",
    "content": "#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\n#if !SPIFFS_READ_ONLY\n\n// Erases a logical block and updates the erase counter.\n// If cache is enabled, all pages that might be cached in this block\n// is dropped.\nstatic s32_t spiffs_gc_erase_block(\n    spiffs *fs,\n    spiffs_block_ix bix) {\n  s32_t res;\n\n  SPIFFS_GC_DBG(\"gc: erase block \"_SPIPRIbl\"\\n\", bix);\n  res = spiffs_erase_block(fs, bix);\n  SPIFFS_CHECK_RES(res);\n\n#if SPIFFS_CACHE\n  {\n    u32_t i;\n    for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {\n      spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);\n    }\n  }\n#endif\n  return res;\n}\n\n// Searches for blocks where all entries are deleted - if one is found,\n// the block is erased. Compared to the non-quick gc, the quick one ensures\n// that no updates are needed on existing objects on pages that are erased.\ns32_t spiffs_gc_quick(\n    spiffs *fs, u16_t max_free_pages) {\n  s32_t res = SPIFFS_OK;\n  u32_t blocks = fs->block_count;\n  spiffs_block_ix cur_block = 0;\n  u32_t cur_block_addr = 0;\n  int cur_entry = 0;\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n\n  SPIFFS_GC_DBG(\"gc_quick: running\\n\");\n#if SPIFFS_GC_STATS\n  fs->stats_gc_runs++;\n#endif\n\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n\n  // find fully deleted blocks\n  // check each block\n  while (res == SPIFFS_OK && blocks--) {\n    u16_t deleted_pages_in_block = 0;\n    u16_t free_pages_in_block = 0;\n\n    int obj_lookup_page = 0;\n    // check each object lookup page\n    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each entry\n      while (res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page &&\n          cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n        if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n          deleted_pages_in_block++;\n        } else if (obj_id == SPIFFS_OBJ_ID_FREE) {\n          // kill scan, go for next block\n          free_pages_in_block++;\n          if (free_pages_in_block > max_free_pages) {\n            obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);\n            res = 1; // kill object lu loop\n            break;\n          }\n        }  else {\n          // kill scan, go for next block\n          obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);\n          res = 1; // kill object lu loop\n          break;\n        }\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n    if (res == 1) res = SPIFFS_OK;\n\n    if (res == SPIFFS_OK &&\n        deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&\n        free_pages_in_block <= max_free_pages) {\n      // found a fully deleted block\n      fs->stats_p_deleted -= deleted_pages_in_block;\n      res = spiffs_gc_erase_block(fs, cur_block);\n      return res;\n    }\n\n    cur_entry = 0;\n    cur_block++;\n    cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n  } // per block\n\n  if (res == SPIFFS_OK) {\n    res = SPIFFS_ERR_NO_DELETED_BLOCKS;\n  }\n  return res;\n}\n\n// Checks if garbage collecting is necessary. If so a candidate block is found,\n// cleansed and erased\ns32_t spiffs_gc_check(\n    spiffs *fs,\n    u32_t len) {\n  s32_t res;\n  s32_t free_pages =\n      (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)\n      - fs->stats_p_allocated - fs->stats_p_deleted;\n  int tries = 0;\n\n  if (fs->free_blocks > 3 &&\n      (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {\n    return SPIFFS_OK;\n  }\n\n  u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);\n//  if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {\n//    SPIFFS_GC_DBG(\"gc: full freeblk:\"_SPIPRIi\" needed:\"_SPIPRIi\" free:\"_SPIPRIi\" dele:\"_SPIPRIi\"\\n\", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);\n//    return SPIFFS_ERR_FULL;\n//  }\n  if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {\n    SPIFFS_GC_DBG(\"gc_check: full freeblk:\"_SPIPRIi\" needed:\"_SPIPRIi\" free:\"_SPIPRIi\" dele:\"_SPIPRIi\"\\n\", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);\n    return SPIFFS_ERR_FULL;\n  }\n\n  do {\n    SPIFFS_GC_DBG(\"\\ngc_check #\"_SPIPRIi\": run gc free_blocks:\"_SPIPRIi\" pfree:\"_SPIPRIi\" pallo:\"_SPIPRIi\" pdele:\"_SPIPRIi\" [\"_SPIPRIi\"] len:\"_SPIPRIi\" of \"_SPIPRIi\"\\n\",\n        tries,\n        fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),\n        len, (u32_t)(free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));\n\n    spiffs_block_ix *cands;\n    int count;\n    spiffs_block_ix cand;\n    s32_t prev_free_pages = free_pages;\n    // if the fs is crammed, ignore block age when selecting candidate - kind of a bad state\n    res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);\n    SPIFFS_CHECK_RES(res);\n    if (count == 0) {\n      SPIFFS_GC_DBG(\"gc_check: no candidates, return\\n\");\n      return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;\n    }\n#if SPIFFS_GC_STATS\n    fs->stats_gc_runs++;\n#endif\n    cand = cands[0];\n    fs->cleaning = 1;\n    //SPIFFS_GC_DBG(\"gcing: cleaning block \"_SPIPRIi\"\\n\", cand);\n    res = spiffs_gc_clean(fs, cand);\n    fs->cleaning = 0;\n    if (res < 0) {\n      SPIFFS_GC_DBG(\"gc_check: cleaning block \"_SPIPRIi\", result \"_SPIPRIi\"\\n\", cand, res);\n    } else {\n      SPIFFS_GC_DBG(\"gc_check: cleaning block \"_SPIPRIi\", result \"_SPIPRIi\"\\n\", cand, res);\n    }\n    SPIFFS_CHECK_RES(res);\n\n    res = spiffs_gc_erase_page_stats(fs, cand);\n    SPIFFS_CHECK_RES(res);\n\n    res = spiffs_gc_erase_block(fs, cand);\n    SPIFFS_CHECK_RES(res);\n\n    free_pages =\n          (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)\n          - fs->stats_p_allocated - fs->stats_p_deleted;\n\n    if (prev_free_pages <= 0 && prev_free_pages == free_pages) {\n      // abort early to reduce wear, at least tried once\n      SPIFFS_GC_DBG(\"gc_check: early abort, no result on gc when fs crammed\\n\");\n      break;\n    }\n\n  } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||\n      (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));\n\n  free_pages =\n        (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)\n        - fs->stats_p_allocated - fs->stats_p_deleted;\n  if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {\n    res = SPIFFS_ERR_FULL;\n  }\n\n  SPIFFS_GC_DBG(\"gc_check: finished, \"_SPIPRIi\" dirty, blocks \"_SPIPRIi\" free, \"_SPIPRIi\" pages free, \"_SPIPRIi\" tries, res \"_SPIPRIi\"\\n\",\n      fs->stats_p_allocated + fs->stats_p_deleted,\n      fs->free_blocks, free_pages, tries, res);\n\n  return res;\n}\n\n// Updates page statistics for a block that is about to be erased\ns32_t spiffs_gc_erase_page_stats(\n    spiffs *fs,\n    spiffs_block_ix bix) {\n  s32_t res = SPIFFS_OK;\n  int obj_lookup_page = 0;\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  int cur_entry = 0;\n  u32_t dele = 0;\n  u32_t allo = 0;\n\n  // check each object lookup page\n  while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n    int entry_offset = obj_lookup_page * entries_per_page;\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n        0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n    // check each entry\n    while (res == SPIFFS_OK &&\n        cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n      spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n      if (obj_id == SPIFFS_OBJ_ID_FREE) {\n      } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n        dele++;\n      } else {\n        allo++;\n      }\n      cur_entry++;\n    } // per entry\n    obj_lookup_page++;\n  } // per object lookup page\n  SPIFFS_GC_DBG(\"gc_check: wipe pallo:\"_SPIPRIi\" pdele:\"_SPIPRIi\"\\n\", allo, dele);\n  fs->stats_p_allocated -= allo;\n  fs->stats_p_deleted -= dele;\n  return res;\n}\n\n// Finds block candidates to erase\ns32_t spiffs_gc_find_candidate(\n    spiffs *fs,\n    spiffs_block_ix **block_candidates,\n    int *candidate_count,\n    char fs_crammed) {\n  s32_t res = SPIFFS_OK;\n  u32_t blocks = fs->block_count;\n  spiffs_block_ix cur_block = 0;\n  u32_t cur_block_addr = 0;\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  int cur_entry = 0;\n\n  // using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score\n  int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));\n  *candidate_count = 0;\n  memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n\n  // divide up work area into block indices and scores\n  spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;\n  s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));\n\n   // align cand_scores on s32_t boundary\n  cand_scores = (s32_t*)(((intptr_t)cand_scores + sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1));\n\n  *block_candidates = cand_blocks;\n\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n\n  // check each block\n  while (res == SPIFFS_OK && blocks--) {\n    u16_t deleted_pages_in_block = 0;\n    u16_t used_pages_in_block = 0;\n\n    int obj_lookup_page = 0;\n    // check each object lookup page\n    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each entry\n      while (res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page &&\n          cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n        if (obj_id == SPIFFS_OBJ_ID_FREE) {\n          // when a free entry is encountered, scan logic ensures that all following entries are free also\n          res = 1; // kill object lu loop\n          break;\n        } else  if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n          deleted_pages_in_block++;\n        } else {\n          used_pages_in_block++;\n        }\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n    if (res == 1) res = SPIFFS_OK;\n\n    // calculate score and insert into candidate table\n    // stoneage sort, but probably not so many blocks\n    if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) {\n      // read erase count\n      spiffs_obj_id erase_count;\n      res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,\n          SPIFFS_ERASE_COUNT_PADDR(fs, cur_block),\n          sizeof(spiffs_obj_id), (u8_t *)&erase_count);\n      SPIFFS_CHECK_RES(res);\n\n      spiffs_obj_id erase_age;\n      if (fs->max_erase_count > erase_count) {\n        erase_age = fs->max_erase_count - erase_count;\n      } else {\n        erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);\n      }\n\n      s32_t score =\n          deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +\n          used_pages_in_block * SPIFFS_GC_HEUR_W_USED +\n          erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);\n      int cand_ix = 0;\n      SPIFFS_GC_DBG(\"gc_check: bix:\"_SPIPRIbl\" del:\"_SPIPRIi\" use:\"_SPIPRIi\" score:\"_SPIPRIi\"\\n\", cur_block, deleted_pages_in_block, used_pages_in_block, score);\n      while (cand_ix < max_candidates) {\n        if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {\n          cand_blocks[cand_ix] = cur_block;\n          cand_scores[cand_ix] = score;\n          break;\n        } else if (cand_scores[cand_ix] < score) {\n          int reorder_cand_ix = max_candidates - 2;\n          while (reorder_cand_ix >= cand_ix) {\n            cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];\n            cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];\n            reorder_cand_ix--;\n          }\n          cand_blocks[cand_ix] = cur_block;\n          cand_scores[cand_ix] = score;\n          break;\n        }\n        cand_ix++;\n      }\n      (*candidate_count)++;\n    }\n\n    cur_entry = 0;\n    cur_block++;\n    cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n  } // per block\n\n  return res;\n}\n\ntypedef enum {\n  FIND_OBJ_DATA,\n  MOVE_OBJ_DATA,\n  MOVE_OBJ_IX,\n  FINISHED\n} spiffs_gc_clean_state;\n\ntypedef struct {\n  spiffs_gc_clean_state state;\n  spiffs_obj_id cur_obj_id;\n  spiffs_span_ix cur_objix_spix;\n  spiffs_page_ix cur_objix_pix;\n  spiffs_page_ix cur_data_pix;\n  int stored_scan_entry_index;\n  u8_t obj_id_found;\n} spiffs_gc;\n\n// Empties given block by moving all data into free pages of another block\n// Strategy:\n//   loop:\n//   scan object lookup for object data pages\n//   for first found id, check spix and load corresponding object index page to memory\n//   push object scan lookup entry index\n//     rescan object lookup, find data pages with same id and referenced by same object index\n//     move data page, update object index in memory\n//     when reached end of lookup, store updated object index\n//   pop object scan lookup entry index\n//   repeat loop until end of object lookup\n//   scan object lookup again for remaining object index pages, move to new page in other block\n//\ns32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {\n  s32_t res = SPIFFS_OK;\n  const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n  // this is the global localizer being pushed and popped\n  int cur_entry = 0;\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  spiffs_gc gc; // our stack frame/state\n  spiffs_page_ix cur_pix = 0;\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n\n  SPIFFS_GC_DBG(\"gc_clean: cleaning block \"_SPIPRIbl\"\\n\", bix);\n\n  memset(&gc, 0, sizeof(spiffs_gc));\n  gc.state = FIND_OBJ_DATA;\n\n  if (fs->free_cursor_block_ix == bix) {\n    // move free cursor to next block, cannot use free pages from the block we want to clean\n    fs->free_cursor_block_ix = (bix+1)%fs->block_count;\n    fs->free_cursor_obj_lu_entry = 0;\n    SPIFFS_GC_DBG(\"gc_clean: move free cursor to block \"_SPIPRIbl\"\\n\", fs->free_cursor_block_ix);\n  }\n\n  while (res == SPIFFS_OK && gc.state != FINISHED) {\n    SPIFFS_GC_DBG(\"gc_clean: state = \"_SPIPRIi\" entry:\"_SPIPRIi\"\\n\", gc.state, cur_entry);\n    gc.obj_id_found = 0; // reset (to no found data page)\n\n    // scan through lookup pages\n    int obj_lookup_page = cur_entry / entries_per_page;\n    u8_t scan = 1;\n    // check each object lookup page\n    while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),\n          SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each object lookup entry\n      while (scan && res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n        cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);\n\n        // act upon object id depending on gc state\n        switch (gc.state) {\n        case FIND_OBJ_DATA:\n          // find a data page\n          if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&\n              ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {\n            // found a data page, stop scanning and handle in switch case below\n            SPIFFS_GC_DBG(\"gc_clean: FIND_DATA state:\"_SPIPRIi\" - found obj id \"_SPIPRIid\"\\n\", gc.state, obj_id);\n            gc.obj_id_found = 1;\n            gc.cur_obj_id = obj_id;\n            gc.cur_data_pix = cur_pix;\n            scan = 0;\n          }\n          break;\n        case MOVE_OBJ_DATA:\n          // evacuate found data pages for corresponding object index we have in memory,\n          // update memory representation\n          if (obj_id == gc.cur_obj_id) {\n            spiffs_page_header p_hdr;\n            res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n            SPIFFS_CHECK_RES(res);\n            SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA found data page \"_SPIPRIid\":\"_SPIPRIsp\" @ \"_SPIPRIpg\"\\n\", gc.cur_obj_id, p_hdr.span_ix, cur_pix);\n            if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {\n              SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA no objix spix match, take in another run\\n\");\n            } else {\n              spiffs_page_ix new_data_pix;\n              if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {\n                // move page\n                res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);\n                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA move objix \"_SPIPRIid\":\"_SPIPRIsp\" page \"_SPIPRIpg\" to \"_SPIPRIpg\"\\n\", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);\n                SPIFFS_CHECK_RES(res);\n                // move wipes obj_lu, reload it\n                res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n                    0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),\n                    SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n                SPIFFS_CHECK_RES(res);\n              } else {\n                // page is deleted but not deleted in lookup, scrap it -\n                // might seem unnecessary as we will erase this block, but\n                // we might get aborted\n                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA wipe objix \"_SPIPRIid\":\"_SPIPRIsp\" page \"_SPIPRIpg\"\\n\", obj_id, p_hdr.span_ix, cur_pix);\n                res = spiffs_page_delete(fs, cur_pix);\n                SPIFFS_CHECK_RES(res);\n                new_data_pix = SPIFFS_OBJ_ID_FREE;\n              }\n              // update memory representation of object index page with new data page\n              if (gc.cur_objix_spix == 0) {\n                // update object index header page\n                ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;\n                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA wrote page \"_SPIPRIpg\" to objix_hdr entry \"_SPIPRIsp\" in mem\\n\", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));\n              } else {\n                // update object index page\n                ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;\n                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA wrote page \"_SPIPRIpg\" to objix entry \"_SPIPRIsp\" in mem\\n\", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));\n              }\n            }\n          }\n          break;\n        case MOVE_OBJ_IX:\n          // find and evacuate object index pages\n          if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&\n              (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {\n            // found an index object id\n            spiffs_page_header p_hdr;\n            spiffs_page_ix new_pix;\n            // load header\n            res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n                0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n            SPIFFS_CHECK_RES(res);\n            if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {\n              // move page\n              res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);\n              SPIFFS_GC_DBG(\"gc_clean: MOVE_OBJIX move objix \"_SPIPRIid\":\"_SPIPRIsp\" page \"_SPIPRIpg\" to \"_SPIPRIpg\"\\n\", obj_id, p_hdr.span_ix, cur_pix, new_pix);\n              SPIFFS_CHECK_RES(res);\n              spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&p_hdr,\n                  SPIFFS_EV_IX_MOV, obj_id, p_hdr.span_ix, new_pix, 0);\n              // move wipes obj_lu, reload it\n              res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n                  0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),\n                  SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n              SPIFFS_CHECK_RES(res);\n            } else {\n              // page is deleted but not deleted in lookup, scrap it -\n              // might seem unnecessary as we will erase this block, but\n              // we might get aborted\n              SPIFFS_GC_DBG(\"gc_clean: MOVE_OBJIX wipe objix \"_SPIPRIid\":\"_SPIPRIsp\" page \"_SPIPRIpg\"\\n\", obj_id, p_hdr.span_ix, cur_pix);\n              res = spiffs_page_delete(fs, cur_pix);\n              if (res == SPIFFS_OK) {\n                spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,\n                    SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);\n              }\n            }\n            SPIFFS_CHECK_RES(res);\n          }\n          break;\n        default:\n          scan = 0;\n          break;\n        } // switch gc state\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop\n    } // per object lookup page\n    if (res != SPIFFS_OK) break;\n\n    // state finalization and switch\n    switch (gc.state) {\n    case FIND_OBJ_DATA:\n      if (gc.obj_id_found) {\n        // handle found data page -\n        // find out corresponding obj ix page and load it to memory\n        spiffs_page_header p_hdr;\n        spiffs_page_ix objix_pix;\n        gc.stored_scan_entry_index = cur_entry; // push cursor\n        cur_entry = 0; // restart scan from start\n        gc.state = MOVE_OBJ_DATA;\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n            0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);\n        SPIFFS_CHECK_RES(res);\n        gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);\n        SPIFFS_GC_DBG(\"gc_clean: FIND_DATA find objix span_ix:\"_SPIPRIsp\"\\n\", gc.cur_objix_spix);\n        res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);\n        if (res == SPIFFS_ERR_NOT_FOUND) {\n          // on borked systems we might get an ERR_NOT_FOUND here -\n          // this is handled by simply deleting the page as it is not referenced\n          // from anywhere\n          SPIFFS_GC_DBG(\"gc_clean: FIND_OBJ_DATA objix not found! Wipe page \"_SPIPRIpg\"\\n\", gc.cur_data_pix);\n          res = spiffs_page_delete(fs, gc.cur_data_pix);\n          SPIFFS_CHECK_RES(res);\n          // then we restore states and continue scanning for data pages\n          cur_entry = gc.stored_scan_entry_index; // pop cursor\n          gc.state = FIND_OBJ_DATA;\n          break; // done\n        }\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_GC_DBG(\"gc_clean: FIND_DATA found object index at page \"_SPIPRIpg\"\\n\", objix_pix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n            0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        // cannot allow a gc if the presumed index in fact is no index, a\n        // check must run or lot of data may be lost\n        SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);\n        gc.cur_objix_pix = objix_pix;\n      } else {\n        // no more data pages found, passed thru all block, start evacuating object indices\n        gc.state = MOVE_OBJ_IX;\n        cur_entry = 0; // restart entry scan index\n      }\n      break;\n    case MOVE_OBJ_DATA: {\n      // store modified objix (hdr) page residing in memory now that all\n      // data pages belonging to this object index and residing in the block\n      // we want to evacuate\n      spiffs_page_ix new_objix_pix;\n      gc.state = FIND_OBJ_DATA;\n      cur_entry = gc.stored_scan_entry_index; // pop cursor\n      if (gc.cur_objix_spix == 0) {\n        // store object index header page\n        res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix);\n        SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA store modified objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", new_objix_pix, 0);\n        SPIFFS_CHECK_RES(res);\n      } else {\n        // store object index page\n        res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);\n        SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA store modified objix page, \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", new_objix_pix, objix->p_hdr.span_ix);\n        SPIFFS_CHECK_RES(res);\n        spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n            SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n      }\n    }\n    break;\n    case MOVE_OBJ_IX:\n      // scanned thru all block, no more object indices found - our work here is done\n      gc.state = FINISHED;\n      break;\n    default:\n      cur_entry = 0;\n      break;\n    } // switch gc.state\n    SPIFFS_GC_DBG(\"gc_clean: state-> \"_SPIPRIi\"\\n\", gc.state);\n  } // while state != FINISHED\n\n\n  return res;\n}\n\n#endif // !SPIFFS_READ_ONLY\n"
  },
  {
    "path": "components/spiffs/spiffs_hydrogen.c",
    "content": "/*\n * spiffs_hydrogen.c\n *\n *  Created on: Jun 16, 2013\n *      Author: petera\n */\n\n#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\n#if SPIFFS_FILEHDL_OFFSET\n#define SPIFFS_FH_OFFS(fs, fh)   ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0)\n#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0)\n#else\n#define SPIFFS_FH_OFFS(fs, fh)   (fh)\n#define SPIFFS_FH_UNOFFS(fs, fh) (fh)\n#endif\n\n#if SPIFFS_CACHE == 1\nstatic s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);\n#endif\n\n#if SPIFFS_BUFFER_HELP\nu32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) {\n  return num_descs * sizeof(spiffs_fd);\n}\n#if SPIFFS_CACHE\nu32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) {\n  return sizeof(spiffs_cache) + num_pages * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs));\n}\n#endif\n#endif\n\nu8_t SPIFFS_mounted(spiffs *fs) {\n  return SPIFFS_CHECK_MOUNT(fs);\n}\n\ns32_t SPIFFS_format(spiffs *fs) {\n#if SPIFFS_READ_ONLY\n  (void)fs;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  if (SPIFFS_CHECK_MOUNT(fs)) {\n    fs->err_code = SPIFFS_ERR_MOUNTED;\n    return -1;\n  }\n\n  s32_t res;\n  SPIFFS_LOCK(fs);\n\n  spiffs_block_ix bix = 0;\n  while (bix < fs->block_count) {\n    fs->max_erase_count = 0;\n    res = spiffs_erase_block(fs, bix);\n    if (res != SPIFFS_OK) {\n      res = SPIFFS_ERR_ERASE_FAIL;\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    bix++;\n  }\n\n  SPIFFS_UNLOCK(fs);\n\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\n#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n\ns32_t SPIFFS_probe_fs(spiffs_config *config) {\n  s32_t res = spiffs_probe(config);\n  return res;\n}\n\n#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n\ns32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,\n    u8_t *fd_space, u32_t fd_space_size,\n    void *cache, u32_t cache_size,\n    spiffs_check_callback check_cb_f) {\n  void *user_data;\n  SPIFFS_LOCK(fs);\n  user_data = fs->user_data;\n  memset(fs, 0, sizeof(spiffs));\n  memcpy(&fs->cfg, config, sizeof(spiffs_config));\n  fs->user_data = user_data;\n  fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n  fs->work = &work[0];\n  fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];\n  memset(fd_space, 0, fd_space_size);\n  // align fd_space pointer to pointer size byte boundary\n  u8_t ptr_size = sizeof(void*);\n  u8_t addr_lsb = ((u8_t)(intptr_t)fd_space) & (ptr_size-1);\n  if (addr_lsb) {\n    fd_space += (ptr_size-addr_lsb);\n    fd_space_size -= (ptr_size-addr_lsb);\n  }\n  fs->fd_space = fd_space;\n  fs->fd_count = (fd_space_size/sizeof(spiffs_fd));\n\n  // align cache pointer to 4 byte boundary\n  addr_lsb = ((u8_t)(intptr_t)cache) & (ptr_size-1);\n  if (addr_lsb) {\n    u8_t *cache_8 = (u8_t *)cache;\n    cache_8 += (ptr_size-addr_lsb);\n    cache = cache_8;\n    cache_size -= (ptr_size-addr_lsb);\n  }\n  if (cache_size & (ptr_size-1)) {\n    cache_size -= (cache_size & (ptr_size-1));\n  }\n\n#if SPIFFS_CACHE\n  fs->cache = cache;\n  fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs)*32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs)*32 : cache_size;\n  spiffs_cache_init(fs);\n#endif\n\n  s32_t res;\n\n#if SPIFFS_USE_MAGIC\n  res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE;\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#endif\n\n  fs->config_magic = SPIFFS_CONFIG_MAGIC;\n\n  res = spiffs_obj_lu_scan(fs);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_DBG(\"page index byte len:         \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs));\n  SPIFFS_DBG(\"object lookup pages:         \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_OBJ_LOOKUP_PAGES(fs));\n  SPIFFS_DBG(\"page pages per block:        \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_PAGES_PER_BLOCK(fs));\n  SPIFFS_DBG(\"page header length:          \"_SPIPRIi\"\\n\", (u32_t)sizeof(spiffs_page_header));\n  SPIFFS_DBG(\"object header index entries: \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_OBJ_HDR_IX_LEN(fs));\n  SPIFFS_DBG(\"object index entries:        \"_SPIPRIi\"\\n\", (u32_t)SPIFFS_OBJ_IX_LEN(fs));\n  SPIFFS_DBG(\"available file descriptors:  \"_SPIPRIi\"\\n\", (u32_t)fs->fd_count);\n  SPIFFS_DBG(\"free blocks:                 \"_SPIPRIi\"\\n\", (u32_t)fs->free_blocks);\n\n  fs->check_cb_f = check_cb_f;\n\n  fs->mounted = 1;\n\n  SPIFFS_UNLOCK(fs);\n\n  return 0;\n}\n\nvoid SPIFFS_unmount(spiffs *fs) {\n  if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return;\n  SPIFFS_LOCK(fs);\n  u32_t i;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->file_nbr != 0) {\n#if SPIFFS_CACHE\n      (void)spiffs_fflush_cache(fs, cur_fd->file_nbr);\n#endif\n      spiffs_fd_return(fs, cur_fd->file_nbr);\n    }\n  }\n  fs->mounted = 0;\n\n  SPIFFS_UNLOCK(fs);\n}\n\ns32_t SPIFFS_errno(spiffs *fs) {\n  return fs->err_code;\n}\n\nvoid SPIFFS_clearerr(spiffs *fs) {\n  fs->err_code = SPIFFS_OK;\n}\n\ns32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)path; (void)mode;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  (void)mode;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n  spiffs_obj_id obj_id;\n  s32_t res;\n\n  res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (const u8_t*)path);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  SPIFFS_UNLOCK(fs);\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\nspiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) {\n  (void)mode;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  spiffs_page_ix pix;\n\n#if SPIFFS_READ_ONLY\n  // not valid flags in read only mode\n  flags &= ~(SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_TRUNC);\n#endif // SPIFFS_READ_ONLY\n\n  s32_t res = spiffs_fd_find_new(fs, &fd, path);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);\n  if ((flags & SPIFFS_O_CREAT) == 0) {\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  if (res == SPIFFS_OK &&\n      (flags & (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) == (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) {\n    // creat and excl and file exists - fail\n    res = SPIFFS_ERR_FILE_EXISTS;\n    spiffs_fd_return(fs, fd->file_nbr);\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  if ((flags & SPIFFS_O_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {\n#if !SPIFFS_READ_ONLY\n    spiffs_obj_id obj_id;\n    // no need to enter conflicting name here, already looked for it above\n    res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, 0);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, &pix);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    flags &= ~SPIFFS_O_TRUNC;\n#endif // !SPIFFS_READ_ONLY\n  } else {\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n  res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);\n  if (res < SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#if !SPIFFS_READ_ONLY\n  if (flags & SPIFFS_O_TRUNC) {\n    res = spiffs_object_truncate(fd, 0, 0);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n#endif // !SPIFFS_READ_ONLY\n\n  fd->fdoffset = 0;\n\n  SPIFFS_UNLOCK(fs);\n\n  return SPIFFS_FH_OFFS(fs, fd->file_nbr);\n}\n\nspiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n\n  s32_t res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_open_by_page(fs, e->pix, fd, flags, mode);\n  if (res < SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#if !SPIFFS_READ_ONLY\n  if (flags & SPIFFS_O_TRUNC) {\n    res = spiffs_object_truncate(fd, 0, 0);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n#endif // !SPIFFS_READ_ONLY\n\n  fd->fdoffset = 0;\n\n  SPIFFS_UNLOCK(fs);\n\n  return SPIFFS_FH_OFFS(fs, fd->file_nbr);\n}\n\nspiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n\n  s32_t res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if (SPIFFS_IS_LOOKUP_PAGE(fs, page_ix)) {\n    res = SPIFFS_ERR_NOT_A_FILE;\n    spiffs_fd_return(fs, fd->file_nbr);\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  res = spiffs_object_open_by_page(fs, page_ix, fd, flags, mode);\n  if (res == SPIFFS_ERR_IS_FREE ||\n      res == SPIFFS_ERR_DELETED ||\n      res == SPIFFS_ERR_NOT_FINALIZED ||\n      res == SPIFFS_ERR_NOT_INDEX ||\n      res == SPIFFS_ERR_INDEX_SPAN_MISMATCH) {\n    res = SPIFFS_ERR_NOT_A_FILE;\n  }\n  if (res < SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if !SPIFFS_READ_ONLY\n  if (flags & SPIFFS_O_TRUNC) {\n    res = spiffs_object_truncate(fd, 0, 0);\n    if (res < SPIFFS_OK) {\n      spiffs_fd_return(fs, fd->file_nbr);\n    }\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n#endif // !SPIFFS_READ_ONLY\n\n  fd->fdoffset = 0;\n\n  SPIFFS_UNLOCK(fs);\n\n  return SPIFFS_FH_OFFS(fs, fd->file_nbr);\n}\n\nstatic s32_t spiffs_hydro_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_O_RDONLY) == 0) {\n    res = SPIFFS_ERR_NOT_READABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  if (fd->size == SPIFFS_UNDEFINED_LEN && len > 0) {\n    // special case for zero sized files\n    res = SPIFFS_ERR_END_OF_OBJECT;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  if (fd->fdoffset + len >= fd->size) {\n    // reading beyond file size\n    s32_t avail = fd->size - fd->fdoffset;\n    if (avail <= 0) {\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_END_OF_OBJECT);\n    }\n    res = spiffs_object_read(fd, fd->fdoffset, avail, (u8_t*)buf);\n    if (res == SPIFFS_ERR_END_OF_OBJECT) {\n      fd->fdoffset += avail;\n      SPIFFS_UNLOCK(fs);\n      return avail;\n    } else {\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n      len = avail;\n    }\n  } else {\n    // reading within file size\n    res = spiffs_object_read(fd, fd->fdoffset, len, (u8_t*)buf);\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n  fd->fdoffset += len;\n\n  SPIFFS_UNLOCK(fs);\n\n  return len;\n}\n\ns32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {\n  s32_t res = spiffs_hydro_read(fs, fh, buf, len);\n  if (res == SPIFFS_ERR_END_OF_OBJECT) {\n    res = 0;\n  }\n  return res;\n}\n\n\n#if !SPIFFS_READ_ONLY\nstatic s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) {\n  (void)fs;\n  s32_t res = SPIFFS_OK;\n  s32_t remaining = len;\n  if (fd->size != SPIFFS_UNDEFINED_LEN && offset < fd->size) {\n    s32_t m_len = MIN((s32_t)(fd->size - offset), len);\n    res = spiffs_object_modify(fd, offset, (u8_t *)buf, m_len);\n    SPIFFS_CHECK_RES(res);\n    remaining -= m_len;\n    u8_t *buf_8 = (u8_t *)buf;\n    buf_8 += m_len;\n    buf = buf_8;\n    offset += m_len;\n  }\n  if (remaining > 0) {\n    res = spiffs_object_append(fd, offset, (u8_t *)buf, remaining);\n    SPIFFS_CHECK_RES(res);\n  }\n  return len;\n\n}\n#endif // !SPIFFS_READ_ONLY\n\ns32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)fh; (void)buf; (void)len;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  u32_t offset;\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_O_WRONLY) == 0) {\n    res = SPIFFS_ERR_NOT_WRITABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  if ((fd->flags & SPIFFS_O_APPEND)) {\n    fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;\n  }\n\n  offset = fd->fdoffset;\n\n#if SPIFFS_CACHE_WR\n  if (fd->cache_page == 0) {\n    // see if object id is associated with cache already\n    fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);\n  }\n#endif\n  if (fd->flags & SPIFFS_O_APPEND) {\n    if (fd->size == SPIFFS_UNDEFINED_LEN) {\n      offset = 0;\n    } else {\n      offset = fd->size;\n    }\n#if SPIFFS_CACHE_WR\n    if (fd->cache_page) {\n      offset = MAX(offset, fd->cache_page->offset + fd->cache_page->size);\n    }\n#endif\n  }\n\n#if SPIFFS_CACHE_WR\n  if ((fd->flags & SPIFFS_O_DIRECT) == 0) {\n    if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) {\n      // small write, try to cache it\n      u8_t alloc_cpage = 1;\n      if (fd->cache_page) {\n        // have a cached page for this fd already, check cache page boundaries\n        if (offset < fd->cache_page->offset || // writing before cache\n            offset > fd->cache_page->offset + fd->cache_page->size || // writing after cache\n            offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page\n        {\n          // boundary violation, write back cache first and allocate new\n          SPIFFS_CACHE_DBG(\"CACHE_WR_DUMP: dumping cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\", boundary viol, offs:\"_SPIPRIi\" size:\"_SPIPRIi\"\\n\",\n              fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);\n          res = spiffs_hydro_write(fs, fd,\n              spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),\n              fd->cache_page->offset, fd->cache_page->size);\n          spiffs_cache_fd_release(fs, fd->cache_page);\n          SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n        } else {\n          // writing within cache\n          alloc_cpage = 0;\n        }\n      }\n\n      if (alloc_cpage) {\n        fd->cache_page = spiffs_cache_page_allocate_by_fd(fs, fd);\n        if (fd->cache_page) {\n          fd->cache_page->offset = offset;\n          fd->cache_page->size = 0;\n          SPIFFS_CACHE_DBG(\"CACHE_WR_ALLO: allocating cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\"\\n\",\n              fd->cache_page->ix, fd->file_nbr, fd->obj_id);\n        }\n      }\n\n      if (fd->cache_page) {\n        u32_t offset_in_cpage = offset - fd->cache_page->offset;\n        SPIFFS_CACHE_DBG(\"CACHE_WR_WRITE: storing to cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\", offs \"_SPIPRIi\":\"_SPIPRIi\" len \"_SPIPRIi\"\\n\",\n            fd->cache_page->ix, fd->file_nbr, fd->obj_id,\n            offset, offset_in_cpage, len);\n        spiffs_cache *cache = spiffs_get_cache(fs);\n        u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);\n        memcpy(&cpage_data[offset_in_cpage], buf, len);\n        fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);\n        fd->fdoffset += len;\n        SPIFFS_UNLOCK(fs);\n        return len;\n      } else {\n        res = spiffs_hydro_write(fs, fd, buf, offset, len);\n        SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n        fd->fdoffset += len;\n        SPIFFS_UNLOCK(fs);\n        return res;\n      }\n    } else {\n      // big write, no need to cache it - but first check if there is a cached write already\n      if (fd->cache_page) {\n        // write back cache first\n        SPIFFS_CACHE_DBG(\"CACHE_WR_DUMP: dumping cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\", big write, offs:\"_SPIPRIi\" size:\"_SPIPRIi\"\\n\",\n            fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);\n        res = spiffs_hydro_write(fs, fd,\n            spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),\n            fd->cache_page->offset, fd->cache_page->size);\n        spiffs_cache_fd_release(fs, fd->cache_page);\n        SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n        // data written below\n      }\n    }\n  }\n#endif\n\n  res = spiffs_hydro_write(fs, fd, buf, offset, len);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  fd->fdoffset += len;\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  s32_t fileSize = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;\n\n  switch (whence) {\n  case SPIFFS_SEEK_CUR:\n    offs = fd->fdoffset+offs;\n    break;\n  case SPIFFS_SEEK_END:\n    offs = fileSize + offs;\n    break;\n  }\n\n  if ((offs > fileSize)) {\n    fd->fdoffset = fileSize;\n    res = SPIFFS_ERR_END_OF_OBJECT;\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  spiffs_span_ix data_spix = offs / SPIFFS_DATA_PAGE_SIZE(fs);\n  spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n  if (fd->cursor_objix_spix != objix_spix) {\n    spiffs_page_ix pix;\n    res = spiffs_obj_lu_find_id_and_span(\n        fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, &pix);\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    fd->cursor_objix_spix = objix_spix;\n    fd->cursor_objix_pix = pix;\n  }\n  fd->fdoffset = offs;\n\n  SPIFFS_UNLOCK(fs);\n\n  return offs;\n}\n\ns32_t SPIFFS_remove(spiffs *fs, const char *path) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)path;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  spiffs_page_ix pix;\n  s32_t res;\n\n  res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_open_by_page(fs, pix, fd, 0,0);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_truncate(fd, 0, 1);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)fh;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_O_WRONLY) == 0) {\n    res = SPIFFS_ERR_NOT_WRITABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n#if SPIFFS_CACHE_WR\n  spiffs_cache_fd_release(fs, fd->cache_page);\n#endif\n\n  res = spiffs_object_truncate(fd, 0, 1);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\nstatic s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {\n  (void)fh;\n  spiffs_page_object_ix_header objix_hdr;\n  spiffs_obj_id obj_id;\n  s32_t res =_spiffs_rd(fs,  SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,\n      SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n  u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , pix)) +\n      SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_obj_id);\n  res =_spiffs_rd(fs,  SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, fh,\n      obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n  s->obj_id = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n  s->type = objix_hdr.type;\n  s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;\n  s->pix = pix;\n  strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN);\n#if SPIFFS_OBJ_META_LEN\n  memcpy(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);\n#endif\n\n  return res;\n}\n\ns32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n\n  s32_t res;\n  spiffs_page_ix pix;\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_stat_pix(fs, pix, 0, s);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n}\n\ns32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  res = spiffs_stat_pix(fs, fd->objix_hdr_pix, fh, s);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n}\n\n// Checks if there are any cached writes for the object id associated with\n// given filehandle. If so, these writes are flushed.\n#if SPIFFS_CACHE == 1\nstatic s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {\n  (void)fs;\n  (void)fh;\n  s32_t res = SPIFFS_OK;\n#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n  if ((fd->flags & SPIFFS_O_DIRECT) == 0) {\n    if (fd->cache_page == 0) {\n      // see if object id is associated with cache already\n      fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);\n    }\n    if (fd->cache_page) {\n      SPIFFS_CACHE_DBG(\"CACHE_WR_DUMP: dumping cache page \"_SPIPRIpg\" for fd \"_SPIPRIfd\":\"_SPIPRIid\", flush, offs:\"_SPIPRIi\" size:\"_SPIPRIi\"\\n\",\n          fd->cache_page->ix, fd->file_nbr,  fd->obj_id, fd->cache_page->offset, fd->cache_page->size);\n      res = spiffs_hydro_write(fs, fd,\n          spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),\n          fd->cache_page->offset, fd->cache_page->size);\n      if (res < SPIFFS_OK) {\n        fs->err_code = res;\n      }\n      spiffs_cache_fd_release(fs, fd->cache_page);\n    }\n  }\n#endif\n\n  return res;\n}\n#endif\n\ns32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {\n  (void)fh;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  s32_t res = SPIFFS_OK;\n#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR\n  SPIFFS_LOCK(fs);\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fflush_cache(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs,res);\n  SPIFFS_UNLOCK(fs);\n#endif\n\n  return res;\n}\n\ns32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n\n  s32_t res = SPIFFS_OK;\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n#if SPIFFS_CACHE\n  res = spiffs_fflush_cache(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#endif\n  res = spiffs_fd_return(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n}\n\ns32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)old_path; (void)new_path;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  if (strlen(new_path) > SPIFFS_OBJ_NAME_LEN - 1 ||\n      strlen(old_path) > SPIFFS_OBJ_NAME_LEN - 1) {\n    SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);\n  }\n  SPIFFS_LOCK(fs);\n\n  spiffs_page_ix pix_old, pix_dummy;\n  spiffs_fd *fd;\n\n  s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)old_path, &pix_old);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)new_path, &pix_dummy);\n  if (res == SPIFFS_ERR_NOT_FOUND) {\n    res = SPIFFS_OK;\n  } else if (res == SPIFFS_OK) {\n    res = SPIFFS_ERR_CONFLICTING_NAME;\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_open_by_page(fs, pix_old, fd, 0, 0);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (const u8_t*)new_path,\n      0, 0, &pix_dummy);\n#if SPIFFS_TEMPORAL_FD_CACHE\n  if (res == SPIFFS_OK) {\n    spiffs_fd_temporal_cache_rehash(fs, old_path, new_path);\n  }\n#endif\n\n  spiffs_fd_return(fs, fd->file_nbr);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n\n#if SPIFFS_OBJ_META_LEN\ns32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)name; (void)meta;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_page_ix pix, pix_dummy;\n  spiffs_fd *fd;\n\n  s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)name, &pix);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_fd_find_new(fs, &fd, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_open_by_page(fs, pix, fd, 0, 0);\n  if (res != SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,\n      0, &pix_dummy);\n\n  spiffs_fd_return(fs, fd->file_nbr);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)fh; (void)meta;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  s32_t res;\n  spiffs_fd *fd;\n  spiffs_page_ix pix_dummy;\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_O_WRONLY) == 0) {\n    res = SPIFFS_ERR_NOT_WRITABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  }\n\n  res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,\n      0, &pix_dummy);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n#endif // SPIFFS_OBJ_META_LEN\n\nspiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {\n  (void)name;\n\n  if (!SPIFFS_CHECK_CFG((fs))) {\n    (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;\n    return 0;\n  }\n\n  if (!SPIFFS_CHECK_MOUNT(fs)) {\n    fs->err_code = SPIFFS_ERR_NOT_MOUNTED;\n    return 0;\n  }\n\n  d->fs = fs;\n  d->block = 0;\n  d->entry = 0;\n  return d;\n}\n\nstatic s32_t spiffs_read_dir_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  (void)user_const_p;\n  s32_t res;\n  spiffs_page_object_ix_header objix_hdr;\n  if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||\n      (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {\n    return SPIFFS_VIS_COUNTINUE;\n  }\n\n  spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);\n  if (res != SPIFFS_OK) return res;\n  if ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) &&\n      objix_hdr.p_hdr.span_ix == 0 &&\n      (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==\n          (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {\n    struct spiffs_dirent *e = (struct spiffs_dirent*)user_var_p;\n    e->obj_id = obj_id;\n    strcpy((char *)e->name, (char *)objix_hdr.name);\n    e->type = objix_hdr.type;\n    e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;\n    e->pix = pix;\n#if SPIFFS_OBJ_META_LEN\n  memcpy(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);\n#endif\n    return SPIFFS_OK;\n  }\n  return SPIFFS_VIS_COUNTINUE;\n}\n\nstruct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {\n  if (!SPIFFS_CHECK_MOUNT(d->fs)) {\n    d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;\n    return 0;\n  }\n  SPIFFS_LOCK(d->fs);\n\n  spiffs_block_ix bix;\n  int entry;\n  s32_t res;\n  struct spiffs_dirent *ret = 0;\n\n  res = spiffs_obj_lu_find_entry_visitor(d->fs,\n      d->block,\n      d->entry,\n      SPIFFS_VIS_NO_WRAP,\n      0,\n      spiffs_read_dir_v,\n      0,\n      e,\n      &bix,\n      &entry);\n  if (res == SPIFFS_OK) {\n    d->block = bix;\n    d->entry = entry + 1;\n    e->obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n    ret = e;\n  } else {\n    d->fs->err_code = res;\n  }\n  SPIFFS_UNLOCK(d->fs);\n  return ret;\n}\n\ns32_t SPIFFS_closedir(spiffs_DIR *d) {\n  SPIFFS_API_CHECK_CFG(d->fs);\n  SPIFFS_API_CHECK_MOUNT(d->fs);\n  return 0;\n}\n\ns32_t SPIFFS_check(spiffs *fs) {\n#if SPIFFS_READ_ONLY\n  (void)fs;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  res = spiffs_lookup_consistency_check(fs, 0);\n\n  res = spiffs_object_index_consistency_check(fs);\n\n  res = spiffs_page_consistency_check(fs);\n\n  res = spiffs_obj_lu_scan(fs);\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {\n  s32_t res = SPIFFS_OK;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs);\n  u32_t blocks = fs->block_count;\n  u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs);\n  u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs);\n  u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page\n\n  if (total) {\n    *total = total_data_pages * data_page_size;\n  }\n\n  if (used) {\n    *used = fs->stats_p_allocated * data_page_size;\n  }\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)max_free_pages;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  res = spiffs_gc_quick(fs, max_free_pages);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  SPIFFS_UNLOCK(fs);\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\n\ns32_t SPIFFS_gc(spiffs *fs, u32_t size) {\n#if SPIFFS_READ_ONLY\n  (void)fs; (void)size;\n  return SPIFFS_ERR_RO_NOT_IMPL;\n#else\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  res = spiffs_gc_check(fs, size);\n\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  SPIFFS_UNLOCK(fs);\n  return 0;\n#endif // SPIFFS_READ_ONLY\n}\n\ns32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if SPIFFS_CACHE_WR\n  res = spiffs_fflush_cache(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#endif\n\n  res = (fd->fdoffset >= (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size));\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n#if SPIFFS_CACHE_WR\n  res = spiffs_fflush_cache(fs, fh);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n#endif\n\n  res = fd->fdoffset;\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) {\n  SPIFFS_LOCK(fs);\n  fs->file_cb_f = cb_func;\n  SPIFFS_UNLOCK(fs);\n  return 0;\n}\n\n#if SPIFFS_IX_MAP\n\ns32_t SPIFFS_ix_map(spiffs *fs,  spiffs_file fh, spiffs_ix_map *map,\n    u32_t offset, u32_t len, spiffs_page_ix *map_buf) {\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if (fd->ix_map) {\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_MAPPED);\n  }\n\n  map->map_buf = map_buf;\n  map->offset = offset;\n  // nb: spix range includes last\n  map->start_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);\n  map->end_spix = (offset + len) / SPIFFS_DATA_PAGE_SIZE(fs);\n  memset(map_buf, 0, sizeof(spiffs_page_ix) * (map->end_spix - map->start_spix + 1));\n  fd->ix_map = map;\n\n  // scan for pixes\n  res = spiffs_populate_ix_map(fs, fd, 0, map->end_spix - map->start_spix + 1);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_ix_unmap(spiffs *fs,  spiffs_file fh) {\n  s32_t res;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if (fd->ix_map == 0) {\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);\n  }\n\n  fd->ix_map = 0;\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset) {\n  s32_t res = SPIFFS_OK;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  fh = SPIFFS_FH_UNOFFS(fs, fh);\n\n  spiffs_fd *fd;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if (fd->ix_map == 0) {\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);\n  }\n\n  spiffs_ix_map *map = fd->ix_map;\n\n  s32_t spix_diff = offset / SPIFFS_DATA_PAGE_SIZE(fs) - map->start_spix;\n  map->offset = offset;\n\n  // move existing pixes if within map offs\n  if (spix_diff != 0) {\n    // move vector\n    int i;\n    const s32_t vec_len = map->end_spix - map->start_spix + 1; // spix range includes last\n    map->start_spix += spix_diff;\n    map->end_spix += spix_diff;\n    if (spix_diff >= vec_len) {\n      // moving beyond range\n      memset(&map->map_buf, 0, vec_len * sizeof(spiffs_page_ix));\n      // populate_ix_map is inclusive\n      res = spiffs_populate_ix_map(fs, fd, 0, vec_len-1);\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    } else if (spix_diff > 0) {\n      // diff positive\n      for (i = 0; i < vec_len - spix_diff; i++) {\n        map->map_buf[i] = map->map_buf[i + spix_diff];\n      }\n      // memset is non-inclusive\n      memset(&map->map_buf[vec_len - spix_diff], 0, spix_diff * sizeof(spiffs_page_ix));\n      // populate_ix_map is inclusive\n      res = spiffs_populate_ix_map(fs, fd, vec_len - spix_diff, vec_len-1);\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    } else {\n      // diff negative\n      for (i = vec_len - 1; i >= -spix_diff; i--) {\n        map->map_buf[i] = map->map_buf[i + spix_diff];\n      }\n      // memset is non-inclusive\n      memset(&map->map_buf[0], 0, -spix_diff * sizeof(spiffs_page_ix));\n      // populate_ix_map is inclusive\n      res = spiffs_populate_ix_map(fs, fd, 0, -spix_diff - 1);\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n    }\n\n  }\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes) {\n  SPIFFS_API_CHECK_CFG(fs);\n  // always add one extra page, the offset might change to the middle of a page\n  return (bytes + SPIFFS_DATA_PAGE_SIZE(fs) ) / SPIFFS_DATA_PAGE_SIZE(fs);\n}\n\ns32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries) {\n  SPIFFS_API_CHECK_CFG(fs);\n  return map_page_ix_entries * SPIFFS_DATA_PAGE_SIZE(fs);\n}\n\n#endif // SPIFFS_IX_MAP\n\n#if SPIFFS_TEST_VISUALISATION\ns32_t SPIFFS_vis(spiffs *fs) {\n  s32_t res = SPIFFS_OK;\n  SPIFFS_API_CHECK_CFG(fs);\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  spiffs_block_ix bix = 0;\n\n  while (bix < fs->block_count) {\n    // check each object lookup page\n    int obj_lookup_page = 0;\n    int cur_entry = 0;\n\n    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each entry\n      while (res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {\n        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];\n        if (cur_entry == 0) {\n          spiffs_printf(_SPIPRIbl\" \", bix);\n        } else if ((cur_entry & 0x3f) == 0) {\n          spiffs_printf(\"     \");\n        }\n        if (obj_id == SPIFFS_OBJ_ID_FREE) {\n          spiffs_printf(SPIFFS_TEST_VIS_FREE_STR);\n        } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n          spiffs_printf(SPIFFS_TEST_VIS_DELE_STR);\n        } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG){\n          spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id));\n        } else {\n          spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id));\n        }\n        cur_entry++;\n        if ((cur_entry & 0x3f) == 0) {\n          spiffs_printf(\"\\n\");\n        }\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n\n    spiffs_obj_id erase_count;\n    res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,\n        SPIFFS_ERASE_COUNT_PADDR(fs, bix),\n        sizeof(spiffs_obj_id), (u8_t *)&erase_count);\n    SPIFFS_CHECK_RES(res);\n\n    if (erase_count != (spiffs_obj_id)-1) {\n      spiffs_printf(\"\\tera_cnt: \"_SPIPRIi\"\\n\", erase_count);\n    } else {\n      spiffs_printf(\"\\tera_cnt: N/A\\n\");\n    }\n\n    bix++;\n  } // per block\n\n  spiffs_printf(\"era_cnt_max: \"_SPIPRIi\"\\n\", fs->max_erase_count);\n  spiffs_printf(\"last_errno:  \"_SPIPRIi\"\\n\", fs->err_code);\n  spiffs_printf(\"blocks:      \"_SPIPRIi\"\\n\", fs->block_count);\n  spiffs_printf(\"free_blocks: \"_SPIPRIi\"\\n\", fs->free_blocks);\n  spiffs_printf(\"page_alloc:  \"_SPIPRIi\"\\n\", fs->stats_p_allocated);\n  spiffs_printf(\"page_delet:  \"_SPIPRIi\"\\n\", fs->stats_p_deleted);\n  SPIFFS_UNLOCK(fs);\n  u32_t total, used;\n  SPIFFS_info(fs, &total, &used);\n  spiffs_printf(\"used:        \"_SPIPRIi\" of \"_SPIPRIi\"\\n\", used, total);\n  return res;\n}\n#endif\n"
  },
  {
    "path": "components/spiffs/spiffs_nucleus.c",
    "content": "#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\n\nstatic s32_t spiffs_page_data_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) {\n  s32_t res = SPIFFS_OK;\n  if (pix == (spiffs_page_ix)-1) {\n    // referring to page 0xffff...., bad object index\n    return SPIFFS_ERR_INDEX_REF_FREE;\n  }\n  if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n    // referring to an object lookup page, bad object index\n    return SPIFFS_ERR_INDEX_REF_LU;\n  }\n  if (pix > SPIFFS_MAX_PAGES(fs)) {\n    // referring to a bad page\n    return SPIFFS_ERR_INDEX_REF_INVALID;\n  }\n#if SPIFFS_PAGE_CHECK\n  spiffs_page_header ph;\n  res = _spiffs_rd(\n      fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,\n      fd->file_nbr,\n      SPIFFS_PAGE_TO_PADDR(fs, pix),\n      sizeof(spiffs_page_header),\n      (u8_t *)&ph);\n  SPIFFS_CHECK_RES(res);\n  SPIFFS_VALIDATE_DATA(ph, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, spix);\n#endif\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\nstatic s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) {\n  s32_t res = SPIFFS_OK;\n  if (pix == (spiffs_page_ix)-1) {\n    // referring to page 0xffff...., bad object index\n    return SPIFFS_ERR_INDEX_FREE;\n  }\n  if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n    // referring to an object lookup page, bad object index\n    return SPIFFS_ERR_INDEX_LU;\n  }\n  if (pix > SPIFFS_MAX_PAGES(fs)) {\n    // referring to a bad page\n    return SPIFFS_ERR_INDEX_INVALID;\n  }\n#if SPIFFS_PAGE_CHECK\n  spiffs_page_header ph;\n  res = _spiffs_rd(\n      fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n      fd->file_nbr,\n      SPIFFS_PAGE_TO_PADDR(fs, pix),\n      sizeof(spiffs_page_header),\n      (u8_t *)&ph);\n  SPIFFS_CHECK_RES(res);\n  SPIFFS_VALIDATE_OBJIX(ph, fd->obj_id, spix);\n#endif\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_CACHE\n\ns32_t spiffs_phys_rd(\n    spiffs *fs,\n    u32_t addr,\n    u32_t len,\n    u8_t *dst) {\n  return SPIFFS_HAL_READ(fs, addr, len, dst);\n}\n\ns32_t spiffs_phys_wr(\n    spiffs *fs,\n    u32_t addr,\n    u32_t len,\n    u8_t *src) {\n  return SPIFFS_HAL_WRITE(fs, addr, len, src);\n}\n\n#endif\n\n#if !SPIFFS_READ_ONLY\ns32_t spiffs_phys_cpy(\n    spiffs *fs,\n    spiffs_file fh,\n    u32_t dst,\n    u32_t src,\n    u32_t len) {\n  (void)fh;\n  s32_t res;\n  u8_t b[SPIFFS_COPY_BUFFER_STACK];\n  while (len > 0) {\n    u32_t chunk_size = MIN(SPIFFS_COPY_BUFFER_STACK, len);\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVS, fh, src, chunk_size, b);\n    SPIFFS_CHECK_RES(res);\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVD,  fh, dst, chunk_size, b);\n    SPIFFS_CHECK_RES(res);\n    len -= chunk_size;\n    src += chunk_size;\n    dst += chunk_size;\n  }\n  return SPIFFS_OK;\n}\n#endif // !SPIFFS_READ_ONLY\n\n// Find object lookup entry containing given id with visitor.\n// Iterate over object lookup pages in each block until a given object id entry is found.\n// When found, the visitor function is called with block index, entry index and user data.\n// If visitor returns SPIFFS_VIS_CONTINUE, the search goes on. Otherwise, the search will be\n// ended and visitor's return code is returned to caller.\n// If no visitor is given (0) the search returns on first entry with matching object id.\n// If no match is found in all look up, SPIFFS_VIS_END is returned.\n// @param fs                    the file system\n// @param starting_block        the starting block to start search in\n// @param starting_lu_entry     the look up index entry to start search in\n// @param flags                 ored combination of SPIFFS_VIS_CHECK_ID, SPIFFS_VIS_CHECK_PH,\n//                              SPIFFS_VIS_NO_WRAP\n// @param obj_id                argument object id\n// @param v                     visitor callback function\n// @param user_const_p          any const pointer, passed to the callback visitor function\n// @param user_var_p            any pointer, passed to the callback visitor function\n// @param block_ix              reported block index where match was found\n// @param lu_entry              reported look up index where match was found\ns32_t spiffs_obj_lu_find_entry_visitor(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    u8_t flags,\n    spiffs_obj_id obj_id,\n    spiffs_visitor_f v,\n    const void *user_const_p,\n    void *user_var_p,\n    spiffs_block_ix *block_ix,\n    int *lu_entry) {\n  s32_t res = SPIFFS_OK;\n  s32_t entry_count = fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs);\n  spiffs_block_ix cur_block = starting_block;\n  u32_t cur_block_addr = starting_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  int cur_entry = starting_lu_entry;\n  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n\n  // wrap initial\n  if (cur_entry > (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) - 1) {\n    cur_entry = 0;\n    cur_block++;\n    cur_block_addr = cur_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n    if (cur_block >= fs->block_count) {\n      if (flags & SPIFFS_VIS_NO_WRAP) {\n        return SPIFFS_VIS_END;\n      } else {\n        // block wrap\n        cur_block = 0;\n        cur_block_addr = 0;\n      }\n    }\n  }\n\n  // check each block\n  while (res == SPIFFS_OK && entry_count > 0) {\n    int obj_lookup_page = cur_entry / entries_per_page;\n    // check each object lookup page\n    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\n      int entry_offset = obj_lookup_page * entries_per_page;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n          0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n      // check each entry\n      while (res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page && // for non-last obj lookup pages\n          cur_entry < (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) // for last obj lookup page\n      {\n        if ((flags & SPIFFS_VIS_CHECK_ID) == 0 || obj_lu_buf[cur_entry-entry_offset] == obj_id) {\n          if (block_ix) *block_ix = cur_block;\n          if (lu_entry) *lu_entry = cur_entry;\n          if (v) {\n            res = v(\n                fs,\n                (flags & SPIFFS_VIS_CHECK_PH) ? obj_id : obj_lu_buf[cur_entry-entry_offset],\n                cur_block,\n                cur_entry,\n                user_const_p,\n                user_var_p);\n            if (res == SPIFFS_VIS_COUNTINUE || res == SPIFFS_VIS_COUNTINUE_RELOAD) {\n              if (res == SPIFFS_VIS_COUNTINUE_RELOAD) {\n                res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n                    0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);\n                SPIFFS_CHECK_RES(res);\n              }\n              res = SPIFFS_OK;\n              cur_entry++;\n              entry_count--;\n              continue;\n            } else {\n              return res;\n            }\n          } else {\n            return SPIFFS_OK;\n          }\n        }\n        entry_count--;\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n    cur_entry = 0;\n    cur_block++;\n    cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n    if (cur_block >= fs->block_count) {\n      if (flags & SPIFFS_VIS_NO_WRAP) {\n        return SPIFFS_VIS_END;\n      } else {\n        // block wrap\n        cur_block = 0;\n        cur_block_addr = 0;\n      }\n    }\n  } // per block\n\n  SPIFFS_CHECK_RES(res);\n\n  return SPIFFS_VIS_END;\n}\n\n#if !SPIFFS_READ_ONLY\ns32_t spiffs_erase_block(\n    spiffs *fs,\n    spiffs_block_ix bix) {\n  s32_t res;\n  u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix);\n  s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n\n  // here we ignore res, just try erasing the block\n  while (size > 0) {\n    SPIFFS_DBG(\"erase \"_SPIPRIad\":\"_SPIPRIi\"\\n\", addr,  SPIFFS_CFG_PHYS_ERASE_SZ(fs));\n    SPIFFS_HAL_ERASE(fs, addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));\n\n    addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);\n    size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);\n  }\n  fs->free_blocks++;\n\n  // register erase count for this block\n  res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,\n      SPIFFS_ERASE_COUNT_PADDR(fs, bix),\n      sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count);\n  SPIFFS_CHECK_RES(res);\n\n#if SPIFFS_USE_MAGIC\n  // finally, write magic\n  spiffs_obj_id magic = SPIFFS_MAGIC(fs, bix);\n  res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,\n      SPIFFS_MAGIC_PADDR(fs, bix),\n      sizeof(spiffs_obj_id), (u8_t *)&magic);\n  SPIFFS_CHECK_RES(res);\n#endif\n\n  fs->max_erase_count++;\n  if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) {\n    fs->max_erase_count = 0;\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\ns32_t spiffs_probe(\n    spiffs_config *cfg) {\n  s32_t res;\n  u32_t paddr;\n  spiffs dummy_fs; // create a dummy fs struct just to be able to use macros\n  memcpy(&dummy_fs.cfg, cfg, sizeof(spiffs_config));\n  dummy_fs.block_count = 0;\n\n  // Read three magics, as one block may be in an aborted erase state.\n  // At least two of these must contain magic and be in decreasing order.\n  spiffs_obj_id magic[3];\n  spiffs_obj_id bix_count[3];\n\n  spiffs_block_ix bix;\n  for (bix = 0; bix < 3; bix++) {\n    paddr = SPIFFS_MAGIC_PADDR(&dummy_fs, bix);\n#if SPIFFS_HAL_CALLBACK_EXTRA\n    // not any proper fs to report here, so callback with null\n    // (cross fingers that no-one gets angry)\n    res = cfg->hal_read_f((void *)0, paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]);\n#else\n    res = cfg->hal_read_f(paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]);\n#endif\n    bix_count[bix] = magic[bix] ^ SPIFFS_MAGIC(&dummy_fs, 0);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  // check that we have sane number of blocks\n  if (bix_count[0] < 3) return SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS;\n  // check that the order is correct, take aborted erases in calculation\n  // first block aborted erase\n  if (magic[0] == (spiffs_obj_id)(-1) && bix_count[1] - bix_count[2] == 1) {\n    return (bix_count[1]+1) * cfg->log_block_size;\n  }\n  // second block aborted erase\n  if (magic[1] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[2] == 2) {\n    return bix_count[0] * cfg->log_block_size;\n  }\n  // third block aborted erase\n  if (magic[2] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[1] == 1) {\n    return bix_count[0] * cfg->log_block_size;\n  }\n  // no block has aborted erase\n  if (bix_count[0] - bix_count[1] == 1 && bix_count[1] - bix_count[2] == 1) {\n    return bix_count[0] * cfg->log_block_size;\n  }\n\n  return SPIFFS_ERR_PROBE_NOT_A_FS;\n}\n#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0\n\n\nstatic s32_t spiffs_obj_lu_scan_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  (void)bix;\n  (void)user_const_p;\n  (void)user_var_p;\n  if (obj_id == SPIFFS_OBJ_ID_FREE) {\n    if (ix_entry == 0) {\n      fs->free_blocks++;\n      // todo optimize further, return SPIFFS_NEXT_BLOCK\n    }\n  } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {\n    fs->stats_p_deleted++;\n  } else {\n    fs->stats_p_allocated++;\n  }\n\n  return SPIFFS_VIS_COUNTINUE;\n}\n\n\n// Scans thru all obj lu and counts free, deleted and used pages\n// Find the maximum block erase count\n// Checks magic if enabled\ns32_t spiffs_obj_lu_scan(\n    spiffs *fs) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n#if SPIFFS_USE_MAGIC\n  spiffs_block_ix unerased_bix = (spiffs_block_ix)-1;\n#endif\n\n  // find out erase count\n  // if enabled, check magic\n  bix = 0;\n  spiffs_obj_id erase_count_final;\n  spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE;\n  spiffs_obj_id erase_count_max = 0;\n  while (bix < fs->block_count) {\n#if SPIFFS_USE_MAGIC\n    spiffs_obj_id magic;\n    res = _spiffs_rd(fs,\n        SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_MAGIC_PADDR(fs, bix) ,\n        sizeof(spiffs_obj_id), (u8_t *)&magic);\n\n    SPIFFS_CHECK_RES(res);\n    if (magic != SPIFFS_MAGIC(fs, bix)) {\n      if (unerased_bix == (spiffs_block_ix)-1) {\n        // allow one unerased block as it might be powered down during an erase\n        unerased_bix = bix;\n      } else {\n        // more than one unerased block, bail out\n        SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS);\n      }\n    }\n#endif\n    spiffs_obj_id erase_count;\n    res = _spiffs_rd(fs,\n        SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_ERASE_COUNT_PADDR(fs, bix) ,\n        sizeof(spiffs_obj_id), (u8_t *)&erase_count);\n    SPIFFS_CHECK_RES(res);\n    if (erase_count != SPIFFS_OBJ_ID_FREE) {\n      erase_count_min = MIN(erase_count_min, erase_count);\n      erase_count_max = MAX(erase_count_max, erase_count);\n    }\n    bix++;\n  }\n\n  if (erase_count_min == 0 && erase_count_max == SPIFFS_OBJ_ID_FREE) {\n    // clean system, set counter to zero\n    erase_count_final = 0;\n  } else if (erase_count_max - erase_count_min > (SPIFFS_OBJ_ID_FREE)/2) {\n    // wrap, take min\n    erase_count_final = erase_count_min+1;\n  } else {\n    erase_count_final = erase_count_max+1;\n  }\n\n  fs->max_erase_count = erase_count_final;\n\n#if SPIFFS_USE_MAGIC\n  if (unerased_bix != (spiffs_block_ix)-1) {\n    // found one unerased block, remedy\n    SPIFFS_DBG(\"mount: erase block \"_SPIPRIbl\"\\n\", bix);\n#if SPIFFS_READ_ONLY\n    res = SPIFFS_ERR_RO_ABORTED_OPERATION;\n#else\n    res = spiffs_erase_block(fs, unerased_bix);\n#endif // SPIFFS_READ_ONLY\n    SPIFFS_CHECK_RES(res);\n  }\n#endif\n\n  // count blocks\n\n  fs->free_blocks = 0;\n  fs->stats_p_allocated = 0;\n  fs->stats_p_deleted = 0;\n\n  res = spiffs_obj_lu_find_entry_visitor(fs,\n      0,\n      0,\n      0,\n      0,\n      spiffs_obj_lu_scan_v,\n      0,\n      0,\n      &bix,\n      &entry);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_OK;\n  }\n\n  SPIFFS_CHECK_RES(res);\n\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\n// Find free object lookup entry\n// Iterate over object lookup pages in each block until a free object id entry is found\ns32_t spiffs_obj_lu_find_free(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    spiffs_block_ix *block_ix,\n    int *lu_entry) {\n  s32_t res;\n  if (!fs->cleaning && fs->free_blocks < 2) {\n    res = spiffs_gc_quick(fs, 0);\n    if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) {\n      res = SPIFFS_OK;\n    }\n    SPIFFS_CHECK_RES(res);\n    if (fs->free_blocks < 2) {\n      return SPIFFS_ERR_FULL;\n    }\n  }\n  res = spiffs_obj_lu_find_id(fs, starting_block, starting_lu_entry,\n      SPIFFS_OBJ_ID_FREE, block_ix, lu_entry);\n  if (res == SPIFFS_OK) {\n    fs->free_cursor_block_ix = *block_ix;\n    fs->free_cursor_obj_lu_entry = (*lu_entry) + 1;\n    if (*lu_entry == 0) {\n      fs->free_blocks--;\n    }\n  }\n  if (res == SPIFFS_ERR_FULL) {\n    SPIFFS_DBG(\"fs full\\n\");\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n// Find object lookup entry containing given id\n// Iterate over object lookup pages in each block until a given object id entry is found\ns32_t spiffs_obj_lu_find_id(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix *block_ix,\n    int *lu_entry) {\n  s32_t res = spiffs_obj_lu_find_entry_visitor(\n      fs, starting_block, starting_lu_entry, SPIFFS_VIS_CHECK_ID, obj_id, 0, 0, 0, block_ix, lu_entry);\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_ERR_NOT_FOUND;\n  }\n  return res;\n}\n\n\nstatic s32_t spiffs_obj_lu_find_id_and_span_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  s32_t res;\n  spiffs_page_header ph;\n  spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n  res = _spiffs_rd(fs, 0, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_header), (u8_t *)&ph);\n  SPIFFS_CHECK_RES(res);\n  if (ph.obj_id == obj_id &&\n      ph.span_ix == *((spiffs_span_ix*)user_var_p) &&\n      (ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED)) == SPIFFS_PH_FLAG_DELET &&\n      !((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (ph.flags & SPIFFS_PH_FLAG_IXDELE) == 0 && ph.span_ix == 0) &&\n      (user_const_p == 0 || *((const spiffs_page_ix*)user_const_p) != pix)) {\n    return SPIFFS_OK;\n  } else {\n    return SPIFFS_VIS_COUNTINUE;\n  }\n}\n\n// Find object lookup entry containing given id and span index\n// Iterate over object lookup pages in each block until a given object id entry is found\ns32_t spiffs_obj_lu_find_id_and_span(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix exclusion_pix,\n    spiffs_page_ix *pix) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n\n  res = spiffs_obj_lu_find_entry_visitor(fs,\n      fs->cursor_block_ix,\n      fs->cursor_obj_lu_entry,\n      SPIFFS_VIS_CHECK_ID,\n      obj_id,\n      spiffs_obj_lu_find_id_and_span_v,\n      exclusion_pix ? &exclusion_pix : 0,\n      &spix,\n      &bix,\n      &entry);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_ERR_NOT_FOUND;\n  }\n\n  SPIFFS_CHECK_RES(res);\n\n  if (pix) {\n    *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  fs->cursor_block_ix = bix;\n  fs->cursor_obj_lu_entry = entry;\n\n  return res;\n}\n\n// Find object lookup entry containing given id and span index in page headers only\n// Iterate over object lookup pages in each block until a given object id entry is found\ns32_t spiffs_obj_lu_find_id_and_span_by_phdr(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix exclusion_pix,\n    spiffs_page_ix *pix) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n\n  res = spiffs_obj_lu_find_entry_visitor(fs,\n      fs->cursor_block_ix,\n      fs->cursor_obj_lu_entry,\n      SPIFFS_VIS_CHECK_PH,\n      obj_id,\n      spiffs_obj_lu_find_id_and_span_v,\n      exclusion_pix ? &exclusion_pix : 0,\n      &spix,\n      &bix,\n      &entry);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_ERR_NOT_FOUND;\n  }\n\n  SPIFFS_CHECK_RES(res);\n\n  if (pix) {\n    *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  fs->cursor_block_ix = bix;\n  fs->cursor_obj_lu_entry = entry;\n\n  return res;\n}\n\n#if SPIFFS_IX_MAP\n\n// update index map of given fd with given object index data\nstatic void spiffs_update_ix_map(spiffs *fs,\n    spiffs_fd *fd, spiffs_span_ix objix_spix, spiffs_page_object_ix *objix) {\n#if SPIFFS_SINGLETON\n  (void)fs;\n#endif\n  spiffs_ix_map *map = fd->ix_map;\n  spiffs_span_ix map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix);\n  spiffs_span_ix map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->end_spix);\n\n  // check if updated ix is within map range\n  if (objix_spix < map_objix_start_spix || objix_spix > map_objix_end_spix) {\n    return;\n  }\n\n  // update memory mapped page index buffer to new pages\n\n  // get range of updated object index map data span indices\n  spiffs_span_ix objix_data_spix_start =\n      SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, objix_spix);\n  spiffs_span_ix objix_data_spix_end = objix_data_spix_start +\n      (objix_spix == 0 ? SPIFFS_OBJ_HDR_IX_LEN(fs) : SPIFFS_OBJ_IX_LEN(fs));\n\n  // calc union of object index range and index map range array\n  spiffs_span_ix map_spix = MAX(map->start_spix, objix_data_spix_start);\n  spiffs_span_ix map_spix_end = MIN(map->end_spix + 1, objix_data_spix_end);\n\n  while (map_spix < map_spix_end) {\n    spiffs_page_ix objix_data_pix;\n    if (objix_spix == 0) {\n      // get data page from object index header page\n      objix_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix_header)))[map_spix];\n    } else {\n      // get data page from object index page\n      objix_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, map_spix)];\n    }\n\n    if (objix_data_pix == (spiffs_page_ix)-1) {\n      // reached end of object, abort\n      break;\n    }\n\n    map->map_buf[map_spix - map->start_spix] = objix_data_pix;\n    SPIFFS_DBG(\"map \"_SPIPRIid\":\"_SPIPRIsp\" (\"_SPIPRIsp\"--\"_SPIPRIsp\") objix.spix:\"_SPIPRIsp\" to pix \"_SPIPRIpg\"\\n\",\n        fd->obj_id, map_spix - map->start_spix,\n        map->start_spix, map->end_spix,\n        objix->p_hdr.span_ix,\n        objix_data_pix);\n\n    map_spix++;\n  }\n}\n\ntypedef struct {\n  spiffs_fd *fd;\n  u32_t remaining_objix_pages_to_visit;\n  spiffs_span_ix map_objix_start_spix;\n  spiffs_span_ix map_objix_end_spix;\n} spiffs_ix_map_populate_state;\n\nstatic s32_t spiffs_populate_ix_map_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  (void)user_const_p;\n  s32_t res;\n  spiffs_ix_map_populate_state *state = (spiffs_ix_map_populate_state *)user_var_p;\n  spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n\n  // load header to check it\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix), (u8_t *)objix);\n  SPIFFS_CHECK_RES(res);\n  SPIFFS_VALIDATE_OBJIX(objix->p_hdr, obj_id, objix->p_hdr.span_ix);\n\n  // check if hdr is ok, and if objix range overlap with ix map range\n  if ((objix->p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==\n      (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE) &&\n      objix->p_hdr.span_ix >= state->map_objix_start_spix &&\n      objix->p_hdr.span_ix <= state->map_objix_end_spix) {\n    // ok, load rest of object index\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_PAGE_TO_PADDR(fs, pix) + sizeof(spiffs_page_object_ix),\n        SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix),\n        (u8_t *)objix + sizeof(spiffs_page_object_ix));\n    SPIFFS_CHECK_RES(res);\n\n    spiffs_update_ix_map(fs, state->fd, objix->p_hdr.span_ix, objix);\n\n    state->remaining_objix_pages_to_visit--;\n    SPIFFS_DBG(\"map \"_SPIPRIid\" (\"_SPIPRIsp\"--\"_SPIPRIsp\") remaining objix pages \"_SPIPRIi\"\\n\",\n        state->fd->obj_id,\n        state->fd->ix_map->start_spix, state->fd->ix_map->end_spix,\n        state->remaining_objix_pages_to_visit);\n  }\n\n  if (res == SPIFFS_OK) {\n    res = state->remaining_objix_pages_to_visit ? SPIFFS_VIS_COUNTINUE : SPIFFS_VIS_END;\n  }\n  return res;\n}\n\n// populates index map, from vector entry start to vector entry end, inclusive\ns32_t spiffs_populate_ix_map(spiffs *fs, spiffs_fd *fd, u32_t vec_entry_start, u32_t vec_entry_end) {\n  s32_t res;\n  spiffs_ix_map *map = fd->ix_map;\n  spiffs_ix_map_populate_state state;\n  vec_entry_start = MIN((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_start);\n  vec_entry_end = MAX((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_end);\n  if (vec_entry_start > vec_entry_end) {\n    return SPIFFS_ERR_IX_MAP_BAD_RANGE;\n  }\n  state.map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_start);\n  state.map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_end);\n  state.remaining_objix_pages_to_visit =\n      state.map_objix_end_spix - state.map_objix_start_spix + 1;\n  state.fd = fd;\n\n  res = spiffs_obj_lu_find_entry_visitor(\n      fs,\n      SPIFFS_BLOCK_FOR_PAGE(fs, fd->objix_hdr_pix),\n      SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, fd->objix_hdr_pix),\n      SPIFFS_VIS_CHECK_ID,\n      fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,\n      spiffs_populate_ix_map_v,\n      0,\n      &state,\n      0,\n      0);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_OK;\n  }\n\n  return res;\n}\n\n#endif\n\n\n#if !SPIFFS_READ_ONLY\n// Allocates a free defined page with given obj_id\n// Occupies object lookup entry and page\n// data may be NULL; where only page header is stored, len and page_offs is ignored\ns32_t spiffs_page_allocate_data(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_page_header *ph,\n    u8_t *data,\n    u32_t len,\n    u32_t page_offs,\n    u8_t finalize,\n    spiffs_page_ix *pix) {\n  s32_t res = SPIFFS_OK;\n  spiffs_block_ix bix;\n  int entry;\n\n  // find free entry\n  res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);\n  SPIFFS_CHECK_RES(res);\n\n  // occupy page in object lookup\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id);\n  SPIFFS_CHECK_RES(res);\n\n  fs->stats_p_allocated++;\n\n  // write page header\n  ph->flags &= ~SPIFFS_PH_FLAG_USED;\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_header), (u8_t*)ph);\n  SPIFFS_CHECK_RES(res);\n\n  // write page data\n  if (data) {\n    res = _spiffs_wr(fs,  SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n        0,SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + sizeof(spiffs_page_header) + page_offs, len, data);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  // finalize header if necessary\n  if (finalize && (ph->flags & SPIFFS_PH_FLAG_FINAL)) {\n    ph->flags &= ~SPIFFS_PH_FLAG_FINAL;\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n        0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + offsetof(spiffs_page_header, flags),\n        sizeof(u8_t),\n        (u8_t *)&ph->flags);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  // return written page\n  if (pix) {\n    *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page.\n// If page data is null, provided header is used for metainfo and page data is physically copied.\ns32_t spiffs_page_move(\n    spiffs *fs,\n    spiffs_file fh,\n    u8_t *page_data,\n    spiffs_obj_id obj_id,\n    spiffs_page_header *page_hdr,\n    spiffs_page_ix src_pix,\n    spiffs_page_ix *dst_pix) {\n  s32_t res;\n  u8_t was_final = 0;\n  spiffs_page_header *p_hdr;\n  spiffs_block_ix bix;\n  int entry;\n  spiffs_page_ix free_pix;\n\n  // find free entry\n  res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);\n  SPIFFS_CHECK_RES(res);\n  free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n\n  if (dst_pix) *dst_pix = free_pix;\n\n  p_hdr = page_data ? (spiffs_page_header *)page_data : page_hdr;\n  if (page_data) {\n    // got page data\n    was_final = (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) == 0;\n    // write unfinalized page\n    p_hdr->flags |= SPIFFS_PH_FLAG_FINAL;\n    p_hdr->flags &= ~SPIFFS_PH_FLAG_USED;\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n        0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), page_data);\n  } else {\n    // copy page data\n    res = spiffs_phys_cpy(fs, fh, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_PAGE_TO_PADDR(fs, src_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs));\n  }\n  SPIFFS_CHECK_RES(res);\n\n  // mark entry in destination object lookup\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),\n      sizeof(spiffs_obj_id),\n      (u8_t *)&obj_id);\n  SPIFFS_CHECK_RES(res);\n\n  fs->stats_p_allocated++;\n\n  if (was_final) {\n    // mark finalized in destination page\n    p_hdr->flags &= ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED);\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n        fh,\n        SPIFFS_PAGE_TO_PADDR(fs, free_pix) + offsetof(spiffs_page_header, flags),\n        sizeof(u8_t),\n        (u8_t *)&p_hdr->flags);\n    SPIFFS_CHECK_RES(res);\n  }\n  // mark source deleted\n  res = spiffs_page_delete(fs, src_pix);\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// Deletes a page and removes it from object lookup.\ns32_t spiffs_page_delete(\n    spiffs *fs,\n    spiffs_page_ix pix) {\n  s32_t res;\n  spiffs_page_header hdr;\n  hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED);\n  // mark deleted entry in source object lookup\n  spiffs_obj_id d_obj_id = SPIFFS_OBJ_ID_DELETED;\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_DELE,\n      0,\n      SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_page_ix),\n      sizeof(spiffs_obj_id),\n      (u8_t *)&d_obj_id);\n  SPIFFS_CHECK_RES(res);\n\n  fs->stats_p_deleted++;\n  fs->stats_p_allocated--;\n\n  // mark deleted in source page\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_DELE,\n      0,\n      SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags),\n      sizeof(u8_t),\n      (u8_t *)&hdr.flags);\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// Create an object index header page with empty index and undefined length\ns32_t spiffs_object_create(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    const u8_t name[],\n    const u8_t meta[],\n    spiffs_obj_type type,\n    spiffs_page_ix *objix_hdr_pix) {\n  s32_t res = SPIFFS_OK;\n  spiffs_block_ix bix;\n  spiffs_page_object_ix_header oix_hdr;\n  int entry;\n\n  res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs));\n  SPIFFS_CHECK_RES(res);\n\n  obj_id |= SPIFFS_OBJ_ID_IX_FLAG;\n\n  // find free entry\n  res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);\n  SPIFFS_CHECK_RES(res);\n  SPIFFS_DBG(\"create: found free page @ \"_SPIPRIpg\" bix:\"_SPIPRIbl\" entry:\"_SPIPRIsp\"\\n\", (spiffs_page_ix)SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);\n\n  // occupy page in object lookup\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id);\n  SPIFFS_CHECK_RES(res);\n\n  fs->stats_p_allocated++;\n\n  // write empty object index page\n  oix_hdr.p_hdr.obj_id = obj_id;\n  oix_hdr.p_hdr.span_ix = 0;\n  oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED);\n  oix_hdr.type = type;\n  oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page\n  strncpy((char*)oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN);\n#if SPIFFS_OBJ_META_LEN\n  if (meta) {\n    memcpy(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN);\n  } else {\n    memset(oix_hdr.meta, 0xff, SPIFFS_OBJ_META_LEN);\n  }\n#else\n  (void) meta;\n#endif\n\n  // update page\n  res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n      0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&oix_hdr);\n\n  SPIFFS_CHECK_RES(res);\n  spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&oix_hdr,\n      SPIFFS_EV_IX_NEW, obj_id, 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), SPIFFS_UNDEFINED_LEN);\n\n  if (objix_hdr_pix) {\n    *objix_hdr_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// update object index header with any combination of name/size/index\n// new_objix_hdr_data may be null, if so the object index header page is loaded\n// name may be null, if so name is not changed\n// size may be null, if so size is not changed\ns32_t spiffs_object_update_index_hdr(\n    spiffs *fs,\n    spiffs_fd *fd,\n    spiffs_obj_id obj_id,\n    spiffs_page_ix objix_hdr_pix,\n    u8_t *new_objix_hdr_data,\n    const u8_t name[],\n    const u8_t meta[],\n    u32_t size,\n    spiffs_page_ix *new_pix) {\n  s32_t res = SPIFFS_OK;\n  spiffs_page_object_ix_header *objix_hdr;\n  spiffs_page_ix new_objix_hdr_pix;\n\n  obj_id |=  SPIFFS_OBJ_ID_IX_FLAG;\n\n  if (new_objix_hdr_data) {\n    // object index header page already given to us, no need to load it\n    objix_hdr = (spiffs_page_object_ix_header *)new_objix_hdr_data;\n  } else {\n    // read object index header page\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n        fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n    SPIFFS_CHECK_RES(res);\n    objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  }\n\n  SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, obj_id, 0);\n\n  // change name\n  if (name) {\n    strncpy((char*)objix_hdr->name, (const char*)name, SPIFFS_OBJ_NAME_LEN);\n  }\n#if SPIFFS_OBJ_META_LEN\n  if (meta) {\n    memcpy(objix_hdr->meta, meta, SPIFFS_OBJ_META_LEN);\n  }\n#else\n  (void) meta;\n#endif\n  if (size) {\n    objix_hdr->size = size;\n  }\n\n  // move and update page\n  res = spiffs_page_move(fs, fd == 0 ? 0 : fd->file_nbr, (u8_t*)objix_hdr, obj_id, 0, objix_hdr_pix, &new_objix_hdr_pix);\n\n  if (res == SPIFFS_OK) {\n    if (new_pix) {\n      *new_pix = new_objix_hdr_pix;\n    }\n    // callback on object index update\n    spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr,\n        new_objix_hdr_data ? SPIFFS_EV_IX_UPD : SPIFFS_EV_IX_UPD_HDR,\n            obj_id, objix_hdr->p_hdr.span_ix, new_objix_hdr_pix, objix_hdr->size);\n    if (fd) fd->objix_hdr_pix = new_objix_hdr_pix; // if this is not in the registered cluster\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\nvoid spiffs_cb_object_event(\n    spiffs *fs,\n    spiffs_page_object_ix *objix,\n    int ev,\n    spiffs_obj_id obj_id_raw,\n    spiffs_span_ix spix,\n    spiffs_page_ix new_pix,\n    u32_t new_size) {\n#if SPIFFS_IX_MAP == 0\n  (void)objix;\n#endif\n  // update index caches in all file descriptors\n  spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG;\n  u32_t i;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n#if SPIFFS_TEMPORAL_FD_CACHE\n    if (cur_fd->score == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;\n#else\n    if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;\n#endif\n    if (spix == 0) {\n      if (ev != SPIFFS_EV_IX_DEL) {\n        SPIFFS_DBG(\"       callback: setting fd \"_SPIPRIfd\":\"_SPIPRIid\" objix_hdr_pix to \"_SPIPRIpg\", size:\"_SPIPRIi\"\\n\", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);\n        cur_fd->objix_hdr_pix = new_pix;\n        if (new_size != 0) {\n          cur_fd->size = new_size;\n        }\n      } else {\n        cur_fd->file_nbr = 0;\n        cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED;\n      }\n    }\n    if (cur_fd->cursor_objix_spix == spix) {\n      if (ev != SPIFFS_EV_IX_DEL) {\n        SPIFFS_DBG(\"       callback: setting fd \"_SPIPRIfd\":\"_SPIPRIid\" span:\"_SPIPRIsp\" objix_pix to \"_SPIPRIpg\"\\n\", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);\n        cur_fd->cursor_objix_pix = new_pix;\n      } else {\n        cur_fd->cursor_objix_pix = 0;\n      }\n    }\n  }\n\n#if SPIFFS_IX_MAP\n\n  // update index maps\n  if (ev == SPIFFS_EV_IX_UPD || ev == SPIFFS_EV_IX_NEW) {\n    for (i = 0; i < fs->fd_count; i++) {\n      spiffs_fd *cur_fd = &fds[i];\n      // check fd opened, having ix map, match obj id\n      if (cur_fd->file_nbr == 0 ||\n          cur_fd->ix_map == 0 ||\n          (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;\n      SPIFFS_DBG(\"       callback: map ix update fd \"_SPIPRIfd\":\"_SPIPRIid\" span:\"_SPIPRIsp\"\\n\", cur_fd->file_nbr, cur_fd->obj_id, spix);\n      spiffs_update_ix_map(fs, cur_fd, spix, objix);\n    }\n  }\n\n#endif\n\n  // callback to user if object index header\n  if (fs->file_cb_f && spix == 0 && (obj_id_raw & SPIFFS_OBJ_ID_IX_FLAG)) {\n    spiffs_fileop_type op;\n    if (ev == SPIFFS_EV_IX_NEW) {\n      op = SPIFFS_CB_CREATED;\n    } else if (ev == SPIFFS_EV_IX_UPD ||\n        ev == SPIFFS_EV_IX_MOV ||\n        ev == SPIFFS_EV_IX_UPD_HDR) {\n      op = SPIFFS_CB_UPDATED;\n    } else if (ev == SPIFFS_EV_IX_DEL) {\n      op = SPIFFS_CB_DELETED;\n    } else {\n      SPIFFS_DBG(\"       callback: WARNING unknown callback event \"_SPIPRIi\"\\n\", ev);\n      return; // bail out\n    }\n    fs->file_cb_f(fs, op, obj_id, new_pix);\n  }\n}\n\n// Open object by id\ns32_t spiffs_object_open_by_id(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_fd *fd,\n    spiffs_flags flags,\n    spiffs_mode mode) {\n  s32_t res = SPIFFS_OK;\n  spiffs_page_ix pix;\n\n  res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);\n  SPIFFS_CHECK_RES(res);\n\n  res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);\n\n  return res;\n}\n\n// Open object by page index\ns32_t spiffs_object_open_by_page(\n    spiffs *fs,\n    spiffs_page_ix pix,\n    spiffs_fd *fd,\n    spiffs_flags flags,\n    spiffs_mode mode) {\n  (void)mode;\n  s32_t res = SPIFFS_OK;\n  spiffs_page_object_ix_header oix_hdr;\n  spiffs_obj_id obj_id;\n\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n      fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&oix_hdr);\n  SPIFFS_CHECK_RES(res);\n\n  spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(fs, pix);\n  int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix);\n\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,\n      0,  SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id);\n\n  fd->fs = fs;\n  fd->objix_hdr_pix = pix;\n  fd->size = oix_hdr.size;\n  fd->offset = 0;\n  fd->cursor_objix_pix = pix;\n  fd->cursor_objix_spix = 0;\n  fd->obj_id = obj_id;\n  fd->flags = flags;\n\n  SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);\n\n  SPIFFS_DBG(\"open: fd \"_SPIPRIfd\" is obj id \"_SPIPRIid\"\\n\", fd->file_nbr, fd->obj_id);\n\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\n// Append to object\n// keep current object index (header) page in fs->work buffer\ns32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {\n  spiffs *fs = fd->fs;\n  s32_t res = SPIFFS_OK;\n  u32_t written = 0;\n\n  SPIFFS_DBG(\"append: \"_SPIPRIi\" bytes @ offs \"_SPIPRIi\" of size \"_SPIPRIi\"\\n\", len, offset, fd->size);\n\n  if (offset > fd->size) {\n    SPIFFS_DBG(\"append: offset reversed to size\\n\");\n    offset = fd->size;\n  }\n\n  res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta\n  if (res != SPIFFS_OK) {\n    SPIFFS_DBG(\"append: gc check fail \"_SPIPRIi\"\\n\", res);\n  }\n  SPIFFS_CHECK_RES(res);\n\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n  spiffs_page_header p_hdr;\n\n  spiffs_span_ix cur_objix_spix = 0;\n  spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;\n  spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;\n  spiffs_page_ix new_objix_hdr_page;\n\n  spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);\n  spiffs_page_ix data_page;\n  u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);\n\n  // write all data\n  while (res == SPIFFS_OK && written < len) {\n    // calculate object index page span index\n    cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n\n    // handle storing and loading of object indices\n    if (cur_objix_spix != prev_objix_spix) {\n      // new object index page\n      // within this clause we return directly if something fails, object index mess-up\n      if (written > 0) {\n        // store previous object index page, unless first pass\n        SPIFFS_DBG(\"append: \"_SPIPRIid\" store objix \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n            cur_objix_pix, prev_objix_spix, written);\n        if (prev_objix_spix == 0) {\n          // this is an update to object index header page\n          objix_hdr->size = offset+written;\n          if (offset == 0) {\n            // was an empty object, update same page (size was 0xffffffff)\n            res = spiffs_page_index_check(fs, fd, cur_objix_pix, 0);\n            SPIFFS_CHECK_RES(res);\n            res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n                fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n            SPIFFS_CHECK_RES(res);\n          } else {\n            // was a nonempty object, update to new page\n            res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n                fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page);\n            SPIFFS_CHECK_RES(res);\n            SPIFFS_DBG(\"append: \"_SPIPRIid\" store new objix_hdr, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n                new_objix_hdr_page, 0, written);\n          }\n        } else {\n          // this is an update to an object index page\n          res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);\n          SPIFFS_CHECK_RES(res);\n\n          res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n              fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n          SPIFFS_CHECK_RES(res);\n          spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n              SPIFFS_EV_IX_UPD,fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);\n          // update length in object index header page\n          res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n              fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page);\n          SPIFFS_CHECK_RES(res);\n          SPIFFS_DBG(\"append: \"_SPIPRIid\" store new size I \"_SPIPRIi\" in objix_hdr, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n              offset+written, new_objix_hdr_page, 0, written);\n        }\n        fd->size = offset+written;\n        fd->offset = offset+written;\n      }\n\n      // create or load new object index page\n      if (cur_objix_spix == 0) {\n        // load object index header page, must always exist\n        SPIFFS_DBG(\"append: \"_SPIPRIid\" load objixhdr page \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", fd->obj_id, cur_objix_pix, cur_objix_spix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n            fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n      } else {\n        spiffs_span_ix len_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, (fd->size-1)/SPIFFS_DATA_PAGE_SIZE(fs));\n        // on subsequent passes, create a new object index page\n        if (written > 0 || cur_objix_spix > len_objix_spix) {\n          p_hdr.obj_id = fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG;\n          p_hdr.span_ix = cur_objix_spix;\n          p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);\n          res = spiffs_page_allocate_data(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,\n              &p_hdr, 0, 0, 0, 1, &cur_objix_pix);\n          SPIFFS_CHECK_RES(res);\n          // quick \"load\" of new object index page\n          memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n          memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));\n          spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n              SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);\n          SPIFFS_DBG(\"append: \"_SPIPRIid\" create objix page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id\n              , cur_objix_pix, cur_objix_spix, written);\n        } else {\n          // on first pass, we load existing object index page\n          spiffs_page_ix pix;\n          SPIFFS_DBG(\"append: \"_SPIPRIid\" find objix span_ix:\"_SPIPRIsp\"\\n\", fd->obj_id, cur_objix_spix);\n          if (fd->cursor_objix_spix == cur_objix_spix) {\n            pix = fd->cursor_objix_pix;\n          } else {\n            res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);\n            SPIFFS_CHECK_RES(res);\n          }\n          SPIFFS_DBG(\"append: \"_SPIPRIid\" found object index at page \"_SPIPRIpg\" [fd size \"_SPIPRIi\"]\\n\", fd->obj_id, pix, fd->size);\n          res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n              fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n          SPIFFS_CHECK_RES(res);\n          SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n          cur_objix_pix = pix;\n        }\n        fd->cursor_objix_pix = cur_objix_pix;\n        fd->cursor_objix_spix = cur_objix_spix;\n        fd->offset = offset+written;\n        fd->size = offset+written;\n      }\n      prev_objix_spix = cur_objix_spix;\n    }\n\n    // write data\n    u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);\n    if (page_offs == 0) {\n      // at beginning of a page, allocate and write a new page of data\n      p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n      p_hdr.span_ix = data_spix;\n      p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL);  // finalize immediately\n      res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n          &p_hdr, &data[written], to_write, page_offs, 1, &data_page);\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" store new data page, \"_SPIPRIpg\":\"_SPIPRIsp\" offset:\"_SPIPRIi\", len \"_SPIPRIi\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n          data_page, data_spix, page_offs, to_write, written);\n    } else {\n      // append to existing page, fill out free data in existing page\n      if (cur_objix_spix == 0) {\n        // get data page from object index header page\n        data_page = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];\n      } else {\n        // get data page from object index page\n        data_page = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];\n      }\n\n      res = spiffs_page_data_check(fs, fd, data_page, data_spix);\n      SPIFFS_CHECK_RES(res);\n\n      res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n          fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" store to existing data page, \"_SPIPRIpg\":\"_SPIPRIsp\" offset:\"_SPIPRIi\", len \"_SPIPRIi\", written \"_SPIPRIi\"\\n\", fd->obj_id\n          , data_page, data_spix, page_offs, to_write, written);\n    }\n\n    if (res != SPIFFS_OK) break;\n\n    // update memory representation of object index page with new data page\n    if (cur_objix_spix == 0) {\n      // update object index header page\n      ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_page;\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" wrote page \"_SPIPRIpg\" to objix_hdr entry \"_SPIPRIsp\" in mem\\n\", fd->obj_id\n          , data_page, data_spix);\n      objix_hdr->size = offset+written;\n    } else {\n      // update object index page\n      ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_page;\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" wrote page \"_SPIPRIpg\" to objix entry \"_SPIPRIsp\" in mem\\n\", fd->obj_id\n          , data_page, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));\n    }\n\n    // update internals\n    page_offs = 0;\n    data_spix++;\n    written += to_write;\n  } // while all data\n\n  fd->size = offset+written;\n  fd->offset = offset+written;\n  fd->cursor_objix_pix = cur_objix_pix;\n  fd->cursor_objix_spix = cur_objix_spix;\n\n  // finalize updated object indices\n  s32_t res2 = SPIFFS_OK;\n  if (cur_objix_spix != 0) {\n    // wrote beyond object index header page\n    // write last modified object index page, unless object header index page\n    SPIFFS_DBG(\"append: \"_SPIPRIid\" store objix page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id,\n        cur_objix_pix, cur_objix_spix, written);\n\n    res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);\n    SPIFFS_CHECK_RES(res2);\n\n    res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n        fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n    SPIFFS_CHECK_RES(res2);\n    spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n        SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);\n\n    // update size in object header index page\n    res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n        fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page);\n    SPIFFS_DBG(\"append: \"_SPIPRIid\" store new size II \"_SPIPRIi\" in objix_hdr, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\", res \"_SPIPRIi\"\\n\", fd->obj_id\n        , offset+written, new_objix_hdr_page, 0, written, res2);\n    SPIFFS_CHECK_RES(res2);\n  } else {\n    // wrote within object index header page\n    if (offset == 0) {\n      // wrote to empty object - simply update size and write whole page\n      objix_hdr->size = offset+written;\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" store fresh objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id\n          , cur_objix_pix, cur_objix_spix, written);\n\n      res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);\n      SPIFFS_CHECK_RES(res2);\n\n      res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n          fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n      SPIFFS_CHECK_RES(res2);\n      // callback on object index update\n      spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,\n          SPIFFS_EV_IX_UPD_HDR, fd->obj_id, objix_hdr->p_hdr.span_ix, cur_objix_pix, objix_hdr->size);\n    } else {\n      // modifying object index header page, update size and make new copy\n      res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n          fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page);\n      SPIFFS_DBG(\"append: \"_SPIPRIid\" store modified objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", fd->obj_id\n          , new_objix_hdr_page, 0, written);\n      SPIFFS_CHECK_RES(res2);\n    }\n  }\n\n  return res;\n} // spiffs_object_append\n#endif // !SPIFFS_READ_ONLY\n\n#if !SPIFFS_READ_ONLY\n// Modify object\n// keep current object index (header) page in fs->work buffer\ns32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {\n  spiffs *fs = fd->fs;\n  s32_t res = SPIFFS_OK;\n  u32_t written = 0;\n\n  res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs));\n  SPIFFS_CHECK_RES(res);\n\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n  spiffs_page_header p_hdr;\n\n  spiffs_span_ix cur_objix_spix = 0;\n  spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;\n  spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;\n  spiffs_page_ix new_objix_hdr_pix;\n\n  spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);\n  spiffs_page_ix data_pix;\n  u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);\n\n\n  // write all data\n  while (res == SPIFFS_OK && written < len) {\n    // calculate object index page span index\n    cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n\n    // handle storing and loading of object indices\n    if (cur_objix_spix != prev_objix_spix) {\n      // new object index page\n      // within this clause we return directly if something fails, object index mess-up\n      if (written > 0) {\n        // store previous object index (header) page, unless first pass\n        if (prev_objix_spix == 0) {\n          // store previous object index header page\n          res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n              fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix);\n          SPIFFS_DBG(\"modify: store modified objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", new_objix_hdr_pix, 0, written);\n          SPIFFS_CHECK_RES(res);\n        } else {\n          // store new version of previous object index page\n          spiffs_page_ix new_objix_pix;\n\n          res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);\n          SPIFFS_CHECK_RES(res);\n\n          res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);\n          SPIFFS_DBG(\"modify: store previous modified objix page, \"_SPIPRIid\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", new_objix_pix, objix->p_hdr.span_ix, written);\n          SPIFFS_CHECK_RES(res);\n          spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix,\n              SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n        }\n      }\n\n      // load next object index page\n      if (cur_objix_spix == 0) {\n        // load object index header page, must exist\n        SPIFFS_DBG(\"modify: load objixhdr page \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", cur_objix_pix, cur_objix_spix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n            fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n      } else {\n        // load existing object index page on first pass\n        spiffs_page_ix pix;\n        SPIFFS_DBG(\"modify: find objix span_ix:\"_SPIPRIsp\"\\n\", cur_objix_spix);\n        if (fd->cursor_objix_spix == cur_objix_spix) {\n          pix = fd->cursor_objix_pix;\n        } else {\n          res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);\n          SPIFFS_CHECK_RES(res);\n        }\n        SPIFFS_DBG(\"modify: found object index at page \"_SPIPRIpg\"\\n\", pix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n            fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n        cur_objix_pix = pix;\n      }\n      fd->cursor_objix_pix = cur_objix_pix;\n      fd->cursor_objix_spix = cur_objix_spix;\n      fd->offset = offset+written;\n      prev_objix_spix = cur_objix_spix;\n    }\n\n    // write partial data\n    u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);\n    spiffs_page_ix orig_data_pix;\n    if (cur_objix_spix == 0) {\n      // get data page from object index header page\n      orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];\n    } else {\n      // get data page from object index page\n      orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];\n    }\n\n    p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n    p_hdr.span_ix = data_spix;\n    p_hdr.flags = 0xff;\n    if (page_offs == 0 && to_write == SPIFFS_DATA_PAGE_SIZE(fs)) {\n      // a full page, allocate and write a new page of data\n      res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n          &p_hdr, &data[written], to_write, page_offs, 1, &data_pix);\n      SPIFFS_DBG(\"modify: store new data page, \"_SPIPRIpg\":\"_SPIPRIsp\" offset:\"_SPIPRIi\", len \"_SPIPRIi\", written \"_SPIPRIi\"\\n\", data_pix, data_spix, page_offs, to_write, written);\n    } else {\n      // write to existing page, allocate new and copy unmodified data\n\n      res = spiffs_page_data_check(fs, fd, orig_data_pix, data_spix);\n      SPIFFS_CHECK_RES(res);\n\n      res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n          &p_hdr, 0, 0, 0, 0, &data_pix);\n      if (res != SPIFFS_OK) break;\n\n      // copy unmodified data\n      if (page_offs > 0) {\n        // before modification\n        res = spiffs_phys_cpy(fs, fd->file_nbr,\n            SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),\n            SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header),\n            page_offs);\n        if (res != SPIFFS_OK) break;\n      }\n      if (page_offs + to_write < SPIFFS_DATA_PAGE_SIZE(fs)) {\n        // after modification\n        res = spiffs_phys_cpy(fs, fd->file_nbr,\n            SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,\n            SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,\n            SPIFFS_DATA_PAGE_SIZE(fs) - (page_offs + to_write));\n        if (res != SPIFFS_OK) break;\n      }\n\n      res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n          fd->file_nbr,\n          SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);\n      if (res != SPIFFS_OK) break;\n      p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;\n      res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n          fd->file_nbr,\n          SPIFFS_PAGE_TO_PADDR(fs, data_pix) + offsetof(spiffs_page_header, flags),\n          sizeof(u8_t),\n          (u8_t *)&p_hdr.flags);\n      if (res != SPIFFS_OK) break;\n\n      SPIFFS_DBG(\"modify: store to existing data page, src:\"_SPIPRIpg\", dst:\"_SPIPRIpg\":\"_SPIPRIsp\" offset:\"_SPIPRIi\", len \"_SPIPRIi\", written \"_SPIPRIi\"\\n\", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);\n    }\n\n    // delete original data page\n    res = spiffs_page_delete(fs, orig_data_pix);\n    if (res != SPIFFS_OK) break;\n    // update memory representation of object index page with new data page\n    if (cur_objix_spix == 0) {\n      // update object index header page\n      ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_pix;\n      SPIFFS_DBG(\"modify: wrote page \"_SPIPRIpg\" to objix_hdr entry \"_SPIPRIsp\" in mem\\n\", data_pix, data_spix);\n    } else {\n      // update object index page\n      ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_pix;\n      SPIFFS_DBG(\"modify: wrote page \"_SPIPRIpg\" to objix entry \"_SPIPRIsp\" in mem\\n\", data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));\n    }\n\n    // update internals\n    page_offs = 0;\n    data_spix++;\n    written += to_write;\n  } // while all data\n\n  fd->offset = offset+written;\n  fd->cursor_objix_pix = cur_objix_pix;\n  fd->cursor_objix_spix = cur_objix_spix;\n\n  // finalize updated object indices\n  s32_t res2 = SPIFFS_OK;\n  if (cur_objix_spix != 0) {\n    // wrote beyond object index header page\n    // write last modified object index page\n    // move and update page\n    spiffs_page_ix new_objix_pix;\n\n    res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);\n    SPIFFS_CHECK_RES(res2);\n\n    res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);\n    SPIFFS_DBG(\"modify: store modified objix page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", new_objix_pix, cur_objix_spix, written);\n    fd->cursor_objix_pix = new_objix_pix;\n    fd->cursor_objix_spix = cur_objix_spix;\n    SPIFFS_CHECK_RES(res2);\n    spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix,\n        SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n\n  } else {\n    // wrote within object index header page\n    res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n        fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix);\n    SPIFFS_DBG(\"modify: store modified objix_hdr page, \"_SPIPRIpg\":\"_SPIPRIsp\", written \"_SPIPRIi\"\\n\", new_objix_hdr_pix, 0, written);\n    SPIFFS_CHECK_RES(res2);\n  }\n\n  return res;\n} // spiffs_object_modify\n#endif // !SPIFFS_READ_ONLY\n\nstatic s32_t spiffs_object_find_object_index_header_by_name_v(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix bix,\n    int ix_entry,\n    const void *user_const_p,\n    void *user_var_p) {\n  (void)user_var_p;\n  s32_t res;\n  spiffs_page_object_ix_header objix_hdr;\n  spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n  if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||\n      (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {\n    return SPIFFS_VIS_COUNTINUE;\n  }\n  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n      0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);\n  SPIFFS_CHECK_RES(res);\n  if (objix_hdr.p_hdr.span_ix == 0 &&\n      (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==\n          (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {\n    if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) {\n      return SPIFFS_OK;\n    }\n  }\n\n  return SPIFFS_VIS_COUNTINUE;\n}\n\n// Finds object index header page by name\ns32_t spiffs_object_find_object_index_header_by_name(\n    spiffs *fs,\n    const u8_t name[SPIFFS_OBJ_NAME_LEN],\n    spiffs_page_ix *pix) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\n\n  res = spiffs_obj_lu_find_entry_visitor(fs,\n      fs->cursor_block_ix,\n      fs->cursor_obj_lu_entry,\n      0,\n      0,\n      spiffs_object_find_object_index_header_by_name_v,\n      name,\n      0,\n      &bix,\n      &entry);\n\n  if (res == SPIFFS_VIS_END) {\n    res = SPIFFS_ERR_NOT_FOUND;\n  }\n  SPIFFS_CHECK_RES(res);\n\n  if (pix) {\n    *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);\n  }\n\n  fs->cursor_block_ix = bix;\n  fs->cursor_obj_lu_entry = entry;\n\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\n// Truncates object to new size. If new size is null, object may be removed totally\ns32_t spiffs_object_truncate(\n    spiffs_fd *fd,\n    u32_t new_size,\n    u8_t remove_full) {\n  s32_t res = SPIFFS_OK;\n  spiffs *fs = fd->fs;\n\n  if ((fd->size == SPIFFS_UNDEFINED_LEN || fd->size == 0) && !remove_full) {\n    // no op\n    return res;\n  }\n\n  // need 2 pages if not removing: object index page + possibly chopped data page\n  if (remove_full == 0) {\n    res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs) * 2);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  spiffs_page_ix objix_pix = fd->objix_hdr_pix;\n  spiffs_span_ix data_spix = (fd->size > 0 ? fd->size-1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs);\n  u32_t cur_size = fd->size == (u32_t)SPIFFS_UNDEFINED_LEN ? 0 : fd->size ;\n  spiffs_span_ix cur_objix_spix = 0;\n  spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n  spiffs_page_ix data_pix;\n  spiffs_page_ix new_objix_hdr_pix;\n\n  // before truncating, check if object is to be fully removed and mark this\n  if (remove_full && new_size == 0) {\n    u8_t flags = ~( SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE);\n    res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,\n        fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, fd->objix_hdr_pix) + offsetof(spiffs_page_header, flags),\n        sizeof(u8_t),\n        (u8_t *)&flags);\n    SPIFFS_CHECK_RES(res);\n  }\n\n  // delete from end of object until desired len is reached\n  while (cur_size > new_size) {\n    cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n\n    // put object index for current data span index in work buffer\n    if (prev_objix_spix != cur_objix_spix) {\n      if (prev_objix_spix != (spiffs_span_ix)-1) {\n        // remove previous object index page\n        SPIFFS_DBG(\"truncate: delete objix page \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", objix_pix, prev_objix_spix);\n\n        res = spiffs_page_index_check(fs, fd, objix_pix, prev_objix_spix);\n        SPIFFS_CHECK_RES(res);\n\n        res = spiffs_page_delete(fs, objix_pix);\n        SPIFFS_CHECK_RES(res);\n        spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,\n            SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);\n        if (prev_objix_spix > 0) {\n          // Update object index header page, unless we totally want to remove the file.\n          // If fully removing, we're not keeping consistency as good as when storing the header between chunks,\n          // would we be aborted. But when removing full files, a crammed system may otherwise\n          // report ERR_FULL a la windows. We cannot have that.\n          // Hence, take the risk - if aborted, a file check would free the lost pages and mend things\n          // as the file is marked as fully deleted in the beginning.\n          if (remove_full == 0) {\n            SPIFFS_DBG(\"truncate: update objix hdr page \"_SPIPRIpg\":\"_SPIPRIsp\" to size \"_SPIPRIi\"\\n\", fd->objix_hdr_pix, prev_objix_spix, cur_size);\n            res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n                fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix);\n            SPIFFS_CHECK_RES(res);\n          }\n          fd->size = cur_size;\n        }\n      }\n      // load current object index (header) page\n      if (cur_objix_spix == 0) {\n        objix_pix = fd->objix_hdr_pix;\n      } else {\n        res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);\n        SPIFFS_CHECK_RES(res);\n      }\n\n      SPIFFS_DBG(\"truncate: load objix page \"_SPIPRIpg\":\"_SPIPRIsp\" for data spix:\"_SPIPRIsp\"\\n\", objix_pix, cur_objix_spix, data_spix);\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n          fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n      SPIFFS_CHECK_RES(res);\n      SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);\n      fd->cursor_objix_pix = objix_pix;\n      fd->cursor_objix_spix = cur_objix_spix;\n      fd->offset = cur_size;\n\n      prev_objix_spix = cur_objix_spix;\n    }\n\n    if (cur_objix_spix == 0) {\n      // get data page from object index header page\n      data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];\n      ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = SPIFFS_OBJ_ID_FREE;\n    } else {\n      // get data page from object index page\n      data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];\n      ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE;\n    }\n\n    SPIFFS_DBG(\"truncate: got data pix \"_SPIPRIpg\"\\n\", data_pix);\n\n    if (new_size == 0 || remove_full || cur_size - new_size >= SPIFFS_DATA_PAGE_SIZE(fs)) {\n      // delete full data page\n      res = spiffs_page_data_check(fs, fd, data_pix, data_spix);\n      if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {\n        SPIFFS_DBG(\"truncate: err validating data pix \"_SPIPRIi\"\\n\", res);\n        break;\n      }\n\n      if (res == SPIFFS_OK) {\n        res = spiffs_page_delete(fs, data_pix);\n        if (res != SPIFFS_OK) {\n          SPIFFS_DBG(\"truncate: err deleting data pix \"_SPIPRIi\"\\n\", res);\n          break;\n        }\n      } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {\n        res = SPIFFS_OK;\n      }\n\n      // update current size\n      if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) {\n        cur_size -= SPIFFS_DATA_PAGE_SIZE(fs);\n      } else {\n        cur_size -= cur_size % SPIFFS_DATA_PAGE_SIZE(fs);\n      }\n      fd->size = cur_size;\n      fd->offset = cur_size;\n      SPIFFS_DBG(\"truncate: delete data page \"_SPIPRIpg\" for data spix:\"_SPIPRIsp\", cur_size:\"_SPIPRIi\"\\n\", data_pix, data_spix, cur_size);\n    } else {\n      // delete last page, partially\n      spiffs_page_header p_hdr;\n      spiffs_page_ix new_data_pix;\n      u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));\n      SPIFFS_DBG(\"truncate: delete \"_SPIPRIi\" bytes from data page \"_SPIPRIpg\" for data spix:\"_SPIPRIsp\", cur_size:\"_SPIPRIi\"\\n\", bytes_to_remove, data_pix, data_spix, cur_size);\n\n      res = spiffs_page_data_check(fs, fd, data_pix, data_spix);\n      if (res != SPIFFS_OK) break;\n\n      p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;\n      p_hdr.span_ix = data_spix;\n      p_hdr.flags = 0xff;\n      // allocate new page and copy unmodified data\n      res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,\n          &p_hdr, 0, 0, 0, 0, &new_data_pix);\n      if (res != SPIFFS_OK) break;\n      res = spiffs_phys_cpy(fs, 0,\n          SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + sizeof(spiffs_page_header),\n          SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),\n          SPIFFS_DATA_PAGE_SIZE(fs) - bytes_to_remove);\n      if (res != SPIFFS_OK) break;\n      // delete original data page\n      res = spiffs_page_delete(fs, data_pix);\n      if (res != SPIFFS_OK) break;\n      p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;\n      res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,\n          fd->file_nbr,\n          SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + offsetof(spiffs_page_header, flags),\n          sizeof(u8_t),\n          (u8_t *)&p_hdr.flags);\n      if (res != SPIFFS_OK) break;\n\n      // update memory representation of object index page with new data page\n      if (cur_objix_spix == 0) {\n        // update object index header page\n        ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;\n        SPIFFS_DBG(\"truncate: wrote page \"_SPIPRIpg\" to objix_hdr entry \"_SPIPRIsp\" in mem\\n\", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));\n      } else {\n        // update object index page\n        ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;\n        SPIFFS_DBG(\"truncate: wrote page \"_SPIPRIpg\" to objix entry \"_SPIPRIsp\" in mem\\n\", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));\n      }\n      cur_size = new_size;\n      fd->size = new_size;\n      fd->offset = cur_size;\n      break;\n    }\n    data_spix--;\n  } // while all data\n\n  // update object indices\n  if (cur_objix_spix == 0) {\n    // update object index header page\n    if (cur_size == 0) {\n      if (remove_full) {\n        // remove object altogether\n        SPIFFS_DBG(\"truncate: remove object index header page \"_SPIPRIpg\"\\n\", objix_pix);\n\n        res = spiffs_page_index_check(fs, fd, objix_pix, 0);\n        SPIFFS_CHECK_RES(res);\n\n        res = spiffs_page_delete(fs, objix_pix);\n        SPIFFS_CHECK_RES(res);\n        spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,\n            SPIFFS_EV_IX_DEL, fd->obj_id, 0, objix_pix, 0);\n      } else {\n        // make uninitialized object\n        SPIFFS_DBG(\"truncate: reset objix_hdr page \"_SPIPRIpg\"\\n\", objix_pix);\n        memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,\n            SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header));\n        res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n            objix_pix, fs->work, 0, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix);\n        SPIFFS_CHECK_RES(res);\n      }\n    } else {\n      // update object index header page\n      SPIFFS_DBG(\"truncate: update object index header page with indices and size\\n\");\n      res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n          objix_pix, fs->work, 0, 0, cur_size, &new_objix_hdr_pix);\n      SPIFFS_CHECK_RES(res);\n    }\n  } else {\n    // update both current object index page and object index header page\n    spiffs_page_ix new_objix_pix;\n\n    res = spiffs_page_index_check(fs, fd, objix_pix, cur_objix_spix);\n    SPIFFS_CHECK_RES(res);\n\n    // move and update object index page\n    res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix_hdr, fd->obj_id, 0, objix_pix, &new_objix_pix);\n    SPIFFS_CHECK_RES(res);\n    spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr,\n        SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n    SPIFFS_DBG(\"truncate: store modified objix page, \"_SPIPRIpg\":\"_SPIPRIsp\"\\n\", new_objix_pix, cur_objix_spix);\n    fd->cursor_objix_pix = new_objix_pix;\n    fd->cursor_objix_spix = cur_objix_spix;\n    fd->offset = cur_size;\n    // update object index header page with new size\n    res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,\n        fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix);\n    SPIFFS_CHECK_RES(res);\n  }\n  fd->size = cur_size;\n\n  return res;\n} // spiffs_object_truncate\n#endif // !SPIFFS_READ_ONLY\n\ns32_t spiffs_object_read(\n    spiffs_fd *fd,\n    u32_t offset,\n    u32_t len,\n    u8_t *dst) {\n  s32_t res = SPIFFS_OK;\n  spiffs *fs = fd->fs;\n  spiffs_page_ix objix_pix;\n  spiffs_page_ix data_pix;\n  spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);\n  u32_t cur_offset = offset;\n  spiffs_span_ix cur_objix_spix;\n  spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;\n  spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;\n  spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;\n\n  while (cur_offset < offset + len) {\n#if SPIFFS_IX_MAP\n    // check if we have a memory, index map and if so, if we're within index map's range\n    // and if so, if the entry is populated\n    if (fd->ix_map && data_spix >= fd->ix_map->start_spix && data_spix <= fd->ix_map->end_spix\n        && fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix]) {\n      data_pix = fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix];\n    } else {\n#endif\n      cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);\n      if (prev_objix_spix != cur_objix_spix) {\n        // load current object index (header) page\n        if (cur_objix_spix == 0) {\n          objix_pix = fd->objix_hdr_pix;\n        } else {\n          SPIFFS_DBG(\"read: find objix \"_SPIPRIid\":\"_SPIPRIsp\"\\n\", fd->obj_id, cur_objix_spix);\n          if (fd->cursor_objix_spix == cur_objix_spix) {\n            objix_pix = fd->cursor_objix_pix;\n          } else {\n            res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);\n            SPIFFS_CHECK_RES(res);\n          }\n        }\n        SPIFFS_DBG(\"read: load objix page \"_SPIPRIpg\":\"_SPIPRIsp\" for data spix:\"_SPIPRIsp\"\\n\", objix_pix, cur_objix_spix, data_spix);\n        res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,\n            fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);\n        SPIFFS_CHECK_RES(res);\n        SPIFFS_VALIDATE_OBJIX(objix->p_hdr, fd->obj_id, cur_objix_spix);\n\n        fd->offset = cur_offset;\n        fd->cursor_objix_pix = objix_pix;\n        fd->cursor_objix_spix = cur_objix_spix;\n\n        prev_objix_spix = cur_objix_spix;\n      }\n\n      if (cur_objix_spix == 0) {\n        // get data page from object index header page\n        data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];\n      } else {\n        // get data page from object index page\n        data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];\n      }\n#if SPIFFS_IX_MAP\n    }\n#endif\n    // all remaining data\n    u32_t len_to_read = offset + len - cur_offset;\n    // remaining data in page\n    len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));\n    // remaining data in file\n    len_to_read = MIN(len_to_read, fd->size);\n    SPIFFS_DBG(\"read: offset:\"_SPIPRIi\" rd:\"_SPIPRIi\" data spix:\"_SPIPRIsp\" is data_pix:\"_SPIPRIpg\" addr:\"_SPIPRIad\"\\n\", cur_offset, len_to_read, data_spix, data_pix,\n        (u32_t)(SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))));\n    if (len_to_read <= 0) {\n      res = SPIFFS_ERR_END_OF_OBJECT;\n      break;\n    }\n    res = spiffs_page_data_check(fs, fd, data_pix, data_spix);\n    SPIFFS_CHECK_RES(res);\n    res = _spiffs_rd(\n        fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,\n        fd->file_nbr,\n        SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)),\n        len_to_read,\n        dst);\n    SPIFFS_CHECK_RES(res);\n    dst += len_to_read;\n    cur_offset += len_to_read;\n    fd->offset = cur_offset;\n    data_spix++;\n  }\n\n  return res;\n}\n\n#if !SPIFFS_READ_ONLY\ntypedef struct {\n  spiffs_obj_id min_obj_id;\n  spiffs_obj_id max_obj_id;\n  u32_t compaction;\n  const u8_t *conflicting_name;\n} spiffs_free_obj_id_state;\n\nstatic s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,\n    const void *user_const_p, void *user_var_p) {\n  if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) {\n    spiffs_obj_id min_obj_id = *((spiffs_obj_id*)user_var_p);\n    const u8_t *conflicting_name = (const u8_t*)user_const_p;\n\n    // if conflicting name parameter is given, also check if this name is found in object index hdrs\n    if (conflicting_name && (id & SPIFFS_OBJ_ID_IX_FLAG)) {\n      spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);\n      int res;\n      spiffs_page_object_ix_header objix_hdr;\n      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n          0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);\n      SPIFFS_CHECK_RES(res);\n      if (objix_hdr.p_hdr.span_ix == 0 &&\n          (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==\n              (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {\n        if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) {\n          return SPIFFS_ERR_CONFLICTING_NAME;\n        }\n      }\n    }\n\n    id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n    u32_t bit_ix = (id-min_obj_id) & 7;\n    int byte_ix = (id-min_obj_id) >> 3;\n    if (byte_ix >= 0 && (u32_t)byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs)) {\n      fs->work[byte_ix] |= (1<<bit_ix);\n    }\n  }\n  return SPIFFS_VIS_COUNTINUE;\n}\n\nstatic s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,\n    const void *user_const_p, void *user_var_p) {\n  (void)user_var_p;\n  if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED && (id & SPIFFS_OBJ_ID_IX_FLAG)) {\n    s32_t res;\n    const spiffs_free_obj_id_state *state = (const spiffs_free_obj_id_state*)user_const_p;\n    spiffs_page_object_ix_header objix_hdr;\n\n    res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,\n        0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, ix_entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&objix_hdr);\n    if (res == SPIFFS_OK && objix_hdr.p_hdr.span_ix == 0 &&\n        ((objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) ==\n            (SPIFFS_PH_FLAG_DELET))) {\n      // ok object look up entry\n      if (state->conflicting_name && strcmp((const char *)state->conflicting_name, (char *)objix_hdr.name) == 0) {\n        return SPIFFS_ERR_CONFLICTING_NAME;\n      }\n\n      id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n      if (id >= state->min_obj_id && id <= state->max_obj_id) {\n        u8_t *map = (u8_t *)fs->work;\n        int ix = (id - state->min_obj_id) / state->compaction;\n        //SPIFFS_DBG(\"free_obj_id: add ix \"_SPIPRIi\" for id \"_SPIPRIid\" min\"_SPIPRIid\" max\"_SPIPRIid\" comp:\"_SPIPRIi\"\\n\", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);\n        map[ix]++;\n      }\n    }\n  }\n  return SPIFFS_VIS_COUNTINUE;\n}\n\n// Scans thru all object lookup for object index header pages. If total possible number of\n// object ids cannot fit into a work buffer, these are grouped. When a group containing free\n// object ids is found, the object lu is again scanned for object ids within group and bitmasked.\n// Finally, the bitmask is searched for a free id\ns32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8_t *conflicting_name) {\n  s32_t res = SPIFFS_OK;\n  u32_t max_objects = (fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) / 2;\n  spiffs_free_obj_id_state state;\n  spiffs_obj_id free_obj_id = SPIFFS_OBJ_ID_FREE;\n  state.min_obj_id = 1;\n  state.max_obj_id = max_objects + 1;\n  if (state.max_obj_id & SPIFFS_OBJ_ID_IX_FLAG) {\n    state.max_obj_id = ((spiffs_obj_id)-1) & ~SPIFFS_OBJ_ID_IX_FLAG;\n  }\n  state.compaction = 0;\n  state.conflicting_name = conflicting_name;\n  while (res == SPIFFS_OK && free_obj_id == SPIFFS_OBJ_ID_FREE) {\n    if (state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8) {\n      // possible to represent in bitmap\n      u32_t i, j;\n      SPIFFS_DBG(\"free_obj_id: BITM min:\"_SPIPRIid\" max:\"_SPIPRIid\"\\n\", state.min_obj_id, state.max_obj_id);\n\n      memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n      res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v,\n          conflicting_name, &state.min_obj_id, 0, 0);\n      if (res == SPIFFS_VIS_END) res = SPIFFS_OK;\n      SPIFFS_CHECK_RES(res);\n      // traverse bitmask until found free obj_id\n      for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs); i++) {\n        u8_t mask = fs->work[i];\n        if (mask == 0xff) {\n          continue;\n        }\n        for (j = 0; j < 8; j++) {\n          if ((mask & (1<<j)) == 0) {\n            *obj_id = (i<<3)+j+state.min_obj_id;\n            return SPIFFS_OK;\n          }\n        }\n      }\n      return SPIFFS_ERR_FULL;\n    } else {\n      // not possible to represent all ids in range in a bitmap, compact and count\n      if (state.compaction != 0) {\n        // select element in compacted table, decrease range and recompact\n        u32_t i, min_i = 0;\n        u8_t *map = (u8_t *)fs->work;\n        u8_t min_count = 0xff;\n\n        for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(u8_t); i++) {\n          if (map[i] < min_count) {\n            min_count = map[i];\n            min_i = i;\n            if (min_count == 0) {\n              break;\n            }\n          }\n        }\n\n        if (min_count == state.compaction) {\n          // there are no free objids!\n          SPIFFS_DBG(\"free_obj_id: compacted table is full\\n\");\n          return SPIFFS_ERR_FULL;\n        }\n\n        SPIFFS_DBG(\"free_obj_id: COMP select index:\"_SPIPRIi\" min_count:\"_SPIPRIi\" min:\"_SPIPRIid\" max:\"_SPIPRIid\" compact:\"_SPIPRIi\"\\n\", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);\n\n        if (min_count == 0) {\n          // no id in this range, skip compacting and use directly\n          *obj_id = min_i * state.compaction + state.min_obj_id;\n          return SPIFFS_OK;\n        } else {\n          SPIFFS_DBG(\"free_obj_id: COMP SEL chunk:\"_SPIPRIi\" min:\"_SPIPRIid\" -> \"_SPIPRIid\"\\n\", state.compaction, state.min_obj_id, state.min_obj_id + min_i *  state.compaction);\n          state.min_obj_id += min_i *  state.compaction;\n          state.max_obj_id = state.min_obj_id + state.compaction;\n          // decrease compaction\n        }\n        if ((state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8)) {\n          // no need for compacting, use bitmap\n          continue;\n        }\n      }\n      // in a work memory of log_page_size bytes, we may fit in log_page_size ids\n      // todo what if compaction is > 255 - then we cannot fit it in a byte\n      state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));\n      SPIFFS_DBG(\"free_obj_id: COMP min:\"_SPIPRIid\" max:\"_SPIPRIid\" compact:\"_SPIPRIi\"\\n\", state.min_obj_id, state.max_obj_id, state.compaction);\n\n      memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n      res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, &state, 0, 0, 0);\n      if (res == SPIFFS_VIS_END) res = SPIFFS_OK;\n      SPIFFS_CHECK_RES(res);\n      state.conflicting_name = 0; // searched for conflicting name once, no need to do it again\n    }\n  }\n\n  return res;\n}\n#endif // !SPIFFS_READ_ONLY\n\n#if SPIFFS_TEMPORAL_FD_CACHE\n// djb2 hash\nstatic u32_t spiffs_hash(spiffs *fs, const u8_t *name) {\n  (void)fs;\n  u32_t hash = 5381;\n  u8_t c;\n  int i = 0;\n  while ((c = name[i++]) && i < SPIFFS_OBJ_NAME_LEN) {\n    hash = (hash * 33) ^ c;\n  }\n  return hash;\n}\n#endif\n\ns32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) {\n#if SPIFFS_TEMPORAL_FD_CACHE\n  u32_t i;\n  u16_t min_score = 0xffff;\n  u32_t cand_ix = (u32_t)-1;\n  u32_t name_hash = name ? spiffs_hash(fs, (const u8_t *)name) : 0;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n\n  if (name) {\n    // first, decrease score of all closed descriptors\n    for (i = 0; i < fs->fd_count; i++) {\n      spiffs_fd *cur_fd = &fds[i];\n      if (cur_fd->file_nbr == 0) {\n        if (cur_fd->score > 1) { // score == 0 indicates never used fd\n          cur_fd->score--;\n        }\n      }\n    }\n  }\n\n  // find the free fd with least score\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->file_nbr == 0) {\n      if (name && cur_fd->name_hash == name_hash) {\n        cand_ix = i;\n        break;\n      }\n      if (cur_fd->score < min_score) {\n        min_score = cur_fd->score;\n        cand_ix = i;\n      }\n    }\n  }\n\n  if (cand_ix != (u32_t)-1) {\n    spiffs_fd *cur_fd = &fds[cand_ix];\n    if (name) {\n      if (cur_fd->name_hash == name_hash && cur_fd->score > 0) {\n        // opened an fd with same name hash, assume same file\n        // set search point to saved obj index page and hope we have a correct match directly\n        // when start searching - if not, we will just keep searching until it is found\n        fs->cursor_block_ix = SPIFFS_BLOCK_FOR_PAGE(fs, cur_fd->objix_hdr_pix);\n        fs->cursor_obj_lu_entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, cur_fd->objix_hdr_pix);\n        // update score\n        if (cur_fd->score < 0xffff-SPIFFS_TEMPORAL_CACHE_HIT_SCORE) {\n          cur_fd->score += SPIFFS_TEMPORAL_CACHE_HIT_SCORE;\n        } else {\n          cur_fd->score = 0xffff;\n        }\n      } else {\n        // no hash hit, restore this fd to initial state\n        cur_fd->score = SPIFFS_TEMPORAL_CACHE_HIT_SCORE;\n        cur_fd->name_hash = name_hash;\n      }\n    }\n    cur_fd->file_nbr = cand_ix+1;\n    *fd = cur_fd;\n    return SPIFFS_OK;\n  } else {\n    return SPIFFS_ERR_OUT_OF_FILE_DESCS;\n  }\n#else\n  (void)name;\n  u32_t i;\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->file_nbr == 0) {\n      cur_fd->file_nbr = i+1;\n      *fd = cur_fd;\n      return SPIFFS_OK;\n    }\n  }\n  return SPIFFS_ERR_OUT_OF_FILE_DESCS;\n#endif\n}\n\ns32_t spiffs_fd_return(spiffs *fs, spiffs_file f) {\n  if (f <= 0 || f > (s16_t)fs->fd_count) {\n    return SPIFFS_ERR_BAD_DESCRIPTOR;\n  }\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  spiffs_fd *fd = &fds[f-1];\n  if (fd->file_nbr == 0) {\n    return SPIFFS_ERR_FILE_CLOSED;\n  }\n  fd->file_nbr = 0;\n#if SPIFFS_IX_MAP\n  fd->ix_map = 0;\n#endif\n  return SPIFFS_OK;\n}\n\ns32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) {\n  if (f <= 0 || f > (s16_t)fs->fd_count) {\n    return SPIFFS_ERR_BAD_DESCRIPTOR;\n  }\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  *fd = &fds[f-1];\n  if ((*fd)->file_nbr == 0) {\n    return SPIFFS_ERR_FILE_CLOSED;\n  }\n  return SPIFFS_OK;\n}\n\n#if SPIFFS_TEMPORAL_FD_CACHE\nvoid spiffs_fd_temporal_cache_rehash(\n    spiffs *fs,\n    const char *old_path,\n    const char *new_path) {\n  u32_t i;\n  u32_t old_hash = spiffs_hash(fs, (const u8_t *)old_path);\n  u32_t new_hash = spiffs_hash(fs, (const u8_t *)new_path);\n  spiffs_fd *fds = (spiffs_fd *)fs->fd_space;\n  for (i = 0; i < fs->fd_count; i++) {\n    spiffs_fd *cur_fd = &fds[i];\n    if (cur_fd->score > 0 && cur_fd->name_hash == old_hash) {\n      cur_fd->name_hash = new_hash;\n    }\n  }\n}\n#endif\n"
  },
  {
    "path": "components/spiffs/spiffs_nucleus.h",
    "content": "/*\n * spiffs_nucleus.h\n *\n *  Created on: Jun 15, 2013\n *      Author: petera\n */\n\n/* SPIFFS layout\n *\n * spiffs is designed for following spi flash characteristics:\n *   - only big areas of data (blocks) can be erased\n *   - erasing resets all bits in a block to ones\n *   - writing pulls ones to zeroes\n *   - zeroes cannot be pulled to ones, without erase\n *   - wear leveling\n *\n * spiffs is also meant to be run on embedded, memory constraint devices.\n *\n * Entire area is divided in blocks. Entire area is also divided in pages.\n * Each block contains same number of pages. A page cannot be erased, but a\n * block can be erased.\n *\n * Entire area must be block_size * x\n * page_size must be block_size / (2^y) where y > 2\n *\n * ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes\n *\n * BLOCK 0  PAGE 0       object lookup 1\n *          PAGE 1       object lookup 2\n *          ...\n *          PAGE n-1     object lookup n\n *          PAGE n       object data 1\n *          PAGE n+1     object data 2\n *          ...\n *          PAGE n+m-1   object data m\n *\n * BLOCK 1  PAGE n+m     object lookup 1\n *          PAGE n+m+1   object lookup 2\n *          ...\n *          PAGE 2n+m-1  object lookup n\n *          PAGE 2n+m    object data 1\n *          PAGE 2n+m    object data 2\n *          ...\n *          PAGE 2n+2m-1 object data m\n * ...\n *\n * n is number of object lookup pages, which is number of pages needed to index all pages\n * in a block by object id\n *   : block_size / page_size * sizeof(obj_id) / page_size\n * m is number data pages, which is number of pages in block minus number of lookup pages\n *   : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size\n * thus, n+m is total number of pages in a block\n *   : block_size / page_size\n *\n * ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256\n *\n * Object lookup pages contain object id entries. Each entry represent the corresponding\n * data page.\n * Assuming a 16 bit object id, an object id being 0xffff represents a free page.\n * An object id being 0x0000 represents a deleted page.\n *\n * ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..\n *     page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..\n *     page 2 : data   : data for object id 0008\n *     page 3 : data   : data for object id 0001\n *     page 4 : data   : data for object id 0aaa\n *     ...\n *\n *\n * Object data pages can be either object index pages or object content.\n * All object data pages contains a data page header, containing object id and span index.\n * The span index denotes the object page ordering amongst data pages with same object id.\n * This applies to both object index pages (when index spans more than one page of entries),\n * and object data pages.\n * An object index page contains page entries pointing to object content page. The entry index\n * in a object index page correlates to the span index in the actual object data page.\n * The first object index page (span index 0) is called object index header page, and also\n * contains object flags (directory/file), size, object name etc.\n *\n * ex:\n *  BLOCK 1\n *    PAGE 256: objectl lookup page 1\n *      [*123] [ 123] [ 123] [ 123]\n *      [ 123] [*123] [ 123] [ 123]\n *      [free] [free] [free] [free] ...\n *    PAGE 257: objectl lookup page 2\n *      [free] [free] [free] [free] ...\n *    PAGE 258: object index page (header)\n *      obj.id:0123 span.ix:0000 flags:INDEX\n *      size:1600 name:ex.txt type:file\n *      [259] [260] [261] [262]\n *    PAGE 259: object data page\n *      obj.id:0123 span.ix:0000 flags:DATA\n *    PAGE 260: object data page\n *      obj.id:0123 span.ix:0001 flags:DATA\n *    PAGE 261: object data page\n *      obj.id:0123 span.ix:0002 flags:DATA\n *    PAGE 262: object data page\n *      obj.id:0123 span.ix:0003 flags:DATA\n *    PAGE 263: object index page\n *      obj.id:0123 span.ix:0001 flags:INDEX\n *      [264] [265] [fre] [fre]\n *      [fre] [fre] [fre] [fre]\n *    PAGE 264: object data page\n *      obj.id:0123 span.ix:0004 flags:DATA\n *    PAGE 265: object data page\n *      obj.id:0123 span.ix:0005 flags:DATA\n *\n */\n#ifndef SPIFFS_NUCLEUS_H_\n#define SPIFFS_NUCLEUS_H_\n\n#define _SPIFFS_ERR_CHECK_FIRST         (SPIFFS_ERR_INTERNAL - 1)\n#define SPIFFS_ERR_CHECK_OBJ_ID_MISM    (SPIFFS_ERR_INTERNAL - 1)\n#define SPIFFS_ERR_CHECK_SPIX_MISM      (SPIFFS_ERR_INTERNAL - 2)\n#define SPIFFS_ERR_CHECK_FLAGS_BAD      (SPIFFS_ERR_INTERNAL - 3)\n#define _SPIFFS_ERR_CHECK_LAST          (SPIFFS_ERR_INTERNAL - 4)\n\n// visitor result, continue searching\n#define SPIFFS_VIS_COUNTINUE            (SPIFFS_ERR_INTERNAL - 20)\n// visitor result, continue searching after reloading lu buffer\n#define SPIFFS_VIS_COUNTINUE_RELOAD     (SPIFFS_ERR_INTERNAL - 21)\n// visitor result, stop searching\n#define SPIFFS_VIS_END                  (SPIFFS_ERR_INTERNAL - 22)\n\n// updating an object index contents\n#define SPIFFS_EV_IX_UPD                (0)\n// creating a new object index\n#define SPIFFS_EV_IX_NEW                (1)\n// deleting an object index\n#define SPIFFS_EV_IX_DEL                (2)\n// moving an object index without updating contents\n#define SPIFFS_EV_IX_MOV                (3)\n// updating an object index header data only, not the table itself\n#define SPIFFS_EV_IX_UPD_HDR            (4)\n\n#define SPIFFS_OBJ_ID_IX_FLAG           ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))\n\n#define SPIFFS_UNDEFINED_LEN            (u32_t)(-1)\n\n#define SPIFFS_OBJ_ID_DELETED           ((spiffs_obj_id)0)\n#define SPIFFS_OBJ_ID_FREE              ((spiffs_obj_id)-1)\n\n#if SPIFFS_USE_MAGIC\n#if !SPIFFS_USE_MAGIC_LENGTH\n#define SPIFFS_MAGIC(fs, bix)           \\\n  ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))\n#else // SPIFFS_USE_MAGIC_LENGTH\n#define SPIFFS_MAGIC(fs, bix)           \\\n  ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))\n#endif // SPIFFS_USE_MAGIC_LENGTH\n#endif // SPIFFS_USE_MAGIC\n\n#define SPIFFS_CONFIG_MAGIC             (0x20090315)\n\n#if SPIFFS_SINGLETON == 0\n#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \\\n  ((fs)->cfg.log_page_size)\n#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \\\n  ((fs)->cfg.log_block_size)\n#define SPIFFS_CFG_PHYS_SZ(fs) \\\n  ((fs)->cfg.phys_size)\n#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \\\n  ((fs)->cfg.phys_erase_block)\n#define SPIFFS_CFG_PHYS_ADDR(fs) \\\n  ((fs)->cfg.phys_addr)\n#endif\n\n// total number of pages\n#define SPIFFS_MAX_PAGES(fs) \\\n  ( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// total number of pages per block, including object lookup pages\n#define SPIFFS_PAGES_PER_BLOCK(fs) \\\n  ( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// number of object lookup pages per block\n#define SPIFFS_OBJ_LOOKUP_PAGES(fs)     \\\n  (MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )\n// checks if page index belongs to object lookup\n#define SPIFFS_IS_LOOKUP_PAGE(fs,pix)     \\\n  (((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))\n// number of object lookup entries in all object lookup pages\n#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \\\n  (SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))\n// converts a block to physical address\n#define SPIFFS_BLOCK_TO_PADDR(fs, block) \\\n  ( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )\n// converts a object lookup entry to page index\n#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \\\n  ((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))\n// converts a object lookup entry to physical address of corresponding page\n#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \\\n  (SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// converts a page to physical address\n#define SPIFFS_PAGE_TO_PADDR(fs, page) \\\n  ( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// converts a physical address to page\n#define SPIFFS_PADDR_TO_PAGE(fs, addr) \\\n  ( ((addr) -  SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// gives index in page for a physical address\n#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \\\n  ( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )\n// returns containing block for given page\n#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \\\n  ( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )\n// returns starting page for block\n#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \\\n  ( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )\n// converts page to entry in object lookup page\n#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \\\n  ( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )\n// returns data size in a data page\n#define SPIFFS_DATA_PAGE_SIZE(fs) \\\n    ( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )\n// returns physical address for block's erase count,\n// always in the physical last entry of the last object lookup page\n#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \\\n  ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )\n// returns physical address for block's magic,\n// always in the physical second last entry of the last object lookup page\n#define SPIFFS_MAGIC_PADDR(fs, bix) \\\n  ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )\n// checks if there is any room for magic in the object luts\n#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \\\n  ( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \\\n    <= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )\n\n// define helpers object\n\n// entries in an object header page index\n#define SPIFFS_OBJ_HDR_IX_LEN(fs) \\\n  ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))\n// entries in an object page index\n#define SPIFFS_OBJ_IX_LEN(fs) \\\n  ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))\n// object index entry for given data span index\n#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \\\n  ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))\n// object index span index number for given data span index or entry\n#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \\\n  ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))\n// get data span index for object index span index\n#define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \\\n  ( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )\n\n#define SPIFFS_OP_T_OBJ_LU    (0<<0)\n#define SPIFFS_OP_T_OBJ_LU2   (1<<0)\n#define SPIFFS_OP_T_OBJ_IX    (2<<0)\n#define SPIFFS_OP_T_OBJ_DA    (3<<0)\n#define SPIFFS_OP_C_DELE      (0<<2)\n#define SPIFFS_OP_C_UPDT      (1<<2)\n#define SPIFFS_OP_C_MOVS      (2<<2)\n#define SPIFFS_OP_C_MOVD      (3<<2)\n#define SPIFFS_OP_C_FLSH      (4<<2)\n#define SPIFFS_OP_C_READ      (5<<2)\n#define SPIFFS_OP_C_WRTHRU    (6<<2)\n\n#define SPIFFS_OP_TYPE_MASK (3<<0)\n#define SPIFFS_OP_COM_MASK  (7<<2)\n\n\n// if 0, this page is written to, else clean\n#define SPIFFS_PH_FLAG_USED   (1<<0)\n// if 0, writing is finalized, else under modification\n#define SPIFFS_PH_FLAG_FINAL  (1<<1)\n// if 0, this is an index page, else a data page\n#define SPIFFS_PH_FLAG_INDEX  (1<<2)\n// if 0, page is deleted, else valid\n#define SPIFFS_PH_FLAG_DELET  (1<<7)\n// if 0, this index header is being deleted\n#define SPIFFS_PH_FLAG_IXDELE (1<<6)\n\n\n#define SPIFFS_CHECK_MOUNT(fs) \\\n  ((fs)->mounted != 0)\n\n#define SPIFFS_CHECK_CFG(fs) \\\n  ((fs)->config_magic == SPIFFS_CONFIG_MAGIC)\n\n#define SPIFFS_CHECK_RES(res) \\\n  do { \\\n    if ((res) < SPIFFS_OK) return (res); \\\n  } while (0);\n\n#define SPIFFS_API_CHECK_MOUNT(fs) \\\n  if (!SPIFFS_CHECK_MOUNT((fs))) { \\\n    (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \\\n    return SPIFFS_ERR_NOT_MOUNTED; \\\n  }\n\n#define SPIFFS_API_CHECK_CFG(fs) \\\n  if (!SPIFFS_CHECK_CFG((fs))) { \\\n    (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \\\n    return SPIFFS_ERR_NOT_CONFIGURED; \\\n  }\n\n#define SPIFFS_API_CHECK_RES(fs, res) \\\n  if ((res) < SPIFFS_OK) { \\\n    (fs)->err_code = (res); \\\n    return (res); \\\n  }\n\n#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \\\n  if ((res) < SPIFFS_OK) { \\\n    (fs)->err_code = (res); \\\n    SPIFFS_UNLOCK(fs); \\\n    return (res); \\\n  }\n\n#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \\\n    if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \\\n    if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \\\n    if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;\n    //if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;\n\n#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \\\n    if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \\\n    if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \\\n    if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \\\n    if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;\n\n\n// check id, only visit matching objec ids\n#define SPIFFS_VIS_CHECK_ID     (1<<0)\n// report argument object id to visitor - else object lookup id is reported\n#define SPIFFS_VIS_CHECK_PH     (1<<1)\n// stop searching at end of all look up pages\n#define SPIFFS_VIS_NO_WRAP      (1<<2)\n\n#if SPIFFS_HAL_CALLBACK_EXTRA\n\n#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \\\n  (_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))\n#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \\\n  (_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))\n#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \\\n  (_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))\n\n#else // SPIFFS_HAL_CALLBACK_EXTRA\n\n#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \\\n  (_fs)->cfg.hal_write_f((_paddr), (_len), (_src))\n#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \\\n  (_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))\n#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \\\n  (_fs)->cfg.hal_erase_f((_paddr), (_len))\n\n#endif // SPIFFS_HAL_CALLBACK_EXTRA\n\n#if SPIFFS_CACHE\n\n#define SPIFFS_CACHE_FLAG_DIRTY       (1<<0)\n#define SPIFFS_CACHE_FLAG_WRTHRU      (1<<1)\n#define SPIFFS_CACHE_FLAG_OBJLU       (1<<2)\n#define SPIFFS_CACHE_FLAG_OBJIX       (1<<3)\n#define SPIFFS_CACHE_FLAG_DATA        (1<<4)\n#define SPIFFS_CACHE_FLAG_TYPE_WR     (1<<7)\n\n#define SPIFFS_CACHE_PAGE_SIZE(fs) \\\n  (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))\n\n#define spiffs_get_cache(fs) \\\n  ((spiffs_cache *)((fs)->cache))\n\n#define spiffs_get_cache_page_hdr(fs, c, ix) \\\n  ((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))\n\n#define spiffs_get_cache_page(fs, c, ix) \\\n  ((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))\n\n// cache page struct\ntypedef struct {\n  // cache flags\n  u8_t flags;\n  // cache page index\n  u8_t ix;\n  // last access of this cache page\n  u32_t last_access;\n  union {\n    // type read cache\n    struct {\n      // read cache page index\n      spiffs_page_ix pix;\n    };\n#if SPIFFS_CACHE_WR\n    // type write cache\n    struct {\n      // write cache\n      spiffs_obj_id obj_id;\n      // offset in cache page\n      u32_t offset;\n      // size of cache page\n      u16_t size;\n    };\n#endif\n  };\n} spiffs_cache_page;\n\n// cache struct\ntypedef struct {\n  u8_t cpage_count;\n  u32_t last_access;\n  u32_t cpage_use_map;\n  u32_t cpage_use_mask;\n  u8_t *cpages;\n} spiffs_cache;\n\n#endif\n\n\n// spiffs nucleus file descriptor\ntypedef struct {\n  // the filesystem of this descriptor\n  spiffs *fs;\n  // number of file descriptor - if 0, the file descriptor is closed\n  spiffs_file file_nbr;\n  // object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted\n  spiffs_obj_id obj_id;\n  // size of the file\n  u32_t size;\n  // cached object index header page index\n  spiffs_page_ix objix_hdr_pix;\n  // cached offset object index page index\n  spiffs_page_ix cursor_objix_pix;\n  // cached offset object index span index\n  spiffs_span_ix cursor_objix_spix;\n  // current absolute offset\n  u32_t offset;\n  // current file descriptor offset\n  u32_t fdoffset;\n  // fd flags\n  spiffs_flags flags;\n#if SPIFFS_CACHE_WR\n  spiffs_cache_page *cache_page;\n#endif\n#if SPIFFS_TEMPORAL_FD_CACHE\n  // djb2 hash of filename\n  u32_t name_hash;\n  // hit score (score == 0 indicates never used fd)\n  u16_t score;\n#endif\n#if SPIFFS_IX_MAP\n  // spiffs index map, if 0 it means unmapped\n  spiffs_ix_map *ix_map;\n#endif\n} spiffs_fd;\n\n\n// object structs\n\n// page header, part of each page except object lookup pages\n// NB: this is always aligned when the data page is an object index,\n// as in this case struct spiffs_page_object_ix is used\ntypedef struct __attribute(( packed )) {\n  // object id\n  spiffs_obj_id obj_id;\n  // object span index\n  spiffs_span_ix span_ix;\n  // flags\n  u8_t flags;\n} spiffs_page_header;\n\n// object index header page header\ntypedef struct __attribute(( packed ))\n#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES\n                __attribute(( aligned(sizeof(spiffs_page_ix)) ))\n#endif\n{\n  // common page header\n  spiffs_page_header p_hdr;\n  // alignment\n  u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];\n  // size of object\n  u32_t size;\n  // type of object\n  spiffs_obj_type type;\n  // name of object\n  u8_t name[SPIFFS_OBJ_NAME_LEN];\n#if SPIFFS_OBJ_META_LEN\n  // metadata. not interpreted by SPIFFS in any way.\n  u8_t meta[SPIFFS_OBJ_META_LEN];\n#endif\n} spiffs_page_object_ix_header;\n\n// object index page header\ntypedef struct __attribute(( packed )) {\n spiffs_page_header p_hdr;\n u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];\n} spiffs_page_object_ix;\n\n// callback func for object lookup visitor\ntypedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,\n    const void *user_const_p, void *user_var_p);\n\n\n#if SPIFFS_CACHE\n#define _spiffs_rd(fs, op, fh, addr, len, dst) \\\n    spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))\n#define _spiffs_wr(fs, op, fh, addr, len, src) \\\n    spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))\n#else\n#define _spiffs_rd(fs, op, fh, addr, len, dst) \\\n    spiffs_phys_rd((fs), (addr), (len), (dst))\n#define _spiffs_wr(fs, op, fh, addr, len, src) \\\n    spiffs_phys_wr((fs), (addr), (len), (src))\n#endif\n\n#ifndef MIN\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#endif\n#ifndef MAX\n#define MAX(a,b) ((a) > (b) ? (a) : (b))\n#endif\n\n// ---------------\n\ns32_t spiffs_phys_rd(\n    spiffs *fs,\n#if SPIFFS_CACHE\n    u8_t op,\n    spiffs_file fh,\n#endif\n    u32_t addr,\n    u32_t len,\n    u8_t *dst);\n\ns32_t spiffs_phys_wr(\n    spiffs *fs,\n#if SPIFFS_CACHE\n    u8_t op,\n    spiffs_file fh,\n#endif\n    u32_t addr,\n    u32_t len,\n    u8_t *src);\n\ns32_t spiffs_phys_cpy(\n    spiffs *fs,\n    spiffs_file fh,\n    u32_t dst,\n    u32_t src,\n    u32_t len);\n\ns32_t spiffs_phys_count_free_blocks(\n    spiffs *fs);\n\ns32_t spiffs_obj_lu_find_entry_visitor(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    u8_t flags,\n    spiffs_obj_id obj_id,\n    spiffs_visitor_f v,\n    const void *user_const_p,\n    void *user_var_p,\n    spiffs_block_ix *block_ix,\n    int *lu_entry);\n\ns32_t spiffs_erase_block(\n    spiffs *fs,\n    spiffs_block_ix bix);\n\n#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH\ns32_t spiffs_probe(\n    spiffs_config *cfg);\n#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH\n\n// ---------------\n\ns32_t spiffs_obj_lu_scan(\n    spiffs *fs);\n\ns32_t spiffs_obj_lu_find_free_obj_id(\n    spiffs *fs,\n    spiffs_obj_id *obj_id,\n    const u8_t *conflicting_name);\n\ns32_t spiffs_obj_lu_find_free(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    spiffs_block_ix *block_ix,\n    int *lu_entry);\n\ns32_t spiffs_obj_lu_find_id(\n    spiffs *fs,\n    spiffs_block_ix starting_block,\n    int starting_lu_entry,\n    spiffs_obj_id obj_id,\n    spiffs_block_ix *block_ix,\n    int *lu_entry);\n\ns32_t spiffs_obj_lu_find_id_and_span(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix exclusion_pix,\n    spiffs_page_ix *pix);\n\ns32_t spiffs_obj_lu_find_id_and_span_by_phdr(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix exclusion_pix,\n    spiffs_page_ix *pix);\n\n// ---------------\n\ns32_t spiffs_page_allocate_data(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_page_header *ph,\n    u8_t *data,\n    u32_t len,\n    u32_t page_offs,\n    u8_t finalize,\n    spiffs_page_ix *pix);\n\ns32_t spiffs_page_move(\n    spiffs *fs,\n    spiffs_file fh,\n    u8_t *page_data,\n    spiffs_obj_id obj_id,\n    spiffs_page_header *page_hdr,\n    spiffs_page_ix src_pix,\n    spiffs_page_ix *dst_pix);\n\ns32_t spiffs_page_delete(\n    spiffs *fs,\n    spiffs_page_ix pix);\n\n// ---------------\n\ns32_t spiffs_object_create(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    const u8_t name[],\n    const u8_t meta[],\n    spiffs_obj_type type,\n    spiffs_page_ix *objix_hdr_pix);\n\ns32_t spiffs_object_update_index_hdr(\n    spiffs *fs,\n    spiffs_fd *fd,\n    spiffs_obj_id obj_id,\n    spiffs_page_ix objix_hdr_pix,\n    u8_t *new_objix_hdr_data,\n    const u8_t name[],\n    const u8_t meta[],\n    u32_t size,\n    spiffs_page_ix *new_pix);\n\n#if SPIFFS_IX_MAP\n\ns32_t spiffs_populate_ix_map(\n    spiffs *fs,\n    spiffs_fd *fd,\n    u32_t vec_entry_start,\n    u32_t vec_entry_end);\n\n#endif\n\nvoid spiffs_cb_object_event(\n    spiffs *fs,\n    spiffs_page_object_ix *objix,\n    int ev,\n    spiffs_obj_id obj_id,\n    spiffs_span_ix spix,\n    spiffs_page_ix new_pix,\n    u32_t new_size);\n\ns32_t spiffs_object_open_by_id(\n    spiffs *fs,\n    spiffs_obj_id obj_id,\n    spiffs_fd *f,\n    spiffs_flags flags,\n    spiffs_mode mode);\n\ns32_t spiffs_object_open_by_page(\n    spiffs *fs,\n    spiffs_page_ix pix,\n    spiffs_fd *f,\n    spiffs_flags flags,\n    spiffs_mode mode);\n\ns32_t spiffs_object_append(\n    spiffs_fd *fd,\n    u32_t offset,\n    u8_t *data,\n    u32_t len);\n\ns32_t spiffs_object_modify(\n    spiffs_fd *fd,\n    u32_t offset,\n    u8_t *data,\n    u32_t len);\n\ns32_t spiffs_object_read(\n    spiffs_fd *fd,\n    u32_t offset,\n    u32_t len,\n    u8_t *dst);\n\ns32_t spiffs_object_truncate(\n    spiffs_fd *fd,\n    u32_t new_len,\n    u8_t remove_object);\n\ns32_t spiffs_object_find_object_index_header_by_name(\n    spiffs *fs,\n    const u8_t name[SPIFFS_OBJ_NAME_LEN],\n    spiffs_page_ix *pix);\n\n// ---------------\n\ns32_t spiffs_gc_check(\n    spiffs *fs,\n    u32_t len);\n\ns32_t spiffs_gc_erase_page_stats(\n    spiffs *fs,\n    spiffs_block_ix bix);\n\ns32_t spiffs_gc_find_candidate(\n    spiffs *fs,\n    spiffs_block_ix **block_candidate,\n    int *candidate_count,\n    char fs_crammed);\n\ns32_t spiffs_gc_clean(\n    spiffs *fs,\n    spiffs_block_ix bix);\n\ns32_t spiffs_gc_quick(\n    spiffs *fs, u16_t max_free_pages);\n\n// ---------------\n\ns32_t spiffs_fd_find_new(\n    spiffs *fs,\n    spiffs_fd **fd,\n    const char *name);\n\ns32_t spiffs_fd_return(\n    spiffs *fs,\n    spiffs_file f);\n\ns32_t spiffs_fd_get(\n    spiffs *fs,\n    spiffs_file f,\n    spiffs_fd **fd);\n\n#if SPIFFS_TEMPORAL_FD_CACHE\nvoid spiffs_fd_temporal_cache_rehash(\n    spiffs *fs,\n    const char *old_path,\n    const char *new_path);\n#endif\n\n#if SPIFFS_CACHE\nvoid spiffs_cache_init(\n    spiffs *fs);\n\nvoid spiffs_cache_drop_page(\n    spiffs *fs,\n    spiffs_page_ix pix);\n\n#if SPIFFS_CACHE_WR\nspiffs_cache_page *spiffs_cache_page_allocate_by_fd(\n    spiffs *fs,\n    spiffs_fd *fd);\n\nvoid spiffs_cache_fd_release(\n    spiffs *fs,\n    spiffs_cache_page *cp);\n\nspiffs_cache_page *spiffs_cache_page_get_by_fd(\n    spiffs *fs,\n    spiffs_fd *fd);\n#endif\n#endif\n\ns32_t spiffs_lookup_consistency_check(\n    spiffs *fs,\n    u8_t check_all_objects);\n\ns32_t spiffs_page_consistency_check(\n    spiffs *fs);\n\ns32_t spiffs_object_index_consistency_check(\n    spiffs *fs);\n\n#endif /* SPIFFS_NUCLEUS_H_ */\n"
  },
  {
    "path": "components/spiffs/spiffs_vfs.c",
    "content": "/*\n * spiffs VFS operations\n *\n * Author: LoBo (loboris@gmail.com / https://github.com/loboris)\n *\n * Part of this code is copied from or inspired by LUA-RTOS_ESP32 project:\n *\n * https://github.com/whitecatboard/Lua-RTOS-ESP32\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n *\n */\n\n\n#include <freertos/FreeRTOS.h>\n\n#include <string.h>\n#include <stdio.h>\n#include <limits.h>\n#include \"esp_log.h\"\n\n#include <sys/stat.h>\n\n#include \"esp_vfs.h\"\n#include \"esp_attr.h\"\n#include <errno.h>\n\n#include <spiffs_vfs.h>\n#include <spiffs.h>\n#include <esp_spiffs.h>\n#include <spiffs_nucleus.h>\n#include \"list.h\"\n#include <sys/fcntl.h>\n#include <sys/dirent.h>\n#include \"sdkconfig.h\"\n\n\n#ifdef PATH_MAX\n#undef PATH_MAX\n#endif\n#define PATH_MAX MAXNAMLEN+8\n\n#define SPIFFS_ERASE_SIZE 4096\n\nint spiffs_is_registered = 0;\nint spiffs_is_mounted = 0;\n\nQueueHandle_t spiffs_mutex = NULL;\n\nstatic int IRAM_ATTR vfs_spiffs_open(const char *path, int flags, int mode);\nstatic ssize_t IRAM_ATTR vfs_spiffs_write(int fd, const void *data, size_t size);\nstatic ssize_t IRAM_ATTR vfs_spiffs_read(int fd, void * dst, size_t size);\nstatic int IRAM_ATTR vfs_spiffs_fstat(int fd, struct stat * st);\nstatic int IRAM_ATTR vfs_spiffs_close(int fd);\nstatic off_t IRAM_ATTR vfs_spiffs_lseek(int fd, off_t size, int mode);\n\ntypedef struct {\n\tDIR dir;\n\tspiffs_DIR spiffs_dir;\n\tchar path[MAXNAMLEN + 1];\n\tstruct dirent ent;\n\tuint8_t read_mount;\n} vfs_spiffs_dir_t;\n\ntypedef struct {\n\tspiffs_file spiffs_file;\n\tchar path[MAXNAMLEN + 1];\n\tuint8_t is_dir;\n} vfs_spiffs_file_t;\n\ntypedef struct {\n\ttime_t mtime;\n\ttime_t ctime;\n\ttime_t atime;\n\tuint8_t spare[SPIFFS_OBJ_META_LEN - (sizeof(time_t)*3)];\n} spiffs_metadata_t;\n\nstatic spiffs fs;\nstatic struct list files;\n\nstatic u8_t *my_spiffs_work_buf;\nstatic u8_t *my_spiffs_fds;\nstatic u8_t *my_spiffs_cache;\n\n\n/*\n * ########################################\n * file names/paths passed to the functions\n * do not contain '/spiffs' prefix\n * ########################################\n */\n\n//----------------------------------------------------\nvoid spiffs_fs_stat(uint32_t *total, uint32_t *used) {\n\tif (SPIFFS_info(&fs, total, used) != SPIFFS_OK) {\n\t\t*total = 0;\n\t\t*used = 0;\n\t}\n}\n\n/*\n * Test if path corresponds to a directory. Return 0 if is not a directory,\n * 1 if it's a directory.\n *\n */\n//-----------------------------------\nstatic int is_dir(const char *path) {\n    spiffs_DIR d;\n    char npath[PATH_MAX + 1];\n    int res = 0;\n\n    struct spiffs_dirent e;\n\n    // Add /. to path\n    strlcpy(npath, path, PATH_MAX);\n    if (strcmp(path,\"/\") != 0) {\n        strlcat(npath,\"/.\", PATH_MAX);\n    } else {\n    \tstrlcat(npath,\".\", PATH_MAX);\n    }\n\n    SPIFFS_opendir(&fs, \"/\", &d);\n    while (SPIFFS_readdir(&d, &e)) {\n        if (strncmp(npath, (const char *)e.name, strlen(npath)) == 0) {\n            res = 1;\n            break;\n        }\n    }\n\n    SPIFFS_closedir(&d);\n\n    return res;\n}\n\n/*\n * This function translate error codes from SPIFFS to errno error codes\n *\n */\n//-------------------------------\nstatic int spiffs_result(int res) {\n    switch (res) {\n        case SPIFFS_OK:\n        case SPIFFS_ERR_END_OF_OBJECT:\n            return 0;\n\n        case SPIFFS_ERR_NOT_FOUND:\n        case SPIFFS_ERR_CONFLICTING_NAME:\n            return ENOENT;\n\n        case SPIFFS_ERR_NOT_WRITABLE:\n        case SPIFFS_ERR_NOT_READABLE:\n            return EACCES;\n\n        case SPIFFS_ERR_FILE_EXISTS:\n            return EEXIST;\n\n        default:\n            return res;\n    }\n}\n\n//-----------------------------------------------------------------------------------------------------\nstatic int IRAM_ATTR vfs_spiffs_getstat(spiffs_file fd, spiffs_stat *st, spiffs_metadata_t *metadata) {\n    int res = SPIFFS_fstat(&fs, fd, st);\n    if (res == SPIFFS_OK) {\n        // Get file's time information from metadata\n        memcpy(metadata, st->meta, sizeof(spiffs_metadata_t));\n\t}\n    return res;\n}\n\n// ## path does not contain '/spiffs' prefix !\n//---------------------------------------------------------------------------\nstatic int IRAM_ATTR vfs_spiffs_open(const char *path, int flags, int mode) {\n\tint fd, result = 0, exists = 0;\n\tspiffs_stat stat;\n\tspiffs_metadata_t meta;\n\n\t// Allocate new file\n\tvfs_spiffs_file_t *file = calloc(1, sizeof(vfs_spiffs_file_t));\n\tif (!file) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\n    // Add file to file list. List index is file descriptor.\n    int res = list_add(&files, file, &fd);\n    if (res) {\n    \tfree(file);\n    \terrno = res;\n    \treturn -1;\n    }\n\n    // Check if file exists\n    if (SPIFFS_stat(&fs, path, &stat) == SPIFFS_OK) exists = 1;\n\n    // Make a copy of path\n\tstrlcpy(file->path, path, MAXNAMLEN);\n\n    // Open file\n    spiffs_flags spiffs_mode = 0;\n\n    // Translate flags to SPIFFS flags\n    if (flags == O_RDONLY)\n    \tspiffs_mode |= SPIFFS_RDONLY;\n\n    if (flags & O_WRONLY)\n    \tspiffs_mode |= SPIFFS_WRONLY;\n\n    if (flags & O_RDWR)\n    \tspiffs_mode = SPIFFS_RDWR;\n\n    if (flags & O_EXCL)\n    \tspiffs_mode |= SPIFFS_EXCL;\n\n    if (flags & O_CREAT)\n    \tspiffs_mode |= SPIFFS_CREAT;\n\n    if (flags & O_TRUNC)\n    \tspiffs_mode |= SPIFFS_TRUNC;\n\n    if (is_dir(path)) {\n        char npath[PATH_MAX + 1];\n\n        // Add /. to path\n        strlcpy(npath, path, PATH_MAX);\n        if (strcmp(path,\"/\") != 0) {\n            strlcat(npath,\"/.\", PATH_MAX);\n        } else {\n        \tstrlcat(npath,\".\", PATH_MAX);\n        }\n\n        // Open SPIFFS file\n        file->spiffs_file = SPIFFS_open(&fs, npath, spiffs_mode, 0);\n        if (file->spiffs_file < 0) {\n            result = spiffs_result(fs.err_code);\n        }\n\n    \tfile->is_dir = 1;\n    } else {\n        // Open SPIFFS file\n        file->spiffs_file = SPIFFS_open(&fs, path, spiffs_mode, 0);\n        if (file->spiffs_file < 0) {\n            result = spiffs_result(fs.err_code);\n        }\n    }\n\n    if (result != 0) {\n    \tlist_remove(&files, fd, 1);\n    \terrno = result;\n    \treturn -1;\n    }\n\n    res = vfs_spiffs_getstat(file->spiffs_file, &stat, &meta);\n\tif (res == SPIFFS_OK) {\n\t\t// update file's time information\n\t\tmeta.atime = time(NULL); // Get the system time to access time\n\t\tif (!exists) meta.ctime = meta.atime;\n\t\tif (spiffs_mode != SPIFFS_RDONLY) meta.mtime = meta.atime;\n\t\tSPIFFS_fupdate_meta(&fs, file->spiffs_file, &meta);\n\t}\n\n    return fd;\n}\n\n//--------------------------------------------------------------------------------\nstatic ssize_t IRAM_ATTR vfs_spiffs_write(int fd, const void *data, size_t size) {\n\tvfs_spiffs_file_t *file;\n\tint res;\n\n    res = list_get(&files, fd, (void **)&file);\n    if (res) {\n\t\terrno = EBADF;\n\t\treturn -1;\n    }\n\n    if (file->is_dir) {\n\t\terrno = EBADF;\n\t\treturn -1;\n    }\n\n    // Write SPIFFS file\n\tres = SPIFFS_write(&fs, file->spiffs_file, (void *)data, size);\n\tif (res >= 0) {\n\t\treturn res;\n\t} else {\n\t\tres = spiffs_result(fs.err_code);\n\t\tif (res != 0) {\n\t\t\terrno = res;\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n//-------------------------------------------------------------------------\nstatic ssize_t IRAM_ATTR vfs_spiffs_read(int fd, void * dst, size_t size) {\n\tvfs_spiffs_file_t *file;\n\tint res;\n\n    res = list_get(&files, fd, (void **)&file);\n    if (res) {\n\t\terrno = EBADF;\n\t\treturn -1;\n    }\n\n    if (file->is_dir) {\n\t\terrno = EBADF;\n\t\treturn -1;\n    }\n\n    // Read SPIFFS file\n\tres = SPIFFS_read(&fs, file->spiffs_file, dst, size);\n\tif (res >= 0) {\n\t\treturn res;\n\t} else {\n\t\tres = spiffs_result(fs.err_code);\n\t\tif (res != 0) {\n\t\t\terrno = res;\n\t\t\treturn -1;\n\t\t}\n\n\t\t// EOF\n\t\treturn 0;\n\t}\n\n\treturn -1;\n}\n\n//---------------------------------------------------------------\nstatic int IRAM_ATTR vfs_spiffs_fstat(int fd, struct stat * st) {\n\tvfs_spiffs_file_t *file;\n    spiffs_stat stat;\n\tint res;\n\tspiffs_metadata_t meta;\n\n    res = list_get(&files, fd, (void **)&file);\n    if (res) {\n\t\terrno = EBADF;\n\t\treturn -1;\n    }\n\n    // Set block size for this file system\n    st->st_blksize = CONFIG_SPIFFS_LOG_PAGE_SIZE;\n\n    // Get file/directory statistics\n    res = vfs_spiffs_getstat(file->spiffs_file, &stat, &meta);\n    if (res == SPIFFS_OK) {\n        // Set file's time information from metadata\n        st->st_mtime = meta.mtime;\n        st->st_ctime = meta.ctime;\n        st->st_atime = meta.atime;\n\n    \tst->st_size = stat.size;\n\n\t} else {\n        st->st_mtime = 0;\n        st->st_ctime = 0;\n        st->st_atime = 0;\n\t\tst->st_size = 0;\n\t    errno = spiffs_result(fs.err_code);\n\t\t//printf(\"SPIFFS_STAT: error %d\\r\\n\", res);\n    \treturn -1;\n    }\n\n    // Test if it's a directory entry\n    if (file->is_dir) st->st_mode = S_IFDIR;\n    else st->st_mode = S_IFREG;\n\n    return 0;\n}\n\n//---------------------------------------------\nstatic int IRAM_ATTR vfs_spiffs_close(int fd) {\n\tvfs_spiffs_file_t *file;\n\tint res;\n\n    res = list_get(&files, fd, (void **)&file);\n    if (res) {\n\t\terrno = EBADF;\n\t\treturn -1;\n    }\n\n\tres = SPIFFS_close(&fs, file->spiffs_file);\n\tif (res) {\n\t\tres = spiffs_result(fs.err_code);\n\t}\n\n\tif (res < 0) {\n\t\terrno = res;\n\t\treturn -1;\n\t}\n\n\tlist_remove(&files, fd, 1);\n\n\treturn 0;\n}\n\n//---------------------------------------------------------------------\nstatic off_t IRAM_ATTR vfs_spiffs_lseek(int fd, off_t size, int mode) {\n\tvfs_spiffs_file_t *file;\n\tint res;\n\n    res = list_get(&files, fd, (void **)&file);\n    if (res) {\n\t\terrno = EBADF;\n\t\treturn -1;\n    }\n\n    if (file->is_dir) {\n\t\terrno = EBADF;\n\t\treturn -1;\n    }\n\n\tint whence = SPIFFS_SEEK_CUR;\n\n    switch (mode) {\n        case SEEK_SET: whence = SPIFFS_SEEK_SET;break;\n        case SEEK_CUR: whence = SPIFFS_SEEK_CUR;break;\n        case SEEK_END: whence = SPIFFS_SEEK_END;break;\n    }\n\n    res = SPIFFS_lseek(&fs, file->spiffs_file, size, whence);\n    if (res < 0) {\n        res = spiffs_result(fs.err_code);\n        errno = res;\n        return -1;\n    }\n\n    return res;\n}\n\n//-------------------------------------------------------------------------\nstatic int IRAM_ATTR vfs_spiffs_stat(const char * path, struct stat * st) {\n\tint fd;\n\tint res;\n\tfd = vfs_spiffs_open(path, 0, 0);\n\tres = vfs_spiffs_fstat(fd, st);\n\tvfs_spiffs_close(fd);\n\n\treturn res;\n}\n\n//--------------------------------------------------------\nstatic int IRAM_ATTR vfs_spiffs_unlink(const char *path) {\n    char npath[PATH_MAX + 1];\n\n    strlcpy(npath, path, PATH_MAX);\n\n    if (is_dir(path)) {\n        // Check if  directory is empty\n    \tint nument = 0;\n    \tsprintf(npath, \"/spiffs\");\n    \tstrlcat(npath, path, PATH_MAX);\n\n    \tDIR *dir = opendir(npath);\n        if (dir) {\n            struct dirent *ent;\n\t\t\t// Read directory entries\n\t\t\twhile ((ent = readdir(dir)) != NULL) {\n\t\t\t\tnument++;\n\t\t\t}\n        }\n        else {\n        \terrno = ENOTEMPTY;\n        \treturn -1;\n        }\n        closedir(dir);\n\n        if (nument > 0) {\n        \t// Directory not empty, cannot remove\n        \terrno = ENOTEMPTY;\n        \treturn -1;\n        }\n\n        strlcpy(npath, path, PATH_MAX);\n    \t// Add /. to path\n\t    if (strcmp(path,\"/\") != 0) {\n\t        strlcat(npath,\"/.\", PATH_MAX);\n\t    }\n\t}\n\n    // Open SPIFFS file\n\tspiffs_file FP = SPIFFS_open(&fs, npath, SPIFFS_RDWR, 0);\n    if (FP < 0) {\n    \terrno = spiffs_result(fs.err_code);\n    \treturn -1;\n    }\n\n    // Remove SPIFSS file\n    if (SPIFFS_fremove(&fs, FP) < 0) {\n        errno = spiffs_result(fs.err_code);\n    \tSPIFFS_close(&fs, FP);\n    \treturn -1;\n    }\n\n\tSPIFFS_close(&fs, FP);\n\n\treturn 0;\n}\n\n//------------------------------------------------------------------------\nstatic int IRAM_ATTR vfs_spiffs_rename(const char *src, const char *dst) {\n    if (SPIFFS_rename(&fs, src, dst) < 0) {\n    \terrno = spiffs_result(fs.err_code);\n    \treturn -1;\n    }\n\n    return 0;\n}\n\n//------------------------------------------------\nstatic DIR* vfs_spiffs_opendir(const char* name) {\n\tstruct stat st;\n\n    if (strcmp(name, \"/\") != 0) {\n    \t// Not on root\n    \tif (vfs_spiffs_stat(name, &st)) {\n    \t\t// Not found\n    \t\terrno = ENOENT;\n    \t\treturn NULL;\n        }\n    \tif (!S_ISDIR(st.st_mode)) {\n    \t\t// Not a directory\n    \t\terrno = ENOTDIR;\n    \t\treturn NULL;\n        }\n    }\n\n\tvfs_spiffs_dir_t *dir = calloc(1, sizeof(vfs_spiffs_dir_t));\n\n\tif (!dir) {\n\t\terrno = ENOMEM;\n\t\treturn NULL;\n\t}\n\n\tif (!SPIFFS_opendir(&fs, name, &dir->spiffs_dir)) {\n        free(dir);\n        errno = spiffs_result(fs.err_code);\n        return NULL;\n    }\n\n\tstrlcpy(dir->path, name, MAXNAMLEN);\n\n\treturn (DIR *)dir;\n}\n\n//---------------------------------------------------\nstatic struct dirent* vfs_spiffs_readdir(DIR* pdir) {\n    int res = 0, len = 0, entries = 0;\n\tvfs_spiffs_dir_t* dir = (vfs_spiffs_dir_t*) pdir;\n\n\tstruct spiffs_dirent e;\n    struct spiffs_dirent *pe = &e;\n\n    struct dirent *ent = &dir->ent;\n\n    char *fn;\n\n    // Clear current dirent\n    memset(ent,0,sizeof(struct dirent));\n\n    // If this is the first call to readdir for pdir, and\n    // directory is the root path, return the mounted point if any\n    if (!dir->read_mount) {\n    \tif (strcmp(dir->path,\"/\") == 0) {\n\t\t\tstrlcpy(ent->d_name, \"/spiffs\", PATH_MAX);\n\t\t\tent->d_type = DT_DIR;\n\t\t\tdir->read_mount = 1;\n\n\t\t\treturn ent;\n    \t}\n\n    \tdir->read_mount = 1;\n    }\n\n    // Search for next entry\n    for(;;) {\n        // Read directory\n        pe = SPIFFS_readdir(&dir->spiffs_dir, pe);\n        if (!pe) {\n            res = spiffs_result(fs.err_code);\n            errno = res;\n            break;\n        }\n\n        // Break condition\n        if (pe->name[0] == 0) break;\n\n        // Get name and length\n        fn = (char *)pe->name;\n        len = strlen(fn);\n\n        // Get entry type and size\n        ent->d_type = DT_REG;\n\n        if (len >= 2) {\n            if (fn[len - 1] == '.') {\n                if (fn[len - 2] == '/') {\n                    ent->d_type = DT_DIR;\n\n                    fn[len - 2] = '\\0';\n\n                    len = strlen(fn);\n\n                    // Skip root dir\n                    if (len == 0) {\n                        continue;\n                    }\n                }\n            }\n        }\n\n        // Skip entries not belonged to path\n        if (strncmp(fn, dir->path, strlen(dir->path)) != 0) {\n            continue;\n        }\n\n        if (strlen(dir->path) > 1) {\n            if (*(fn + strlen(dir->path)) != '/') {\n                continue;\n            }\n        }\n\n        // Skip root directory\n        fn = fn + strlen(dir->path);\n        len = strlen(fn);\n        if (len == 0) {\n            continue;\n        }\n\n        // Skip initial /\n        if (len > 1) {\n            if (*fn == '/') {\n                fn = fn + 1;\n                len--;\n            }\n        }\n\n        // Skip subdirectories\n        if (strchr(fn,'/')) {\n            continue;\n        }\n\n        //ent->d_fsize = pe->size;\n\n        strlcpy(ent->d_name, fn, MAXNAMLEN);\n\n        entries++;\n\n        break;\n    }\n\n    if (entries > 0) {\n    \treturn ent;\n    } else {\n    \treturn NULL;\n    }\n}\n\n//--------------------------------------------------\nstatic int IRAM_ATTR vfs_piffs_closedir(DIR* pdir) {\n\tvfs_spiffs_dir_t* dir = (vfs_spiffs_dir_t*) pdir;\n\tint res;\n\n\tif (!pdir) {\n\t\terrno = EBADF;\n\t\treturn -1;\n\t}\n\n\tif ((res = SPIFFS_closedir(&dir->spiffs_dir)) < 0) {\n\t\terrno = spiffs_result(fs.err_code);;\n\t\treturn -1;\n\t}\n\n\tfree(dir);\n\n    return 0;\n}\n\n//--------------------------------------------------------------------\nstatic int IRAM_ATTR vfs_spiffs_mkdir(const char *path, mode_t mode) {\n    char npath[PATH_MAX + 1];\n    int res;\n\n    // Add /. to path\n    strlcpy(npath, path, PATH_MAX);\n    if ((strcmp(path,\"/\") != 0) && (strcmp(path,\"/.\") != 0)) {\n        strlcat(npath,\"/.\", PATH_MAX);\n    }\n\n    spiffs_file fd = SPIFFS_open(&fs, npath, SPIFFS_CREAT, 0);\n    if (fd < 0) {\n        res = spiffs_result(fs.err_code);\n        errno = res;\n        return -1;\n    }\n\n    if (SPIFFS_close(&fs, fd) < 0) {\n        res = spiffs_result(fs.err_code);\n        errno = res;\n        return -1;\n    }\n\n\tspiffs_metadata_t meta;\n\tmeta.atime = time(NULL); // Get the system time to access time\n\tmeta.ctime = meta.atime;\n\tmeta.mtime = meta.atime;\n\tSPIFFS_update_meta(&fs, npath, &meta);\n\n    return 0;\n}\n\n\nstatic const char tag[] = \"[SPIFFS]\";\n\n//==================\nint spiffs_mount() {\n\n\tif (!spiffs_is_registered) return 0;\n\tif (spiffs_is_mounted) return 1;\n\n\tspiffs_config cfg;\n    int res = 0;\n    int retries = 0;\n    int err = 0;\n\n    ESP_LOGI(tag, \"Mounting SPIFFS files system\");\n\n    cfg.phys_addr \t\t = CONFIG_SPIFFS_BASE_ADDR;\n    cfg.phys_size \t\t = CONFIG_SPIFFS_SIZE;\n    cfg.phys_erase_block = SPIFFS_ERASE_SIZE;\n    cfg.log_page_size    = CONFIG_SPIFFS_LOG_PAGE_SIZE;\n    cfg.log_block_size   = CONFIG_SPIFFS_LOG_BLOCK_SIZE;\n\n\tcfg.hal_read_f  = (spiffs_read)low_spiffs_read;\n\tcfg.hal_write_f = (spiffs_write)low_spiffs_write;\n\tcfg.hal_erase_f = (spiffs_erase)low_spiffs_erase;\n\n    my_spiffs_work_buf = malloc(cfg.log_page_size * 8);\n    if (!my_spiffs_work_buf) {\n    \terr = 1;\n    \tgoto err_exit;\n    }\n\n    int fds_len = sizeof(spiffs_fd) * SPIFFS_TEMPORAL_CACHE_HIT_SCORE;\n    my_spiffs_fds = malloc(fds_len);\n    if (!my_spiffs_fds) {\n        free(my_spiffs_work_buf);\n    \terr = 2;\n    \tgoto err_exit;\n    }\n\n    int cache_len = cfg.log_page_size * SPIFFS_TEMPORAL_CACHE_HIT_SCORE;\n    my_spiffs_cache = malloc(cache_len);\n    if (!my_spiffs_cache) {\n        free(my_spiffs_work_buf);\n        free(my_spiffs_fds);\n    \terr = 3;\n    \tgoto err_exit;\n    }\n\n    ESP_LOGI(tag, \"Start address: 0x%x; Size %d KB\", cfg.phys_addr, cfg.phys_size / 1024);\n    ESP_LOGI(tag, \"  Work buffer: %d B\", cfg.log_page_size * 8);\n    ESP_LOGI(tag, \"   FDS buffer: %d B\", sizeof(spiffs_fd) * SPIFFS_TEMPORAL_CACHE_HIT_SCORE);\n    ESP_LOGI(tag, \"   Cache size: %d B\", cfg.log_page_size * SPIFFS_TEMPORAL_CACHE_HIT_SCORE);\n    while (retries < 2) {\n\t\tres = SPIFFS_mount(\n\t\t\t\t&fs, &cfg, my_spiffs_work_buf, my_spiffs_fds,\n\t\t\t\tfds_len, my_spiffs_cache, cache_len, NULL\n\t\t);\n\n\t\tif (res < 0) {\n\t\t\tif (fs.err_code == SPIFFS_ERR_NOT_A_FS) {\n\t\t\t\tESP_LOGW(tag, \"No file system detected, formating...\");\n\t\t\t\tSPIFFS_unmount(&fs);\n\t\t\t\tres = SPIFFS_format(&fs);\n\t\t\t\tif (res < 0) {\n\t\t\t        free(my_spiffs_work_buf);\n\t\t\t        free(my_spiffs_fds);\n\t\t\t        free(my_spiffs_cache);\n\t\t\t\t\tESP_LOGE(tag, \"Format error\");\n\t\t\t\t\tgoto exit;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t        free(my_spiffs_work_buf);\n\t\t        free(my_spiffs_fds);\n\t\t        free(my_spiffs_cache);\n\t\t\t\tESP_LOGE(tag, \"Error mounting fs (%d)\", res);\n\t\t\t\tgoto exit;\n\t\t\t}\n\t\t}\n\t\telse break;\n\t\tretries++;\n    }\n\n    if (retries > 1) {\n        free(my_spiffs_work_buf);\n        free(my_spiffs_fds);\n        free(my_spiffs_cache);\n\t\tESP_LOGE(tag, \"Can't mount\");\n\t\tgoto exit;\n    }\n\n    list_init(&files, 0);\n\n    ESP_LOGI(tag, \"Mounted\");\n\n    spiffs_is_mounted = 1;\n    return 1;\n\nerr_exit:\n\tESP_LOGE(tag, \"Error allocating fs structures (%d)\", err);\nexit:\n\tesp_vfs_unregister(\"/spiffs\");\n\tspiffs_is_registered = 0;\n\treturn 0;\n}\n\n//==========================\nvoid vfs_spiffs_register() {\n\n\tif (spiffs_is_registered) return;\n\n\tif (spiffs_mutex == NULL) {\n\t\tspiffs_mutex = xSemaphoreCreateMutex();\n\t\tif (spiffs_mutex == NULL) {\n            ESP_LOGE(tag, \"Error creating SPIFFS mutex\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\tesp_vfs_t vfs = {\n        //.fd_offset = 0, // not available in latest esp-idf\n        .flags = ESP_VFS_FLAG_DEFAULT,\n        .write = &vfs_spiffs_write,\n        .open = &vfs_spiffs_open,\n        .fstat = &vfs_spiffs_fstat,\n        .close = &vfs_spiffs_close,\n        .read = &vfs_spiffs_read,\n        .lseek = &vfs_spiffs_lseek,\n        .stat = &vfs_spiffs_stat,\n        .link = NULL,\n        .unlink = &vfs_spiffs_unlink,\n        .rename = &vfs_spiffs_rename,\n\t\t.mkdir = &vfs_spiffs_mkdir,\n\t\t.opendir = &vfs_spiffs_opendir,\n\t\t.readdir = &vfs_spiffs_readdir,\n\t\t.closedir = &vfs_piffs_closedir,\n    };\n\n    ESP_LOGI(tag, \"Registering SPIFFS file system\");\n    esp_err_t res = esp_vfs_register(SPIFFS_BASE_PATH, &vfs, NULL);\n    if (res != ESP_OK) {\n        ESP_LOGE(tag, \"Error, SPIFFS file system not registered\");\n        return;\n    }\n\tspiffs_is_registered = 1;\n\n\tspiffs_mount();\n}\n\n//=============================\nint spiffs_unmount(int unreg) {\n\n\tif (!spiffs_is_mounted) return 0;\n\n\tSPIFFS_unmount(&fs);\n    spiffs_is_mounted = 0;\n\n    if (unreg) {\n    \tesp_vfs_unregister(\"/spiffs\");\n    \tspiffs_is_registered = 0;\n    }\n\treturn 1;\n}\n"
  },
  {
    "path": "components/spiffs/spiffs_vfs.h",
    "content": "/*\n * spiffs VFS public function\n *\n * Author: LoBo (loboris@gmail.com / https://github.com/loboris)\n *\n * Part of this code is copied from or inspired by LUA-RTOS_ESP32 project:\n *\n * https://github.com/whitecatboard/Lua-RTOS-ESP32\n * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.\n * Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)\n *\n */\n\n#define SPIFFS_BASE_PATH \"/spiffs\"\n\n\nint spiffs_is_registered;\nint spiffs_is_mounted;\n\nvoid vfs_spiffs_register();\nint spiffs_mount();\nint spiffs_unmount(int unreg);\nvoid spiffs_fs_stat(uint32_t *total, uint32_t *used);\n"
  },
  {
    "path": "components/spiffs_image/Makefile.projbuild",
    "content": "SPIFFS_IMAGE_COMPONENT_PATH := $(COMPONENT_PATH)\nifeq ($(OS),Windows_NT)\n\tMKSPIFFS_BIN=\"mkspiffs.exe\"\nelse\n\tMKSPIFFS_BIN=\"mkspiffs\"\nendif\n\n.PHONY: flashfs\n.PHONY: makefs\n.PHONY: copyfs\n\nflashfs: $(SDKCONFIG_MAKEFILE) mkspiffs\n\t@echo \"Making spiffs image ...\"\n\t@echo \"$(ESPTOOLPY_WRITE_FLASH)\"\n\t$(MKSPIFFS_COMPONENT_PATH)/../mkspiffs/src/$(MKSPIFFS_BIN) -c $(SPIFFS_IMAGE_COMPONENT_PATH)/image -b $(CONFIG_SPIFFS_LOG_BLOCK_SIZE) -p $(CONFIG_SPIFFS_LOG_PAGE_SIZE) -s $(CONFIG_SPIFFS_SIZE) $(BUILD_DIR_BASE)/spiffs_image.img\n\t$(ESPTOOLPY_WRITE_FLASH) $(CONFIG_SPIFFS_BASE_ADDR) $(BUILD_DIR_BASE)/spiffs_image.img\n\nmakefs: $(SDKCONFIG_MAKEFILE) mkspiffs\n\t@echo \"Making spiffs image ...\"\n\t@echo \"$(ESPTOOLPY_WRITE_FLASH)\"\n\t$(MKSPIFFS_COMPONENT_PATH)/../mkspiffs/src/$(MKSPIFFS_BIN) -c $(SPIFFS_IMAGE_COMPONENT_PATH)/image -b $(CONFIG_SPIFFS_LOG_BLOCK_SIZE) -p $(CONFIG_SPIFFS_LOG_PAGE_SIZE) -s $(CONFIG_SPIFFS_SIZE) $(BUILD_DIR_BASE)/spiffs_image.img\n\ncopyfs: \n\t@echo \"Flashing spiffs image ...\"\n\t@echo \"$(ESPTOOLPY_WRITE_FLASH)\"\n\t$(ESPTOOLPY_WRITE_FLASH) $(CONFIG_SPIFFS_BASE_ADDR) $(SPIFFS_IMAGE_COMPONENT_PATH)/spiffs_image.img\n"
  },
  {
    "path": "components/spiffs_image/component.mk",
    "content": "#\n# Component Makefile\n#\n\nCOMPONENT_SRCDIRS := \nCOMPONENT_ADD_INCLUDEDIRS := \n"
  },
  {
    "path": "components/spiffs_image/image/fonts/ocrfont.c",
    "content": "// OCR_A_Extended_M.c\r\n// Font type    : Full (95 characters)\r\n// Font size    : 16x24 pixels\r\n// Memory usage : 4564 bytes\r\n\r\n#if defined(__AVR__)\r\n\t#include <avr/pgmspace.h>\r\n\t#define fontdatatype const uint8_t\r\n#elif defined(__PIC32MX__)\r\n\t#define PROGMEM\r\n\t#define fontdatatype const unsigned char\r\n#elif defined(__arm__)\r\n\t#define PROGMEM\r\n\t#define fontdatatype const unsigned char\r\n#endif\r\n\r\nfontdatatype OCR_A_Extended_M[4564] PROGMEM={\r\n0x10,0x18,0x20,0x5F,\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // <space>\r\n0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // !\r\n0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x1E,0x78,0x1E,0x78,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // \"\r\n0x00,0x00,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x1F,0xF8,0x1F,0xF8,0x06,0x60,0x06,0x60,0x06,0x60,0x1F,0xF8,0x1F,0xF8,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // #\r\n0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0xF8,0x1F,0xF8,0x18,0x00,0x18,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x18,0x00,0x18,0x1F,0xF8,0x1F,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // $\r\n0x00,0x00,0x1C,0x00,0x1C,0x18,0x1C,0x18,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0xE0,0x00,0xC0,0x01,0x80,0x01,0x80,0x03,0x00,0x07,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x38,0x18,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // %\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xC0,0x0F,0xC0,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x0C,0xC0,0x07,0x80,0x07,0x00,0x0F,0x80,0x1D,0xC8,0x18,0xF8,0x18,0x70,0x18,0xF0,0x0F,0xD8,0x0F,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // &\r\n0x00,0x00,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // '\r\n0x00,0x00,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x80,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x80,0x01,0x80,0x00,0xC0,0x00,0x60,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // (\r\n0x00,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x01,0x80,0x01,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x01,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // )\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x19,0x88,0x19,0x98,0x0F,0xF0,0x07,0xE0,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x0F,0xF0,0x1D,0xB8,0x11,0x98,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // *\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0xF8,0x1F,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // +\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x07,0xE0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // ,\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // -\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // .\r\n0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x60,0x00,0xC0,0x00,0xC0,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // /\r\n\r\n0x00,0x00,0x0F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 0\r\n0x00,0x00,0x1F,0x80,0x1F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x98,0x01,0x98,0x01,0x98,0x01,0x98,0x01,0x98,0x01,0x98,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 1\r\n0x00,0x00,0x1F,0xF0,0x1F,0xF8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0F,0xF8,0x1F,0xF0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 2\r\n0x00,0x00,0x1F,0xF8,0x1F,0xFC,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x07,0xF8,0x07,0xF8,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x1F,0xFC,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 3\r\n0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x1F,0xF8,0x1F,0xF8,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 4\r\n0x00,0x00,0x07,0xF8,0x07,0xF8,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x07,0xF0,0x07,0xF8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x18,0x18,0x1F,0xF8,0x07,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 5\r\n0x00,0x00,0x1C,0x00,0x1C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 6\r\n0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 7\r\n0x00,0x00,0x07,0xE0,0x07,0xE0,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x0F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 8\r\n0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 9\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // :\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x07,0xE0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // ;\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x78,0x00,0xE0,0x01,0xC0,0x07,0x00,0x0E,0x00,0x1C,0x00,0x0E,0x00,0x07,0x00,0x01,0xC0,0x00,0xE0,0x00,0x78,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // <\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // =\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x1E,0x00,0x07,0x00,0x03,0x80,0x00,0xE0,0x00,0x70,0x00,0x38,0x00,0x70,0x00,0xE0,0x03,0x80,0x07,0x00,0x1E,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // >\r\n0x00,0x00,0x00,0x20,0x00,0x60,0x01,0xF0,0x03,0x98,0x07,0x18,0x0E,0x18,0x18,0x70,0x10,0xE0,0x01,0xC0,0x03,0x80,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // ?\r\n\r\n0x00,0x00,0x07,0xE0,0x0F,0xF0,0x18,0x18,0x18,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0F,0x98,0x0F,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // @\r\n0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x0C,0x30,0x0F,0xF0,0x0F,0xF0,0x0C,0x30,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // A\r\n0x00,0x00,0x1F,0xF0,0x1F,0xF8,0x18,0x1C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x1C,0x1F,0xF8,0x1F,0xF8,0x18,0x1C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x1C,0x1F,0xF8,0x1F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // B\r\n0x00,0x00,0x01,0xFC,0x03,0xFC,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1C,0x00,0x0C,0x00,0x0E,0x00,0x06,0x00,0x07,0x00,0x03,0xFC,0x01,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // C\r\n0x00,0x00,0x1F,0xC0,0x1F,0xE0,0x06,0x70,0x06,0x30,0x06,0x30,0x06,0x18,0x06,0x18,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x1C,0x06,0x18,0x06,0x38,0x06,0x30,0x06,0x70,0x1F,0xE0,0x1F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // D\r\n0x00,0x00,0x1F,0xFC,0x1F,0xFC,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xC0,0x1F,0xC0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xFC,0x1F,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // E\r\n0x00,0x00,0x1F,0xFC,0x1F,0xFC,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xF0,0x1F,0xF0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // F\r\n0x00,0x00,0x01,0xF8,0x03,0xF8,0x03,0x00,0x06,0x00,0x0E,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0F,0xF8,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // G\r\n0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // H\r\n0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // I\r\n0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x07,0xF0,0x03,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // J\r\n0x00,0x00,0x18,0x0C,0x18,0x18,0x18,0x30,0x18,0x60,0x18,0xC0,0x19,0x80,0x1B,0x00,0x1E,0x00,0x1C,0x00,0x1E,0x00,0x1F,0x00,0x1B,0x80,0x19,0xC0,0x18,0xE0,0x18,0x70,0x18,0x30,0x18,0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // K\r\n0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // L\r\n0x00,0x00,0x1C,0x38,0x1C,0x38,0x1E,0x78,0x1E,0xF8,0x1B,0xD8,0x19,0x98,0x19,0x98,0x19,0x98,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // M\r\n0x00,0x00,0x1C,0x18,0x1C,0x18,0x1E,0x18,0x1E,0x18,0x1E,0x18,0x1B,0x18,0x1B,0x18,0x1B,0x18,0x19,0x98,0x19,0x98,0x18,0xD8,0x18,0xD8,0x18,0xD8,0x18,0x78,0x18,0x78,0x18,0x78,0x18,0x38,0x18,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // N\r\n0x00,0x00,0x03,0xC0,0x03,0xC0,0x06,0x60,0x06,0x60,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x06,0x60,0x06,0x60,0x03,0xC0,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // O\r\n\r\n0x00,0x00,0x1F,0xF0,0x1F,0xF0,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF0,0x1F,0xF0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // P\r\n0x00,0x00,0x00,0x70,0x00,0xF8,0x01,0xD8,0x03,0x98,0x07,0x18,0x0C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x19,0x98,0x19,0x98,0x19,0xF0,0x18,0xE0,0x19,0xC0,0x1B,0xE0,0x1F,0x78,0x0E,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // Q\r\n0x00,0x00,0x1F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF0,0x19,0x80,0x19,0x80,0x18,0xC0,0x18,0xC0,0x18,0x60,0x18,0x60,0x18,0x30,0x18,0x30,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // R\r\n0x00,0x00,0x0F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x18,0x0C,0x00,0x06,0x00,0x06,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x00,0xC0,0x00,0x60,0x00,0x60,0x00,0x30,0x18,0x18,0x18,0x18,0x1F,0xF8,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // S\r\n0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x19,0x98,0x19,0x98,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // T\r\n0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // U\r\n0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x06,0x60,0x06,0x60,0x07,0xE0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // V\r\n0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // W\r\n0x00,0x00,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x06,0x60,0x06,0x60,0x03,0xC0,0x03,0xC0,0x01,0x80,0x01,0x80,0x03,0xC0,0x03,0xC0,0x06,0x60,0x06,0x60,0x0C,0x30,0x0C,0x30,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // X\r\n0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x30,0x0E,0x60,0x07,0xE0,0x03,0xC0,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // Y\r\n0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x60,0x00,0xC0,0x00,0xC0,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // Z\r\n0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // [\r\n0x00,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x06,0x00,0x07,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x00,0xC0,0x00,0xC0,0x00,0x60,0x00,0x70,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // <backslash>\r\n0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // ]\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x07,0xE0,0x0E,0x70,0x0E,0x70,0x1C,0x30,0x1C,0x38,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // ^\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,  // _\r\n\r\n0x00,0x00,0x06,0x00,0x07,0xC0,0x03,0xE0,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // `\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF0,0x07,0xF0,0x00,0x18,0x00,0x18,0x00,0x18,0x0F,0xF8,0x0F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x1F,0xF8,0x0F,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // a\r\n0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1B,0xE0,0x1F,0xF0,0x1E,0x38,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1C,0x18,0x1E,0x38,0x1F,0xF0,0x1B,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // b\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC,0x07,0xFC,0x0E,0x00,0x1C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1C,0x00,0x0E,0x00,0x07,0xFC,0x03,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // c\r\n0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x07,0xD8,0x0F,0xF8,0x1C,0x78,0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x1C,0x78,0x0F,0xF8,0x07,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // d\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x0F,0xF0,0x1C,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x18,0x00,0x18,0x00,0x1C,0x00,0x0F,0xF8,0x07,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // e\r\n0x00,0x00,0x00,0xFC,0x01,0xFC,0x03,0x80,0x03,0x00,0x03,0x00,0x0F,0xF0,0x0F,0xF0,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // f\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xD8,0x0F,0xF8,0x1C,0x78,0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x1C,0x78,0x0F,0xF8,0x07,0xD8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x38,0x0F,0xF0,0x0F,0xE0,  // g\r\n0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x19,0xF0,0x1B,0xF0,0x1F,0x18,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // h\r\n0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x0F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // i\r\n0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xF8,0x03,0xF8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0C,0x18,0x0C,0x18,0x07,0xF0,0x03,0xE0,  // j\r\n0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x30,0x18,0x60,0x18,0xC0,0x19,0x80,0x1B,0x80,0x1F,0x00,0x1E,0x00,0x1F,0x00,0x19,0x80,0x18,0xC0,0x18,0x60,0x18,0x30,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // k\r\n0x00,0x00,0x0F,0x80,0x0F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // l\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x78,0x3F,0xFC,0x39,0xCC,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // m\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0xF0,0x1B,0xF0,0x1F,0x18,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // n\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x0F,0xF0,0x1C,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1C,0x38,0x0F,0xF0,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // o\r\n\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1B,0xC0,0x1F,0xE0,0x1E,0x70,0x1C,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1C,0x38,0x1E,0x70,0x1F,0xE0,0x1B,0xC0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,  // p\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xD8,0x0F,0xF8,0x1C,0x78,0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x1C,0x78,0x0F,0xF8,0x07,0xD8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,  // q\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0xF0,0x1B,0xF8,0x1F,0x0C,0x1C,0x0C,0x18,0x0C,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // r\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x00,0x1E,0x00,0x07,0x80,0x01,0xF0,0x00,0x70,0x00,0x18,0x00,0x18,0x18,0x18,0x1F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // s\r\n0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x1F,0xF8,0x1F,0xF8,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x0C,0x06,0x1C,0x03,0xF8,0x01,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // t\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x18,0xF8,0x0F,0xD8,0x07,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // u\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x38,0x38,0x18,0x30,0x18,0x30,0x0C,0x60,0x0C,0x60,0x06,0xC0,0x06,0xC0,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // v\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x33,0xCC,0x1F,0xF8,0x1E,0x78,0x1C,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // w\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x1C,0x38,0x0C,0x30,0x06,0x60,0x03,0xC0,0x03,0xC0,0x01,0x80,0x03,0xC0,0x06,0xE0,0x0E,0x70,0x0C,0x30,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // x\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x38,0x38,0x18,0x30,0x18,0x30,0x0C,0x60,0x0C,0x60,0x06,0xC0,0x07,0xC0,0x07,0x80,0x01,0x80,0x03,0x80,0x03,0x00,0x03,0x00,0x3E,0x00,0x3E,0x00,  // y\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x38,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x1C,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // z\r\n0x00,0x00,0x00,0xF8,0x01,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0x00,0x1F,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // {\r\n0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // |\r\n0x00,0x00,0x1F,0x00,0x1F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0xF8,0x00,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // }\r\n0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x8C,0x1F,0xFC,0x18,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // ~\r\n};\r\n"
  },
  {
    "path": "components/spiffs_image/image/spiffs.info",
    "content": "INTRODUCTION\n\nSpiffs is a file system intended for SPI NOR flash devices on embedded targets.\nSpiffs is designed with following characteristics in mind:\n\n  * Small (embedded) targets, sparse RAM without heap\n  * Only big areas of data (blocks) can be erased\n  * An erase will reset all bits in block to ones\n  * Writing pulls one to zeroes\n  * Zeroes can only be pulled to ones by erase\n  * Wear leveling\n"
  },
  {
    "path": "main/Kconfig.projbuild",
    "content": "menu \"ePaper Display DEMO Configuration\"\n\nconfig SPIFFS_BASE_ADDR\n    hex \"SPIFFS Base address\"\n    range 0x100000 0x1FFE000\n    default 0x180000\n    help\n\tStarting address of the SPIFFS area in ESP32 Flash\n\tWrite the address in hex format, 0x180000\n\nconfig SPIFFS_SIZE\n    int \"SPIFFS Size in bytes\"\n    range 262144 2097152\n    default 1048576\n\nconfig SPIFFS_LOG_BLOCK_SIZE\n    int \"SPIFFS Logical block size\"\n    range 4098 65536\n    default 8192\n\nconfig SPIFFS_LOG_PAGE_SIZE\n    int \"SPIFFS Logical page size\"\n    range 256 2048\n    default 256\n    help\n\tSet it to the phisycal page size og the used SPI Flash chip.\n\nconfig EXAMPLE_USE_WIFI\n    bool \"Use wifi in TFT Demo\"\n    default n\n    help\n        If WiFi is used ntp server will be used to provide the exact time\n        and file timestamps will be correct.\nconfig WIFI_SSID\n    string \"WiFi SSID\"\n   \tdepends on EXAMPLE_USE_WIFI\n    default \"myssid\"\n    help\n\tSSID (network name) for the demo to connect to.\n\nconfig WIFI_PASSWORD\n    string \"WiFi Password\"\n   \tdepends on EXAMPLE_USE_WIFI\n    default \"mypassword\"\n    help\n\tWiFi password (WPA or WPA2) for the demo to use.\n\n\nendmenu\n"
  },
  {
    "path": "main/component.mk",
    "content": "#\n# Main Makefile. This is basically the same as a component makefile.\n#\n# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)\n\nCOMPONENT_SRCDIRS := . \nCOMPONENT_ADD_INCLUDEDIRS := .\n"
  },
  {
    "path": "main/ePaper.c",
    "content": "/* ePaper demo\n *\n *  Author: LoBo (loboris@gmail.com, loboris.github)\n*/\n\n#include <time.h>\n#include <errno.h>\n#include <sys/fcntl.h>\n#include <stdio.h>\n#include <time.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_system.h\"\n#include \"driver/gpio.h\"\n#include \"esp_system.h\"\n#include \"esp_heap_alloc_caps.h\"\n#include \"spiffs_vfs.h\"\n#include \"esp_log.h\"\n\n#ifdef CONFIG_EXAMPLE_USE_WIFI\n\n#include \"esp_wifi.h\"\n#include \"esp_system.h\"\n#include \"esp_event.h\"\n#include \"esp_event_loop.h\"\n#include \"freertos/event_groups.h\"\n#include \"esp_attr.h\"\n#include <sys/time.h>\n#include <unistd.h>\n#include \"lwip/err.h\"\n#include \"apps/sntp/sntp.h\"\n#include \"nvs_flash.h\"\n\n#endif\n\n\n#include \"spi_master_lobo.h\"\n#include \"img1.h\"\n#include \"img2.h\"\n#include \"img3.h\"\n#include \"img_hacking.c\"\n#include \"EPD.h\"\n//#include \"EPDspi.h\"\n\n#define DELAYTIME 1500\n\n\n\nstatic struct tm* tm_info;\nstatic char tmp_buff[128];\nstatic time_t time_now, time_last = 0;\nstatic const char *file_fonts[3] = {\"/spiffs/fonts/DotMatrix_M.fon\", \"/spiffs/fonts/Ubuntu.fon\", \"/spiffs/fonts/Grotesk24x48.fon\"};\nstatic const char tag[] = \"[Eink Demo]\";\n\n//==================================================================================\n#ifdef CONFIG_EXAMPLE_USE_WIFI\n\n\n/* FreeRTOS event group to signal when we are connected & ready to make a request */\nstatic EventGroupHandle_t wifi_event_group;\n\n/* The event group allows multiple bits for each event,\n   but we only care about one event - are we connected\n   to the AP with an IP? */\nconst int CONNECTED_BIT = 0x00000001;\n\n//------------------------------------------------------------\nstatic esp_err_t event_handler(void *ctx, system_event_t *event)\n{\n    switch(event->event_id) {\n    case SYSTEM_EVENT_STA_START:\n        esp_wifi_connect();\n        break;\n    case SYSTEM_EVENT_STA_GOT_IP:\n        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);\n        break;\n    case SYSTEM_EVENT_STA_DISCONNECTED:\n        /* This is a workaround as ESP32 WiFi libs don't currently\n           auto-reassociate. */\n        esp_wifi_connect();\n        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);\n        break;\n    default:\n        break;\n    }\n    return ESP_OK;\n}\n\n//-------------------------------\nstatic void initialise_wifi(void)\n{\n    tcpip_adapter_init();\n    wifi_event_group = xEventGroupCreate();\n    ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );\n    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );\n    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );\n    wifi_config_t wifi_config = {\n        .sta = {\n            .ssid = CONFIG_WIFI_SSID,\n            .password = CONFIG_WIFI_PASSWORD,\n        },\n    };\n    ESP_LOGI(tag, \"Setting WiFi configuration SSID %s...\", wifi_config.sta.ssid);\n    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );\n    ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );\n    ESP_ERROR_CHECK( esp_wifi_start() );\n}\n\n//-------------------------------\nstatic void initialize_sntp(void)\n{\n    ESP_LOGI(tag, \"Initializing SNTP\");\n    sntp_setoperatingmode(SNTP_OPMODE_POLL);\n    sntp_setservername(0, \"pool.ntp.org\");\n    sntp_init();\n}\n\n//--------------------------\nstatic int obtain_time(void)\n{\n\tint res = 1;\n    initialise_wifi();\n    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);\n\n    initialize_sntp();\n\n    // wait for time to be set\n    int retry = 0;\n    const int retry_count = 20;\n\n    time(&time_now);\n\ttm_info = localtime(&time_now);\n\n    while(tm_info->tm_year < (2016 - 1900) && ++retry < retry_count) {\n        //ESP_LOGI(tag, \"Waiting for system time to be set... (%d/%d)\", retry, retry_count);\n\t\tvTaskDelay(500 / portTICK_RATE_MS);\n        time(&time_now);\n    \ttm_info = localtime(&time_now);\n    }\n    if (tm_info->tm_year < (2016 - 1900)) {\n    \tESP_LOGI(tag, \"System time NOT set.\");\n    \tres = 0;\n    }\n    else {\n    \tESP_LOGI(tag, \"System time is set.\");\n    }\n\n    ESP_ERROR_CHECK( esp_wifi_stop() );\n    return res;\n}\n\n#endif  //CONFIG_EXAMPLE_USE_WIFI\n//==================================================================================\n\n\n//=============\nvoid app_main()\n{\n\n    // ========  PREPARE DISPLAY INITIALIZATION  =========\n\n    esp_err_t ret;\n\n\tdisp_buffer = pvPortMallocCaps(EPD_DISPLAY_WIDTH * (EPD_DISPLAY_HEIGHT/8), MALLOC_CAP_DMA);\n\tassert(disp_buffer);\n\tdrawBuff = disp_buffer;\n\n\tgs_disp_buffer = pvPortMallocCaps(EPD_DISPLAY_WIDTH * EPD_DISPLAY_HEIGHT, MALLOC_CAP_DMA);\n\tassert(gs_disp_buffer);\n\tgs_drawBuff = gs_disp_buffer;\n\n\t// ====  CONFIGURE SPI DEVICES(s)  ====================================================================================\n\n\tgpio_set_direction(DC_Pin, GPIO_MODE_OUTPUT);\n\tgpio_set_level(DC_Pin, 1);\n\tgpio_set_direction(RST_Pin, GPIO_MODE_OUTPUT);\n\tgpio_set_level(RST_Pin, 0);\n\tgpio_set_direction(BUSY_Pin, GPIO_MODE_INPUT);\n    gpio_set_pull_mode(BUSY_Pin, GPIO_PULLUP_ONLY);\n\n#if POWER_Pin\n\tgpio_set_direction(POWER_Pin, GPIO_MODE_OUTPUT);\n\tgpio_set_level(POWER_Pin, 1);\n#endif\n\n    spi_lobo_bus_config_t buscfg={\n        .miso_io_num = -1,\t\t\t\t// set SPI MISO pin\n        .mosi_io_num = MOSI_Pin,\t\t// set SPI MOSI pin\n        .sclk_io_num = SCK_Pin,\t\t\t// set SPI CLK pin\n        .quadwp_io_num=-1,\n        .quadhd_io_num=-1,\n\t\t.max_transfer_sz = 5*1024,\t\t// max transfer size is 4736 bytes\n    };\n    spi_lobo_device_interface_config_t devcfg={\n        .clock_speed_hz=40000000,\t\t// SPI clock is 40 MHz\n        .mode=0,\t\t\t\t\t\t// SPI mode 0\n        .spics_io_num=-1,\t\t\t\t// we will use external CS pin\n\t\t.spics_ext_io_num = CS_Pin,\t\t// external CS pin\n\t\t.flags=SPI_DEVICE_HALFDUPLEX,\t// ALWAYS SET  to HALF DUPLEX MODE for display spi !!\n    };\n\n    // ====================================================================================================================\n\n\n\tvTaskDelay(500 / portTICK_RATE_MS);\n\tprintf(\"\\r\\n=================================\\r\\n\");\n    printf(\"ePaper display DEMO, LoBo 06/2017\\r\\n\");\n\tprintf(\"=================================\\r\\n\\r\\n\");\n\n\t// ==================================================================\n\t// ==== Initialize the SPI bus and attach the EPD to the SPI bus ====\n\n\tret=spi_lobo_bus_add_device(SPI_BUS, &buscfg, &devcfg, &disp_spi);\n    assert(ret==ESP_OK);\n\tprintf(\"SPI: display device added to spi bus\\r\\n\");\n\n\t// ==== Test select/deselect ====\n\tret = spi_lobo_device_select(disp_spi, 1);\n    assert(ret==ESP_OK);\n\tret = spi_lobo_device_deselect(disp_spi);\n    assert(ret==ESP_OK);\n\n\tprintf(\"SPI: attached display device, speed=%u\\r\\n\", spi_lobo_get_speed(disp_spi));\n\tprintf(\"SPI: bus uses native pins: %s\\r\\n\", spi_lobo_uses_native_pins(disp_spi) ? \"true\" : \"false\");\n\n\tprintf(\"\\r\\n-------------------\\r\\n\");\n\tprintf(\"ePaper demo started\\r\\n\");\n\tprintf(\"-------------------\\r\\n\");\n\n\n\tEPD_DisplayClearFull();\n\n#ifdef CONFIG_EXAMPLE_USE_WIFI\n\n    ESP_ERROR_CHECK( nvs_flash_init() );\n\n    EPD_DisplayClearPart();\n\tEPD_fillScreen(_bg);\n\tEPD_setFont(DEFAULT_FONT, NULL);\n\tsprintf(tmp_buff, \"Waiting for NTP time...\");\n\tEPD_print(tmp_buff, CENTER, CENTER);\n\tEPD_drawRect(10,10,274,108, EPD_BLACK);\n\tEPD_drawRect(12,12,270,104, EPD_BLACK);\n\tEPD_UpdateScreen();\n\n\t// ===== Set time zone ======\n\tsetenv(\"TZ\", \"CET-1CEST\", 0);\n\ttzset();\n\t// ==========================\n\n    time(&time_now);\n\ttm_info = localtime(&time_now);\n\n\t// Is time set? If not, tm_year will be (1970 - 1900).\n    if (tm_info->tm_year < (2016 - 1900)) {\n        ESP_LOGI(tag, \"Time is not set yet. Connecting to WiFi and getting time over NTP.\");\n        if (obtain_time()) {\n        }\n        else {\n        }\n        time(&time_now);\n    }\n#endif\n\n    // ==== Initialize the file system ====\n    printf(\"\\r\\n\\n\");\n\tvfs_spiffs_register();\n    if (spiffs_is_mounted) {\n        ESP_LOGI(tag, \"File system mounted.\");\n    }\n    else {\n        ESP_LOGE(tag, \"Error mounting file system.\");\n    }\n\n\t//=========\n    // Run demo\n    //=========\n\n\t/*\n\tEPD_DisplayClearFull();\n    EPD_DisplayClearPart();\n\tEPD_fillScreen(_bg);\n\t//EPD_DisplaySetPart(0x00);\n\t//EPD_DisplaySetPart(0xFF);\n\n\n    uint8_t LUTTest1[31]\t= {0x32, 0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};\n    uint8_t LUTTest2[31]\t= {0x32, 0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};\n\t_gs = 0;\n\t_fg = 1;\n\t_bg = 0;\n\tint n = 0;\n\twhile (1) {\n\t\t//EPD_DisplayClearFull();\n\t\tEPD_fillRect(14, 14, 100, 100, ((n&1) ? 0 : 1));\n\t\tEPD_fillRect(_width/2+14, 14, 100, 100, ((n&1) ? 1 : 0));\n\t\t//LUT_part = LUTTest1;\n\t\tEPD_DisplayPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, disp_buffer);\n\t\t//EPD_wait(2000);\n\t\t//LUT_part = LUTTest2;\n\t\t//EPD_DisplayFull(disp_buffer);\n\t\tprintf(\"Updated\\r\\n\");\n\t\tEPD_wait(4000);\n\t\tn++;\n\n\n\t\tn = 0;\n\t\tprintf(\"\\r\\n==== FULL UPDATE TEST ====\\r\\n\\n\");\n\t\tEPD_DisplayClearFull();\n\t\twhile (n < 2) {\n\t\t\tEPD_fillScreen(_bg);\n\t\t\tprintf(\"Black\\r\\n\");\n\t\t\tEPD_fillRect(0,0,_width/2,_height-1, EPD_BLACK);\n\n\t\t\tEPD_fillRect(20,20,_width/2-40,_height-1-40, EPD_WHITE);\n\t\t\tEPD_DisplayFull(disp_buffer);\n\t\t\tEPD_wait(4000);\n\n\t\t\tprintf(\"White\\r\\n\");\n\t\t\tEPD_fillRect(0,0,_width/2,_height-1, EPD_WHITE);\n\t\t\tEPD_DisplayFull(disp_buffer);\n\t\t\tEPD_wait(2000);\n\t\t\tn++;\n\t\t}\n\n\t\tprintf(\"\\r\\n==== PARTIAL UPDATE TEST ====\\r\\n\\n\");\n\t\tEPD_DisplayClearFull();\n\t\tn = 0;\n\t\twhile (n < 2) {\n\t\t\tEPD_fillScreen(_bg);\n\t\t\tprintf(\"Black\\r\\n\");\n\t\t\tEPD_fillRect(0,0,_width/2,_height-1, EPD_BLACK);\n\n\t\t\tEPD_fillRect(20,20,_width/2-40,_height-1-40, EPD_WHITE);\n\t\t\tEPD_DisplayPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, disp_buffer);\n\t\t\tEPD_wait(4000);\n\n\t\t\tprintf(\"White\\r\\n\");\n\t\t\tEPD_fillRect(0,0,_width/2,_height-1, EPD_WHITE);\n\t\t\tEPD_DisplayPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, disp_buffer);\n\t\t\tEPD_wait(2000);\n\t\t\tn++;\n\t\t}\n\n\t\tprintf(\"\\r\\n==== PARTIAL UPDATE TEST - gray scale ====\\r\\n\\n\");\n\t\tEPD_DisplayClearFull();\n\t\tn = 0;\n\t\twhile (n < 3) {\n\t\t\tEPD_fillScreen(_bg);\n\t\t\tLUT_part = LUT_gs;\n\t\t\tfor (uint8_t sh=1; sh<16; sh++) {\n\t\t\t\tLUT_gs[21] = sh;\n\t\t\t\tprintf(\"Black (%d)\\r\\n\", LUT_gs[21]);\n\t\t\t\tEPD_fillRect((sh-1)*19,0,19,_height, EPD_BLACK);\n\t\t\t\tEPD_DisplayPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, disp_buffer);\n\t\t\t}\n\t\t\tEPD_wait(4000);\n\n\t\t\t//LUT_part = LUTDefault_part;\n\t\t\tprintf(\"White\\r\\n\");\n\t\t\t//EPD_DisplayPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, disp_buffer);\n\t\t\t//EPD_DisplaySetPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, 0xFF);\n\t\t\tLUT_gs[21] = 15;\n\t\t\tLUT_gs[1] = 0x28;\n\t\t\tEPD_fillRect(190,0,76,_height, EPD_WHITE);\n\t\t\tEPD_DisplayPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, disp_buffer);\n\t\t\tEPD_wait(2000);\n\n\t\t\tEPD_fillRect(0,0,_width,_height, EPD_WHITE);\n\t\t\tEPD_DisplayPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, disp_buffer);\n\t\t\tLUT_gs[1] = 0x18;\n\t\t\tEPD_wait(2000);\n\t\t\tn++;\n\t\t}\n\t\tLUT_part = LUTDefault_part;\n\t}\n*/\n\n\n\tprintf(\"==== START ====\\r\\n\\n\");\n\n\t_gs = 1;\n\tuint32_t tstart;\n\tint pass = 0, ftype = 9;\n    while (1) {\n    \tftype++;\n    \tif (ftype > 10) {\n    \t\tftype = 1;\n    \t\tfor (int t=40; t>0; t--) {\n\t\t\t\tprintf(\"Wait %d seconds ...  \\r\", t);\n\t\t\t\tfflush(stdout);\n\t\t\t\tEPD_wait(1000);\n    \t\t}\n\t\t\tprintf(\"                      \\r\");\n\t\t\tfflush(stdout);\n\t\t\t_gs ^= 1;\n    \t}\n    \tprintf(\"\\r\\n-- Test %d\\r\\n\", ftype);\n    \tEPD_DisplayClearPart();\n\n    \t//EPD_Cls(0);\n\t\tEPD_fillScreen(_bg);\n\t\t_fg = 15;\n\t\t_bg = 0;\n\n\t\tEPD_drawRect(1,1,294,126, EPD_BLACK);\n\n\t\tint y = 4;\n\t\ttstart = clock();\n\t\tif (ftype == 1) {\n\t\t\tfor (int f=0; f<4; f++) {\n\t\t\t\tif (f == 0) _fg = 15;\n\t\t\t\telse if (f == 1) _fg = 9;\n\t\t\t\telse if (f == 2) _fg = 5;\n\t\t\t\telse if (f == 2) _fg = 3;\n\t\t\t\tEPD_setFont(f, NULL);\n\t\t\t\tif (f == 3) {\n\t\t\t\t\tEPD_print(\"Welcome to \", 4, y);\n\t\t\t\t\tfont_rotate = 90;\n\t\t\t\t\tEPD_print(\"ESP32\", EPD_getStringWidth(\"Welcome to \")+EPD_getfontheight()+4, y);\n\t\t\t\t\tfont_rotate = 0;\n\t\t\t\t}\n\t\t\t\telse if (f == 1) {\n\t\t\t\t\tEPD_print(\"HR chars: \\xA6\\xA8\\xB4\\xB5\\xB0\", 4, y);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tEPD_print(\"Welcome to ESP32\", 4, y);\n\t\t\t\t}\n\t\t\t\ty += EPD_getfontheight() + 2;\n\t\t\t}\n\t\t\tfont_rotate = 45;\n\t\t\tEPD_print(\"ESP32\", LASTX+8, LASTY);\n\t\t\tfont_rotate = 0;\n\t\t\t_fg = 15;\n\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\tsprintf(tmp_buff, \"Pass: %d\", pass+1);\n\t\t\tEPD_print(tmp_buff, 4, 128-EPD_getfontheight()-2);\n\t\t\tEPD_UpdateScreen();\n\t\t}\n\t\telse if (ftype == 2) {\n\t\t\torientation = LANDSCAPE_180;\n\t\t\tfor (int f=4; f<FONT_7SEG; f++) {\n\t\t\t\tif (f == 4) _fg = 15;\n\t\t\t\telse if (f == 5) _fg = 9;\n\t\t\t\telse if (f == 6) _fg = 5;\n\t\t\t\telse if (f == 7) _fg = 3;\n\t\t\t\tEPD_setFont(f, NULL);\n\t\t\t\tEPD_print(\"Welcome to ESP32\", 4, y);\n\t\t\t\ty += EPD_getfontheight() + 1;\n\t\t\t}\n\t\t\t_fg = 15;\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\tsprintf(tmp_buff, \"Pass: %d (rotated 180)\", pass+1);\n\t\t\tEPD_print(tmp_buff, 4, 128-EPD_getfontheight()-2);\n\t\t\torientation = LANDSCAPE_0;\n\t\t\tEPD_UpdateScreen();\n\t\t}\n\t\telse if (ftype == 3) {\n\t\t\tfor (int f=0; f<3; f++) {\n\t\t\t\tif (f == 0) _fg = 15;\n\t\t\t\telse if (f == 1) _fg = 9;\n\t\t\t\telse if (f == 2) _fg = 5;\n\t\t\t\tEPD_setFont(USER_FONT, file_fonts[f]);\n\t\t\t\tif (f == 0) font_line_space = 4;\n\t\t\t\tEPD_print(\"Welcome to ESP32\", 4, y);\n\t\t\t\tfont_line_space = 0;\n\t\t\t\ty += EPD_getfontheight() + 2;\n\t\t\t}\n\t\t\t_fg = 15;\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\tsprintf(tmp_buff, \"Pass: %d (Fonts from file)\", pass+1);\n\t\t\tEPD_print(tmp_buff, 4, 128-EPD_getfontheight()-2);\n\t\t\tEPD_UpdateScreen();\n\t\t}\n\t\telse if (ftype == 4) {\n\t\t\ty = 16;\n\t\t\ttime(&time_now);\n\t\t\ttm_info = localtime(&time_now);\n\t\t\tint _sec = -1, y2, _day = -1;\n\n\t\t\tEPD_setFont(FONT_7SEG, NULL);\n\t\t\tset_7seg_font_atrib(10, 2, 0, 15);\n\t\t\ty2 = y + EPD_getfontheight() + 10;\n\n\t\t\tfor (int t=0; t<100; t++) {\n\t\t\t\ttime(&time_now);\n\t\t\t\ttm_info = localtime(&time_now);\n\t\t\t\tif (tm_info->tm_sec != _sec) {\n\t\t\t\t\t_sec = tm_info->tm_sec;\n\t\t\t\t\tsprintf(tmp_buff, \"%02d:%02d:%02d\", tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec);\n\t\t\t\t\t_fg = 15;\t\t\t\t\t\t\t// fill = 15\n\t\t\t\t\tset_7seg_font_atrib(10, 2, 0, 15);\t// outline = 15\n\t\t\t\t\tEPD_print(tmp_buff, CENTER, y);\n\t\t\t\t\t_fg = 15;\n\t\t\t\t\tif (tm_info->tm_mday != _day) {\n\t\t\t\t\t\tsprintf(tmp_buff, \"%02d.%02d.%04d\", tm_info->tm_mday, tm_info->tm_mon + 1, tm_info->tm_year+1900);\n\t\t\t\t\t\t_fg = 7;\t\t\t\t\t\t\t// fill = 7\n\t\t\t\t\t\tset_7seg_font_atrib(8, 2, 1, 15);\t// outline = 15\n\t\t\t\t\t\tEPD_print(tmp_buff, CENTER, y2);\n\t\t\t\t\t\t_fg = 15;\n\t\t\t\t\t}\n\t\t\t\t\tEPD_UpdateScreen();\n\t\t\t\t}\n\t\t\t\tEPD_wait(100);\n\t\t\t}\n\t\t\ttstart = clock();\n\t\t\t_fg = 15;\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\tfont_rotate = 90;\n\t\t\tsprintf(tmp_buff, \"%02d:%02d:%02d %02d/%02d\", tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, tm_info->tm_mday, tm_info->tm_mon + 1);\n\t\t\tEPD_print(tmp_buff, 20, 4);\n\t\t\tfont_rotate = 0;\n\t\t\tsprintf(tmp_buff, \"Pass: %d\", pass+1);\n\t\t\tEPD_print(tmp_buff, 4, 128-EPD_getfontheight()-2);\n\t\t\tEPD_UpdateScreen();\n\t\t}\n\t\telse if (ftype == 5) {\n\t\t\tuint8_t old_gs = _gs;\n\t\t\t_gs = 1;\n\t\t\tEPD_drawRect(4,4,20,20, 15);\n\n\t\t\tEPD_fillRect(27,5,18,18, 1);\n\t\t\tEPD_drawRect(26,4,20,20, 15);\n\n\t\t\tEPD_drawCircle(66,16,10, 15);\n\n\t\t\tEPD_fillCircle(92,16,10, 2);\n\t\t\tEPD_drawCircle(92,16,11, 15);\n\n\t\t\tEPD_fillRect(185,4,80,80, 3);\n\t\t\tEPD_drawRect(185,4,80,80, 15);\n\n\t\t\tEPD_fillCircle(225,44,35, 0);\n\t\t\tEPD_drawCircle(225,44,35, 15);\n\t\t\tEPD_fillCircle(225,44,35, 5);\n\n\t\t\tEPD_fillCircle(225,44,20, 0);\n\t\t\tEPD_drawCircle(225,44,20, 15);\n\n\t\t\torientation = LANDSCAPE_180;\n\t\t\tEPD_drawRect(4,4,20,20, 15);\n\n\t\t\tEPD_fillRect(27,5,18,18, 1);\n\t\t\tEPD_drawRect(26,4,20,20, 15);\n\n\t\t\tEPD_drawCircle(66,16,10, 15);\n\n\t\t\tEPD_fillCircle(92,16,10, 2);\n\t\t\tEPD_drawCircle(92,16,11, 15);\n\n\t\t\tEPD_fillRect(185,4,80,80, 3);\n\t\t\tEPD_drawRect(185,4,80,80, 15);\n\n\t\t\tEPD_fillCircle(225,44,35, 0);\n\t\t\tEPD_drawCircle(225,44,35, 15);\n\t\t\tEPD_fillCircle(225,44,35, 5);\n\n\t\t\tEPD_fillCircle(225,44,20, 0);\n\t\t\tEPD_drawCircle(225,44,20, 15);\n\t\t\torientation = LANDSCAPE_0;\n\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\tfont_rotate = 90;\n\t\t\tsprintf(tmp_buff, \"Pass: %d\", pass+1);\n\t\t\tEPD_print(\"Gray scale demo\", _width/2+EPD_getfontheight()+2, 4);\n\t\t\tEPD_print(tmp_buff, _width/2, 4);\n\t\t\tfont_rotate = 0;\n\n\t\t\tEPD_UpdateScreen();\n\t\t\t_gs = old_gs;\n\t\t}\n\t\telse if (ftype == 6) {\n\t\t\tuint8_t old_gs = _gs;\n\t\t\t_gs = 0;\n\t\t\tmemcpy(disp_buffer, (unsigned char *)gImage_img1, sizeof(gImage_img1));\n\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\tsprintf(tmp_buff, \"Pass: %d\", pass+1);\n\t\t\tEPD_print(tmp_buff, 4, 128-EPD_getfontheight()-2);\n\n\t\t\tEPD_UpdateScreen();\n\t\t\t_gs = old_gs;\n\t\t}\n\t\telse if (ftype == 7) {\n\t\t\tuint8_t old_gs = _gs;\n\t\t\t_gs = 0;\n\t\t\tmemcpy(disp_buffer, (unsigned char *)gImage_img3, sizeof(gImage_img3));\n\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\t_fg = 0;\n\t\t\t_bg = 1;\n\t\t\tsprintf(tmp_buff, \"Pass: %d\", pass+1);\n\t\t\tEPD_print(tmp_buff, 4, 128-EPD_getfontheight()-2);\n\n\t\t\tEPD_UpdateScreen();\n\t\t\t_fg = 15;\n\t\t\t_bg = 0;\n\t\t\t_gs = old_gs;\n\t\t}\n\t\telse if (ftype == 8) {\n\t\t\tuint8_t old_gs = _gs;\n\t\t\t_gs = 1;\n\t\t\tint i, x, y;\n\t        uint8_t last_lvl = 0;\n\t\t    for (i=0; i<16; i++) {\n\t\t        for (x = 0; x < EPD_DISPLAY_WIDTH; x++) {\n\t\t          for (y = 0; y < EPD_DISPLAY_HEIGHT; y++) {\n\t\t        \t  uint8_t pix = img_hacking[(x * EPD_DISPLAY_HEIGHT) + (EPD_DISPLAY_HEIGHT-y-1)];\n\t\t        \t  if ((pix > last_lvl) && (pix <= lvl_buf[i])) {\n\t\t        \t\t  gs_disp_buffer[(y * EPD_DISPLAY_WIDTH) + x] = i;\n\t\t        \t\t  gs_used_shades |= (1 << i);\n\t\t        \t  }\n\t\t          }\n\t\t        }\n\t\t        last_lvl = lvl_buf[i];\n\t\t    }\n\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\tsprintf(tmp_buff, \"Pass: %d (Gray scale image)\", pass+1);\n\t\t\tEPD_print(tmp_buff, 4, 128-EPD_getfontheight()-2);\n\n\t\t\tEPD_UpdateScreen();\n\t\t\t_gs = old_gs;\n\t\t}\n\t\telse if (ftype == 9) {\n\t\t\tuint8_t old_gs = _gs;\n\t\t\t_gs = 0;\n\t\t\tmemcpy(disp_buffer, gImage_img2, sizeof(gImage_img2));\n\n\t\t\tEPD_setFont(DEFAULT_FONT, NULL);\n\t\t\tsprintf(tmp_buff, \"Pass: %d\", pass+1);\n\t\t\tEPD_print(tmp_buff, 4, 4);\n\n\t\t\tEPD_UpdateScreen();\n\t\t\t_gs = old_gs;\n\t\t}\n\t\telse if (ftype == 10) {\n\t\t\tif (spiffs_is_mounted) {\n\t\t\t\t// ** Show scaled (1/8, 1/4, 1/2 size) JPG images\n\t\t\t\t\tuint8_t old_gs = _gs;\n\t\t\t\t\t_gs = 1;\n\t\t\t\t\tEPD_Cls();\n\t\t\t\t\tEPD_jpg_image(CENTER, CENTER, 0, SPIFFS_BASE_PATH\"/images/evolution-of-human.jpg\", NULL, 0);\n\t\t\t\t\tEPD_UpdateScreen();\n\t\t\t\t\tEPD_wait(5000);\n\n\t\t\t\t\tEPD_Cls();\n\t\t\t\t\tEPD_jpg_image(CENTER, CENTER, 0, SPIFFS_BASE_PATH\"/images/people_silhouettes.jpg\", NULL, 0);\n\t\t\t\t\tEPD_UpdateScreen();\n\t\t\t\t\tEPD_wait(5000);\n\n\t\t\t\t\tEPD_Cls();\n\t\t\t\t\tEPD_jpg_image(CENTER, CENTER, 0, SPIFFS_BASE_PATH\"/images/silhouettes-dancing.jpg\", NULL, 0);\n\t\t\t\t\tEPD_UpdateScreen();\n\t\t\t\t\tEPD_wait(5000);\n\n\t\t\t\t\tEPD_Cls();\n\t\t\t\t\tEPD_jpg_image(CENTER, CENTER, 0, SPIFFS_BASE_PATH\"/images/girl_silhouettes.jpg\", NULL, 0);\n\t\t\t\t\tEPD_UpdateScreen();\n\t\t\t\t\tEPD_wait(5000);\n\n\t\t\t\t\tEPD_Cls();\n\t\t\t\t\tEPD_jpg_image(CENTER, CENTER, 0, SPIFFS_BASE_PATH\"/images/animal-silhouettes.jpg\", NULL, 0);\n\t\t\t\t\tEPD_UpdateScreen();\n\t\t\t\t\tEPD_wait(5000);\n\n\t\t\t\t\tEPD_Cls();\n\t\t\t\t\tEPD_jpg_image(CENTER, CENTER, 0, SPIFFS_BASE_PATH\"/images/Flintstones.jpg\", NULL, 0);\n\t\t\t\t\tEPD_UpdateScreen();\n\t\t\t\t\tEPD_wait(5000);\n\n\t\t\t\t\t_gs = old_gs;\n\t\t\t}\n\t\t}\n\n\t\t//EPD_DisplayPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, disp_buffer);\n\t\ttstart = clock() - tstart;\n\t\tpass++;\n    \tprintf(\"-- Type: %d Pass: %d Time: %u ms\\r\\n\", ftype, pass, tstart);\n\n    \tEPD_PowerOff();\n\t\tEPD_wait(8000);\n    }\n\n}\n"
  },
  {
    "path": "main/ePaper.h",
    "content": "/**\r\n  ******************************************************************************\r\n  * File Name          : main.h\r\n  * Description        : This file contains the common defines of the application\r\n  ******************************************************************************\r\n  *\r\n  * COPYRIGHT(c) 2017 STMicroelectronics\r\n  *\r\n  * Redistribution and use in source and binary forms, with or without modification,\r\n  * are permitted provided that the following conditions are met:\r\n  *   1. Redistributions of source code must retain the above copyright notice,\r\n  *      this list of conditions and the following disclaimer.\r\n  *   2. Redistributions in binary form must reproduce the above copyright notice,\r\n  *      this list of conditions and the following disclaimer in the documentation\r\n  *      and/or other materials provided with the distribution.\r\n  *   3. Neither the name of STMicroelectronics nor the names of its contributors\r\n  *      may be used to endorse or promote products derived from this software\r\n  *      without specific prior written permission.\r\n  *\r\n  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r\n  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r\n  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\n  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r\n  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r\n  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n  *\r\n  ******************************************************************************\r\n  */\r\n/* Define to prevent recursive inclusion -------------------------------------*/\r\n#ifndef __EPAPER_H\r\n#define __EPAPER_H\r\n  /* Includes ------------------------------------------------------------------*/\r\n\r\n/* USER CODE BEGIN Includes */\r\n#include \"spi_master_lobo.h\"\r\n\r\n/* USER CODE END Includes */\r\n\r\n/* Private define ------------------------------------------------------------*/\r\n\r\n#define SCK_Pin\t\t18\r\n#define MOSI_Pin\t23\r\n#define MISO_Pin\t19\r\n#define DC_Pin\t\t26\r\n#define BUSY_Pin\t32\r\n#define RST_Pin\t\t27\r\n#define CS_Pin\t\t5\r\n\r\nspi_lobo_device_handle_t disp_spi;\r\n\r\n/* USER CODE BEGIN Private defines */\r\n//cs\r\n//dc\r\n//rst\r\n//busy\r\n\r\n\r\n/* USER CODE END Private defines */\r\n\r\n/**\r\n  * @}\r\n  */ \r\n\r\n/**\r\n  * @}\r\n*/ \r\n\r\n#endif /* __EPAPER_H */\r\n/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/\r\n"
  },
  {
    "path": "main/img1.h",
    "content": "const unsigned char gImage_img1[4736] = { /* 0X01,0X01,0X28,0X01,0X80,0X00, */\r\n0XCC,0XCE,0XEC,0XBA,0XCC,0XB3,0XCD,0X10,0X01,0X15,0XEC,0X50,0X01,0X31,0X34,0XA2,\r\n0X33,0X31,0X17,0X45,0X33,0X4C,0X72,0X4C,0X00,0X4A,0X10,0X00,0X00,0X4E,0X41,0X18,\r\n0XCC,0XCE,0XE8,0XBA,0XCC,0XB3,0XAC,0X30,0X01,0X15,0XE0,0X00,0X01,0X10,0XBC,0XC7,\r\n0X33,0X35,0X37,0XED,0X33,0X4C,0XD2,0X84,0X00,0X43,0X10,0X00,0X00,0XEA,0X00,0X18,\r\n0XCD,0XCA,0XCC,0X16,0XCC,0XB3,0X3D,0X52,0X01,0X3C,0XC8,0X00,0X00,0X0D,0XDF,0X20,\r\n0X32,0X35,0X73,0XE9,0X33,0X4D,0XD4,0X28,0X00,0X43,0X20,0X00,0X00,0XA2,0X20,0XDA,\r\n0XCD,0XEE,0X8E,0XB6,0XCC,0XB2,0X6A,0X80,0X01,0X15,0XC8,0X00,0X00,0X58,0X1B,0X01,\r\n0X33,0X11,0X71,0X59,0X33,0X5D,0XB4,0X38,0X00,0X4A,0XA0,0X00,0X00,0X87,0XE4,0XAC,\r\n0XEC,0XEE,0XDE,0XAE,0XCC,0XA3,0X5A,0XC4,0X01,0X35,0X50,0X00,0X00,0X30,0X13,0X42,\r\n0X13,0X33,0X23,0XF1,0X37,0X5C,0XEC,0X28,0X00,0X83,0XA0,0X00,0X00,0XCE,0XCC,0X3C,\r\n0XED,0XCC,0XDC,0X0E,0XC8,0XA3,0X32,0X90,0X00,0X5D,0X40,0X00,0X01,0X21,0X23,0XD3,\r\n0X3A,0X7B,0X6B,0XF1,0X37,0X5D,0XDC,0X68,0X01,0X22,0XA8,0X00,0X00,0X5E,0XCA,0X0C,\r\n0XC5,0X86,0X95,0X5E,0XC9,0XA2,0XB2,0X90,0X00,0X8F,0X44,0X00,0X00,0X20,0X30,0XD3,\r\n0X3B,0X79,0XEE,0XA1,0X36,0X5D,0X5D,0X28,0X22,0X31,0XB8,0X00,0X00,0X1F,0XCF,0X28,\r\n0XCC,0XD6,0X31,0X7E,0XE9,0XA3,0XE0,0XD0,0X00,0X8E,0X44,0X00,0X00,0XA0,0X20,0X97,\r\n0X77,0X2D,0XDF,0X89,0X3E,0X5C,0X3E,0X2C,0X02,0X23,0XB0,0X00,0X00,0X1D,0X2F,0X28,\r\n0X89,0XD2,0XA4,0XF6,0XC3,0XA3,0XD0,0XD0,0X04,0XDE,0XC0,0X00,0X00,0XE2,0XA0,0XC7,\r\n0X7E,0XBF,0X5B,0X29,0X3C,0XDD,0X6E,0X28,0X01,0X03,0X28,0X00,0X00,0X1D,0X0D,0X34,\r\n0XC3,0X40,0XEE,0XDE,0XE3,0X22,0XB0,0XD0,0X04,0X6D,0XD2,0X00,0X00,0XE2,0XF2,0X53,\r\n0X3C,0XFF,0X31,0X63,0X1E,0XDF,0XEF,0X28,0X01,0X16,0XE8,0X00,0X00,0X1D,0X09,0X0C,\r\n0XD7,0X2A,0XCF,0XBC,0XF1,0X20,0X30,0XD0,0X04,0X4B,0X3A,0X00,0X00,0XC2,0XB6,0XA2,\r\n0X69,0XD5,0X74,0XD3,0X8E,0XDF,0XDA,0X28,0X01,0X35,0XCC,0X20,0X00,0X35,0X49,0X59,\r\n0XBE,0XAE,0X9B,0X6E,0XF3,0X22,0XED,0XD0,0X04,0X8E,0XF4,0X00,0X00,0XCA,0XB6,0XA6,\r\n0X45,0X73,0XE5,0XBB,0X4D,0XDD,0X32,0X2C,0X01,0X73,0X3A,0X00,0X00,0X35,0X49,0X49,\r\n0XFB,0X9C,0X3E,0XCD,0XF2,0X26,0XED,0XD0,0X04,0X0D,0XD4,0X00,0X00,0XC2,0XB4,0X35,\r\n0X2C,0XE3,0XD3,0X37,0X2D,0XDB,0XB0,0X20,0X02,0XB7,0X7B,0X00,0X00,0X3D,0X4A,0XC0,\r\n0XD7,0X3E,0XAC,0XDD,0XD6,0X2C,0XDF,0XD0,0X05,0X4D,0XDC,0X80,0X00,0XC4,0XB4,0X3E,\r\n0XB9,0XC9,0X7B,0X62,0X6B,0XD3,0X60,0X20,0X00,0X37,0X77,0X00,0X00,0X33,0X4B,0XC1,\r\n0X4E,0XB7,0X8D,0XBD,0X95,0X2D,0XBD,0XD0,0X04,0X8D,0XBC,0XB0,0X00,0XCC,0XB4,0X34,\r\n0XF5,0X6C,0XF6,0XD2,0X6A,0XD6,0XD2,0X20,0X03,0X76,0XF3,0X40,0X00,0X32,0X4A,0XC3,\r\n0X2B,0X93,0X5B,0X6D,0XB5,0X3B,0X6D,0XD0,0X04,0X0F,0XFC,0X90,0X00,0XCB,0XB5,0X28,\r\n0XDC,0XFE,0XED,0XBA,0XCE,0XCD,0XB2,0X20,0X01,0XB3,0X35,0X40,0X00,0X2C,0X42,0XD7,\r\n0X67,0X4B,0X36,0XE5,0X73,0X36,0XDD,0XD0,0X04,0X4D,0XFE,0X00,0X10,0X93,0X9D,0X28,\r\n0XBA,0XB5,0XDB,0X3E,0X8C,0XDB,0X72,0X20,0X03,0X3E,0XF1,0X40,0X0B,0X6C,0X62,0XD3,\r\n0X4D,0XDB,0X6D,0XD3,0XF7,0X2D,0XCD,0XC0,0X04,0XC7,0XFC,0X00,0X00,0X93,0X94,0X0D,\r\n0XF6,0X6C,0XB6,0XED,0X29,0XFB,0X32,0X30,0X01,0X3B,0XF0,0X10,0X03,0X6C,0X4B,0X60,\r\n0X2B,0XB7,0XDB,0X32,0XDE,0X0C,0XED,0XC0,0X04,0X8F,0XEC,0X00,0X00,0X91,0XB0,0X9E,\r\n0XDD,0X4D,0X6D,0XDF,0XE5,0XF7,0XB2,0X10,0X02,0X75,0XF0,0X00,0X02,0X6E,0X4F,0X61,\r\n0X62,0XF2,0XB6,0XE1,0X3E,0X2A,0XDD,0XC0,0X05,0X0F,0XFC,0X03,0X04,0X91,0X30,0X9C,\r\n0XBD,0X5F,0XDB,0X3E,0XD3,0XFF,0X62,0X2C,0X02,0XFB,0XF2,0X04,0X43,0X6E,0X0F,0X63,\r\n0X57,0XB5,0X6D,0XC3,0XEC,0X33,0X9D,0XC0,0X08,0X0F,0XFC,0X01,0X00,0X91,0XC0,0X9C,\r\n0XEC,0XCA,0XB6,0XFD,0X3B,0XCC,0XE2,0X10,0X03,0XBB,0XF3,0X04,0X02,0X6E,0X3F,0X63,\r\n0X37,0X7F,0XDB,0X23,0XD4,0X7B,0XAD,0XC0,0X08,0X4F,0XEC,0XC2,0X05,0X11,0XC0,0X9C,\r\n0XDB,0XB5,0X6D,0XDD,0XFF,0XAE,0XF6,0X10,0X02,0XBF,0XFB,0X28,0X10,0XCE,0X4B,0X63,\r\n0X6C,0XCA,0XB6,0XE3,0XD2,0XFB,0X51,0XC0,0X0D,0X4F,0XE4,0XD2,0X00,0X31,0X34,0X9C,\r\n0XB7,0X7F,0XDB,0X3D,0XBD,0X2D,0XFE,0X20,0X02,0XB7,0XFB,0X28,0X10,0X4C,0XD3,0X65,\r\n0XDB,0XB5,0X6F,0XF2,0XD6,0XF7,0X51,0X80,0X09,0X5F,0XED,0XD3,0X00,0XB3,0X04,0X12,\r\n0X6C,0XCA,0XB4,0XCF,0X6B,0XBD,0XEE,0X20,0X04,0XAF,0XF2,0X2C,0X00,0X4C,0X2B,0XED,\r\n0XB7,0X7F,0XFB,0X3B,0XBC,0XD6,0XB1,0XD0,0X13,0X5F,0XED,0XC1,0X00,0XB3,0XD5,0X12,\r\n0XDB,0XB5,0X4F,0XE4,0XD3,0X6B,0XEE,0X04,0X04,0XBF,0XF2,0X24,0X00,0X0C,0X21,0X6C,\r\n0X6C,0XDA,0XB4,0X9B,0XAD,0XBD,0X51,0XC2,0X11,0X5F,0XED,0X92,0X00,0XF3,0X4C,0X92,\r\n0XB7,0X6F,0XFF,0XE6,0XFA,0XF7,0XEE,0X30,0X0E,0XBF,0XF2,0X48,0X00,0X0C,0XB3,0X6D,\r\n0XDB,0XBB,0X56,0XBB,0X2F,0X5D,0X31,0X82,0X10,0X5F,0XCD,0X22,0X80,0XF3,0X4C,0X12,\r\n0X6C,0XED,0XAB,0XC6,0XF0,0XAB,0XEE,0X40,0X07,0XBF,0XF2,0X8D,0X00,0X0C,0XB3,0XA9,\r\n0XB7,0XB6,0XFE,0XBB,0XBF,0XFE,0XB5,0X2B,0X10,0X4F,0XC9,0X72,0X21,0X73,0X4C,0X56,\r\n0XDA,0XDB,0XAB,0XEE,0XCA,0XAB,0XDA,0X80,0X0B,0XBF,0XF4,0X88,0X80,0X8C,0XB5,0XA8,\r\n0XEF,0X6E,0XFF,0XFB,0X75,0XFF,0XED,0X28,0X14,0X7F,0XCA,0X27,0X40,0X71,0X42,0X57,\r\n0X3B,0XBB,0XAB,0XFD,0XBE,0XEB,0XB2,0X84,0X03,0X9F,0XF1,0XD0,0X01,0X0E,0XB5,0X08,\r\n0XEC,0XEE,0XFF,0XFF,0XD3,0X7F,0XDD,0X30,0X18,0X6F,0XCC,0X2A,0X80,0XB1,0X40,0X97,\r\n0XB7,0XBB,0XAA,0XFC,0XED,0XEF,0XA2,0XC4,0X07,0XBF,0XF3,0X45,0X00,0XCE,0XBA,0X68,\r\n0XDA,0XEE,0XFF,0XFF,0X3B,0XFF,0XFD,0X10,0X10,0X7F,0XCC,0XB0,0X00,0X31,0X45,0X97,\r\n0X6F,0XBB,0XAD,0XF7,0XD4,0XEF,0XD4,0X42,0X0B,0XBF,0XF3,0X4A,0X00,0XCE,0XB1,0X68,\r\n0XBA,0XEE,0XF3,0X5A,0XFF,0XFF,0XEF,0X0C,0X14,0X7F,0XCC,0XB0,0XA1,0X31,0X4C,0X06,\r\n0XEF,0XBB,0XBE,0XEF,0X53,0XEF,0XB0,0XB0,0X0B,0XBF,0XF3,0X4A,0X00,0XCE,0X83,0XF1,\r\n0XBA,0XEF,0XDB,0XBF,0XAC,0XFF,0XEF,0X42,0X24,0X7F,0XDC,0XB4,0XC0,0X31,0X38,0X1E,\r\n0XEF,0XBA,0XEF,0XD6,0XFB,0XFF,0XB4,0X0C,0X13,0XFF,0XF3,0X6A,0X01,0XCE,0X87,0XC1,\r\n0XBA,0XDF,0XFF,0XEF,0XAF,0XFF,0XDB,0XA0,0X2C,0X3F,0XCC,0X95,0X40,0X31,0X70,0X34,\r\n0XEF,0XFF,0XFF,0X3E,0XF5,0XFF,0X74,0X54,0X03,0XFF,0XFB,0X60,0X01,0XCE,0X8D,0X8B,\r\n0XBB,0X7F,0XFF,0XEF,0X5B,0XFF,0XDB,0X00,0X34,0X7F,0XC4,0X9A,0X80,0X31,0X72,0X74,\r\n0XFC,0XFF,0XFF,0XFD,0XEF,0XFF,0X6C,0XAA,0X0B,0XFF,0XFF,0X45,0X01,0XEE,0X8C,0X8B,\r\n0XFF,0XFF,0XFF,0XF3,0X7B,0XFF,0XB3,0X54,0X24,0X7F,0XD2,0XA8,0X01,0X15,0X73,0X35,\r\n0XFF,0XFF,0XFF,0XFE,0XAF,0XFF,0XEC,0X00,0X1B,0XFF,0XED,0X46,0X00,0XEA,0X8C,0XC8,\r\n0XFF,0XFF,0XFF,0XFF,0XF7,0XFF,0XFB,0X2A,0X44,0X7F,0XDE,0XB9,0X03,0X15,0X72,0X12,\r\n0XFF,0XFF,0XFF,0XD7,0XBB,0XFF,0X64,0XC0,0X33,0XBF,0XF3,0X46,0X08,0XFE,0X8D,0X4C,\r\n0XFF,0XFF,0XFF,0XBF,0XDF,0XFF,0XFB,0X28,0X4C,0XFF,0XCC,0XB9,0XC3,0X01,0X70,0X03,\r\n0XFF,0XFF,0XFF,0XD7,0XFF,0XFD,0X24,0X14,0X13,0X7F,0XF7,0X44,0X28,0XFE,0X8E,0XB4,\r\n0XFF,0XFF,0XFF,0X7F,0XDF,0XFE,0XFA,0XC2,0X6C,0XBF,0XD8,0X32,0X55,0X01,0X70,0X4B,\r\n0XFF,0XFF,0XFF,0XCF,0XBF,0XFF,0XB5,0X28,0X13,0XFF,0XE7,0X4C,0X02,0XFE,0X8B,0X94,\r\n0XFF,0XFF,0XFF,0X3F,0XFF,0XFF,0XDA,0X42,0X4C,0XFF,0XD8,0X12,0X05,0X09,0X74,0X53,\r\n0XFF,0XFF,0XFD,0XF4,0XFF,0XFF,0X65,0X28,0X33,0X7F,0XF7,0X4C,0X00,0XF6,0X83,0X00,\r\n0XFF,0XFF,0XFB,0X5F,0XBF,0XFF,0XBA,0X94,0X4C,0XFF,0XD8,0X12,0X37,0X0B,0X74,0XBB,\r\n0XFF,0XFF,0XFE,0XAA,0XFF,0XFF,0XD4,0X42,0X23,0XFF,0XAF,0X0C,0X80,0XF4,0X8B,0X45,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XEB,0X28,0X5C,0XFF,0XF0,0X22,0X43,0X0B,0XF4,0XB8,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XD4,0X93,0X23,0X7F,0XBE,0X9C,0XAC,0XF4,0X0B,0X47,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFA,0X68,0X1D,0XFF,0XC9,0X42,0X03,0X0B,0XF4,0XB8,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XCD,0X04,0XC2,0XFF,0X76,0X39,0XAC,0XFC,0X4B,0X47,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF6,0XB3,0X3D,0XFF,0XD9,0X44,0X53,0X07,0XB4,0XA8,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XD0,0X48,0X03,0X7F,0X6E,0XB2,0XAC,0XF8,0XDB,0X57,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X24,0XDC,0XFF,0XD1,0X4C,0X53,0X0F,0X64,0XA8,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X92,0X23,0XFF,0X2E,0XB3,0X94,0XF2,0XAA,0X57,\r\n0XFF,0XFF,0XFF,0XFF,0XBF,0XFF,0XFE,0X49,0X5D,0XFF,0XD1,0X44,0X43,0X0D,0X6B,0XA8,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X69,0X24,0XA3,0XFF,0X24,0X51,0XA2,0XF2,0XFC,0X57,\r\n0XFF,0XFF,0XFF,0XFF,0X5F,0XFF,0XF6,0X92,0X5D,0XFF,0XDB,0X0C,0X01,0X5F,0X53,0XA8,\r\n0XFF,0XFF,0XFE,0XFF,0XFF,0XFF,0XE8,0X49,0X23,0XFF,0X20,0XA2,0X86,0XE9,0XEC,0X57,\r\n0XFF,0XFF,0XFF,0XFF,0X3F,0XFF,0XFF,0X24,0XDC,0XFF,0XCA,0X49,0X41,0X1F,0X53,0XAA,\r\n0XFF,0XFF,0XFE,0XFE,0XFF,0XFF,0XE0,0X92,0X23,0XFF,0X35,0X24,0X0A,0XE4,0XBC,0X55,\r\n0XFF,0XFF,0XFF,0XFF,0XBF,0XFF,0XFE,0X41,0X5F,0XFF,0XC8,0XDB,0X45,0X5F,0XC3,0XAA,\r\n0XFF,0XFF,0XFF,0X7E,0XFF,0XFF,0XE9,0X3C,0XA0,0XFF,0X32,0X20,0X2A,0XA1,0X7E,0XD5,\r\n0XFF,0XFF,0XFF,0XFF,0XBF,0XFF,0XF6,0XC3,0X5F,0XFF,0XC9,0X49,0X15,0X5E,0XB3,0X58,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE9,0X14,0X23,0XFF,0X34,0X34,0XCA,0XA5,0XDD,0X47,\r\n0XFF,0XFF,0XFF,0XFF,0XBF,0XFF,0XFE,0X49,0XDD,0XFF,0XCB,0X82,0X05,0X5A,0X67,0XF8,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE1,0XA6,0X23,0XFF,0X74,0XB8,0XAA,0XA5,0XB9,0X57,\r\n0XFF,0XFF,0XFF,0XFF,0XBF,0XFF,0XFE,0X10,0XDF,0XFF,0XC3,0XC2,0X2F,0XFB,0X47,0XAC,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE9,0XCB,0X23,0XFF,0XFD,0X7F,0XFF,0XFC,0XB8,0XF7,\r\n0XFF,0XFF,0XFF,0XFF,0X7F,0XFF,0XF6,0X34,0XBF,0XFF,0XC3,0XFF,0XFF,0XFF,0XE7,0X08,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE9,0X82,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X98,0XF7,\r\n0XFF,0XFF,0XFF,0X7F,0X7F,0XFF,0XFE,0X5B,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X67,0X48,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE1,0XA7,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XD0,0XBF,\r\n0XFF,0XFF,0XFF,0XFF,0X7F,0XFF,0XFE,0X5B,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X3E,0XF4,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF1,0X45,0X54,0XF7,0XFF,0XFF,0XFF,0XFF,0XCB,0X8B,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XCC,0X3A,0XAB,0XF7,0XFF,0XFF,0XFF,0XF4,0XFE,0XFE,\r\n0XFF,0XFF,0XFE,0XFF,0XFF,0XFF,0XF0,0X85,0X3A,0XFF,0XFF,0XFF,0XFF,0XDB,0X33,0X53,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X0A,0XA2,0XFF,0XC7,0XFF,0XFF,0XF5,0X6F,0XCF,0XED,\r\n0XFF,0XFF,0XFD,0X7F,0XFF,0XFF,0X37,0XE9,0X5F,0XFF,0XFF,0XFB,0X5F,0XBD,0X7B,0X3F,\r\n0XFF,0XFF,0XFE,0XFF,0XFF,0XFF,0X0F,0XF0,0X3F,0X8F,0XFF,0XFD,0XF4,0XFF,0XAE,0XD2,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X0F,0X48,0XD7,0XF7,0XFF,0XEE,0X0B,0X3D,0XF7,0XBF,\r\n0XFF,0XFF,0XFE,0XFF,0XFF,0XFF,0X15,0XB4,0X0F,0X3F,0XFC,0XF3,0XFF,0XD2,0XDA,0XE9,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X8C,0XD0,0X16,0XF7,0XF3,0XFD,0X57,0XFF,0X6F,0XBF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X82,0XC0,0X0F,0XFA,0XDF,0X4A,0XBB,0XCD,0XBA,0XD4,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X1D,0XFF,0X34,0XFF,0XDF,0X76,0X4F,0XEB,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XBC,0X00,0X3F,0XFE,0XEB,0XB7,0X57,0XBB,0XF5,0X3E,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XD2,0X02,0XBB,0XFF,0X1E,0XD9,0XCC,0XCD,0X2E,0XCB,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XAD,0XCC,0X7E,0X7C,0XF3,0X76,0X33,0X76,0XD3,0XFC,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFA,0X23,0XD7,0X9A,0X1C,0XC9,0X8A,0XAB,0XAC,0X9F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XAF,0XDC,0XE4,0X34,0X6B,0X36,0X45,0XD6,0XF7,0XF5,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X23,0X12,0XCB,0X3E,0XC9,0XBA,0X3B,0X1B,0XAA,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XB3,0XD4,0XD1,0X38,0XCD,0X36,0X47,0XCE,0XF4,0XD5,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XDE,0X2B,0X1E,0XCF,0X73,0XC9,0XBD,0X7B,0X0F,0X6A,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFB,0XD4,0X00,0X31,0X8C,0X36,0X52,0X8D,0XF2,0X97,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X2B,0XA2,0XFE,0XF3,0XC9,0X4F,0XFB,0X3F,0XF9,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X7B,0XC4,0X0F,0XFB,0X4C,0X34,0X3D,0X2D,0XDB,0X4E,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X3B,0XF3,0XFC,0XB3,0XC0,0X42,0XD7,0X7D,0XB7,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X7B,0XC4,0X0F,0XFF,0X5C,0X38,0X3F,0XA8,0X8A,0XCB,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XBC,0X33,0XFF,0XFC,0X83,0XC4,0X44,0XF7,0XF5,0X74,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0XDB,0XCC,0X1F,0XFB,0X7E,0X20,0X3F,0X5A,0XAA,0XAF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X7E,0X33,0XEF,0XFC,0X81,0X90,0X81,0XAF,0X7F,0XF2,\r\n0XFF,0XFF,0XF7,0XFF,0XFF,0XFE,0XDB,0XCC,0X3F,0XF7,0X7E,0X40,0X1E,0XF9,0XD4,0X4D,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X3D,0X33,0XDF,0XF8,0X01,0X80,0X03,0X4E,0X2B,0X3E,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFA,0XCC,0X3E,0XE7,0XFE,0X00,0X2D,0XB7,0XFE,0XE3,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X5F,0X22,0XEF,0X38,0X01,0XCB,0XEA,0XF9,0X75,0X3C,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XBC,0XBB,0X3F,0XEA,0XBE,0X3F,0XFF,0XFF,0XBF,0XCB,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF3,0XBC,0XF3,0XFF,0XCA,0XFF,0XFF,0XFC,0XD4,0XFE,\r\n0XFF,0XFF,0XFB,0XFF,0XFF,0XFF,0XDF,0XFF,0XFF,0XFF,0XFF,0XFF,0XDF,0XFF,0X7F,0X35,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XBF,0XFF,0X3F,0XFF,0XFF,0XFF,0XFF,0XF0,0X95,0XCA,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFD,0XCF,0XFF,0XFF,0XFF,0XDF,0XFF,0XEE,0XF7,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XBF,0XF5,0X70,0X0E,0XFF,0XFF,0XFF,0XFE,0XF5,0X2D,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X58,0XEF,0XFF,0XFF,0XFF,0XDD,0X7F,0X1B,0XF6,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XBE,0XA7,0XF0,0X2C,0XFF,0XFF,0XEF,0XD5,0XEC,0XA9,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XDF,0XCB,0XEC,0XFF,0X7F,0XFF,0XB5,0XBF,0X53,0XFE,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XBF,0XF5,0X73,0XFC,0XFF,0XFF,0XEA,0XD4,0XEC,0XD3,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC4,0X0A,0XCC,0XFF,0XFF,0XFF,0X7D,0X6F,0XBB,0X2C,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE8,0XD5,0X33,0XFC,0XFF,0XFF,0XAB,0XBE,0XFD,0XD7,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF7,0X20,0XCC,0XFF,0XFF,0XFF,0XEC,0XFB,0XBE,0XAA,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0XCB,0X33,0XFC,0XFE,0XFF,0XF7,0XFC,0XD3,0X6B,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X34,0XCD,0XFF,0XFF,0XFF,0XCB,0XBF,0XFD,0XAF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF4,0XCF,0X33,0XFD,0X3F,0XFF,0XFF,0XD2,0X0E,0X78,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X32,0XCD,0XFF,0XF4,0XFF,0XCC,0XFD,0XF3,0XDF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF4,0XCD,0X33,0XFD,0X1F,0XFF,0XFF,0XDF,0XFD,0X32,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X32,0XC4,0XFE,0XF3,0X7F,0XDF,0XF5,0X57,0XDF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFB,0XF4,0XCD,0X3B,0XF9,0X0D,0XFF,0XFD,0X7B,0XDD,0X6A,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFD,0XFF,0X36,0XC0,0X7E,0X32,0X7F,0XBF,0XDF,0X62,0X95,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFB,0XF4,0XCB,0X28,0X3C,0X8D,0X7F,0XFC,0XF4,0XDF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X34,0XD6,0X92,0X20,0X5F,0XFF,0X4F,0X33,0X01,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFB,0XF2,0XCB,0X29,0X25,0XD2,0X17,0XFC,0XBD,0XCF,0XFE,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFD,0XFE,0XB5,0XD6,0XD8,0X0C,0X0F,0XFF,0XE6,0XFC,0XA1,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF7,0XFB,0X4A,0X69,0X21,0XE0,0X05,0XFF,0XFB,0XAB,0XDB,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFD,0XFC,0XB5,0XBA,0XDA,0XEB,0XB3,0X3F,0XFE,0X77,0X6D,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF3,0XFF,0X4E,0XCD,0X65,0XF4,0X48,0XDF,0XFB,0XDC,0XBD,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF2,0XB3,0X72,0X9B,0XFB,0X36,0X37,0XCF,0X23,0XE7,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF1,0X3D,0X4D,0XBF,0X6C,0XCC,0X81,0XC9,0X7D,0XFF,0X5C,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF6,0XDA,0XB3,0X53,0X93,0X73,0X6A,0X16,0XB7,0X54,0XA3,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFB,0XFF,0X4C,0XBC,0X6C,0X8C,0X94,0X0B,0XCA,0XAF,0XDC,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF5,0X38,0XB3,0X4F,0X93,0X73,0X40,0X34,0XFF,0XF5,0X73,\r\n0XFF,0XFB,0XFF,0XFF,0XFF,0XFB,0XCF,0X4D,0XB5,0X6C,0X8C,0XBA,0XAF,0X3C,0X2A,0XCE,\r\n0XFF,0XFE,0XFF,0XFF,0XFF,0XE5,0X7A,0XB6,0XEA,0X93,0X73,0X45,0X11,0XC3,0XFB,0X39,\r\n0XFF,0XFF,0X7F,0XFF,0XFF,0XFB,0XAD,0X4B,0X3D,0X4C,0X8C,0XB0,0XEE,0XFF,0X5D,0XD7,\r\n0XFF,0XF3,0XFF,0XFF,0XFF,0XED,0XFA,0XBC,0XC2,0XA3,0X73,0X4E,0X13,0X5D,0XEA,0X2C,\r\n0XFF,0XFF,0X3F,0XFF,0XFF,0XF3,0XFF,0XD7,0X7E,0X5C,0X84,0XA1,0XEE,0XEE,0XDF,0XD7,\r\n0XFF,0XFD,0XFF,0XFF,0XFF,0XCD,0XFA,0XE9,0XA3,0X83,0X7B,0X56,0X13,0X13,0XEB,0X68,\r\n0XFF,0XFF,0X3F,0XFF,0XFF,0XF7,0XFF,0X36,0X5F,0X7C,0X84,0XA9,0XEE,0XFF,0XBB,0XBE,\r\n0XFF,0XFF,0XDF,0XFF,0XFF,0XEB,0XF9,0XD9,0XAC,0X82,0X51,0X56,0X13,0X8C,0XCC,0X4B,\r\n0XFF,0XFC,0X3D,0XF7,0XFF,0XFF,0XFE,0XE6,0XF7,0X5C,0X0E,0XAB,0XEE,0XF7,0XF7,0XA9,\r\n0XFF,0XFF,0XDF,0X0D,0XDF,0XE5,0XFB,0X1B,0XAA,0XA2,0X01,0X55,0X13,0XAB,0X2A,0XEA,\r\n0XFF,0XFC,0X4C,0XF2,0XFF,0XFB,0XFD,0XEC,0XFD,0X55,0X06,0XAA,0XEE,0XDC,0XFF,0X3D,\r\n0XFF,0XFE,0XF7,0XFD,0X2F,0XEF,0XFA,0X57,0X33,0XA8,0X01,0X55,0X17,0X37,0XCD,0XD7,\r\n0XFF,0XFB,0X09,0X52,0XDF,0XF5,0XFD,0XAA,0XFC,0X56,0X0E,0XAE,0XAB,0XCD,0X72,0X7C,\r\n0XFF,0XFC,0XF4,0X8D,0X7F,0XFB,0XFA,0X7D,0X93,0XA8,0X21,0X51,0X17,0X7A,0XAF,0X83,\r\n0XFF,0XFF,0X0B,0X6E,0XFF,0XF7,0XFD,0X86,0X6C,0X54,0X8E,0X2C,0XEC,0XCF,0XFD,0X7C,\r\n0XFF,0XFC,0XD0,0X39,0XFF,0XFB,0XFA,0XF9,0X93,0X00,0X21,0X50,0X17,0XB5,0XF2,0X83,\r\n0XFF,0XFA,0X01,0XF7,0XFF,0XEF,0XFD,0X06,0X6C,0X80,0XDE,0X84,0XAD,0X5A,0X2F,0X7C,\r\n0XFF,0XFE,0XC0,0X9B,0XEF,0XF3,0XFA,0XFB,0X92,0X2A,0X00,0X52,0X52,0XD7,0XDD,0XD3,\r\n0XFF,0XF9,0X03,0X67,0X7F,0XDF,0XFF,0XA4,0X6C,0X80,0XAB,0X05,0X0F,0X6B,0X6B,0X2C,\r\n0XFF,0XFE,0X00,0XDF,0XDF,0XF3,0XFA,0XDF,0XD3,0X2A,0X54,0X00,0XF1,0XB4,0XBC,0XF3,\r\n0XFF,0XF4,0X03,0X38,0X7F,0XCF,0XFF,0X62,0X2C,0X14,0X00,0X01,0X0E,0XCB,0XD7,0XAC,\r\n0XFF,0XF0,0X04,0X47,0XCF,0X7D,0XFA,0XBF,0XF3,0XC0,0X40,0X00,0X53,0X34,0XAA,0XFF,\r\n0X5D,0XFC,0X00,0XB9,0X35,0X83,0XFF,0XFF,0XFA,0X2B,0X0B,0X00,0X0F,0XEB,0XFF,0XFF,\r\n0X86,0XF4,0X84,0X44,0XC8,0XFF,0XFF,0XFF,0XF9,0X50,0XE4,0X20,0XA0,0XBF,0XFF,0XFF,\r\n0XB9,0X72,0X00,0X42,0X34,0X2F,0XFF,0XFF,0XF4,0XAF,0X1B,0X90,0X1B,0XFF,0XFF,0XFF,\r\n0XC2,0X08,0X00,0X05,0X13,0XFF,0XFF,0XFF,0XFA,0X50,0XE4,0X48,0XAF,0XFF,0XFF,0XFF,\r\n0XF9,0XB2,0X00,0X08,0X0D,0XFF,0XFF,0XFF,0XFD,0XAF,0X13,0X23,0XFF,0XFF,0XFF,0XFF,\r\n0XE9,0X44,0X00,0X03,0XB3,0XFF,0XFF,0XFD,0XFA,0X50,0XCC,0XBF,0XFF,0XFF,0XFF,0XFE,\r\n0XF8,0X00,0X00,0X0C,0X07,0XFF,0XF5,0X07,0XFD,0XAF,0X23,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFE,0X00,0X00,0X10,0X1F,0XFF,0XFF,0XF9,0XFE,0X50,0X9F,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XF4,0X00,0X00,0X04,0X3F,0XFF,0XF4,0X07,0XFF,0XAE,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,\r\n0XF8,0X00,0X00,0X00,0XFF,0XFF,0XFB,0XF8,0XFF,0X53,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XE4,0X00,0X00,0X00,0XFF,0XFF,0XFC,0X3F,0X7C,0XAF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XF8,0X00,0X08,0X03,0XFF,0XFF,0XFF,0XFE,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XE0,0X00,0XBC,0X0F,0XFF,0XFF,0XFD,0XFF,0X7E,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XF0,0X0B,0XFE,0X0F,0XFF,0XFF,0XEA,0XFF,0XBF,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XC0,0X0F,0XFF,0XFF,0XFF,0XFC,0XBF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XF0,0X6F,0X7F,0XFF,0XFF,0X3F,0XEF,0XFF,0XFF,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XC0,0X3F,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XF0,0XFC,0X3D,0XFE,0XFF,0XFF,0XFF,0XFF,0XFF,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XC0,0XEE,0XF2,0XFF,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XA0,0XF4,0X7F,0XF1,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFD,\r\n0XC0,0XDF,0XF5,0XFE,0XBF,0XFF,0XFF,0XFF,0XFF,0XBF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XA0,0X75,0XFF,0X31,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFD,\r\n0XC0,0X54,0X55,0XEA,0XDF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0X80,0X54,0X21,0X14,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF5,\r\n0XC0,0X00,0X48,0XC2,0X9F,0XFF,0XFF,0XFF,0XFF,0XDF,0XFF,0XFF,0XFF,0XFF,0XFE,0X35,\r\n0X80,0X00,0XB2,0X3E,0X87,0XFF,0XFF,0XDF,0XFF,0XBF,0XFF,0XFF,0XFF,0XFF,0XFF,0XDA,\r\n0XE0,0X00,0X4C,0XFF,0X67,0XFF,0X34,0XAF,0XFF,0XDF,0XFF,0XFF,0XFF,0XFF,0XFE,0XFB,\r\n0X00,0X00,0X23,0XFF,0XBB,0XFF,0XCF,0XFF,0XFF,0X5F,0XFF,0XFF,0XFF,0XFF,0XFF,0X3E,\r\n0XC0,0X00,0X5F,0XFF,0X7F,0XFF,0XB0,0XD7,0XFF,0X2F,0XFF,0XBF,0XFF,0XFF,0XFF,0XF7,\r\n0X00,0X00,0X7F,0XFF,0XDF,0XFD,0XCB,0X7F,0XFC,0XB7,0XFF,0XDF,0XFF,0XFF,0XE4,0XB1,\r\n0XC2,0X00,0X3F,0XFF,0X3F,0XFB,0X20,0XF5,0X5E,0X0B,0XFD,0X7F,0XFF,0XFF,0XFF,0XDC,\r\n0X00,0X00,0X7F,0XFF,0XEF,0XFD,0XDC,0XEE,0XB1,0X7D,0X57,0XDF,0XFF,0XF5,0XF7,0X57,\r\n0X84,0X00,0X3F,0XFE,0X17,0XFF,0X20,0X7F,0XF4,0X07,0XFD,0X77,0XFF,0XF3,0XDC,0XA8,\r\n0X00,0X80,0XBF,0XFF,0XFF,0XFE,0XD8,0XBF,0XE2,0X79,0X02,0X88,0X7F,0XDC,0X67,0XF7,\r\n0X20,0X00,0XFF,0XFE,0X0F,0XFD,0X23,0X47,0XC2,0X8F,0XFD,0X55,0X8C,0XF3,0XDA,0X1E,\r\n0X00,0X00,0X7F,0XFF,0XFF,0XEB,0XD8,0X39,0X42,0X74,0X4A,0X80,0X73,0X4C,0XAF,0XF3,\r\n0XC6,0X02,0XFF,0XFE,0XBF,0XEC,0X20,0X2F,0XE3,0X8B,0X25,0X6A,0X9E,0XAB,0X78,0X5E,\r\n0X0A,0X47,0X3F,0XFD,0X7F,0X37,0XB8,0X31,0X22,0X74,0XBA,0X85,0X6B,0X77,0X47,0XA3,\r\n0X86,0X54,0XFF,0XFF,0XBF,0XDC,0XA6,0X76,0XC5,0X8B,0XE4,0X60,0X55,0X9C,0XFC,0XFC,\r\n0X2F,0X0F,0X5F,0XFC,0XFE,0XE2,0XD8,0X7B,0XB4,0X7E,0XFB,0X13,0X3E,0XE3,0X27,0X0B,\r\n0X8C,0X83,0XBF,0XFF,0X3F,0X3F,0X44,0X24,0X42,0XB3,0X04,0XC0,0XC3,0X5E,0XDB,0XF4,\r\n0X2E,0XDF,0XFF,0XFC,0XFE,0XF9,0X34,0XFB,0X02,0XCD,0XF2,0X3D,0X3D,0XA5,0X34,0XCF,\r\n0XCC,0X3B,0XFF,0XFF,0XFF,0XBE,0XC2,0X14,0XA3,0X32,0X0C,0X80,0XD6,0XFD,0XCF,0X31,\r\n0X1E,0X5F,0XFF,0XF8,0XFE,0XF5,0X68,0XA3,0X5A,0XDD,0XE3,0X75,0X69,0X52,0X74,0XDE,\r\n0XED,0XBD,0XFF,0XFF,0X7F,0X5B,0X12,0XC8,0X2D,0X62,0X18,0X0A,0XB7,0XAD,0XAB,0X61,\r\n0X1A,0X7F,0XFF,0XF9,0XFD,0XAD,0XE3,0X30,0X82,0XDD,0X45,0XF1,0X58,0XF3,0X5E,0X9E,\r\n0XEF,0XFB,0XFF,0XFE,0XFB,0XF3,0X18,0X8D,0X3D,0X6A,0X3A,0X0E,0XCF,0XDD,0XE3,0XE1,\r\n0X17,0X7F,0XFF,0XFB,0XFC,0XFC,0XE2,0XA2,0X07,0XB5,0X85,0XE1,0X74,0XAD,0X1D,0X5B,\r\n0XBF,0X7B,0XFF,0X7C,0XFB,0XFB,0X1D,0X19,0XF8,0XCE,0X5A,0X1C,0XAB,0XF7,0XF3,0XAC,\r\n0XDF,0XBF,0XFF,0XBB,0XFE,0XFC,0XE2,0XC2,0X07,0X31,0XA5,0XE3,0XFE,0X8C,0X1C,0XB3,\r\n0XBF,0XEB,0XFF,0XFF,0XDF,0XFB,0X39,0X3D,0XC8,0XD6,0X5A,0X1C,0X15,0XF3,0XEF,0XCE,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0XC6,0XC2,0X0F,0X49,0XA5,0XE3,0XEB,0X5C,0XDA,0X3B,\r\n0XBF,0XFB,0XFF,0XFF,0XFF,0XFF,0X79,0X3D,0XAA,0XB6,0X5A,0X1C,0X3E,0XE3,0X25,0XDC,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X86,0XCA,0X5D,0X49,0XA5,0XE3,0XD3,0X3E,0XDE,0X27,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X79,0X35,0X0F,0XB6,0X52,0X1C,0X6D,0XFF,0X77,0XD8,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X8E,0XCA,0XF4,0X69,0XA9,0XE3,0X12,0X11,0XCD,0X67,\r\n0XFF,0XFF,0XFE,0XFF,0XFF,0XFF,0XF1,0X35,0X0B,0X96,0X56,0X1C,0XEF,0XEE,0X76,0XB8,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X8E,0XCA,0XFC,0X6B,0XA9,0XE3,0X11,0X51,0X89,0X4F,\r\n0XFF,0XFF,0XFE,0XBF,0XFF,0XFF,0XF1,0X35,0X37,0XB4,0X56,0X1C,0XEE,0XAE,0X7B,0XFA,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XCC,0XAA,0XD8,0X4B,0X91,0XE2,0X1B,0XF1,0XAD,0X2D,\r\n0XFF,0XFF,0XFE,0XDF,0XFF,0XFF,0XF3,0X55,0X6F,0XB0,0X4A,0X1D,0XA5,0X1E,0X72,0XF2,\r\n0XFF,0XF7,0XFF,0X2F,0XFF,0XFF,0XCC,0XBA,0X90,0X4D,0X15,0XE2,0XDA,0XE5,0X8F,0X8D,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF2,0X45,0XEF,0XB2,0X82,0X14,0X6F,0XEA,0XF0,0X72,\r\n0XFF,0XF7,0XFD,0X57,0X7F,0XFF,0XCD,0XBA,0X30,0X48,0X09,0XEB,0X11,0X35,0X0F,0XAD,\r\n0XFF,0XFF,0XFF,0XEF,0XFF,0XFF,0XF2,0X65,0XCD,0XB2,0XB4,0X10,0X4E,0XCA,0XFB,0XD2,\r\n0XFF,0XF7,0XFD,0X3F,0XFF,0XFF,0XDD,0X9A,0X30,0X4D,0X4B,0X6C,0X0B,0XFF,0X0C,0XAD,\r\n0XFF,0XFF,0XF3,0XDF,0XFF,0XFF,0XE2,0X65,0XC3,0X32,0XB0,0X80,0X01,0X10,0XF7,0X52,\r\n0XFF,0XF7,0XFD,0X7F,0XFF,0XFF,0XFD,0XBA,0X78,0XC9,0X4C,0X72,0XA0,0XAB,0X0B,0XAD,\r\n0XFF,0XFB,0XF6,0XDF,0XFF,0XFF,0XF2,0X45,0X84,0X36,0XB2,0X8D,0X0E,0XDC,0XF4,0X57,\r\n0XFF,0XEF,0XFB,0X3F,0XFF,0XFF,0XFD,0XBB,0X5B,0X41,0X45,0X60,0XB3,0XA7,0X3F,0XA8,\r\n0XFF,0XFF,0XFD,0XFF,0XFF,0XFF,0XF2,0X4D,0X80,0X0A,0XB2,0X96,0X1C,0X58,0XC4,0XF7,\r\n0XFF,0XEF,0XFA,0X5F,0XFF,0XFF,0XFE,0XB2,0X6D,0X01,0X49,0X48,0XA3,0XEB,0X3B,0X50,\r\n0XFF,0XFF,0XFF,0XBF,0XFF,0XFF,0XF3,0X6D,0X90,0XCA,0X84,0X37,0X0D,0X3D,0XEB,0XAF,\r\n0XFF,0XEF,0XFA,0XFF,0XFF,0XFF,0XFC,0XD2,0X44,0X25,0X22,0X88,0XA2,0XC3,0X3C,0XD0,\r\n0XFF,0XFF,0XFD,0X3D,0XFF,0XFF,0XEF,0X2D,0X03,0X12,0XC9,0X77,0X5D,0X3D,0XD3,0X2F,\r\n0XFF,0XEF,0XFB,0XFF,0XFF,0XFF,0XF2,0XF6,0XA8,0XE9,0X04,0X08,0XA6,0XC0,0XBD,0XF0,\r\n0XFF,0XFF,0XFC,0X7C,0XFF,0XFF,0XEE,0X89,0X53,0X14,0X32,0XB6,0X59,0X3F,0X46,0XDE,\r\n0XFF,0XEF,0XF7,0XB7,0XFF,0XFF,0XFB,0X76,0XAC,0X41,0X0C,0X49,0XA6,0XC2,0XBB,0X31,\r\n0XFF,0XF7,0XFC,0XFB,0XFF,0XFF,0XED,0X89,0X51,0X20,0XD3,0XB4,0X5B,0X3F,0XD4,0XDE,\r\n0XFF,0XDF,0XF3,0X3E,0XFF,0XFF,0XFA,0XF6,0XAE,0X80,0X2C,0X02,0XAC,0XD5,0X4F,0X31,\r\n0XFF,0XF7,0XDC,0XFB,0XFF,0XFF,0XEF,0XF9,0X41,0X20,0XC3,0XF8,0XD3,0X0B,0X70,0XCE,\r\n0XFF,0XCF,0XAB,0XFE,0XDF,0XFF,0XF5,0X76,0XB4,0XD0,0X3C,0X02,0X2E,0XF4,0X8F,0X31,\r\n0XFF,0XFF,0XFC,0X7B,0X7F,0XFF,0XFE,0XFB,0X41,0X00,0X81,0XFC,0XD3,0XBB,0XF0,0XCE,\r\n0XFF,0XEF,0XEB,0XFD,0XDF,0XFF,0XEB,0XEC,0X80,0X03,0X7C,0X03,0X2C,0X4E,0X2F,0X71,\r\n0XFF,0XFF,0XF4,0XFB,0X3F,0XFF,0XFE,0XF7,0X41,0X0C,0X02,0XBC,0X93,0XF1,0XD0,0X8D,\r\n0XFF,0XFF,0XFB,0XFD,0XCF,0XFF,0XEB,0XFA,0X80,0XA0,0X28,0X43,0X6C,0X1E,0X2F,0X70,\r\n0XFF,0XFF,0XCD,0X7A,0X3F,0XFF,0XFE,0XF5,0X4A,0X48,0XD7,0X3C,0X93,0XE9,0XD0,0X8A,\r\n0XFF,0XFF,0X72,0XFD,0XCF,0XFF,0XEB,0XFE,0XB4,0XA2,0X28,0XC3,0X6D,0X37,0X2F,0X71,\r\n0XFF,0XFF,0XED,0XF2,0X3F,0XFF,0XFE,0XF3,0X4B,0X1C,0X97,0X3C,0XD2,0XE8,0XD0,0X8E,\r\n0XFF,0XDF,0X37,0XFD,0XCF,0XFF,0XEB,0XFD,0XB4,0XE3,0X68,0XCB,0X2D,0X17,0X6E,0X71,\r\n0XFF,0XBF,0XD0,0XF2,0X3F,0XFF,0XFE,0XF6,0XCB,0X1C,0X97,0X34,0X52,0XE8,0X91,0X8E,\r\n0XFF,0XDF,0XFF,0XFE,0XDF,0XFF,0XEB,0XFB,0X34,0XC3,0X68,0XCB,0X8B,0X97,0X6A,0X71,\r\n0XFF,0XEF,0XC3,0XF3,0XAF,0XFF,0XFD,0XF5,0XCB,0X3C,0X97,0X34,0X4C,0X68,0X95,0X8E,\r\n0XFF,0X3F,0XFD,0XFF,0XFF,0XFF,0XF7,0XEA,0XB4,0XC1,0X48,0XCB,0X13,0XB7,0X6A,0X71,\r\n0XFF,0XDF,0XE7,0XEF,0XFF,0XFF,0XFC,0XF5,0X4B,0XBC,0X37,0X34,0XCC,0X4E,0X95,0X8E,\r\n0XFF,0X3D,0XFB,0XF3,0XDF,0XFF,0XCB,0XEA,0XB4,0X42,0XC8,0XCB,0X13,0XB3,0X68,0X71,\r\n0XFF,0XDF,0XEF,0XEF,0XFF,0XFF,0XFF,0XF5,0X5B,0XB9,0X27,0X34,0X0D,0X5D,0X92,0X8E,\r\n0XFE,0XBD,0XF3,0XFF,0XBF,0XFF,0XF5,0XDA,0XA4,0X44,0XD0,0XC5,0X92,0XAE,0X6C,0X71,\r\n0XFF,0X5F,0XCD,0XD7,0XFF,0XFF,0XCF,0XB5,0X5B,0XB3,0X2F,0X32,0X4D,0X75,0X92,0X8A,\r\n0XFE,0XBC,0XB6,0XAB,0XBF,0XFF,0XF0,0XCA,0XA4,0X04,0XD0,0XC1,0X32,0X8A,0X6D,0X75,\r\n0XFF,0X5F,0XDF,0XFF,0XDF,0XFF,0X5F,0X75,0X5A,0X81,0X2F,0X00,0X8D,0X75,0X92,0X8A,\r\n};\r\n"
  },
  {
    "path": "main/img2.h",
    "content": "const unsigned char gImage_img2[4736] = { /* 0X01,0X01,0X28,0X01,0X80,0X00, */\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X7F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X7F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X01,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X01,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X03,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X03,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X07,0XFF,0XF6,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X04,0X14,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XD0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XDF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0X1F,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XF0,0X01,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X07,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X07,0XC0,0X02,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0X88,0X00,0X00,0X03,0XC0,0X38,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0X80,0X00,0X00,0X07,0X80,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0X00,0X00,0X00,0X03,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0X00,0X00,0X00,0X07,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFE,0X00,0X00,0X00,0X01,0X40,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X02,0X22,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X07,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X3F,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X3F,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X01,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFC,0X00,0X00,0X00,0X03,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFE,0X00,0X00,0X00,0X03,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFE,0X00,0X00,0X00,0X03,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFE,0X00,0X00,0X00,0X07,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0X00,0X00,0X00,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0X80,0X00,0X0F,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XC0,0X00,0X0F,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XE0,0X00,0X3F,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XF8,0X00,0XFF,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFE,0X1F,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X03,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XA2,0XAF,0X80,0X00,0X02,0XAF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF7,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X9F,0XFF,0XFF,0XE7,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X0F,0XFF,0XFF,0XE3,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X0F,0XFF,0XFF,0XE1,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X07,0XFF,0XFF,0XE1,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X0F,0XFF,0XFF,0XF1,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X07,0XFF,0XFF,0XF0,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X07,0XFF,0XFF,0XF0,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X03,0XFF,0XFF,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X03,0XFF,0XFF,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X03,0XFF,0XFC,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X01,0XFF,0XF0,0X00,0X7F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X01,0XFF,0XE0,0X00,0X3F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X01,0XFF,0XC0,0X00,0X7F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0XFF,0X80,0X00,0X3F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF2,0X00,0X00,0XFF,0X80,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0XF0,0X00,0X0F,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X00,0X00,0X0F,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X07,0X00,0X00,0X00,0X00,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X0F,0X80,0X00,0X00,0X03,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XF5,0XFF,0XFF,0XFF,0XC0,0X04,0X00,0X00,0X00,0X03,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFC,0X40,0X7F,0XFF,0X55,0X40,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFC,0X00,0X1F,0XF4,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFC,0X00,0X1F,0X40,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFC,0X00,0X1C,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFC,0XFF,\r\n0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFC,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0X00,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFC,0X7F,\r\n0XFF,0XFF,0XFF,0XFF,0XAB,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFC,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XF8,0X7F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X40,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X1B,0X00,0X00,0X00,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X07,0XFF,0XE8,0X00,0X00,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X80,0X00,0X00,0X5F,0XFE,0X00,0X00,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X07,0XFF,0X80,0X00,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X80,0X00,0X07,0XFF,0XF0,0X00,0X00,0X7F,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X07,0XFF,0XFF,0X00,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X8F,0XFF,0XFF,0XE8,0X00,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFD,0XFF,0XFF,0XFF,0XFF,0XAA,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0X9F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0X8F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XE5,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XF3,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XC1,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XC0,0X01,0XF7,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0X80,0X00,0XC3,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X3F,0XFF,0XFF,0X37,0XFF,0XFF,0X7F,\r\n0X80,0X00,0X01,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X75,\r\n0X00,0X00,0X01,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X40,\r\n0X00,0X00,0X00,0X7F,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X20,\r\n0X00,0X00,0X00,0X0F,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X40,\r\n0X00,0X00,0X00,0X07,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X60,\r\n0X00,0X00,0X00,0X03,0XF0,0X00,0X00,0X2D,0X30,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X00,0X00,0X00,0X03,0XE0,0X00,0X0B,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X00,0X00,0X00,0X03,0XC0,0X0B,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X20,\r\n0X00,0X00,0X00,0X03,0X83,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X60,\r\n0X00,0X00,0X00,0X03,0XEF,0XFF,0X40,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X60,\r\n0X00,0X00,0X00,0X00,0XF8,0XD0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X00,0X00,0X00,0X00,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X40,\r\n0X00,0X00,0X00,0X00,0X78,0X00,0X00,0X22,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X60,\r\n0X00,0X00,0X00,0X00,0XF8,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X60,\r\n0X00,0X00,0X00,0X00,0XFE,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X00,0X00,0X00,0X03,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X40,\r\n0X00,0X00,0X00,0X03,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X60,\r\n0X00,0X00,0X00,0X0F,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X60,\r\n0X00,0X00,0X00,0X0F,0XFD,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X80,0X00,0X00,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XC0,0X00,0X00,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XE0,0X00,0X00,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XF0,0X00,0X20,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFE,0XCB,0XFB,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XA0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0X80,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X02,0XFF,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X00,0X2A,0XAF,0XFF,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XAA,0XAA,0XAF,0XFF,0XFF,0XFE,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,\r\n0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,\r\n};\r\n"
  },
  {
    "path": "main/img3.h",
    "content": "const unsigned char gImage_img3[4736] = { /* 0X01,0X01,0X28,0X01,0X80,0X00, */\r\n0X20,0XC4,0X34,0X40,0X44,0X40,0X00,0X00,0X0F,0XFF,0XCC,0XAC,0X00,0X00,0X00,0X00,\r\n0X9E,0X3B,0X8B,0XBF,0XBB,0X10,0X00,0X00,0X03,0XF0,0X37,0X50,0X00,0X00,0X00,0X00,\r\n0X61,0X84,0X70,0X40,0X44,0XC0,0X00,0X00,0X0F,0XEF,0XC8,0XA8,0X00,0X00,0X00,0X00,\r\n0X0A,0X72,0X8F,0X15,0X12,0X00,0X00,0X00,0X03,0XFE,0XBF,0X44,0X00,0X00,0X00,0X00,\r\n0XB4,0X8D,0X60,0XEA,0XE9,0X00,0X00,0X00,0X0F,0XD3,0XE0,0XB2,0X00,0X00,0X00,0X00,\r\n0X4B,0X32,0X1D,0X14,0X16,0XC0,0X00,0X00,0X03,0XEE,0X9F,0X48,0X00,0X00,0X00,0X00,\r\n0X24,0XC9,0XA2,0XC3,0XC8,0X00,0X00,0X00,0X0F,0XFB,0X60,0XA0,0X00,0X00,0X00,0X00,\r\n0X91,0X16,0X4C,0X3C,0X33,0X00,0X00,0X00,0X03,0XFF,0XDE,0X58,0X00,0X00,0X00,0X00,\r\n0X6E,0XE9,0XB3,0XC3,0X4C,0X00,0X00,0X00,0X0F,0XFD,0X63,0XA0,0X00,0X00,0X00,0X00,\r\n0X00,0X04,0X4C,0X28,0X92,0X80,0X00,0X00,0X07,0XF2,0X9D,0X4C,0X00,0X00,0X00,0X00,\r\n0XB7,0XFB,0X23,0X56,0X69,0X00,0X00,0X00,0X0B,0XFF,0XF2,0XB0,0X00,0X00,0X00,0X00,\r\n0X48,0X04,0XD8,0XA9,0X94,0X00,0X00,0X00,0X0F,0XFA,0XCF,0X44,0X00,0X00,0X00,0X00,\r\n0X23,0X6A,0X27,0X12,0X42,0X00,0X00,0X00,0X03,0XFF,0XBD,0XF0,0X00,0X00,0X00,0X00,\r\n0X9C,0X95,0XC8,0XED,0X38,0X00,0X00,0X00,0X0F,0XFF,0XF2,0X00,0X00,0X00,0X00,0X00,\r\n0X61,0X2A,0X35,0X12,0XC4,0X00,0X00,0X00,0X0F,0XFF,0X4F,0XE8,0X00,0X00,0X00,0X00,\r\n0X0E,0XD1,0X4A,0XC9,0X30,0X00,0X00,0X00,0X03,0XFF,0XF8,0X30,0X00,0X00,0X00,0X00,\r\n0XB1,0X2E,0XA4,0X36,0X8A,0X00,0X00,0X00,0X0F,0XFF,0X2F,0XDC,0X00,0X00,0X00,0X00,\r\n0X4A,0XD1,0X5B,0XC9,0X70,0X00,0X00,0X00,0X0B,0XFF,0XF2,0XA0,0X00,0X00,0X00,0X00,\r\n0X14,0X0C,0XA4,0X24,0X8C,0X00,0X00,0X00,0X0F,0XFF,0XAF,0XD0,0X00,0X00,0X00,0X00,\r\n0XEB,0XF3,0X13,0X5B,0X60,0X00,0X00,0X00,0X0B,0XFF,0XDA,0X28,0X00,0X00,0X00,0X00,\r\n0X04,0X0C,0XEC,0XA4,0X1A,0X00,0X00,0X00,0X0F,0XFF,0XED,0XD0,0X00,0X00,0X00,0X00,\r\n0XB3,0XD3,0X13,0X13,0XE0,0X00,0X00,0X00,0X0B,0XFF,0X33,0X28,0X00,0X00,0X00,0X00,\r\n0X48,0X28,0XA8,0XEC,0X0C,0X00,0X00,0X00,0X0F,0XF2,0XCC,0XD2,0X80,0X00,0X00,0X00,\r\n0X36,0XD7,0X57,0X01,0X70,0X00,0X00,0X00,0X0B,0XFF,0XB3,0X2C,0X00,0X00,0X00,0X00,\r\n0X89,0X28,0XA8,0XFE,0X85,0X00,0X00,0X00,0X0F,0XFF,0XDD,0XF2,0X00,0X00,0X00,0X00,\r\n0X66,0XC6,0X46,0X01,0X38,0X00,0X00,0X00,0X0F,0XFF,0XF7,0X0A,0XC0,0X00,0X00,0X00,\r\n0X11,0X39,0XB9,0XBA,0XC4,0X00,0X00,0X00,0X0F,0XFD,0X5D,0XF5,0X00,0X00,0X00,0X00,\r\n0XAC,0XC6,0X46,0X45,0X33,0X00,0X00,0X00,0X0F,0XFA,0XA2,0X08,0X80,0X00,0X00,0X00,\r\n0X52,0X31,0XB1,0XAA,0XC8,0X00,0X00,0X00,0X0F,0XFF,0XFD,0XB6,0X00,0X00,0X00,0X00,\r\n0X0D,0XCC,0X4C,0X54,0X34,0X00,0X00,0X00,0X0F,0XFF,0XEE,0XEB,0X80,0X00,0X00,0X00,\r\n0XE2,0X33,0X33,0X2B,0XC3,0X00,0X00,0X00,0X0F,0XFF,0XB3,0X14,0X00,0X00,0X00,0X00,\r\n0X1C,0XCC,0XCC,0XC4,0X38,0X00,0X00,0X00,0X0F,0XFF,0XDA,0XEB,0X00,0X00,0X00,0X00,\r\n0X43,0X33,0X33,0X3B,0X44,0X00,0X00,0X00,0X0F,0XFF,0XED,0X34,0X00,0X00,0X00,0X00,\r\n0XB4,0XCC,0XCC,0XC4,0XAA,0X00,0X00,0X00,0X0F,0XFF,0XF6,0XCA,0X00,0X00,0X00,0X00,\r\n0X0B,0X33,0X33,0X33,0X51,0X00,0X00,0X00,0X0F,0XFF,0XEA,0XB5,0X80,0X00,0X00,0X00,\r\n0XF0,0XCC,0XCC,0XCC,0XAC,0X80,0X00,0X00,0X0F,0XFF,0XFD,0X48,0X00,0X00,0X00,0X00,\r\n0X0F,0X33,0X33,0X33,0X12,0X00,0X00,0X00,0X0F,0XFF,0XEE,0XB6,0XC0,0X00,0X00,0X00,\r\n0X50,0XCC,0XCC,0XCC,0XE8,0X80,0X00,0X00,0X0F,0XFB,0XFD,0X40,0X00,0X00,0X00,0X00,\r\n0XAB,0X33,0X33,0X33,0X16,0X00,0X00,0X00,0X0F,0XFC,0XD6,0XBB,0X00,0X00,0X00,0X00,\r\n0X14,0XCC,0XCC,0XCC,0XC9,0X00,0X00,0X00,0X0F,0XFF,0XBB,0X44,0X80,0X00,0X00,0X00,\r\n0XCA,0X32,0X33,0X33,0X32,0X80,0X00,0X00,0X0F,0XFF,0XE5,0XB0,0X00,0X00,0X00,0X00,\r\n0X35,0XCD,0XCC,0XCC,0XCC,0X40,0X00,0X00,0X0F,0XFF,0XFE,0X48,0X00,0X00,0X00,0X00,\r\n0X82,0X32,0X33,0X33,0X33,0X00,0X00,0X00,0X0F,0XFF,0XF3,0XB6,0X00,0X00,0X00,0X00,\r\n0X7C,0XCD,0XCC,0XCC,0XCC,0X80,0X00,0X00,0X0F,0XFF,0XFF,0X40,0X00,0X00,0X00,0X00,\r\n0X83,0X22,0X33,0X33,0X32,0X40,0X00,0X00,0X0F,0XFF,0XFD,0X1A,0X00,0X00,0X00,0X00,\r\n0X2C,0XDD,0XCC,0XCC,0XCD,0X00,0X00,0X00,0X0F,0XFF,0XE4,0XE4,0X00,0X00,0X00,0X00,\r\n0XD3,0X22,0X33,0X33,0X32,0X80,0X00,0X00,0X0F,0XFF,0XDA,0X12,0X00,0X00,0X00,0X00,\r\n0X28,0XD9,0XCC,0XCC,0XCC,0X40,0X00,0X00,0X0F,0XFF,0XAB,0XA8,0X00,0X00,0X00,0X00,\r\n0X97,0X26,0X23,0X33,0X33,0X20,0X00,0X00,0X0F,0XFC,0XFC,0XD4,0X00,0X00,0X00,0X00,\r\n0X48,0XD9,0XDC,0XCC,0XCC,0X80,0X00,0X00,0X0F,0XFF,0XFF,0X4A,0X00,0X00,0X00,0X00,\r\n0XB7,0X26,0X23,0X33,0X33,0X40,0X00,0X00,0X07,0XFF,0XF3,0X21,0X00,0X00,0X00,0X00,\r\n0X00,0XD9,0XDC,0XCC,0XCC,0X20,0X00,0X00,0X0F,0XFF,0XFC,0XBC,0X00,0X00,0X00,0X00,\r\n0XFF,0X26,0X23,0X33,0X33,0X90,0X00,0X00,0X0B,0XFF,0XC2,0XC1,0X00,0X00,0X00,0X00,\r\n0X00,0XD9,0XDC,0XCC,0XCC,0X48,0X00,0X00,0X0F,0XFF,0XFF,0X5C,0X00,0X00,0X00,0X00,\r\n0XB7,0X26,0X23,0X33,0X33,0X23,0X00,0X00,0X0F,0XFF,0XEB,0XA0,0X00,0X00,0X00,0X00,\r\n0X48,0XD9,0XDC,0XCC,0XCC,0XD0,0X00,0X00,0X03,0XFF,0X15,0X5A,0X00,0X00,0X00,0X00,\r\n0XB7,0X26,0X23,0X33,0X33,0X0C,0X80,0X00,0X0F,0XFF,0XEA,0X84,0X00,0X00,0X00,0X00,\r\n0X00,0X99,0XDC,0XCC,0XCC,0XE2,0X40,0X00,0X0F,0XFF,0X3B,0X7A,0X00,0X00,0X00,0X00,\r\n0XFF,0X66,0X23,0X33,0X33,0X19,0X00,0X00,0X03,0XFE,0XDE,0X84,0X00,0X00,0X00,0X00,\r\n0X00,0X99,0XDC,0XCC,0XCC,0XC4,0XB0,0X00,0X0F,0XFF,0XEB,0XFB,0X00,0X00,0X00,0X00,\r\n0XB7,0X66,0X23,0X33,0X33,0X33,0X40,0X00,0X0F,0XFF,0XF4,0X10,0X00,0X00,0X00,0X00,\r\n0X48,0X99,0XDC,0XCC,0XCC,0XCC,0X00,0X00,0X03,0XFF,0XFB,0XCC,0X00,0X00,0X00,0X00,\r\n0XB6,0X66,0X23,0X33,0X33,0X21,0XB0,0X00,0X0F,0XFF,0XDC,0XA3,0X00,0X00,0X00,0X00,\r\n0X01,0X99,0XDC,0XCC,0XCC,0XDE,0X40,0X00,0X0F,0XFA,0XF7,0X7C,0X00,0X00,0X00,0X00,\r\n0XFE,0X66,0X23,0X33,0X33,0X21,0X10,0X00,0X07,0XFF,0X3D,0X90,0X00,0X00,0X00,0X00,\r\n0X01,0X99,0XDC,0XCC,0XCC,0XCC,0XC8,0X00,0X0B,0XFF,0XCF,0XC5,0X00,0X00,0X00,0X00,\r\n0XB6,0X66,0X23,0X33,0X33,0X32,0X24,0X00,0X0F,0XFF,0XF1,0X40,0X00,0X00,0X00,0X00,\r\n0X49,0X99,0XDC,0XCC,0XCC,0XC5,0X90,0X00,0X07,0XFF,0X2E,0X20,0X00,0X00,0X00,0X00,\r\n0XB4,0X66,0X23,0X33,0X33,0X3A,0X4A,0X00,0X0F,0XFE,0XF9,0XC0,0X00,0X00,0X00,0X00,\r\n0X0B,0X99,0XDC,0XCC,0XCC,0XC4,0XA4,0X00,0X17,0XFF,0XBF,0X24,0X00,0X00,0X00,0X00,\r\n0XE4,0X66,0X23,0X33,0X33,0X33,0X11,0X00,0X0F,0XFF,0XC4,0XB8,0X00,0X00,0X00,0X00,\r\n0X1B,0X99,0XDC,0XCC,0XCC,0XC8,0XC4,0X00,0X07,0XFF,0XFA,0X80,0X00,0X00,0X00,0X00,\r\n0XA4,0X66,0X23,0X33,0X33,0X36,0X32,0X80,0X1F,0XFF,0XDA,0XFA,0X00,0X00,0X00,0X00,\r\n0X5B,0X99,0XDC,0XCC,0XCC,0XC9,0X48,0X20,0X03,0XFF,0X3F,0X40,0X00,0X00,0X00,0X00,\r\n0XA4,0X66,0X23,0X33,0X33,0X32,0X92,0XC8,0X0F,0XFF,0XFC,0XAE,0XC0,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCC,0X69,0X00,0X33,0XFD,0XF3,0XF1,0X00,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X33,0X04,0X34,0X8F,0XFF,0XDF,0X4C,0X60,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XC8,0XB2,0XC2,0X37,0XFF,0XED,0XF3,0X80,0X00,0X00,0X00,\r\n0XAC,0X66,0X23,0X33,0X33,0X37,0X49,0X18,0XCB,0XFF,0XF6,0X0C,0X40,0X00,0X00,0X00,\r\n0X53,0X99,0XDC,0XCC,0XCC,0XC8,0X24,0X43,0X3F,0XFF,0X2B,0XE3,0X20,0X00,0X00,0X00,\r\n0XAC,0X66,0X23,0X33,0X33,0X33,0X93,0X28,0XCF,0XFC,0XFD,0X18,0X80,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCC,0X6C,0XD2,0X33,0XFF,0XD2,0XA2,0X00,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X31,0X01,0X09,0XEF,0XFF,0X6F,0XDC,0X00,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCE,0XB4,0X64,0X3F,0XFD,0XFE,0XE3,0X80,0X00,0X00,0X00,\r\n0XAC,0X66,0X23,0X33,0X33,0X31,0X4B,0X12,0XFF,0XFA,0XFB,0X3C,0X40,0X00,0X00,0X00,\r\n0X53,0X99,0XDC,0XCC,0XCC,0XCC,0X24,0XCD,0X3F,0XFF,0XFF,0XD2,0X00,0X00,0X00,0X00,\r\n0XAC,0X66,0X23,0X33,0X33,0X33,0X91,0X20,0XFF,0XFF,0XFC,0XAF,0XC0,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCC,0X4C,0X56,0X3F,0XFF,0XBB,0XF5,0X00,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X31,0X33,0X09,0XFF,0XFF,0XFF,0XFC,0X30,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCE,0XC8,0XE2,0X2F,0XFF,0XEF,0X02,0X40,0X00,0X00,0X00,\r\n0XAC,0X66,0X23,0X33,0X33,0X31,0X26,0X0C,0XF7,0XFF,0XFD,0XFA,0X80,0X00,0X00,0X00,\r\n0X53,0X99,0XDC,0XCC,0XCC,0XCC,0X90,0XB3,0X3F,0XFF,0XEA,0XAD,0X48,0X00,0X00,0X00,\r\n0XAC,0X66,0X23,0X33,0X33,0X32,0X4B,0X48,0XD7,0XFD,0XFD,0X52,0XB0,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCD,0X30,0X25,0X0D,0X40,0XFE,0XAD,0X40,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X32,0XCB,0X98,0X00,0X00,0XFB,0X52,0XA8,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCC,0X24,0X40,0X00,0X02,0X7D,0XCD,0X30,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X33,0X91,0X00,0X00,0X20,0X7E,0XEA,0XE8,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCC,0X4C,0X00,0X00,0X00,0X15,0X3F,0XB0,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X31,0X32,0X00,0X00,0X00,0X0E,0XD0,0X50,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCE,0XC8,0X00,0X00,0X00,0X0B,0X3D,0XF0,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X31,0X20,0X00,0X00,0X00,0X0C,0XCA,0X08,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCC,0X9C,0X00,0X00,0X00,0X03,0XE3,0XF0,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X33,0X40,0X00,0X00,0X00,0X00,0X7D,0X40,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCC,0XA8,0X00,0X00,0X00,0X00,0X00,0X70,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X32,0X50,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCD,0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X30,0X10,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XD0,0X00,0X00,0X00,0X00,0X00,0X35,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X30,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XC8,0X30,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X37,0X08,0X00,0X00,0X00,0X00,0X0C,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC8,0XA0,0X00,0X00,0X00,0X0C,0XB3,0X80,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X37,0X5C,0X00,0X00,0X00,0X3E,0XDC,0X40,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC8,0X80,0X00,0X00,0X00,0XCF,0XB7,0XB0,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X36,0X70,0X00,0X00,0X00,0XF3,0XDD,0X40,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC9,0X8C,0X00,0X00,0X23,0XFD,0X40,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X36,0X62,0X00,0X00,0X35,0X56,0XAB,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC9,0X19,0X00,0X00,0X02,0XBB,0XFC,0X20,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X36,0XA4,0X00,0X00,0X01,0XFF,0X10,0XC8,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC9,0X4B,0XA0,0X00,0X00,0X54,0XE3,0X20,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X36,0XB0,0X0C,0X3B,0X81,0XEB,0X0C,0XD0,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC9,0X0E,0XD2,0XCF,0XFC,0X7C,0X3F,0X48,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X36,0XE1,0X29,0X35,0XF1,0X10,0XD1,0X20,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC9,0X14,0X94,0X00,0X00,0X03,0X6F,0XD8,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X36,0XAB,0X40,0X00,0X00,0X03,0XD0,0X02,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC9,0X40,0X00,0X00,0X00,0X0D,0X6F,0XEC,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X36,0XBC,0X00,0X00,0X00,0X1A,0XDB,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC1,0X00,0X00,0X00,0X00,0X0F,0X2C,0XE0,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X26,0XD0,0X00,0X00,0X00,0X0D,0XF7,0X50,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC1,0X20,0X00,0X00,0X00,0X03,0X50,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X26,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC1,0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X20,0X40,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XC0,0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0X00,0X00,0X00,0X00,0X00,0X00,0X0D,0X70,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X20,0X80,0X00,0X00,0X00,0X00,0XBA,0X0C,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X00,0X00,0X00,0X00,0X02,0XED,0XF0,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0XA0,0X00,0X00,0X00,0X07,0X96,0X8C,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X40,0X00,0X00,0X00,0X04,0XFB,0X72,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0XA0,0X00,0X00,0X00,0X07,0X44,0XC4,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X00,0X00,0X00,0X00,0X0C,0XFB,0X35,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0XF0,0X00,0X01,0XA8,0X03,0X4D,0XD2,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X00,0X00,0X01,0X7F,0XBE,0XB2,0X00,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0XD0,0X00,0X00,0XF5,0XF3,0XCD,0XCF,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCF,0X28,0X00,0X03,0XFC,0X1E,0XB2,0X50,0X80,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X30,0XC0,0X00,0X00,0X00,0X0B,0X5F,0X2E,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCF,0X3C,0X00,0X00,0X00,0X1D,0XA0,0XB3,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0X82,0X80,0X00,0X00,0X0A,0XDF,0X4C,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X69,0X48,0X00,0X00,0X37,0X68,0XB3,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0X94,0X32,0X00,0XB2,0XBD,0XB7,0X4C,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCF,0X2B,0XCD,0X0D,0XFF,0XD6,0XC8,0XB2,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X30,0XC4,0X20,0XD6,0XCC,0XEB,0X3F,0X4C,0X80,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCF,0X32,0X97,0X2B,0XB3,0X3D,0XC5,0XB3,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0X89,0X48,0XD4,0XFF,0XD6,0X7A,0XCC,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X64,0XB2,0X2F,0X6C,0XEB,0XAD,0X32,0X80,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0X1A,0X4C,0XD2,0XB3,0X3D,0X56,0XCC,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCF,0XC1,0X13,0X2D,0XDE,0XD6,0XFB,0X32,0X00,0X00,0X00,\r\n0XEC,0X66,0X23,0X33,0X33,0X30,0X2C,0XC8,0XD7,0X7B,0XAB,0X4D,0XCC,0X00,0X00,0X00,\r\n0X13,0X99,0XDC,0XCC,0XCC,0XCF,0X53,0X26,0X28,0XCC,0XFD,0XB2,0X32,0X80,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0X88,0X91,0XD7,0X77,0X56,0XDD,0XCD,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X66,0X6C,0X2D,0XBD,0XBB,0X62,0X30,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0X11,0X02,0X92,0XD6,0XCD,0XBF,0X8E,0X80,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0XCA,0XB5,0X6F,0X6B,0X76,0XC8,0XE1,0X00,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X30,0X24,0X48,0X91,0XBC,0XBB,0X37,0X1C,0X00,0X00,0X00,\r\n0X73,0X99,0XDC,0XCC,0XCC,0XCF,0X53,0X26,0X2E,0XD7,0XCD,0XEC,0XE3,0X00,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X30,0XA8,0X91,0XD3,0X6A,0X72,0X93,0X1C,0X80,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X06,0X4C,0X2D,0XBD,0XDD,0X6C,0XE2,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0XF0,0XB2,0XD2,0XD7,0X37,0XBB,0X1D,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X0B,0X04,0X2F,0X6C,0XD8,0XC4,0XE0,0X00,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X30,0X54,0XDB,0X51,0XB3,0X6F,0X3B,0X1E,0X00,0X00,0X00,\r\n0X73,0X99,0XDC,0XCC,0XCC,0XCF,0XA2,0X20,0XAE,0XDD,0XB5,0XEC,0XE1,0X00,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X30,0X59,0X8D,0X13,0X76,0XDA,0X13,0X1E,0X80,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X04,0X32,0XEC,0XDB,0X2F,0XFE,0XE1,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0XF2,0XC8,0X13,0X2C,0XF1,0X41,0X14,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X09,0X27,0X6D,0XF7,0X8E,0XBF,0XEB,0X00,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X30,0XD6,0X90,0X92,0XDA,0X75,0X50,0X10,0X00,0X00,0X00,\r\n0X73,0X99,0XDC,0XCC,0XCC,0XCF,0X20,0X4A,0X6F,0X2D,0XDB,0XAF,0XE8,0X00,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X30,0XDB,0X25,0X10,0XF7,0X34,0XF4,0X14,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X04,0X92,0XAF,0XB8,0XCF,0X0B,0XE0,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X30,0XF1,0X28,0X52,0XCF,0X72,0XF5,0X1A,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCF,0X0E,0X93,0X2D,0X7A,0X9D,0X5A,0XE4,0X80,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X30,0XD0,0X4C,0X92,0XAF,0XEA,0XA5,0X00,0X00,0X00,0X00,\r\n0X73,0X99,0XDC,0XCC,0XCC,0XCF,0X2B,0X21,0X6F,0XD2,0X57,0X5A,0XF3,0X00,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X30,0XC4,0X94,0X10,0X7D,0XB9,0XAD,0X0C,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCE,0X3A,0X49,0XAF,0XD3,0X4E,0XF3,0X71,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X31,0X81,0XB0,0X51,0X2C,0XF5,0X0C,0X8A,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCE,0X6C,0X00,0X00,0XFB,0X2B,0XF7,0X74,0X80,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X31,0X92,0XC0,0X00,0X4E,0XD4,0X28,0X8B,0X00,0X00,0X00,\r\n0X73,0X99,0XDC,0XCC,0XCC,0XCC,0X29,0X20,0X00,0X73,0X7F,0XD7,0X70,0X00,0X00,0X00,\r\n0X8C,0X66,0X23,0X33,0X33,0X33,0XC4,0X40,0X00,0X5D,0X01,0X28,0X88,0X00,0X00,0X00,\r\n0X33,0X99,0XDC,0XCC,0XCC,0XCC,0X33,0X30,0X00,0XB0,0X00,0X17,0X72,0X00,0X00,0X00,\r\n0XCC,0X66,0X23,0X33,0X33,0X32,0X8C,0X80,0X01,0X50,0X00,0X28,0X89,0X00,0X00,0X00,\r\n0X33,0X19,0XDC,0XCC,0XCC,0XCD,0X62,0X50,0X06,0XC0,0X00,0X17,0X64,0X00,0X00,0X00,\r\n0X8C,0XE6,0X23,0X33,0X33,0X32,0X99,0X00,0X01,0X40,0X00,0X00,0X12,0X00,0X00,0X00,\r\n0X73,0X19,0XDC,0XCC,0XCC,0XCC,0X44,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X8C,0XE6,0X23,0X33,0X33,0X33,0X31,0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X19,0XDC,0XCC,0XCC,0XCC,0XC0,0X40,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XC4,0XE6,0X23,0X33,0X33,0X33,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X3B,0X19,0XDC,0XCC,0XCC,0XCC,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X84,0XE6,0X23,0X33,0X33,0X32,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X73,0X19,0XDC,0XCC,0XCC,0XCD,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X8C,0XC6,0X23,0X33,0X33,0X32,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X33,0X39,0XDC,0XCC,0XCC,0XCC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XC4,0XC6,0X23,0X33,0X33,0X33,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X20,0X00,0X00,\r\n0X3B,0X39,0XDC,0XCC,0XCC,0XCC,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X80,0X00,0X00,\r\n0X84,0XC6,0X23,0X33,0X33,0X32,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0X40,0X00,0X00,\r\n0X73,0X39,0XDC,0XCC,0XCC,0XCD,0X00,0X00,0X00,0X00,0X00,0X00,0X0C,0X20,0X00,0X00,\r\n0X8C,0XC6,0X23,0X33,0X33,0X32,0X80,0X00,0X00,0X00,0X00,0X01,0X43,0X00,0X00,0X00,\r\n0X33,0X39,0X9C,0XCC,0XCC,0XCC,0X00,0X00,0X00,0X00,0X00,0X06,0XBC,0X00,0X00,0X00,\r\n0XCC,0XC6,0X63,0X33,0X33,0X33,0XA0,0X00,0X00,0X00,0X00,0X19,0X43,0X00,0X00,0X00,\r\n0X32,0X39,0X9C,0XCC,0XCC,0XCC,0X50,0X00,0X00,0X00,0X00,0X06,0XBC,0X80,0X00,0X00,\r\n0X8D,0XC6,0X43,0X33,0X33,0X32,0XAB,0X20,0X00,0X80,0X00,0X19,0X43,0X00,0X00,0X00,\r\n0X52,0X39,0XBC,0XCC,0XCC,0XCD,0X10,0X80,0X00,0X00,0X00,0X06,0XBC,0X80,0X00,0X00,\r\n0XAC,0XC6,0X42,0X33,0X33,0X32,0XCA,0X40,0X00,0X00,0X00,0X19,0X43,0X00,0X00,0X00,\r\n0X13,0X39,0XBD,0XCC,0XCC,0XCC,0X25,0X20,0X00,0X03,0X1D,0X66,0XBC,0XC0,0X00,0X00,\r\n0XCC,0XC6,0X42,0X33,0X33,0X33,0XD0,0X10,0X00,0X00,0XE1,0X99,0X43,0X00,0X00,0X00,\r\n0X33,0X31,0XBD,0XCC,0XCC,0XCC,0X0A,0XC0,0X00,0X00,0X04,0X66,0XA8,0X00,0X00,0X00,\r\n0X88,0XCE,0X42,0X33,0X33,0X31,0X65,0X10,0X08,0X00,0X01,0XB9,0X53,0XC0,0X00,0X00,\r\n0X57,0X31,0XB9,0X8C,0XCC,0XCE,0X90,0X4B,0X27,0X80,0X00,0X46,0X80,0X00,0X00,0X00,\r\n0XA8,0XCC,0X46,0X73,0X33,0X31,0X4D,0X24,0XD8,0X7A,0XF3,0XB9,0X6B,0X00,0X00,0X00,\r\n0X13,0X33,0XB9,0X8C,0XCC,0XCC,0X30,0X90,0X07,0XAD,0X0C,0X46,0X90,0X80,0X00,0X00,\r\n0XCC,0XCC,0X46,0X73,0X33,0X33,0XC4,0X43,0X38,0X56,0XF3,0XB9,0X6B,0X00,0X00,0X00,\r\n0X33,0X33,0X31,0X8C,0XCC,0XCC,0X1B,0X2C,0XC7,0XA9,0X0D,0X46,0X84,0X40,0X00,0X00,\r\n0X88,0XCC,0XCC,0X73,0X33,0X31,0X60,0X90,0X18,0XF6,0XF2,0XB9,0X71,0X00,0X00,0X00,\r\n0X57,0X33,0X33,0X0C,0XCC,0XCE,0X8A,0X43,0X47,0X1B,0X0D,0X46,0X80,0X00,0X00,0X00,\r\n0XA8,0XCC,0XCC,0XD3,0X33,0X31,0X35,0X2C,0X28,0XE4,0XF2,0XB9,0X50,0X00,0X00,0X00,\r\n0X13,0X33,0X33,0X2C,0XCC,0XCC,0XC8,0X81,0X57,0X3B,0X0D,0X46,0XA8,0X00,0X00,0X00,\r\n0XCC,0XCC,0XCC,0XD3,0X33,0X33,0X22,0X34,0X08,0XCC,0XF2,0XB9,0X54,0X00,0X00,0X00,\r\n0X31,0X33,0X33,0X2C,0XCC,0XCC,0X9C,0XC0,0X37,0X73,0X4D,0X46,0XA0,0X00,0X00,0X00,\r\n0X8E,0XCC,0XCC,0X93,0X33,0X31,0X43,0X00,0X00,0X1D,0X72,0XB9,0X5A,0X80,0X00,0X00,\r\n0X61,0X33,0X33,0X6C,0XC8,0XCE,0XA8,0X00,0X00,0X01,0X0D,0X46,0XA4,0X00,0X00,0X00,\r\n0X1C,0XCC,0XCC,0X93,0X37,0X30,0X52,0X00,0X00,0X00,0X06,0XB9,0X53,0X00,0X00,0X00,\r\n0XA3,0X33,0X32,0X4C,0XC8,0XCF,0X0C,0X00,0X00,0X00,0X01,0X46,0XA8,0X80,0X00,0X00,\r\n0X4C,0XCC,0XCD,0XB3,0X37,0X30,0XE0,0X00,0X00,0X00,0X06,0XB9,0X53,0X40,0X00,0X00,\r\n0X32,0X31,0X32,0X4C,0XC0,0XCB,0X18,0X00,0X00,0X70,0X12,0XC6,0XAC,0X00,0X00,0X00,\r\n0X85,0X8E,0XCD,0XA3,0X3F,0X34,0X40,0X00,0X00,0X00,0X03,0X39,0X51,0X00,0X00,0X00,\r\n0X7A,0X71,0X10,0X58,0XC0,0X8B,0XA8,0X00,0X00,0X00,0X05,0XC6,0XAC,0X80,0X00,0X00,\r\n0X04,0X8C,0XEF,0X27,0X37,0X70,0X10,0X00,0X00,0X00,0X00,0X79,0X52,0X00,0X00,0X00,\r\n0XB3,0X33,0X10,0XD8,0X88,0X8F,0XC0,0X00,0X00,0X00,0X00,0X16,0XAD,0X00,0X00,0X00,\r\n0X4C,0XCC,0XCF,0X07,0X77,0X30,0X30,0X00,0X00,0X00,0X00,0X01,0X00,0X00,0X00,0X00,\r\n0X23,0X31,0X30,0XF0,0X80,0XCD,0X40,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X98,0XCE,0XCB,0X0D,0X3B,0X20,0X10,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X66,0X11,0X14,0XB2,0XC4,0X50,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X09,0XEC,0XEB,0X4D,0X3B,0XA0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XB2,0X13,0X10,0XB2,0XC4,0X40,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X4C,0XCC,0XCF,0X04,0X12,0XA0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X23,0X31,0X30,0XFB,0XED,0X40,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X94,0XCE,0XCD,0X04,0X12,0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X6A,0X11,0X22,0XB2,0XC9,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X05,0XEA,0X5D,0X4D,0X36,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XB2,0X15,0XA0,0XB2,0XC9,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X4C,0XCA,0X4F,0X0C,0X24,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X23,0X31,0X30,0XE3,0XDA,0XB8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X94,0XCE,0XCD,0X18,0X25,0X46,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X6A,0X11,0X12,0XA6,0X92,0XB1,0X30,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0X05,0XEA,0XE9,0X59,0X6D,0X0A,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,\r\n0XB0,0X14,0X16,0X82,0X90,0XF4,0X68,0X00,0X00,0X00,0X00,0X00,0X0A,0X00,0X00,0X00,\r\n0X4E,0XCB,0XC8,0X7C,0X4F,0X0B,0X10,0X00,0X00,0X00,0X00,0X00,0X20,0X00,0X00,0X00,\r\n0X21,0X34,0X37,0X83,0XA0,0X50,0XA0,0X00,0X00,0X00,0X00,0X00,0X0A,0X00,0X00,0X00,\r\n0X9A,0XC3,0X40,0X54,0X5B,0XAF,0X48,0X00,0X00,0X00,0X00,0X03,0XA4,0X00,0X00,0X00,\r\n0X44,0X3C,0XBD,0X2B,0X24,0X50,0X20,0X00,0X00,0X60,0X0A,0X3C,0X40,0X00,0X00,0X00,\r\n0X33,0X81,0X02,0XD0,0XCB,0X05,0X90,0X00,0X00,0X00,0X0B,0X81,0X00,0X00,0X00,0X00,\r\n0X88,0X6E,0XED,0X0E,0X30,0XFA,0X48,0X00,0X00,0X00,0X04,0X68,0X00,0X00,0X00,0X00,\r\n0X56,0X91,0X10,0XF1,0X8E,0X05,0X12,0X00,0X00,0X00,0X01,0X94,0X00,0X00,0X00,0X00,\r\n0X21,0X2C,0XAE,0X0A,0X51,0XD0,0XCC,0X00,0X20,0X00,0X01,0X41,0X00,0X00,0X00,0X00,\r\n0X9A,0XC3,0X41,0XD4,0XAA,0X2F,0X20,0XC0,0X0A,0X00,0X00,0X28,0X00,0X00,0X00,0X00,\r\n0X44,0X38,0X3A,0X2B,0X55,0X40,0X4B,0X10,0X31,0XB0,0X6D,0X54,0X00,0X00,0X00,0X00,\r\n0X33,0X47,0XC4,0XD0,0X00,0XBD,0X24,0X02,0X4E,0X4A,0X92,0X00,0X00,0X00,0X00,0X00,\r\n0X88,0XA8,0X2B,0X0F,0XFF,0X02,0X90,0XC8,0X01,0XB5,0X6D,0XCB,0X00,0X00,0X00,0X00,\r\n0X57,0X12,0X90,0XE0,0X00,0XEC,0X4B,0X22,0X96,0X4A,0X92,0X30,0X00,0X00,0X00,0X00,\r\n0X20,0XED,0X6E,0X15,0X55,0X13,0X14,0X08,0X09,0XB5,0X6D,0X40,0X00,0X00,0X00,0X00,\r\n0X9A,0X12,0X91,0XAA,0XAA,0XA8,0XC0,0XA2,0XA6,0X4A,0X90,0X88,0X00,0X00,0X00,0X00,\r\n0X45,0X44,0X44,0X55,0X55,0X56,0X2A,0X08,0X49,0XB5,0X6F,0X70,0X00,0X00,0X00,0X00,\r\n0X2A,0XBB,0X3B,0X00,0X00,0X01,0X40,0XA2,0X15,0X4A,0X90,0X00,0X00,0X00,0X00,0X00,\r\n0X91,0X04,0XC4,0XFF,0XFF,0XFC,0XAA,0X09,0X44,0XB5,0X6A,0XC0,0X00,0X00,0X00,0X00,\r\n0X4C,0XF3,0X33,0X00,0X00,0X03,0X00,0XA0,0X13,0X4A,0X95,0X20,0X00,0X00,0X00,0X00,\r\n0X22,0X08,0X88,0XAA,0XAA,0XA8,0XAA,0X08,0X0A,0XB5,0X6A,0X88,0X00,0X00,0X00,0X00,\r\n};\r\n"
  },
  {
    "path": "main/img_hacking.c",
    "content": "#include <stdint.h>\n\n/*\n * original image found on https://www.flickr.com/photos/adulau/9464930917/\n * (Alexandre Dulaunoy)\n *\n * \"Feel free to reuse, use and abuse my pictures under the CC-SA license,\n *  the GNU Free Documentation License or the GNU General Public License.\"\n *\n * image is cropped and resized to 296x128 pixels.\n */\n\nconst uint8_t img_hacking[37888] = {\n    0x83,0x8e,0x85,0x78,0x69,0x5f,0x4c,0x3e,0x33,0x37,0x3c,0x41,0x40,0x43,0x52,0x5e,\n    0x6b,0x75,0x77,0x72,0x6c,0x6b,0x6d,0x75,0x89,0x90,0x8f,0x8d,0x7c,0x7d,0x7c,0x74,\n    0x6b,0x61,0x5b,0x59,0x5a,0x5d,0x5e,0x5d,0x5c,0x5b,0x58,0x58,0x5a,0x5d,0x5d,0x5f,\n    0x60,0x60,0x5f,0x66,0x70,0x72,0x6e,0x69,0x62,0x57,0x4e,0x4f,0x53,0x5a,0x5f,0x6d,\n    0x8d,0xa7,0xad,0xa9,0xa0,0x8e,0x65,0x3f,0x32,0x2e,0x2d,0x2d,0x30,0x33,0x36,0x3c,\n    0x3c,0x3b,0x3a,0x38,0x3a,0x3e,0x43,0x46,0x46,0x47,0x49,0x4c,0x4e,0x4d,0x4f,0x4c,\n    0x48,0x44,0x42,0x43,0x41,0x3d,0x3b,0x38,0x33,0x2f,0x34,0x39,0x3d,0x44,0x44,0x3b,\n    0x31,0x2f,0x2d,0x34,0x3c,0x3c,0x3a,0x37,0x2e,0x26,0x28,0x2b,0x30,0x3a,0x43,0x49,\n    0x88,0x8d,0x86,0x78,0x6a,0x62,0x50,0x3d,0x31,0x32,0x3b,0x3e,0x43,0x41,0x44,0x51,\n    0x5d,0x69,0x72,0x75,0x76,0x71,0x71,0x80,0x97,0x9c,0x99,0x93,0x7f,0x7f,0x7e,0x74,\n    0x6a,0x60,0x58,0x5a,0x5e,0x61,0x63,0x65,0x63,0x62,0x60,0x5f,0x5f,0x62,0x63,0x65,\n    0x65,0x65,0x62,0x62,0x68,0x71,0x72,0x6c,0x65,0x5e,0x55,0x52,0x56,0x5b,0x61,0x6d,\n    0x78,0x8f,0xac,0xb0,0xab,0x9e,0x87,0x59,0x37,0x2e,0x31,0x2e,0x2f,0x34,0x36,0x3c,\n    0x3f,0x40,0x3f,0x3e,0x3e,0x42,0x47,0x49,0x4b,0x4c,0x4c,0x4d,0x4d,0x50,0x4f,0x4d,\n    0x4b,0x47,0x45,0x42,0x3f,0x3d,0x3c,0x38,0x32,0x31,0x32,0x35,0x37,0x39,0x39,0x33,\n    0x2e,0x30,0x34,0x39,0x3d,0x3c,0x36,0x2e,0x2a,0x27,0x25,0x2d,0x35,0x3b,0x3f,0x4a,\n    0x86,0x89,0x84,0x76,0x6b,0x65,0x50,0x3f,0x30,0x2f,0x38,0x3c,0x41,0x44,0x40,0x42,\n    0x4f,0x5a,0x67,0x72,0x77,0x7a,0x75,0x7e,0x9e,0x9d,0x99,0x92,0x7f,0x7e,0x7b,0x72,\n    0x64,0x5d,0x58,0x59,0x5d,0x63,0x67,0x69,0x68,0x67,0x66,0x65,0x64,0x66,0x67,0x68,\n    0x68,0x68,0x66,0x67,0x66,0x69,0x72,0x73,0x71,0x6a,0x5a,0x54,0x59,0x5d,0x65,0x6b,\n    0x7a,0x86,0x9a,0xaf,0xb1,0xa8,0x97,0x7e,0x4d,0x38,0x36,0x37,0x37,0x39,0x3b,0x40,\n    0x43,0x45,0x42,0x42,0x43,0x48,0x4b,0x4c,0x4b,0x4a,0x47,0x48,0x4a,0x4c,0x4b,0x4d,\n    0x50,0x48,0x42,0x3c,0x38,0x35,0x34,0x31,0x2d,0x2b,0x2e,0x2f,0x32,0x32,0x33,0x31,\n    0x30,0x33,0x38,0x3e,0x3d,0x3b,0x38,0x32,0x2f,0x2c,0x29,0x2f,0x38,0x3d,0x42,0x49,\n    0x80,0x89,0x85,0x79,0x75,0x68,0x53,0x3c,0x31,0x30,0x35,0x3a,0x40,0x42,0x40,0x40,\n    0x43,0x4f,0x5c,0x6c,0x75,0x78,0x76,0x7f,0x94,0x92,0x90,0x8b,0x7d,0x7b,0x77,0x6f,\n    0x69,0x5e,0x5a,0x58,0x5e,0x63,0x67,0x6c,0x6e,0x6d,0x6a,0x6b,0x6a,0x6b,0x6c,0x6c,\n    0x6d,0x6d,0x6b,0x6b,0x69,0x69,0x74,0x7c,0x7b,0x73,0x6d,0x5b,0x5b,0x60,0x66,0x72,\n    0x80,0x89,0x90,0xa2,0xb2,0xaf,0xa6,0x92,0x70,0x45,0x3d,0x3f,0x3f,0x41,0x43,0x49,\n    0x48,0x4a,0x48,0x47,0x48,0x4b,0x4b,0x4a,0x49,0x49,0x45,0x45,0x44,0x49,0x4a,0x4a,\n    0x4d,0x4a,0x40,0x36,0x30,0x2a,0x27,0x24,0x23,0x24,0x28,0x2d,0x32,0x34,0x30,0x33,\n    0x37,0x3b,0x41,0x47,0x48,0x49,0x47,0x44,0x41,0x3f,0x3e,0x3f,0x41,0x41,0x46,0x4a,\n    0x85,0x8b,0x82,0x7b,0x73,0x65,0x4d,0x38,0x30,0x30,0x33,0x37,0x3d,0x41,0x3f,0x40,\n    0x3f,0x45,0x52,0x62,0x6e,0x72,0x75,0x79,0x88,0x8a,0x8a,0x83,0x7d,0x7c,0x77,0x73,\n    0x6f,0x63,0x5e,0x5b,0x5b,0x5f,0x6a,0x7d,0x86,0x80,0x73,0x70,0x6f,0x6f,0x6e,0x6e,\n    0x70,0x70,0x6d,0x6d,0x6e,0x6d,0x78,0x83,0x7c,0x76,0x72,0x64,0x5e,0x62,0x6a,0x76,\n    0x83,0x8f,0x95,0x97,0xac,0xb4,0xae,0x9e,0x86,0x5d,0x45,0x46,0x47,0x47,0x48,0x4d,\n    0x4b,0x4b,0x4b,0x4b,0x4d,0x4c,0x4c,0x4a,0x48,0x48,0x46,0x44,0x43,0x45,0x48,0x4a,\n    0x48,0x44,0x3b,0x2f,0x26,0x20,0x1d,0x1b,0x1f,0x27,0x2f,0x34,0x38,0x38,0x38,0x35,\n    0x37,0x3a,0x3f,0x43,0x46,0x45,0x47,0x4b,0x4c,0x4b,0x4a,0x48,0x48,0x48,0x4b,0x4d,\n    0x89,0x8b,0x87,0x7f,0x77,0x66,0x50,0x39,0x30,0x2f,0x33,0x37,0x39,0x3e,0x40,0x3b,\n    0x3f,0x44,0x4a,0x52,0x5f,0x68,0x71,0x75,0x7e,0x8d,0x94,0x8f,0x82,0x7d,0x7b,0x7a,\n    0x75,0x6c,0x65,0x5d,0x58,0x62,0x86,0x9e,0xa6,0xa8,0x98,0x7b,0x72,0x70,0x6f,0x6f,\n    0x6f,0x70,0x6f,0x6e,0x6f,0x70,0x71,0x84,0x80,0x7a,0x76,0x6d,0x67,0x67,0x6f,0x7c,\n    0x89,0x94,0x97,0x96,0xa1,0xb4,0xaf,0xa3,0x8e,0x71,0x4a,0x47,0x4b,0x4b,0x4d,0x51,\n    0x51,0x4f,0x4c,0x4d,0x4e,0x4e,0x4d,0x4d,0x49,0x47,0x48,0x49,0x48,0x48,0x48,0x4c,\n    0x4c,0x4a,0x41,0x36,0x2f,0x26,0x23,0x26,0x2d,0x32,0x35,0x38,0x37,0x35,0x35,0x34,\n    0x36,0x39,0x3a,0x3a,0x3a,0x3b,0x43,0x4c,0x4f,0x4f,0x4b,0x45,0x45,0x49,0x4c,0x4d,\n    0x82,0x83,0x86,0x83,0x7b,0x6d,0x53,0x3d,0x31,0x30,0x2f,0x33,0x36,0x3c,0x3d,0x3e,\n    0x3e,0x3f,0x43,0x43,0x4c,0x5c,0x66,0x6e,0x8f,0xa9,0xa5,0xa2,0x8a,0x7f,0x80,0x80,\n    0x7d,0x75,0x68,0x5f,0x59,0x6d,0x92,0x9e,0xa1,0xa2,0x93,0x7d,0x6e,0x6a,0x6a,0x6a,\n    0x68,0x69,0x68,0x68,0x69,0x6d,0x6d,0x71,0x76,0x78,0x76,0x70,0x6e,0x6f,0x73,0x81,\n    0x8d,0x95,0x9a,0x9a,0x9a,0xa7,0xb3,0xab,0x9e,0x8c,0x6b,0x5d,0x55,0x4f,0x4f,0x53,\n    0x52,0x4e,0x4e,0x4e,0x4f,0x4e,0x4e,0x4b,0x4b,0x48,0x4a,0x4c,0x49,0x47,0x48,0x47,\n    0x47,0x47,0x42,0x3b,0x39,0x37,0x36,0x38,0x3e,0x3e,0x3b,0x37,0x37,0x34,0x31,0x30,\n    0x34,0x35,0x33,0x31,0x2e,0x36,0x3f,0x47,0x46,0x43,0x3d,0x38,0x37,0x38,0x3f,0x43,\n    0x74,0x7b,0x83,0x85,0x80,0x72,0x59,0x3e,0x32,0x32,0x31,0x33,0x35,0x39,0x3d,0x3d,\n    0x3c,0x3e,0x3d,0x3f,0x41,0x49,0x56,0x67,0x9b,0xa8,0xab,0xa8,0x93,0x86,0x85,0x84,\n    0x83,0x76,0x69,0x60,0x59,0x62,0x85,0x9a,0x99,0x8d,0x7c,0x6b,0x63,0x60,0x5f,0x5e,\n    0x5e,0x5d,0x5f,0x60,0x62,0x64,0x65,0x69,0x6d,0x75,0x78,0x77,0x77,0x78,0x7c,0x87,\n    0x91,0x97,0x9c,0x9d,0x9a,0xa1,0xb3,0xb4,0xb2,0xb7,0xb1,0x97,0x7a,0x5f,0x54,0x52,\n    0x50,0x4f,0x4d,0x4e,0x4f,0x4e,0x4e,0x4b,0x4b,0x48,0x4a,0x4b,0x48,0x44,0x46,0x44,\n    0x42,0x45,0x42,0x3e,0x3e,0x3c,0x3b,0x3c,0x41,0x3f,0x3e,0x3e,0x36,0x31,0x2c,0x2b,\n    0x2b,0x2b,0x29,0x27,0x2b,0x35,0x3d,0x45,0x44,0x3c,0x32,0x2e,0x2c,0x34,0x3a,0x3b,\n    0x68,0x78,0x82,0x83,0x7c,0x71,0x5b,0x3d,0x2e,0x31,0x31,0x30,0x32,0x36,0x3c,0x3f,\n    0x39,0x3b,0x3a,0x3c,0x3f,0x3f,0x42,0x54,0x8f,0x9b,0xa2,0x9f,0x98,0x93,0x8e,0x87,\n    0x7f,0x71,0x67,0x5e,0x56,0x54,0x57,0x62,0x66,0x63,0x5c,0x55,0x55,0x54,0x55,0x54,\n    0x54,0x54,0x57,0x59,0x5b,0x5e,0x5f,0x63,0x69,0x73,0x78,0x7c,0x7e,0x80,0x84,0x8b,\n    0x95,0x98,0x9d,0x9b,0x9d,0x9d,0xb2,0xb8,0xc2,0xd1,0xcb,0xb7,0x9f,0x75,0x53,0x4f,\n    0x4e,0x4d,0x4c,0x4c,0x4e,0x4e,0x4a,0x49,0x4b,0x48,0x49,0x4b,0x47,0x43,0x45,0x45,\n    0x46,0x45,0x46,0x45,0x41,0x3f,0x3e,0x3e,0x3c,0x3b,0x39,0x38,0x33,0x2f,0x2c,0x2e,\n    0x2d,0x2b,0x2c,0x2e,0x34,0x3b,0x44,0x4d,0x47,0x3e,0x35,0x2d,0x2c,0x33,0x39,0x38,\n    0x6a,0x77,0x80,0x82,0x7d,0x74,0x60,0x43,0x31,0x30,0x33,0x30,0x30,0x34,0x39,0x3c,\n    0x39,0x39,0x39,0x3a,0x3d,0x3e,0x3b,0x3a,0x5a,0x74,0x82,0x9c,0xa2,0x9e,0x97,0x88,\n    0x79,0x6d,0x63,0x5c,0x57,0x53,0x51,0x4f,0x4d,0x4d,0x4d,0x4d,0x4d,0x4e,0x4f,0x50,\n    0x51,0x54,0x55,0x59,0x5b,0x5f,0x61,0x64,0x68,0x71,0x7b,0x80,0x83,0x85,0x8a,0x8f,\n    0x96,0x9b,0x9e,0x9d,0x9c,0x9d,0xa8,0xb4,0xce,0xdb,0xdb,0xcd,0xb4,0x7d,0x4e,0x4a,\n    0x49,0x4a,0x4a,0x4b,0x50,0x4f,0x4e,0x4d,0x4e,0x4a,0x48,0x46,0x42,0x3e,0x3f,0x40,\n    0x42,0x41,0x41,0x3f,0x3f,0x3d,0x3d,0x3d,0x3f,0x3c,0x3b,0x3c,0x3f,0x3a,0x38,0x35,\n    0x36,0x35,0x36,0x38,0x3f,0x44,0x4e,0x56,0x55,0x49,0x40,0x38,0x35,0x3b,0x40,0x3f,\n    0x72,0x7e,0x84,0x83,0x7c,0x73,0x62,0x46,0x31,0x2f,0x35,0x32,0x2f,0x31,0x34,0x3b,\n    0x3b,0x38,0x38,0x38,0x3c,0x3c,0x3b,0x34,0x34,0x48,0x6e,0x8f,0x96,0x9c,0x95,0x7e,\n    0x72,0x67,0x61,0x5a,0x57,0x54,0x52,0x50,0x4f,0x4d,0x4d,0x4a,0x4b,0x4e,0x50,0x53,\n    0x55,0x59,0x5c,0x5f,0x63,0x66,0x67,0x6a,0x6f,0x73,0x7d,0x84,0x86,0x89,0x8e,0x93,\n    0x99,0x9d,0x9e,0x9d,0x9f,0x9f,0x9b,0xa8,0xcc,0xde,0xde,0xd3,0xb5,0x79,0x47,0x43,\n    0x43,0x45,0x4a,0x4d,0x52,0x52,0x53,0x50,0x52,0x4f,0x4b,0x46,0x42,0x3e,0x3e,0x3f,\n    0x3e,0x3f,0x3f,0x3f,0x3d,0x3b,0x39,0x35,0x34,0x38,0x3d,0x42,0x47,0x45,0x42,0x3f,\n    0x3e,0x3e,0x3f,0x42,0x45,0x49,0x52,0x59,0x58,0x4d,0x44,0x38,0x34,0x3b,0x40,0x40,\n    0x7a,0x85,0x8a,0x86,0x7e,0x76,0x63,0x47,0x30,0x2e,0x33,0x34,0x2e,0x2f,0x31,0x36,\n    0x3a,0x38,0x37,0x37,0x38,0x3a,0x3a,0x38,0x32,0x34,0x58,0x70,0x84,0x8c,0x7e,0x75,\n    0x6f,0x65,0x61,0x5a,0x57,0x54,0x53,0x52,0x51,0x4f,0x4f,0x4f,0x51,0x53,0x57,0x59,\n    0x5d,0x61,0x63,0x69,0x6e,0x72,0x75,0x78,0x7a,0x7d,0x80,0x88,0x8b,0x8d,0x92,0x97,\n    0x9a,0x9d,0x9f,0x9f,0xa0,0x9e,0x99,0xa5,0xcc,0xdd,0xdc,0xd4,0xb3,0x74,0x43,0x40,\n    0x41,0x44,0x49,0x4e,0x51,0x54,0x56,0x54,0x53,0x50,0x4b,0x46,0x40,0x3c,0x3c,0x3c,\n    0x3b,0x39,0x39,0x36,0x35,0x35,0x33,0x2f,0x30,0x36,0x3a,0x3d,0x42,0x43,0x45,0x45,\n    0x42,0x42,0x41,0x41,0x45,0x4b,0x4e,0x51,0x50,0x48,0x41,0x37,0x33,0x35,0x3b,0x3c,\n    0x81,0x8d,0x8e,0x87,0x7e,0x71,0x5f,0x45,0x30,0x2d,0x33,0x34,0x31,0x2c,0x2f,0x31,\n    0x36,0x38,0x35,0x36,0x36,0x37,0x3a,0x39,0x39,0x34,0x36,0x4b,0x5e,0x61,0x69,0x6f,\n    0x6a,0x64,0x60,0x5b,0x57,0x55,0x56,0x56,0x54,0x53,0x53,0x57,0x58,0x5a,0x5d,0x5f,\n    0x64,0x69,0x6c,0x75,0x7a,0x7f,0x83,0x86,0x87,0x88,0x8a,0x8d,0x8e,0x93,0x95,0x98,\n    0x9b,0x9e,0x9f,0x9f,0x9f,0x9e,0x9a,0xa7,0xcd,0xde,0xdd,0xd2,0xae,0x6a,0x3e,0x3c,\n    0x3e,0x42,0x47,0x4b,0x50,0x54,0x56,0x55,0x53,0x51,0x4b,0x45,0x3e,0x3a,0x38,0x39,\n    0x3b,0x37,0x34,0x2f,0x2b,0x2a,0x2c,0x2c,0x2e,0x32,0x34,0x36,0x3a,0x3e,0x3e,0x40,\n    0x41,0x41,0x3f,0x3c,0x3f,0x45,0x46,0x47,0x45,0x40,0x38,0x35,0x2d,0x2d,0x37,0x3c,\n    0x83,0x8f,0x8f,0x87,0x7e,0x76,0x63,0x49,0x35,0x2f,0x33,0x33,0x32,0x2d,0x2e,0x30,\n    0x34,0x36,0x34,0x35,0x36,0x37,0x38,0x38,0x38,0x37,0x32,0x33,0x3e,0x4b,0x56,0x61,\n    0x67,0x63,0x5e,0x5b,0x57,0x56,0x57,0x57,0x57,0x57,0x5a,0x5b,0x5e,0x61,0x66,0x6b,\n    0x72,0x77,0x7b,0x81,0x85,0x89,0x8c,0x8d,0x8f,0x90,0x90,0x93,0x92,0x95,0x98,0x9a,\n    0x9d,0x9e,0x9f,0x9f,0x9f,0x9c,0x9a,0xab,0xcf,0xdd,0xda,0xcd,0xa3,0x5d,0x3c,0x3b,\n    0x3f,0x43,0x45,0x49,0x50,0x54,0x56,0x53,0x50,0x4e,0x46,0x41,0x3e,0x40,0x40,0x43,\n    0x46,0x44,0x3d,0x3a,0x36,0x2d,0x27,0x27,0x2a,0x2b,0x2a,0x2b,0x2e,0x30,0x31,0x36,\n    0x37,0x39,0x3a,0x37,0x34,0x38,0x3a,0x3c,0x3a,0x38,0x31,0x2c,0x26,0x2a,0x32,0x37,\n    0x83,0x8c,0x8d,0x87,0x80,0x76,0x65,0x4a,0x36,0x2d,0x30,0x32,0x34,0x30,0x2d,0x30,\n    0x30,0x36,0x36,0x33,0x35,0x35,0x35,0x37,0x37,0x37,0x37,0x34,0x33,0x39,0x45,0x51,\n    0x58,0x60,0x60,0x5b,0x56,0x56,0x57,0x58,0x5a,0x5c,0x5e,0x61,0x69,0x6d,0x73,0x79,\n    0x7d,0x83,0x86,0x8b,0x8e,0x91,0x91,0x92,0x94,0x95,0x95,0x98,0x99,0x99,0x9a,0x9c,\n    0x9d,0x9d,0x9d,0x9d,0x9d,0x9c,0x96,0xac,0xce,0xd9,0xd5,0xc3,0x96,0x50,0x38,0x3b,\n    0x41,0x45,0x46,0x49,0x4d,0x53,0x54,0x54,0x4f,0x48,0x3d,0x38,0x38,0x3f,0x45,0x4b,\n    0x4d,0x4f,0x4b,0x45,0x3f,0x39,0x33,0x30,0x2e,0x2d,0x29,0x24,0x21,0x24,0x25,0x2f,\n    0x32,0x36,0x35,0x36,0x38,0x37,0x32,0x31,0x33,0x31,0x2b,0x2a,0x24,0x27,0x30,0x34,\n    0x80,0x88,0x89,0x84,0x7c,0x73,0x61,0x49,0x36,0x29,0x2c,0x30,0x33,0x32,0x2e,0x2f,\n    0x31,0x34,0x35,0x33,0x34,0x33,0x32,0x34,0x35,0x35,0x35,0x33,0x33,0x2f,0x38,0x42,\n    0x49,0x50,0x54,0x59,0x58,0x57,0x57,0x5a,0x5f,0x64,0x68,0x6e,0x75,0x7b,0x80,0x85,\n    0x89,0x8c,0x8e,0x8f,0x93,0x91,0x92,0x93,0x97,0x97,0x98,0x9a,0x9b,0x9b,0x9b,0x9c,\n    0x9c,0x9d,0x9d,0x9d,0x9d,0x9d,0x95,0xab,0xcd,0xd1,0xcb,0xb5,0x84,0x43,0x3b,0x3e,\n    0x44,0x46,0x49,0x4c,0x4e,0x52,0x54,0x55,0x4f,0x45,0x3c,0x3a,0x39,0x3b,0x48,0x4f,\n    0x54,0x57,0x56,0x50,0x46,0x41,0x3d,0x37,0x32,0x30,0x2b,0x26,0x23,0x22,0x25,0x2b,\n    0x2f,0x37,0x39,0x39,0x3b,0x3a,0x35,0x30,0x32,0x2e,0x29,0x27,0x27,0x24,0x29,0x2f,\n    0x7c,0x84,0x84,0x80,0x79,0x71,0x5d,0x48,0x36,0x28,0x28,0x2f,0x32,0x32,0x2d,0x2f,\n    0x31,0x31,0x35,0x34,0x33,0x32,0x30,0x32,0x31,0x32,0x31,0x31,0x31,0x32,0x2f,0x33,\n    0x39,0x42,0x47,0x4c,0x54,0x59,0x5e,0x62,0x6a,0x71,0x76,0x7c,0x82,0x87,0x89,0x8d,\n    0x8f,0x91,0x91,0x91,0x92,0x93,0x94,0x94,0x98,0x99,0x9a,0x9c,0x9e,0x9e,0x9e,0x9e,\n    0x9e,0x9d,0x9c,0x9c,0x9c,0x9c,0x96,0xb0,0xcc,0xc8,0xbc,0xa4,0x6d,0x3f,0x3f,0x44,\n    0x48,0x4a,0x4c,0x4e,0x50,0x54,0x59,0x53,0x4d,0x44,0x3c,0x3a,0x3b,0x3e,0x49,0x51,\n    0x55,0x58,0x59,0x55,0x4b,0x43,0x3f,0x3a,0x36,0x31,0x2a,0x25,0x24,0x24,0x27,0x2a,\n    0x32,0x3b,0x3f,0x40,0x3b,0x3c,0x38,0x33,0x31,0x2b,0x28,0x26,0x25,0x23,0x23,0x2a,\n    0x7a,0x83,0x86,0x81,0x7b,0x71,0x60,0x4a,0x35,0x28,0x25,0x2e,0x33,0x34,0x30,0x34,\n    0x36,0x35,0x36,0x37,0x35,0x34,0x33,0x32,0x33,0x31,0x30,0x2f,0x2f,0x2f,0x30,0x31,\n    0x30,0x31,0x38,0x41,0x4a,0x58,0x66,0x71,0x79,0x7f,0x83,0x87,0x89,0x8c,0x90,0x91,\n    0x8f,0x8f,0x90,0x92,0x91,0x91,0x94,0x95,0x98,0x9b,0x9d,0x9e,0xa0,0xa0,0xa0,0xa1,\n    0xa0,0x9f,0x9f,0x9f,0x9f,0x9a,0x9c,0xb9,0xbf,0xb8,0xa9,0x91,0x57,0x40,0x45,0x4b,\n    0x4d,0x4e,0x51,0x52,0x52,0x52,0x52,0x52,0x4b,0x45,0x3f,0x3d,0x3b,0x41,0x49,0x51,\n    0x55,0x57,0x55,0x52,0x4d,0x47,0x41,0x3a,0x38,0x32,0x2c,0x25,0x27,0x29,0x2e,0x34,\n    0x3d,0x45,0x44,0x44,0x41,0x3f,0x3a,0x35,0x2e,0x2a,0x25,0x21,0x1f,0x21,0x23,0x28,\n    0x78,0x82,0x89,0x8a,0x83,0x78,0x75,0x81,0x84,0x7b,0x76,0x77,0x6c,0x5a,0x50,0x51,\n    0x53,0x54,0x52,0x52,0x52,0x52,0x52,0x52,0x4f,0x4d,0x49,0x46,0x43,0x40,0x3c,0x3a,\n    0x37,0x35,0x34,0x38,0x41,0x52,0x64,0x77,0x85,0x8a,0x8c,0x8c,0x90,0x91,0x8f,0x93,\n    0x97,0x9d,0xa3,0xa4,0x9f,0x99,0x96,0x96,0x9b,0x9d,0xa0,0xa0,0xa1,0xa2,0xa3,0xa3,\n    0xa2,0xa0,0xa0,0x9f,0x9e,0x9b,0xa5,0xaf,0xaa,0xa3,0x96,0x71,0x4b,0x4b,0x4d,0x50,\n    0x53,0x55,0x57,0x55,0x53,0x52,0x4e,0x4f,0x4b,0x48,0x44,0x3f,0x3e,0x43,0x47,0x4d,\n    0x50,0x53,0x53,0x52,0x4d,0x4b,0x44,0x3e,0x35,0x31,0x2d,0x29,0x28,0x2c,0x35,0x3f,\n    0x46,0x4b,0x49,0x44,0x43,0x3f,0x3a,0x37,0x33,0x2c,0x26,0x1f,0x1d,0x23,0x28,0x32,\n    0x7a,0x84,0x89,0x8d,0x89,0x88,0xa2,0xb7,0xc4,0xbf,0xb2,0xa3,0x93,0x83,0x79,0x78,\n    0x7a,0x7d,0x7c,0x7c,0x7e,0x7e,0x7f,0x7f,0x7d,0x7b,0x7c,0x79,0x76,0x73,0x71,0x6d,\n    0x67,0x62,0x58,0x4d,0x4c,0x53,0x5d,0x70,0x81,0x8c,0x8f,0x8d,0x8f,0x90,0x9d,0xad,\n    0xb8,0xbe,0xc2,0xc0,0xb3,0xa5,0x9c,0x99,0x9c,0x9d,0xa0,0x9f,0xa1,0xa5,0xa6,0xa5,\n    0xa3,0xa1,0x9f,0x9e,0x9b,0x9c,0x9d,0x9b,0x92,0x89,0x77,0x50,0x4a,0x4d,0x51,0x54,\n    0x58,0x5a,0x5b,0x5a,0x56,0x54,0x51,0x4d,0x4b,0x48,0x46,0x41,0x3f,0x43,0x45,0x46,\n    0x47,0x4a,0x4c,0x4c,0x49,0x48,0x44,0x40,0x39,0x31,0x31,0x2e,0x2b,0x2e,0x39,0x44,\n    0x48,0x4a,0x47,0x42,0x3f,0x39,0x3a,0x3a,0x39,0x33,0x2c,0x23,0x21,0x2a,0x2f,0x37,\n    0x7c,0x83,0x88,0x8e,0x8a,0x90,0xad,0xc1,0xc8,0xbb,0xae,0xa1,0x93,0x89,0x87,0x8a,\n    0x8c,0x8f,0x8f,0x92,0x94,0x94,0x96,0x96,0x96,0x94,0x94,0x95,0x96,0x93,0x90,0x90,\n    0x8f,0x89,0x84,0x7d,0x76,0x6e,0x6e,0x72,0x7a,0x83,0x89,0x8f,0x92,0xa0,0xb5,0xca,\n    0xd7,0xde,0xde,0xd4,0xc6,0xb1,0x9d,0x99,0x9b,0x9d,0x9e,0x9e,0xa4,0xa8,0xa9,0xa8,\n    0xa6,0xa1,0x9d,0x9c,0x9a,0x97,0x8f,0x84,0x77,0x68,0x55,0x4c,0x4f,0x52,0x55,0x5a,\n    0x5e,0x60,0x5f,0x5d,0x5a,0x57,0x55,0x52,0x4f,0x4d,0x49,0x46,0x45,0x46,0x46,0x44,\n    0x42,0x40,0x43,0x45,0x45,0x42,0x42,0x41,0x3e,0x39,0x38,0x35,0x30,0x2e,0x35,0x3c,\n    0x41,0x43,0x41,0x3e,0x36,0x34,0x36,0x3b,0x3d,0x3b,0x36,0x31,0x32,0x37,0x3a,0x3f,\n    0x7d,0x81,0x86,0x8d,0x88,0x77,0x75,0x7c,0x7b,0x6f,0x70,0x74,0x7a,0x81,0x83,0x89,\n    0x8b,0x8e,0x8f,0x90,0x92,0x94,0x96,0x96,0x97,0x94,0x95,0x98,0x9a,0x9c,0x9e,0x9f,\n    0x9d,0x9e,0x9a,0x94,0x8f,0x84,0x7a,0x79,0x7d,0x82,0x88,0x8d,0x8f,0xaf,0xcd,0xdf,\n    0xe9,0xed,0xea,0xe2,0xd1,0xb8,0x9c,0x9a,0x9a,0x9d,0x9e,0x9f,0xa9,0xaa,0xab,0xaa,\n    0xa6,0xa2,0x9e,0x9a,0x98,0x91,0x81,0x6f,0x5d,0x53,0x4b,0x4e,0x50,0x54,0x58,0x60,\n    0x63,0x63,0x63,0x61,0x5e,0x5b,0x57,0x55,0x52,0x50,0x4c,0x4a,0x4a,0x49,0x45,0x45,\n    0x42,0x39,0x39,0x3b,0x3d,0x42,0x3e,0x3e,0x40,0x3d,0x3b,0x3b,0x36,0x2f,0x34,0x33,\n    0x37,0x3a,0x3a,0x3a,0x34,0x31,0x36,0x3b,0x3e,0x42,0x40,0x3e,0x3f,0x41,0x42,0x46,\n    0x7f,0x80,0x83,0x88,0x83,0x73,0x6b,0x68,0x6e,0x74,0x78,0x78,0x7d,0x7c,0x81,0x86,\n    0x89,0x8b,0x8c,0x8e,0x8f,0x90,0x90,0x91,0x91,0x90,0x91,0x91,0x93,0x93,0x96,0x96,\n    0x97,0x97,0x98,0x99,0x99,0x91,0x8c,0x81,0x7d,0x80,0x85,0x86,0x8e,0xbe,0xdc,0xe9,\n    0xf0,0xf2,0xee,0xe5,0xd4,0xb8,0x9e,0x9a,0x9d,0x9e,0xa1,0xa4,0xac,0xac,0xad,0xab,\n    0xa6,0xa1,0x9e,0x9a,0x95,0x89,0x79,0x66,0x56,0x4e,0x4c,0x4b,0x4f,0x54,0x5a,0x5c,\n    0x61,0x63,0x62,0x61,0x5f,0x5c,0x5a,0x57,0x54,0x52,0x4f,0x4d,0x4c,0x4c,0x4a,0x45,\n    0x42,0x3d,0x35,0x33,0x35,0x3b,0x3d,0x3c,0x40,0x3f,0x41,0x42,0x3b,0x34,0x34,0x34,\n    0x33,0x34,0x37,0x36,0x32,0x33,0x36,0x3a,0x3c,0x46,0x4c,0x4a,0x4b,0x49,0x46,0x48,\n    0x7f,0x7e,0x7f,0x7f,0x7f,0x76,0x6b,0x6d,0x73,0x7b,0x7c,0x7c,0x7b,0x7d,0x83,0x87,\n    0x8a,0x8c,0x8d,0x8d,0x8e,0x91,0x90,0x90,0x90,0x91,0x91,0x92,0x92,0x93,0x96,0x95,\n    0x94,0x95,0x95,0x94,0x91,0x8d,0x88,0x83,0x7f,0x7d,0x7d,0x7e,0x90,0xc1,0xdc,0xeb,\n    0xf1,0xf3,0xf0,0xe8,0xd5,0xb7,0x9e,0x9b,0x9f,0xa1,0xa3,0xa6,0xad,0xad,0xaf,0xac,\n    0xa6,0xa0,0x9b,0x98,0x91,0x80,0x72,0x5f,0x50,0x4d,0x49,0x48,0x4d,0x53,0x57,0x5d,\n    0x60,0x63,0x61,0x5e,0x5c,0x59,0x56,0x55,0x52,0x52,0x4e,0x4b,0x4b,0x4b,0x4b,0x47,\n    0x42,0x3b,0x38,0x34,0x30,0x34,0x37,0x3a,0x41,0x44,0x48,0x4a,0x44,0x3c,0x38,0x35,\n    0x32,0x33,0x34,0x34,0x35,0x37,0x35,0x38,0x3d,0x47,0x4e,0x51,0x51,0x4e,0x48,0x45,\n    0x7d,0x7b,0x7b,0x7e,0x7d,0x77,0x6c,0x72,0x75,0x7e,0x7d,0x7b,0x7b,0x80,0x84,0x87,\n    0x8a,0x8d,0x8f,0x8e,0x91,0x94,0x91,0x90,0x90,0x90,0x90,0x91,0x93,0x94,0x95,0x93,\n    0x94,0x95,0x96,0x96,0x8f,0x8a,0x86,0x81,0x81,0x78,0x78,0x78,0x89,0xb4,0xd5,0xea,\n    0xf1,0xf3,0xf0,0xe7,0xd5,0xb8,0xa0,0x9c,0xa3,0xa5,0xa8,0xac,0xb0,0xb0,0xb0,0xab,\n    0xa6,0x9f,0x9c,0x92,0x83,0x75,0x68,0x56,0x4c,0x4a,0x49,0x48,0x4d,0x50,0x55,0x59,\n    0x5a,0x5e,0x5b,0x59,0x54,0x52,0x50,0x52,0x51,0x4e,0x4c,0x4b,0x4a,0x48,0x4b,0x4d,\n    0x49,0x41,0x3a,0x34,0x2f,0x30,0x31,0x3a,0x47,0x4c,0x4c,0x4d,0x48,0x44,0x41,0x38,\n    0x32,0x32,0x35,0x35,0x36,0x39,0x3b,0x3d,0x43,0x4a,0x4f,0x54,0x53,0x4e,0x48,0x43,\n    0x7b,0x79,0x7c,0x82,0x80,0x7a,0x70,0x74,0x77,0x7c,0x7b,0x7a,0x7c,0x7f,0x84,0x87,\n    0x8a,0x8d,0x90,0x91,0x94,0x93,0x91,0x91,0x8e,0x8f,0x91,0x8f,0x94,0x94,0x93,0x92,\n    0x95,0x95,0x97,0x92,0x8a,0x88,0x85,0x84,0x81,0x7b,0x77,0x73,0x77,0x93,0xc1,0xde,\n    0xef,0xf3,0xf1,0xe8,0xd6,0xb9,0x9f,0x9f,0xa3,0xa6,0xaa,0xb1,0xb2,0xb2,0xb1,0xad,\n    0xa3,0xa0,0x94,0x87,0x76,0x66,0x5a,0x52,0x4e,0x4a,0x49,0x49,0x4a,0x4d,0x51,0x53,\n    0x53,0x54,0x52,0x52,0x4b,0x4d,0x50,0x50,0x4f,0x4d,0x4b,0x48,0x46,0x47,0x4b,0x4e,\n    0x4d,0x47,0x41,0x34,0x2c,0x2d,0x33,0x38,0x42,0x49,0x4e,0x4e,0x49,0x47,0x45,0x3d,\n    0x39,0x36,0x38,0x36,0x37,0x3a,0x3f,0x40,0x46,0x4b,0x4d,0x54,0x56,0x50,0x4b,0x45,\n    0x7e,0x81,0x83,0x87,0x83,0x78,0x71,0x73,0x7a,0x7c,0x7e,0x7f,0x81,0x84,0x84,0x87,\n    0x8a,0x8d,0x91,0x90,0x94,0x95,0x92,0x91,0x8f,0x92,0x90,0x90,0x95,0x92,0x92,0x91,\n    0x92,0x96,0x94,0x8c,0x87,0x87,0x87,0x89,0x82,0x7d,0x78,0x72,0x72,0x75,0x99,0xce,\n    0xe6,0xef,0xf1,0xe7,0xd5,0xb8,0x9f,0xa1,0xa5,0xa9,0xac,0xb3,0xb4,0xb3,0xb1,0xaa,\n    0xa2,0x9c,0x8a,0x76,0x67,0x5a,0x4d,0x50,0x4f,0x4f,0x4e,0x4e,0x4f,0x52,0x54,0x52,\n    0x52,0x4f,0x4f,0x4e,0x4b,0x4c,0x4e,0x50,0x4e,0x4e,0x4c,0x47,0x47,0x47,0x4b,0x4e,\n    0x4f,0x4c,0x45,0x38,0x2c,0x2a,0x33,0x3c,0x3e,0x48,0x4f,0x51,0x4c,0x4a,0x45,0x40,\n    0x3e,0x3b,0x3b,0x39,0x3c,0x41,0x43,0x44,0x43,0x4a,0x4f,0x55,0x54,0x4f,0x49,0x45,\n    0x7f,0x83,0x87,0x85,0x7f,0x72,0x70,0x71,0x78,0x7c,0x83,0x86,0x8a,0x8e,0x8c,0x8c,\n    0x89,0x8d,0x90,0x92,0x94,0x95,0x94,0x92,0x92,0x90,0x90,0x91,0x92,0x8f,0x90,0x8f,\n    0x94,0x94,0x8e,0x89,0x86,0x86,0x8a,0x89,0x86,0x7d,0x78,0x72,0x70,0x72,0x7d,0xb5,\n    0xdb,0xea,0xea,0xe1,0xcd,0xb2,0xa1,0xa3,0xa7,0xa9,0xb0,0xb5,0xb4,0xb5,0xaf,0xa6,\n    0xa0,0x93,0x7c,0x65,0x5a,0x4d,0x4c,0x4d,0x4f,0x51,0x53,0x54,0x54,0x53,0x52,0x53,\n    0x53,0x4e,0x4e,0x4d,0x4c,0x4e,0x4e,0x51,0x50,0x50,0x4e,0x4a,0x46,0x47,0x48,0x4a,\n    0x49,0x46,0x42,0x39,0x30,0x2d,0x32,0x3d,0x44,0x4e,0x52,0x50,0x4c,0x4b,0x48,0x44,\n    0x45,0x43,0x3f,0x3f,0x45,0x42,0x45,0x43,0x41,0x48,0x4d,0x50,0x53,0x50,0x4a,0x43,\n    0x7f,0x81,0x81,0x80,0x79,0x6d,0x6d,0x71,0x79,0x82,0x8b,0x8c,0x8f,0x90,0x94,0x96,\n    0x92,0x92,0x90,0x92,0x95,0x96,0x95,0x94,0x90,0x8f,0x92,0x93,0x90,0x8f,0x8e,0x91,\n    0x94,0x92,0x8d,0x87,0x86,0x89,0x8d,0x8b,0x87,0x80,0x7b,0x76,0x71,0x6f,0x74,0x98,\n    0xc7,0xdc,0xde,0xd3,0xc0,0xab,0xa3,0xa5,0xa8,0xaa,0xaf,0xb4,0xb5,0xb3,0xab,0xa1,\n    0x95,0x83,0x6f,0x5e,0x4e,0x4c,0x4e,0x4e,0x51,0x53,0x54,0x57,0x59,0x58,0x55,0x56,\n    0x55,0x52,0x52,0x52,0x53,0x53,0x54,0x56,0x55,0x55,0x51,0x4e,0x4c,0x49,0x45,0x47,\n    0x47,0x45,0x41,0x3c,0x3a,0x39,0x3c,0x43,0x4a,0x50,0x52,0x4f,0x50,0x4d,0x4c,0x4a,\n    0x49,0x49,0x48,0x4a,0x4b,0x46,0x43,0x40,0x3f,0x45,0x4d,0x50,0x51,0x51,0x4e,0x46,\n    0x7e,0x7d,0x7e,0x7a,0x75,0x6d,0x6b,0x70,0x7b,0x8d,0x8a,0x88,0x8c,0x90,0x96,0x98,\n    0x98,0x97,0x93,0x91,0x93,0x94,0x93,0x92,0x91,0x91,0x92,0x91,0x8f,0x8f,0x8f,0x92,\n    0x93,0x90,0x89,0x85,0x86,0x8a,0x8f,0x8c,0x88,0x81,0x7b,0x77,0x73,0x72,0x74,0x84,\n    0xa9,0xc1,0xc7,0xc0,0xae,0xa2,0xa4,0xa6,0xa9,0xac,0xb0,0xb2,0xaf,0xa9,0xa2,0x90,\n    0x81,0x6f,0x61,0x58,0x52,0x51,0x51,0x50,0x50,0x51,0x53,0x56,0x5a,0x5c,0x5c,0x5a,\n    0x58,0x56,0x55,0x56,0x57,0x56,0x57,0x57,0x57,0x55,0x52,0x4f,0x4c,0x4a,0x43,0x43,\n    0x44,0x44,0x43,0x42,0x43,0x43,0x45,0x49,0x4e,0x50,0x4e,0x4f,0x51,0x4c,0x4a,0x4b,\n    0x4b,0x4d,0x4f,0x4d,0x4a,0x46,0x41,0x3d,0x3a,0x40,0x4a,0x4f,0x54,0x52,0x4e,0x45,\n    0x7f,0x7f,0x86,0x81,0x7a,0x71,0x6b,0x73,0x89,0x91,0x88,0x7f,0x8f,0xa0,0xa4,0x9a,\n    0x97,0x96,0x97,0x97,0x91,0x90,0x92,0x91,0x91,0x92,0x91,0x91,0x8f,0x8d,0x90,0x91,\n    0x91,0x8d,0x88,0x86,0x88,0x8b,0x8f,0x8c,0x87,0x81,0x7a,0x77,0x73,0x72,0x73,0x78,\n    0x89,0x9d,0xa2,0xa0,0xa1,0xa2,0xa5,0xa6,0xa9,0xac,0xaf,0xac,0xa7,0x9d,0x8c,0x77,\n    0x6e,0x63,0x5b,0x57,0x5d,0x5d,0x5a,0x56,0x54,0x54,0x54,0x59,0x5c,0x5d,0x61,0x5f,\n    0x5d,0x5b,0x59,0x59,0x5b,0x5b,0x5d,0x5c,0x5b,0x5b,0x57,0x54,0x50,0x4c,0x4a,0x48,\n    0x47,0x46,0x48,0x49,0x4a,0x4b,0x4e,0x51,0x52,0x52,0x51,0x4c,0x4d,0x49,0x4a,0x4b,\n    0x4b,0x4c,0x51,0x51,0x4c,0x48,0x44,0x3f,0x38,0x3f,0x49,0x50,0x54,0x54,0x50,0x48,\n    0x83,0x83,0x8c,0x89,0x81,0x72,0x6d,0x7d,0x8c,0x8e,0x80,0x88,0xa5,0xab,0xaa,0x97,\n    0x8a,0x8c,0x91,0x9a,0x9c,0x99,0x94,0x91,0x91,0x92,0x93,0x93,0x90,0x8f,0x90,0x8f,\n    0x8e,0x89,0x87,0x85,0x88,0x8c,0x8e,0x8c,0x85,0x81,0x7b,0x78,0x74,0x73,0x74,0x75,\n    0x75,0x7f,0x87,0x91,0x9c,0xa2,0xa5,0xa8,0xaa,0xad,0xad,0xa7,0x9c,0x8d,0x75,0x66,\n    0x61,0x5a,0x59,0x60,0x65,0x63,0x60,0x5c,0x58,0x55,0x57,0x59,0x5c,0x63,0x65,0x62,\n    0x61,0x5f,0x5a,0x59,0x5c,0x5c,0x61,0x62,0x60,0x5f,0x5b,0x57,0x50,0x51,0x4e,0x4b,\n    0x4a,0x49,0x4b,0x4c,0x4e,0x4f,0x52,0x51,0x4f,0x4f,0x4e,0x48,0x47,0x47,0x46,0x4c,\n    0x4d,0x4e,0x52,0x53,0x4f,0x4a,0x44,0x41,0x3e,0x44,0x49,0x50,0x54,0x54,0x4f,0x49,\n    0x82,0x87,0x8c,0x89,0x82,0x77,0x73,0x87,0x8c,0x8a,0x78,0x98,0xb0,0xb3,0xa7,0x82,\n    0x6e,0x82,0x8f,0x9e,0xa1,0x9f,0x9b,0x97,0x90,0x94,0x94,0x94,0x94,0x91,0x90,0x8d,\n    0x8c,0x87,0x88,0x89,0x8a,0x8b,0x8f,0x8d,0x86,0x80,0x7c,0x77,0x75,0x73,0x75,0x74,\n    0x72,0x70,0x7a,0x88,0x96,0xa1,0xa6,0xa7,0xaa,0xac,0xad,0xa1,0x90,0x7b,0x65,0x59,\n    0x58,0x55,0x5b,0x64,0x67,0x69,0x66,0x62,0x5c,0x5c,0x5a,0x5b,0x62,0x66,0x69,0x68,\n    0x65,0x62,0x5d,0x5a,0x5e,0x63,0x66,0x67,0x62,0x60,0x5d,0x58,0x55,0x55,0x53,0x4e,\n    0x4d,0x4d,0x4b,0x4b,0x51,0x54,0x53,0x50,0x4b,0x49,0x4a,0x47,0x44,0x42,0x45,0x4e,\n    0x4f,0x51,0x55,0x52,0x53,0x50,0x4d,0x4b,0x47,0x4d,0x50,0x52,0x55,0x55,0x51,0x4b,\n    0x82,0x86,0x8d,0x8f,0x86,0x77,0x7a,0x87,0x8a,0x81,0x74,0x95,0xa9,0xb0,0x9a,0x72,\n    0x5f,0x75,0x8d,0xa0,0xa0,0xa0,0x9d,0x9b,0x97,0x94,0x95,0x95,0x93,0x93,0x93,0x8f,\n    0x8c,0x89,0x8a,0x8a,0x8b,0x8d,0x8f,0x8b,0x86,0x81,0x7d,0x78,0x75,0x73,0x74,0x76,\n    0x72,0x6c,0x6f,0x7c,0x8e,0x9f,0xa9,0xa8,0xa7,0xad,0xa8,0x9b,0x86,0x6e,0x5c,0x53,\n    0x53,0x59,0x61,0x66,0x68,0x67,0x66,0x63,0x5f,0x5e,0x60,0x61,0x64,0x6a,0x6d,0x6c,\n    0x67,0x62,0x61,0x60,0x5f,0x63,0x67,0x68,0x66,0x64,0x5f,0x5a,0x58,0x55,0x52,0x4f,\n    0x4e,0x4d,0x49,0x4a,0x4b,0x4e,0x4e,0x4c,0x4a,0x4a,0x46,0x44,0x44,0x41,0x45,0x4d,\n    0x51,0x50,0x53,0x55,0x53,0x55,0x53,0x50,0x4f,0x52,0x56,0x55,0x55,0x56,0x52,0x4a,\n    0x7b,0x82,0x8a,0x8d,0x81,0x77,0x7e,0x84,0x88,0x79,0x76,0x91,0xa6,0xa9,0x94,0x73,\n    0x67,0x7e,0x91,0x97,0x9e,0x9e,0x9b,0x9b,0x9b,0x9a,0x9a,0x98,0x96,0x96,0x97,0x94,\n    0x91,0x90,0x8f,0x8d,0x8c,0x8c,0x8f,0x8a,0x85,0x81,0x7e,0x78,0x75,0x73,0x74,0x76,\n    0x71,0x69,0x65,0x72,0x88,0x9a,0xa7,0xab,0xae,0xb2,0xad,0x9f,0x8a,0x6d,0x59,0x57,\n    0x58,0x5f,0x62,0x63,0x64,0x62,0x64,0x64,0x63,0x63,0x65,0x67,0x69,0x6c,0x6f,0x70,\n    0x6c,0x66,0x61,0x60,0x63,0x64,0x66,0x67,0x67,0x66,0x5e,0x59,0x58,0x55,0x4f,0x4f,\n    0x4c,0x49,0x46,0x4b,0x49,0x49,0x49,0x47,0x48,0x48,0x42,0x3e,0x41,0x41,0x46,0x4b,\n    0x53,0x55,0x56,0x56,0x57,0x54,0x53,0x54,0x59,0x5a,0x5e,0x5c,0x5a,0x5b,0x56,0x4e,\n    0x74,0x7f,0x8a,0x86,0x7a,0x71,0x7a,0x81,0x83,0x74,0x79,0x8a,0xa9,0xb0,0x99,0x7d,\n    0x6f,0x86,0x94,0x98,0x96,0x96,0x96,0x9a,0x9b,0x9c,0x9d,0x9c,0x9c,0x9b,0x98,0x9a,\n    0x99,0x97,0x95,0x91,0x8d,0x8d,0x8c,0x89,0x85,0x81,0x7e,0x78,0x74,0x73,0x75,0x75,\n    0x71,0x69,0x66,0x6b,0x7e,0x92,0xa1,0xad,0xba,0xbc,0xb7,0xab,0x96,0x76,0x64,0x62,\n    0x5d,0x5e,0x5f,0x60,0x5f,0x5d,0x5d,0x5f,0x62,0x64,0x68,0x6a,0x6e,0x6f,0x70,0x71,\n    0x6f,0x68,0x60,0x5f,0x61,0x64,0x67,0x66,0x67,0x63,0x5b,0x57,0x53,0x54,0x4e,0x4c,\n    0x47,0x46,0x45,0x49,0x48,0x47,0x46,0x47,0x46,0x3f,0x3e,0x39,0x3b,0x42,0x44,0x4a,\n    0x55,0x59,0x59,0x58,0x55,0x55,0x56,0x58,0x5e,0x60,0x63,0x5f,0x5e,0x5a,0x57,0x4c,\n    0x74,0x80,0x8b,0x86,0x7a,0x6f,0x78,0x7c,0x7c,0x73,0x7b,0x8a,0xb0,0xb5,0xa7,0x8b,\n    0x7b,0x8b,0x93,0x99,0x96,0x94,0x94,0x97,0x9b,0x9d,0x9d,0xa0,0xa2,0xa3,0xa1,0xa1,\n    0xa0,0x9e,0x9a,0x93,0x91,0x8f,0x8c,0x88,0x85,0x81,0x7d,0x78,0x74,0x73,0x75,0x75,\n    0x72,0x6a,0x65,0x64,0x77,0x8f,0xa8,0xbc,0xcb,0xce,0xc6,0xb9,0xa5,0x86,0x6b,0x63,\n    0x60,0x5d,0x5c,0x5c,0x5b,0x58,0x59,0x5b,0x5f,0x62,0x67,0x6a,0x6d,0x6f,0x6e,0x6e,\n    0x6d,0x65,0x5e,0x5a,0x59,0x5e,0x62,0x67,0x66,0x61,0x5a,0x53,0x50,0x4f,0x4a,0x49,\n    0x46,0x45,0x48,0x4c,0x4c,0x49,0x4a,0x48,0x3e,0x3c,0x38,0x36,0x38,0x40,0x46,0x4d,\n    0x55,0x59,0x5b,0x5b,0x5a,0x58,0x57,0x59,0x5c,0x5f,0x5f,0x62,0x5c,0x57,0x52,0x4b,\n    0x78,0x88,0x89,0x85,0x74,0x6e,0x75,0x7a,0x79,0x76,0x7a,0x8a,0xac,0xae,0xa2,0x8b,\n    0x83,0x8e,0x94,0x97,0x95,0x95,0x94,0x95,0x97,0x99,0x9e,0xa2,0xa3,0xa5,0xa9,0xa8,\n    0xa5,0xa1,0x9b,0x98,0x95,0x94,0x8d,0x86,0x83,0x7f,0x7d,0x77,0x74,0x74,0x74,0x74,\n    0x72,0x6a,0x65,0x62,0x68,0x8f,0xae,0xc8,0xd8,0xda,0xd3,0xc6,0xac,0x8e,0x6e,0x61,\n    0x5c,0x58,0x57,0x56,0x53,0x55,0x57,0x5a,0x5d,0x60,0x61,0x66,0x6a,0x6c,0x6d,0x6f,\n    0x6b,0x63,0x5d,0x56,0x56,0x59,0x5f,0x67,0x64,0x5e,0x58,0x52,0x4a,0x45,0x41,0x3f,\n    0x3e,0x40,0x47,0x4f,0x4e,0x4d,0x4b,0x44,0x3c,0x39,0x33,0x33,0x36,0x3b,0x41,0x4d,\n    0x55,0x58,0x5c,0x5f,0x60,0x59,0x57,0x59,0x5a,0x60,0x64,0x62,0x5f,0x57,0x50,0x4a,\n    0x7f,0x8b,0x8a,0x83,0x73,0x70,0x73,0x76,0x75,0x77,0x7a,0x85,0x9d,0xa2,0x9c,0x89,\n    0x8d,0x93,0x98,0x99,0x96,0x95,0x95,0x96,0x9a,0x9b,0x9c,0x9f,0xa5,0xa7,0xaa,0xa9,\n    0xa9,0xa4,0x9d,0x9e,0x9e,0x9b,0x95,0x8b,0x86,0x81,0x7e,0x78,0x74,0x73,0x75,0x76,\n    0x75,0x6d,0x67,0x63,0x66,0x8c,0xb1,0xcf,0xdd,0xe1,0xd9,0xc8,0xaf,0x8d,0x6c,0x5d,\n    0x57,0x57,0x56,0x56,0x57,0x57,0x58,0x59,0x5c,0x61,0x62,0x64,0x68,0x6c,0x70,0x72,\n    0x70,0x69,0x61,0x57,0x53,0x57,0x60,0x66,0x66,0x5e,0x55,0x4d,0x43,0x40,0x3c,0x3b,\n    0x39,0x40,0x49,0x4f,0x51,0x53,0x51,0x47,0x3e,0x38,0x31,0x31,0x37,0x3c,0x42,0x4b,\n    0x52,0x57,0x5b,0x62,0x63,0x5e,0x59,0x57,0x57,0x5d,0x61,0x63,0x5d,0x54,0x4b,0x48,\n    0x82,0x8e,0x8c,0x84,0x74,0x74,0x72,0x72,0x71,0x77,0x77,0x7e,0x85,0x8f,0x93,0x94,\n    0x94,0x98,0x98,0x97,0x96,0x96,0x95,0x97,0x99,0x9b,0x9a,0x9e,0x9f,0xa5,0xa8,0xa8,\n    0xa6,0xa4,0xa5,0xa6,0xa3,0xa0,0x98,0x8f,0x8a,0x84,0x7f,0x79,0x76,0x74,0x77,0x78,\n    0x77,0x71,0x6d,0x68,0x66,0x84,0xb3,0xd2,0xe1,0xe2,0xd7,0xc5,0xae,0x8e,0x6b,0x5b,\n    0x54,0x52,0x54,0x57,0x5a,0x5c,0x5b,0x5b,0x5d,0x60,0x62,0x64,0x6b,0x6e,0x76,0x79,\n    0x75,0x6c,0x64,0x5a,0x56,0x59,0x5f,0x65,0x66,0x5d,0x55,0x48,0x3e,0x38,0x35,0x33,\n    0x36,0x43,0x4c,0x51,0x54,0x56,0x4f,0x47,0x40,0x38,0x31,0x33,0x3c,0x41,0x43,0x4a,\n    0x50,0x53,0x59,0x60,0x62,0x5e,0x5a,0x53,0x53,0x56,0x5c,0x5c,0x58,0x50,0x49,0x45,\n    0x89,0x91,0x8b,0x88,0x7e,0x77,0x70,0x6e,0x71,0x78,0x76,0x80,0x87,0x90,0x95,0x99,\n    0x99,0x9a,0x98,0x97,0x96,0x95,0x96,0x97,0x9a,0x9c,0x9d,0xa0,0x9e,0xa1,0xa4,0xa7,\n    0xa6,0xa5,0xa5,0xa7,0xa6,0xa4,0x95,0x90,0x8c,0x87,0x83,0x79,0x75,0x75,0x77,0x79,\n    0x79,0x75,0x71,0x6c,0x6a,0x7d,0xb1,0xce,0xde,0xe0,0xd6,0xc1,0xa8,0x89,0x6f,0x62,\n    0x56,0x55,0x56,0x5a,0x5e,0x62,0x65,0x62,0x62,0x62,0x62,0x67,0x6d,0x74,0x79,0x7d,\n    0x78,0x71,0x67,0x60,0x5d,0x5f,0x62,0x67,0x66,0x5e,0x55,0x49,0x3c,0x34,0x33,0x31,\n    0x36,0x42,0x4a,0x4e,0x51,0x53,0x4d,0x46,0x43,0x40,0x3b,0x3c,0x43,0x46,0x46,0x4d,\n    0x4f,0x4e,0x55,0x62,0x65,0x62,0x5e,0x56,0x52,0x57,0x5b,0x5c,0x5b,0x56,0x4f,0x4b,\n    0x88,0x8f,0x8d,0x89,0x80,0x77,0x70,0x6b,0x70,0x77,0x77,0x82,0x8a,0x92,0x96,0x99,\n    0x99,0x9a,0x97,0x97,0x97,0x96,0x97,0x97,0x99,0x9c,0x9f,0x9f,0x9f,0xa1,0xa0,0xa1,\n    0xa0,0xa2,0xa2,0xa5,0xa4,0xa1,0x93,0x91,0x8d,0x8a,0x87,0x7b,0x75,0x75,0x77,0x79,\n    0x79,0x77,0x72,0x6e,0x6e,0x7f,0xae,0xcb,0xd9,0xdb,0xcf,0xba,0xa1,0x85,0x6e,0x6a,\n    0x63,0x5e,0x5c,0x5e,0x61,0x63,0x68,0x68,0x68,0x66,0x66,0x6a,0x6f,0x76,0x7a,0x7c,\n    0x7a,0x73,0x68,0x64,0x60,0x61,0x65,0x69,0x65,0x5d,0x54,0x48,0x3c,0x33,0x31,0x31,\n    0x35,0x3d,0x43,0x49,0x4d,0x4f,0x4d,0x4b,0x4b,0x4a,0x47,0x44,0x47,0x48,0x46,0x4b,\n    0x4c,0x4d,0x54,0x5f,0x64,0x61,0x5d,0x55,0x50,0x53,0x57,0x58,0x59,0x57,0x50,0x49,\n    0x82,0x8a,0x8e,0x8a,0x82,0x76,0x6e,0x6a,0x72,0x75,0x7b,0x83,0x8e,0x95,0x97,0x98,\n    0x98,0x98,0x98,0x98,0x96,0x96,0x98,0x99,0x9b,0x9d,0x9f,0x9f,0x9f,0xa1,0xa0,0xa0,\n    0x9d,0x9e,0x9f,0xa2,0xa1,0x9d,0x94,0x98,0x9a,0x9a,0x90,0x83,0x78,0x74,0x77,0x7b,\n    0x7a,0x79,0x77,0x72,0x6f,0x7e,0xab,0xc6,0xd3,0xd2,0xc2,0xb0,0x98,0x81,0x76,0x72,\n    0x70,0x6b,0x64,0x63,0x65,0x66,0x68,0x6c,0x69,0x67,0x68,0x6b,0x70,0x75,0x78,0x78,\n    0x74,0x6e,0x65,0x62,0x5f,0x5f,0x63,0x67,0x62,0x59,0x53,0x49,0x3a,0x33,0x31,0x33,\n    0x35,0x39,0x42,0x49,0x4c,0x4f,0x52,0x52,0x51,0x52,0x52,0x4a,0x49,0x48,0x45,0x47,\n    0x49,0x4e,0x55,0x5f,0x60,0x5d,0x59,0x56,0x52,0x54,0x55,0x53,0x50,0x4e,0x46,0x44,\n    0x7e,0x8c,0x8f,0x8d,0x85,0x74,0x6c,0x6b,0x75,0x76,0x7f,0x85,0x8f,0x95,0x97,0x99,\n    0x99,0x99,0x98,0x98,0x98,0x98,0x97,0x99,0x9b,0x9e,0x9f,0xa0,0xa0,0xa0,0xa0,0x9f,\n    0x9d,0x9e,0x9e,0xa0,0xa1,0x9e,0x9b,0xa0,0xa4,0xa6,0x9c,0x8a,0x81,0x76,0x77,0x7b,\n    0x79,0x76,0x73,0x70,0x6f,0x7c,0x9e,0xb5,0xbc,0xba,0xac,0x96,0x83,0x79,0x77,0x77,\n    0x74,0x71,0x6f,0x66,0x67,0x66,0x66,0x65,0x60,0x5e,0x61,0x68,0x6e,0x6f,0x72,0x71,\n    0x6d,0x62,0x5e,0x5e,0x5b,0x5a,0x5d,0x60,0x59,0x56,0x4e,0x45,0x3b,0x35,0x34,0x34,\n    0x34,0x38,0x42,0x49,0x49,0x4a,0x4c,0x50,0x51,0x53,0x54,0x4c,0x46,0x46,0x46,0x43,\n    0x48,0x4d,0x53,0x56,0x5a,0x5a,0x57,0x56,0x55,0x55,0x57,0x52,0x4f,0x48,0x3f,0x3f,\n    0x80,0x8f,0x8e,0x8d,0x83,0x73,0x6a,0x6e,0x76,0x78,0x81,0x88,0x91,0x97,0x99,0x99,\n    0x99,0x99,0x99,0x99,0x98,0x98,0x9a,0x9b,0x9d,0x9f,0xa0,0xa0,0xa0,0xa0,0xa0,0x9e,\n    0x9d,0x9d,0xa0,0xa0,0xa2,0x9e,0x9f,0xa5,0xa9,0xaa,0xa4,0x97,0x8d,0x81,0x79,0x77,\n    0x78,0x75,0x71,0x70,0x70,0x75,0x86,0x9b,0xa3,0x9d,0x90,0x7d,0x6a,0x69,0x71,0x72,\n    0x73,0x73,0x6f,0x6d,0x64,0x60,0x5d,0x59,0x55,0x54,0x59,0x62,0x67,0x6a,0x6d,0x6a,\n    0x64,0x5d,0x59,0x55,0x51,0x50,0x53,0x57,0x54,0x53,0x4a,0x43,0x41,0x3b,0x39,0x3b,\n    0x3b,0x3c,0x42,0x47,0x45,0x46,0x48,0x4c,0x4e,0x4f,0x4e,0x4b,0x48,0x44,0x45,0x3f,\n    0x41,0x49,0x4d,0x4d,0x52,0x51,0x50,0x4e,0x4d,0x57,0x5a,0x58,0x54,0x4d,0x3c,0x33,\n    0x8a,0x8f,0x8d,0x8c,0x84,0x74,0x6b,0x71,0x76,0x7b,0x82,0x8b,0x94,0x96,0x98,0x9a,\n    0x9a,0x9a,0x99,0x98,0x98,0x9a,0x9b,0x9c,0x9f,0xa0,0xa1,0xa1,0xa1,0xa0,0x9f,0x9e,\n    0x9d,0x9e,0xa1,0xa2,0xa4,0x9e,0x9f,0xa3,0xaa,0xac,0xa9,0xa4,0x99,0x8e,0x80,0x79,\n    0x76,0x74,0x6f,0x6e,0x6f,0x70,0x75,0x80,0x86,0x7e,0x72,0x66,0x61,0x5f,0x64,0x6d,\n    0x6f,0x70,0x6d,0x69,0x67,0x5b,0x51,0x4c,0x48,0x4a,0x51,0x5d,0x64,0x68,0x6a,0x64,\n    0x5e,0x53,0x4d,0x45,0x42,0x45,0x49,0x4c,0x4f,0x50,0x4b,0x47,0x43,0x41,0x40,0x41,\n    0x44,0x44,0x45,0x47,0x45,0x44,0x44,0x46,0x4b,0x4b,0x4c,0x4e,0x4c,0x48,0x45,0x3e,\n    0x3e,0x45,0x48,0x46,0x48,0x4a,0x48,0x48,0x4a,0x56,0x5d,0x5d,0x56,0x4a,0x3a,0x2b,\n    0x8d,0x8c,0x8b,0x8a,0x83,0x76,0x6e,0x71,0x76,0x7f,0x84,0x8f,0x95,0x97,0x98,0x9a,\n    0x9a,0x9a,0x99,0x99,0x9a,0x9b,0x9d,0x9e,0x9f,0xa0,0xa1,0xa1,0xa1,0xa0,0x9f,0xa0,\n    0xa0,0xa0,0xa1,0xa2,0xa3,0xa0,0xa0,0xa3,0xa8,0xae,0xb0,0xae,0xa5,0x9a,0x8d,0x81,\n    0x75,0x72,0x70,0x6d,0x6d,0x71,0x77,0x7c,0x77,0x6e,0x65,0x5e,0x5f,0x5c,0x5a,0x5f,\n    0x6a,0x6c,0x69,0x67,0x68,0x63,0x52,0x43,0x3c,0x3f,0x48,0x56,0x62,0x68,0x65,0x5b,\n    0x51,0x49,0x3e,0x32,0x2e,0x37,0x40,0x3f,0x46,0x4b,0x4b,0x45,0x45,0x47,0x45,0x48,\n    0x4a,0x47,0x42,0x41,0x3e,0x3b,0x3d,0x40,0x45,0x4b,0x4f,0x53,0x51,0x4d,0x48,0x41,\n    0x3d,0x40,0x3d,0x3d,0x3c,0x3a,0x3e,0x4a,0x51,0x59,0x61,0x5f,0x58,0x4d,0x3c,0x2e,\n    0x8f,0x8c,0x8a,0x8c,0x86,0x7b,0x74,0x74,0x78,0x80,0x87,0x92,0x97,0x99,0x9a,0x9b,\n    0x9a,0x9a,0x99,0x9b,0x9c,0x9d,0x9e,0x9d,0x9e,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,\n    0x9f,0x9f,0xa1,0xa2,0xa4,0xa2,0xa1,0xa4,0xa9,0xb0,0xb2,0xb3,0xaf,0xa5,0x99,0x8c,\n    0x7e,0x73,0x6f,0x6d,0x6e,0x77,0x83,0x85,0x85,0x7f,0x70,0x67,0x65,0x62,0x5f,0x5e,\n    0x5f,0x67,0x6a,0x68,0x67,0x64,0x5f,0x4f,0x3e,0x3f,0x48,0x57,0x63,0x66,0x65,0x57,\n    0x4a,0x40,0x33,0x29,0x25,0x2b,0x38,0x3e,0x47,0x4b,0x4b,0x45,0x45,0x46,0x43,0x46,\n    0x47,0x45,0x3e,0x3c,0x39,0x37,0x3b,0x3f,0x47,0x4f,0x57,0x55,0x51,0x4f,0x4a,0x44,\n    0x3e,0x3b,0x3a,0x37,0x36,0x37,0x3e,0x49,0x55,0x56,0x5b,0x5a,0x52,0x4c,0x3d,0x30,\n    0x8e,0x89,0x8b,0x8b,0x8a,0x80,0x7c,0x77,0x79,0x82,0x8a,0x93,0x97,0x99,0x9a,0x9a,\n    0x9b,0x9c,0x9b,0x9b,0x9c,0x9d,0x9d,0x9e,0x9e,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa1,\n    0xa2,0xa1,0xa1,0xa2,0xa3,0xa3,0xa2,0xa6,0xab,0xb0,0xb4,0xb3,0xb3,0xaf,0xa6,0x98,\n    0x89,0x79,0x70,0x6e,0x6e,0x7a,0x87,0x89,0x85,0x83,0x7d,0x71,0x6b,0x69,0x66,0x64,\n    0x63,0x62,0x69,0x6d,0x6b,0x65,0x5f,0x58,0x4e,0x42,0x47,0x58,0x62,0x67,0x61,0x58,\n    0x4b,0x38,0x2b,0x27,0x24,0x2a,0x36,0x44,0x4b,0x4e,0x4d,0x48,0x46,0x44,0x42,0x43,\n    0x43,0x41,0x3c,0x3a,0x38,0x36,0x3b,0x48,0x50,0x57,0x5e,0x60,0x5c,0x55,0x4f,0x48,\n    0x42,0x3e,0x3b,0x38,0x35,0x34,0x3e,0x49,0x53,0x55,0x56,0x52,0x49,0x40,0x36,0x2a,\n    0x8d,0x8c,0x8a,0x8d,0x93,0x84,0x7b,0x78,0x7a,0x85,0x8e,0x93,0x98,0x99,0x9a,0x9b,\n    0x9a,0x9b,0x9b,0x9c,0x9d,0x9d,0x9e,0x9e,0x9f,0xa0,0xa0,0xa0,0xa2,0xa2,0xa1,0xa1,\n    0xa1,0xa1,0xa0,0xa0,0xa1,0xa3,0xa2,0xa7,0xac,0xaf,0xb4,0xb5,0xb5,0xb5,0xb0,0xa3,\n    0x94,0x85,0x74,0x6e,0x6e,0x75,0x83,0x83,0x81,0x7b,0x77,0x71,0x70,0x6c,0x69,0x67,\n    0x67,0x64,0x63,0x67,0x6e,0x6a,0x6a,0x62,0x56,0x4e,0x47,0x51,0x5f,0x65,0x63,0x5b,\n    0x4d,0x3d,0x2c,0x26,0x25,0x29,0x36,0x43,0x4c,0x4d,0x4c,0x49,0x45,0x3f,0x41,0x3e,\n    0x3c,0x39,0x39,0x38,0x35,0x36,0x3d,0x4c,0x56,0x5d,0x63,0x64,0x64,0x57,0x4d,0x48,\n    0x45,0x44,0x3f,0x3e,0x39,0x38,0x44,0x4c,0x50,0x50,0x50,0x48,0x3d,0x31,0x2a,0x23,\n    0x8d,0x8e,0x8e,0x90,0x93,0x7f,0x76,0x73,0x7f,0x88,0x8f,0x95,0x97,0x99,0x9a,0x9a,\n    0x9a,0x9b,0x9c,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,0xa1,\n    0xa2,0xa2,0xa2,0xa2,0xa2,0xa3,0xa2,0xa6,0xac,0xb0,0xb4,0xb6,0xb6,0xb5,0xb3,0xad,\n    0xa1,0x90,0x7e,0x70,0x6d,0x70,0x75,0x7a,0x76,0x74,0x75,0x78,0x7b,0x7c,0x7d,0x7e,\n    0x80,0x82,0x84,0x87,0x8e,0x98,0x9c,0x93,0x7c,0x63,0x53,0x4f,0x5b,0x64,0x64,0x5d,\n    0x54,0x43,0x32,0x29,0x26,0x2e,0x35,0x41,0x4d,0x4d,0x4c,0x49,0x45,0x40,0x3b,0x39,\n    0x38,0x37,0x37,0x39,0x38,0x3c,0x45,0x4e,0x59,0x62,0x65,0x67,0x63,0x58,0x4f,0x4c,\n    0x4b,0x48,0x47,0x44,0x41,0x41,0x47,0x4e,0x50,0x50,0x49,0x3e,0x31,0x27,0x21,0x1f,\n    0x8f,0x90,0x92,0x8f,0x8c,0x76,0x70,0x71,0x82,0x8c,0x91,0x95,0x97,0x99,0x9a,0x9a,\n    0x9a,0x9c,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa1,0xa0,0xa1,\n    0xa2,0xa2,0xa2,0xa2,0xa3,0xa4,0xa4,0xa7,0xac,0xaf,0xb4,0xb6,0xb6,0xb5,0xb4,0xb1,\n    0xab,0x9d,0x8b,0x78,0x6f,0x72,0x7a,0x8e,0x9b,0xa2,0xa6,0xa7,0xab,0xae,0xb1,0xb4,\n    0xb5,0xb7,0xb9,0xbb,0xba,0xc1,0xc3,0xb4,0x9d,0x82,0x65,0x51,0x5b,0x64,0x65,0x5c,\n    0x53,0x46,0x37,0x28,0x24,0x2b,0x2f,0x3e,0x49,0x4b,0x4a,0x45,0x43,0x40,0x3d,0x3c,\n    0x3c,0x3a,0x3a,0x3b,0x3d,0x43,0x4d,0x53,0x59,0x62,0x69,0x6b,0x64,0x5b,0x54,0x50,\n    0x4f,0x50,0x51,0x4e,0x4b,0x4a,0x4b,0x4d,0x4e,0x49,0x40,0x37,0x2d,0x23,0x1e,0x1e,\n    0x8f,0x92,0x91,0x8e,0x88,0x70,0x6b,0x71,0x85,0x8e,0x93,0x96,0x98,0x9a,0x9b,0x9c,\n    0x9b,0x9c,0x9d,0x9e,0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,0xa0,\n    0xa1,0xa2,0xa2,0xa2,0xa3,0xa4,0xa5,0xa7,0xab,0xaf,0xb3,0xb6,0xb6,0xb6,0xb6,0xb4,\n    0xb1,0xa6,0x94,0x82,0x73,0x7c,0x99,0xb1,0xc0,0xc9,0xca,0xcb,0xcd,0xd0,0xd2,0xd3,\n    0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xcd,0xb6,0x95,0x6f,0x57,0x5c,0x62,0x62,0x5b,\n    0x52,0x43,0x33,0x26,0x1d,0x22,0x29,0x36,0x41,0x46,0x43,0x41,0x40,0x3e,0x3e,0x3e,\n    0x3f,0x3e,0x3e,0x41,0x43,0x4a,0x4e,0x52,0x57,0x5b,0x63,0x66,0x64,0x5b,0x56,0x54,\n    0x54,0x56,0x59,0x55,0x54,0x56,0x54,0x4f,0x4d,0x44,0x39,0x30,0x2b,0x21,0x1d,0x1d,\n    0x91,0x8f,0x8d,0x8d,0x83,0x6d,0x6c,0x74,0x8b,0x8f,0x95,0x97,0x99,0x99,0x9b,0x9c,\n    0x9c,0x9c,0x9c,0x9c,0x9e,0x9e,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,0xa1,\n    0xa1,0xa1,0xa2,0xa2,0xa4,0xa4,0xa5,0xa7,0xaa,0xae,0xb2,0xb4,0xb5,0xb7,0xb6,0xb6,\n    0xb5,0xae,0x9e,0x8c,0x7a,0x8e,0xb5,0xca,0xd9,0xdd,0xdc,0xdd,0xdf,0xe0,0xe3,0xe2,\n    0xe4,0xe5,0xe5,0xe5,0xe6,0xe7,0xe4,0xd8,0xc2,0xa6,0x77,0x5c,0x60,0x61,0x5d,0x59,\n    0x4f,0x40,0x31,0x26,0x1d,0x21,0x2a,0x35,0x3e,0x40,0x3d,0x3e,0x39,0x39,0x3d,0x3f,\n    0x3e,0x42,0x42,0x46,0x4c,0x4f,0x4e,0x4e,0x53,0x57,0x5b,0x5e,0x5d,0x57,0x58,0x57,\n    0x58,0x5a,0x5d,0x5a,0x5c,0x5f,0x5c,0x54,0x4c,0x42,0x33,0x2b,0x26,0x1f,0x1c,0x1b,\n    0x92,0x8f,0x88,0x8a,0x80,0x6f,0x71,0x7d,0x91,0x94,0x97,0x98,0x99,0x9a,0x9c,0x9a,\n    0x9c,0x9d,0x9f,0x9e,0x9f,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,0xa1,\n    0xa1,0xa1,0xa2,0xa2,0xa4,0xa4,0xa5,0xa6,0xaa,0xad,0xb1,0xb3,0xb4,0xb5,0xb8,0xb7,\n    0xb5,0xb2,0xa5,0x95,0x86,0x98,0xba,0xd1,0xdb,0xde,0xdf,0xdd,0xe1,0xe2,0xe5,0xe5,\n    0xe7,0xe7,0xe7,0xe6,0xe5,0xe2,0xe1,0xd5,0xc2,0xa7,0x7e,0x65,0x63,0x56,0x52,0x4f,\n    0x46,0x37,0x2b,0x25,0x1f,0x21,0x29,0x34,0x3b,0x3b,0x36,0x36,0x35,0x37,0x39,0x3e,\n    0x43,0x44,0x45,0x47,0x4b,0x4d,0x4d,0x4d,0x4e,0x53,0x52,0x52,0x55,0x54,0x55,0x57,\n    0x5d,0x60,0x62,0x60,0x60,0x61,0x5e,0x55,0x4b,0x41,0x31,0x27,0x23,0x1d,0x1c,0x1c,\n    0x95,0x8d,0x84,0x88,0x81,0x84,0x89,0x90,0x97,0x99,0x9a,0x9c,0x9d,0x9d,0x9d,0x9e,\n    0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,\n    0xa1,0xa1,0xa2,0xa2,0xa4,0xa4,0xa4,0xa6,0xa9,0xad,0xaf,0xb3,0xb3,0xb4,0xb6,0xb9,\n    0xb6,0xb4,0xad,0x9f,0x90,0x9e,0xb6,0xc7,0xcf,0xcb,0xc6,0xc6,0xc9,0xd1,0xd5,0xd8,\n    0xda,0xdb,0xda,0xd7,0xd4,0xd4,0xd5,0xc8,0xb8,0xa3,0x85,0x68,0x62,0x51,0x45,0x41,\n    0x38,0x2c,0x23,0x23,0x1e,0x22,0x29,0x32,0x37,0x37,0x2f,0x2d,0x29,0x2e,0x34,0x3a,\n    0x3f,0x45,0x47,0x48,0x49,0x4b,0x4c,0x4c,0x4c,0x4e,0x51,0x4e,0x55,0x53,0x55,0x58,\n    0x5e,0x61,0x61,0x61,0x62,0x62,0x61,0x59,0x4a,0x3d,0x2f,0x24,0x1e,0x1c,0x1b,0x20,\n    0x96,0x8b,0x82,0x86,0x8c,0x88,0x8a,0x98,0x9d,0x9c,0x9d,0x9d,0x9e,0x9f,0x9f,0xa0,\n    0xa0,0xa0,0xa0,0xa1,0xa0,0xa0,0x9f,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,\n    0xa1,0xa1,0xa2,0xa2,0xa4,0xa4,0xa5,0xa7,0xab,0xac,0xae,0xb1,0xb2,0xb2,0xb4,0xb7,\n    0xb7,0xb4,0xb0,0xa3,0x95,0x9f,0xae,0xb6,0xb1,0xa1,0x95,0x91,0x98,0xa1,0xab,0xb5,\n    0xb8,0xba,0xb7,0xb2,0xad,0xad,0xaf,0xa1,0x9c,0x91,0x7c,0x68,0x5e,0x49,0x3b,0x30,\n    0x27,0x22,0x1f,0x1d,0x1a,0x20,0x27,0x2c,0x2d,0x2e,0x29,0x22,0x21,0x27,0x2e,0x34,\n    0x3c,0x42,0x47,0x49,0x4d,0x4d,0x4a,0x49,0x49,0x4a,0x4d,0x50,0x52,0x50,0x4f,0x55,\n    0x5b,0x5c,0x5d,0x5d,0x5e,0x5b,0x5e,0x5a,0x4f,0x3d,0x31,0x29,0x1f,0x1d,0x1c,0x22,\n    0x95,0x8b,0x85,0x8a,0x8e,0x8c,0x91,0x97,0x9d,0x9e,0x9d,0x9f,0xa0,0x9f,0x9f,0xa0,\n    0xa0,0xa0,0xa1,0xa1,0xa0,0xa1,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,\n    0xa1,0xa1,0xa2,0xa2,0xa4,0xa4,0xa5,0xa7,0xaa,0xac,0xaf,0xb1,0xb1,0xb2,0xb3,0xb6,\n    0xb6,0xb4,0xb1,0xa9,0x9f,0xa4,0xa8,0xa2,0x96,0x7b,0x5e,0x50,0x59,0x62,0x71,0x82,\n    0x89,0x88,0x80,0x7a,0x72,0x73,0x7b,0x79,0x7e,0x7b,0x74,0x69,0x5c,0x42,0x31,0x22,\n    0x1b,0x1b,0x1b,0x18,0x16,0x1c,0x23,0x25,0x27,0x26,0x22,0x1e,0x1f,0x26,0x2f,0x38,\n    0x40,0x46,0x4c,0x4e,0x4f,0x49,0x44,0x46,0x49,0x49,0x4d,0x4f,0x52,0x4e,0x4b,0x50,\n    0x5c,0x5a,0x5a,0x5b,0x5a,0x53,0x54,0x57,0x50,0x41,0x36,0x2c,0x23,0x21,0x20,0x27,\n    0x90,0x88,0x84,0x88,0x82,0x84,0x89,0x94,0x9d,0x9c,0x9c,0x9f,0x9f,0x9f,0xa0,0xa0,\n    0xa0,0xa0,0xa0,0xa0,0xa0,0xa1,0xa2,0xa1,0xa1,0xa1,0xa0,0xa2,0xa3,0xa3,0xa2,0xa2,\n    0xa2,0xa2,0xa2,0xa3,0xa3,0xa5,0xa5,0xa6,0xaa,0xad,0xae,0xaf,0xb0,0xb0,0xb3,0xb3,\n    0xb4,0xb4,0xb1,0xaf,0xa6,0xa3,0x99,0x85,0x72,0x58,0x3b,0x29,0x27,0x29,0x33,0x40,\n    0x4a,0x4b,0x44,0x36,0x2f,0x2c,0x33,0x44,0x5d,0x6b,0x6e,0x6c,0x5c,0x40,0x2e,0x1e,\n    0x16,0x16,0x15,0x14,0x13,0x1c,0x21,0x25,0x25,0x23,0x20,0x1f,0x21,0x26,0x2d,0x3a,\n    0x48,0x50,0x51,0x52,0x51,0x4a,0x41,0x3e,0x45,0x43,0x46,0x48,0x49,0x46,0x48,0x4d,\n    0x58,0x59,0x55,0x53,0x53,0x4e,0x4e,0x50,0x4f,0x43,0x39,0x2c,0x25,0x22,0x22,0x26,\n    0x8a,0x87,0x88,0x8b,0x83,0x81,0x89,0x94,0x9b,0x9c,0x9b,0x9d,0x9f,0x9f,0xa0,0xa0,\n    0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa1,0xa1,0xa1,0xa1,0xa0,0xa3,0xa4,0xa3,0xa3,0xa2,\n    0xa2,0xa2,0xa2,0xa3,0xa3,0xa5,0xa5,0xa6,0xaa,0xac,0xae,0xae,0xae,0xaf,0xb2,0xb3,\n    0xb3,0xb4,0xb2,0xaf,0xa8,0x9b,0x87,0x6c,0x53,0x3d,0x2e,0x27,0x22,0x20,0x2b,0x36,\n    0x41,0x43,0x3d,0x30,0x27,0x22,0x23,0x30,0x55,0x69,0x74,0x73,0x63,0x45,0x32,0x21,\n    0x16,0x13,0x13,0x15,0x14,0x1c,0x24,0x27,0x25,0x25,0x24,0x22,0x24,0x2b,0x33,0x3f,\n    0x4b,0x52,0x56,0x56,0x55,0x4d,0x41,0x3a,0x3d,0x3a,0x3c,0x3e,0x3d,0x3b,0x41,0x47,\n    0x50,0x57,0x53,0x4e,0x4d,0x4a,0x4c,0x4b,0x47,0x41,0x38,0x2c,0x22,0x21,0x23,0x24,\n    0x86,0x83,0x82,0x8b,0x84,0x83,0x8a,0x95,0x9c,0x9b,0x9a,0x9c,0x9f,0xa0,0xa0,0x9f,\n    0x9f,0x9f,0x9f,0x9f,0x9f,0xa0,0xa0,0xa1,0xa2,0xa1,0xa1,0xa1,0xa2,0xa2,0xa2,0xa2,\n    0xa2,0xa2,0xa2,0xa2,0xa4,0xa4,0xa5,0xa7,0xa9,0xac,0xac,0xad,0xae,0xb0,0xb2,0xb2,\n    0xb3,0xb1,0xaf,0xaa,0xa1,0x8b,0x76,0x56,0x36,0x2e,0x2b,0x27,0x1e,0x1b,0x27,0x33,\n    0x37,0x38,0x35,0x2d,0x26,0x21,0x27,0x34,0x5b,0x70,0x79,0x76,0x69,0x48,0x36,0x25,\n    0x1a,0x14,0x14,0x15,0x15,0x1a,0x20,0x25,0x25,0x26,0x25,0x23,0x28,0x31,0x3a,0x44,\n    0x4c,0x50,0x56,0x52,0x4e,0x45,0x3a,0x36,0x37,0x38,0x3b,0x3b,0x32,0x33,0x3a,0x41,\n    0x4c,0x51,0x52,0x4e,0x46,0x43,0x42,0x42,0x42,0x3e,0x37,0x2c,0x22,0x20,0x23,0x22,\n    0x88,0x86,0x85,0x87,0x82,0x82,0x8c,0x97,0x9d,0x9b,0x9a,0x9c,0x9e,0x9f,0xa0,0x9f,\n    0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xa0,0xa1,0xa1,0xa1,0xa1,0xa1,0xa2,0xa2,0xa2,0xa2,\n    0xa2,0xa2,0xa2,0xa2,0xa4,0xa4,0xa5,0xa7,0xa9,0xac,0xac,0xad,0xae,0xb0,0xb1,0xb2,\n    0xb0,0xac,0xa7,0xa1,0x9a,0x82,0x65,0x3f,0x2a,0x2a,0x2b,0x26,0x20,0x1a,0x20,0x2b,\n    0x2f,0x31,0x29,0x24,0x22,0x22,0x2a,0x39,0x60,0x71,0x7a,0x7a,0x6c,0x4d,0x3b,0x2b,\n    0x1e,0x15,0x13,0x14,0x15,0x19,0x20,0x23,0x25,0x27,0x25,0x24,0x28,0x33,0x3c,0x45,\n    0x4c,0x51,0x54,0x50,0x47,0x3e,0x37,0x33,0x31,0x37,0x36,0x35,0x32,0x33,0x3b,0x46,\n    0x4f,0x52,0x54,0x47,0x3d,0x38,0x37,0x38,0x3a,0x3a,0x37,0x2c,0x24,0x1f,0x20,0x21,\n    0x87,0x88,0x88,0x8d,0x82,0x85,0x8d,0x98,0x9f,0x9b,0x9c,0x9b,0x9d,0x9e,0xa0,0xa0,\n    0xa0,0xa0,0x9f,0x9f,0x9e,0x9f,0x9f,0xa0,0xa1,0xa0,0xa0,0xa0,0xa1,0xa1,0xa2,0xa2,\n    0xa2,0xa2,0xa2,0xa2,0xa4,0xa4,0xa5,0xa7,0xa9,0xab,0xac,0xad,0xae,0xb0,0xb1,0xb1,\n    0xb0,0xab,0xa0,0x9a,0x94,0x83,0x6c,0x48,0x31,0x27,0x27,0x20,0x1b,0x19,0x17,0x20,\n    0x29,0x28,0x22,0x1c,0x1d,0x1e,0x27,0x38,0x5f,0x70,0x77,0x75,0x6c,0x51,0x42,0x32,\n    0x23,0x19,0x15,0x17,0x16,0x19,0x21,0x24,0x26,0x26,0x24,0x22,0x28,0x30,0x3a,0x43,\n    0x49,0x4e,0x4c,0x47,0x3c,0x38,0x34,0x35,0x35,0x37,0x36,0x36,0x37,0x39,0x3f,0x4a,\n    0x51,0x55,0x4f,0x46,0x3a,0x32,0x2e,0x31,0x34,0x35,0x32,0x2c,0x29,0x22,0x21,0x20,\n    0x8c,0x8f,0x8d,0x8b,0x7f,0x82,0x8a,0x99,0xa1,0x9e,0x9c,0x9b,0x9c,0x9f,0x9f,0xa2,\n    0xa2,0xa2,0xa2,0xa0,0xa0,0xa0,0x9f,0xa0,0xa0,0xa0,0xa0,0xa0,0xa1,0xa2,0xa2,0xa2,\n    0xa2,0xa2,0xa2,0xa3,0xa3,0xa5,0xa5,0xa7,0xa9,0xab,0xad,0xae,0xae,0xaf,0xb0,0xb1,\n    0xb0,0xab,0x9e,0x94,0x8f,0x88,0x72,0x55,0x39,0x27,0x21,0x1a,0x13,0x10,0x15,0x1b,\n    0x20,0x21,0x1c,0x1a,0x1e,0x1f,0x28,0x3b,0x5b,0x6a,0x71,0x70,0x68,0x57,0x48,0x3c,\n    0x2c,0x20,0x1a,0x19,0x19,0x20,0x28,0x28,0x28,0x27,0x27,0x28,0x2d,0x32,0x3d,0x46,\n    0x49,0x4b,0x4a,0x42,0x39,0x33,0x2f,0x30,0x37,0x38,0x3a,0x3b,0x44,0x43,0x47,0x4e,\n    0x54,0x53,0x4a,0x42,0x35,0x29,0x26,0x28,0x2e,0x2f,0x2e,0x2e,0x2c,0x29,0x26,0x24,\n    0x8f,0x92,0x8d,0x8b,0x7e,0x81,0x89,0x9a,0xa0,0xa0,0x9b,0x9b,0x9b,0x9e,0xa0,0xa1,\n    0xa1,0xa0,0xa1,0xa1,0xa0,0x9f,0x9f,0xa0,0xa0,0xa0,0xa0,0xa0,0xa1,0xa2,0xa2,0xa2,\n    0xa2,0xa2,0xa2,0xa3,0xa3,0xa5,0xa5,0xa7,0xa9,0xab,0xad,0xae,0xae,0xaf,0xb0,0xb1,\n    0xaf,0xaa,0x9e,0x92,0x8d,0x89,0x79,0x61,0x50,0x40,0x39,0x25,0x11,0x0d,0x12,0x19,\n    0x1f,0x21,0x21,0x1f,0x21,0x22,0x2a,0x3c,0x56,0x63,0x6e,0x6a,0x61,0x55,0x4b,0x3f,\n    0x31,0x25,0x1d,0x1c,0x1e,0x22,0x27,0x28,0x28,0x28,0x2c,0x2e,0x30,0x39,0x42,0x49,\n    0x4b,0x4d,0x4c,0x46,0x3d,0x36,0x2e,0x30,0x38,0x38,0x3a,0x3c,0x43,0x47,0x47,0x4f,\n    0x50,0x4e,0x46,0x3d,0x30,0x26,0x22,0x25,0x29,0x2a,0x2c,0x2d,0x30,0x2c,0x29,0x26,\n    0x93,0x92,0x8c,0x88,0x7b,0x82,0x8d,0x9a,0xa0,0xa0,0x9d,0x9c,0x9c,0x9d,0x9e,0xa1,\n    0xa1,0xa2,0xa1,0xa1,0xa1,0xa0,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa2,0xa2,0xa2,\n    0xa2,0xa1,0xa2,0xa2,0xa3,0xa4,0xa5,0xa6,0xa9,0xab,0xac,0xad,0xaf,0xb0,0xb2,0xb3,\n    0xb1,0xab,0x9e,0x92,0x8b,0x88,0x83,0x78,0x78,0x75,0x61,0x44,0x23,0x11,0x15,0x1d,\n    0x24,0x27,0x29,0x25,0x25,0x25,0x2b,0x3a,0x52,0x60,0x67,0x65,0x5e,0x59,0x51,0x46,\n    0x38,0x2c,0x24,0x22,0x23,0x26,0x27,0x2a,0x2c,0x2f,0x33,0x33,0x36,0x3f,0x45,0x4c,\n    0x51,0x52,0x50,0x4b,0x42,0x3d,0x38,0x34,0x36,0x39,0x37,0x36,0x3b,0x41,0x43,0x46,\n    0x46,0x43,0x3c,0x35,0x2c,0x25,0x21,0x24,0x28,0x2e,0x2f,0x32,0x32,0x2e,0x30,0x2e,\n    0x90,0x8d,0x88,0x83,0x79,0x83,0x8e,0x9b,0xa0,0xa0,0x9e,0x9c,0x9b,0x9b,0x9c,0xa0,\n    0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa2,0xa1,0xa1,\n    0xa1,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xaa,0xac,0xac,0xad,0xaf,0xb0,0xb3,0xb3,\n    0xb1,0xab,0x9d,0x8f,0x87,0x89,0x8d,0x91,0x9d,0x97,0x7d,0x5d,0x38,0x1e,0x1b,0x26,\n    0x2c,0x31,0x31,0x2b,0x2a,0x25,0x29,0x3b,0x51,0x5d,0x62,0x62,0x5c,0x5a,0x54,0x4b,\n    0x3e,0x35,0x2d,0x26,0x26,0x29,0x29,0x2b,0x2e,0x31,0x31,0x35,0x3a,0x47,0x4c,0x51,\n    0x53,0x57,0x56,0x4d,0x47,0x40,0x3b,0x33,0x33,0x34,0x33,0x33,0x35,0x37,0x3c,0x3a,\n    0x37,0x31,0x2e,0x29,0x26,0x24,0x21,0x25,0x29,0x2d,0x30,0x35,0x37,0x33,0x33,0x32,\n    0x8c,0x87,0x7f,0x7e,0x7b,0x85,0x90,0x9c,0x9f,0x9e,0x9e,0x9c,0x9b,0x9a,0x9d,0x9e,\n    0x9f,0xa0,0xa1,0xa1,0xa1,0xa1,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa2,0xa1,0xa1,\n    0xa1,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xaa,0xac,0xac,0xad,0xaf,0xb0,0xb3,0xb2,\n    0xb3,0xad,0x9d,0x8e,0x88,0x87,0x93,0xa4,0xb1,0xa9,0x90,0x6d,0x4c,0x2f,0x2c,0x30,\n    0x38,0x3f,0x3a,0x32,0x2c,0x26,0x29,0x3b,0x50,0x5c,0x62,0x61,0x5b,0x5b,0x57,0x4f,\n    0x45,0x3d,0x32,0x2b,0x2a,0x2e,0x2e,0x2c,0x2a,0x2e,0x34,0x3a,0x40,0x4a,0x50,0x53,\n    0x55,0x58,0x5a,0x51,0x4b,0x45,0x40,0x37,0x34,0x30,0x30,0x31,0x31,0x33,0x34,0x30,\n    0x2c,0x27,0x25,0x21,0x20,0x22,0x24,0x28,0x2e,0x31,0x36,0x39,0x3b,0x39,0x36,0x37,\n    0x8b,0x86,0x7a,0x79,0x7b,0x87,0x90,0x9a,0x9d,0x9e,0x9e,0x9c,0x9b,0x9b,0x9b,0x9e,\n    0xa0,0x9f,0xa0,0xa1,0xa1,0xa0,0x9e,0x9f,0x9f,0xa0,0xa0,0xa2,0xa2,0xa2,0xa1,0xa1,\n    0xa1,0xa1,0xa1,0xa1,0xa4,0xa5,0xa7,0xa8,0xab,0xac,0xac,0xad,0xaf,0xb0,0xb3,0xb3,\n    0xb2,0xae,0xa2,0x97,0x8d,0x89,0x90,0xa6,0xb1,0xad,0x99,0x73,0x4f,0x3a,0x3a,0x3d,\n    0x3f,0x43,0x3d,0x34,0x2a,0x24,0x27,0x3a,0x4f,0x5b,0x61,0x60,0x5b,0x5a,0x5a,0x53,\n    0x4b,0x43,0x3b,0x35,0x32,0x34,0x2e,0x2b,0x28,0x2c,0x31,0x37,0x42,0x48,0x4f,0x53,\n    0x56,0x57,0x56,0x51,0x4c,0x46,0x41,0x39,0x37,0x30,0x2c,0x2b,0x2b,0x2d,0x2b,0x2a,\n    0x26,0x21,0x1d,0x1a,0x1c,0x1e,0x25,0x2a,0x31,0x35,0x39,0x3b,0x3e,0x3c,0x3a,0x3a,\n    0x8e,0x86,0x77,0x77,0x78,0x89,0x90,0x98,0x9c,0x9c,0x9e,0x9d,0x9d,0x9c,0x9b,0x9c,\n    0x9c,0x9d,0x9f,0x9f,0xa0,0x9f,0x9f,0x9f,0x9f,0xa0,0x9f,0xa1,0xa1,0xa1,0xa1,0xa1,\n    0xa1,0xa1,0xa1,0xa2,0xa4,0xa5,0xa7,0xa8,0xab,0xac,0xac,0xad,0xaf,0xb0,0xb3,0xb3,\n    0xb2,0xb1,0xa9,0x9a,0x8e,0x8b,0x8f,0xa1,0xa8,0xa7,0x96,0x6c,0x46,0x45,0x49,0x47,\n    0x47,0x43,0x3b,0x34,0x29,0x24,0x26,0x3b,0x4e,0x5a,0x5f,0x5f,0x5a,0x59,0x5d,0x59,\n    0x54,0x4a,0x43,0x3e,0x39,0x38,0x33,0x2f,0x2d,0x31,0x37,0x3b,0x43,0x47,0x4d,0x53,\n    0x57,0x58,0x54,0x4f,0x4d,0x44,0x41,0x3a,0x35,0x2f,0x29,0x27,0x28,0x28,0x2a,0x2b,\n    0x28,0x24,0x1e,0x18,0x19,0x1d,0x21,0x26,0x2c,0x34,0x39,0x3d,0x3e,0x40,0x3e,0x3e,\n    0x92,0x88,0x79,0x75,0x7c,0x89,0x90,0x97,0x9b,0x9c,0x9c,0x9d,0x9d,0x9d,0x9c,0x9a,\n    0x9b,0x9d,0x9e,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,0xa0,0xa1,\n    0xa1,0xa1,0xa1,0xa1,0xa4,0xa5,0xa7,0xa8,0xab,0xac,0xac,0xad,0xaf,0xb0,0xb3,0xb3,\n    0xb4,0xb2,0xa9,0x9c,0x92,0x88,0x8a,0x9b,0xa7,0xa7,0xa1,0x80,0x63,0x5a,0x54,0x4b,\n    0x46,0x43,0x3c,0x36,0x2e,0x22,0x25,0x3c,0x4f,0x5a,0x5e,0x5c,0x57,0x5a,0x5d,0x5c,\n    0x55,0x4f,0x48,0x44,0x3b,0x38,0x36,0x35,0x32,0x36,0x3b,0x3e,0x46,0x49,0x4c,0x51,\n    0x53,0x51,0x51,0x4f,0x4a,0x42,0x3c,0x38,0x34,0x2a,0x27,0x28,0x27,0x2a,0x2d,0x2e,\n    0x2a,0x27,0x22,0x1a,0x16,0x19,0x1f,0x24,0x28,0x2f,0x33,0x38,0x3b,0x3a,0x3b,0x3c,\n    0x94,0x8a,0x76,0x7a,0x85,0x90,0x93,0x97,0x9a,0x9b,0x9c,0x9d,0x9d,0x9f,0x9d,0x9c,\n    0x9a,0x9c,0x9d,0x9e,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,0xa0,\n    0xa1,0xa1,0xa1,0xa1,0xa3,0xa4,0xa6,0xa8,0xaa,0xab,0xad,0xae,0xaf,0xb0,0xb3,0xb3,\n    0xb3,0xb1,0xa6,0x99,0x8d,0x85,0x8b,0x9f,0xac,0xae,0xae,0x9e,0x8b,0x74,0x60,0x4f,\n    0x48,0x45,0x3f,0x35,0x2c,0x24,0x2a,0x3e,0x50,0x59,0x5e,0x5c,0x59,0x5b,0x5d,0x5d,\n    0x58,0x53,0x4d,0x46,0x3e,0x38,0x35,0x35,0x36,0x39,0x3d,0x41,0x47,0x4a,0x4c,0x4d,\n    0x50,0x4e,0x4e,0x4d,0x44,0x3d,0x3b,0x37,0x33,0x28,0x26,0x26,0x25,0x29,0x30,0x33,\n    0x32,0x31,0x2b,0x20,0x1b,0x1d,0x21,0x24,0x26,0x2c,0x30,0x33,0x34,0x37,0x37,0x35,\n    0x95,0x85,0x74,0x7e,0x8b,0x96,0x97,0x96,0x99,0x99,0x9a,0x9d,0x9d,0x9f,0x9f,0x9e,\n    0x9b,0x9b,0x9a,0x9d,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,0xa0,\n    0xa1,0xa1,0xa1,0xa1,0xa3,0xa4,0xa6,0xa7,0xaa,0xab,0xad,0xae,0xaf,0xb0,0xb3,0xb3,\n    0xb3,0xb0,0xa3,0x97,0x8b,0x85,0x8b,0xa2,0xb6,0xbd,0xc0,0xaf,0x9e,0x87,0x6b,0x50,\n    0x48,0x46,0x3e,0x33,0x2b,0x25,0x2a,0x41,0x51,0x5b,0x5f,0x5d,0x58,0x5b,0x5d,0x5d,\n    0x5b,0x55,0x4d,0x44,0x3b,0x38,0x34,0x33,0x35,0x38,0x3c,0x41,0x49,0x4a,0x4a,0x48,\n    0x49,0x4a,0x4b,0x48,0x40,0x3c,0x37,0x35,0x30,0x2d,0x2b,0x29,0x25,0x2a,0x35,0x3b,\n    0x39,0x37,0x33,0x2d,0x28,0x27,0x2a,0x2a,0x28,0x29,0x2c,0x2f,0x32,0x36,0x35,0x33,\n    0x8f,0x7e,0x77,0x87,0x96,0x9a,0x96,0x96,0x99,0x99,0x99,0x9b,0x9e,0xa0,0xa1,0xa0,\n    0x9d,0x9a,0x99,0x9b,0x9e,0x9e,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xa0,\n    0xa1,0xa1,0xa1,0xa2,0xa4,0xa4,0xa6,0xa6,0xa9,0xab,0xad,0xae,0xaf,0xb0,0xb3,0xb3,\n    0xb4,0xaf,0xa4,0x96,0x8c,0x89,0x92,0xa6,0xbb,0xc9,0xcb,0xbf,0xac,0x95,0x72,0x53,\n    0x4b,0x47,0x3f,0x34,0x2f,0x29,0x2e,0x46,0x57,0x5e,0x62,0x5e,0x57,0x5b,0x5d,0x5f,\n    0x5d,0x57,0x4e,0x47,0x3d,0x38,0x33,0x33,0x37,0x39,0x3e,0x42,0x48,0x47,0x48,0x48,\n    0x49,0x47,0x49,0x46,0x41,0x3f,0x3e,0x37,0x33,0x33,0x33,0x32,0x30,0x35,0x3d,0x47,\n    0x44,0x41,0x3e,0x39,0x37,0x34,0x32,0x32,0x31,0x2e,0x2c,0x2e,0x32,0x35,0x35,0x31,\n    0x82,0x77,0x7a,0x8b,0x96,0x96,0x94,0x94,0x96,0x96,0x98,0x98,0x9b,0x9f,0xa1,0xa0,\n    0x9e,0x9c,0x99,0x97,0x9c,0x9d,0x9e,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xa0,\n    0xa1,0xa1,0xa1,0xa2,0xa4,0xa4,0xa6,0xa6,0xa9,0xab,0xad,0xae,0xaf,0xb0,0xb3,0xb3,\n    0xb3,0xaf,0xa4,0x97,0x8d,0x8d,0x99,0xab,0xbe,0xc9,0xcc,0xc4,0xb3,0x97,0x76,0x56,\n    0x4b,0x49,0x40,0x34,0x2e,0x29,0x30,0x49,0x59,0x61,0x63,0x5f,0x58,0x5b,0x5e,0x5f,\n    0x5e,0x59,0x50,0x49,0x3d,0x37,0x34,0x38,0x39,0x3b,0x3d,0x40,0x42,0x42,0x42,0x42,\n    0x43,0x42,0x43,0x43,0x42,0x41,0x41,0x3c,0x37,0x36,0x36,0x34,0x37,0x3b,0x43,0x48,\n    0x48,0x49,0x48,0x44,0x42,0x41,0x3c,0x3b,0x3c,0x36,0x31,0x32,0x33,0x34,0x33,0x2e,\n    0x7d,0x7a,0x7b,0x87,0x88,0x88,0x8a,0x8f,0x93,0x96,0x97,0x96,0x98,0x9c,0xa0,0x9f,\n    0x9f,0x9d,0x9a,0x98,0x99,0x9c,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9f,0x9f,0x9f,0xa0,\n    0xa1,0xa1,0xa1,0xa2,0xa4,0xa4,0xa6,0xa6,0xa9,0xaa,0xac,0xae,0xaf,0xb0,0xb3,0xb3,\n    0xb3,0xaf,0xa5,0x9a,0x94,0x98,0xa2,0xb0,0xbe,0xc6,0xc9,0xc2,0xaf,0x95,0x71,0x55,\n    0x49,0x44,0x3c,0x33,0x2f,0x2a,0x32,0x4d,0x5c,0x64,0x64,0x5f,0x59,0x5c,0x5e,0x5f,\n    0x5e,0x59,0x52,0x4b,0x40,0x3a,0x3a,0x39,0x38,0x39,0x3b,0x3e,0x41,0x40,0x3d,0x3f,\n    0x3c,0x3f,0x40,0x42,0x45,0x46,0x45,0x41,0x3c,0x3a,0x38,0x38,0x3a,0x3d,0x45,0x48,\n    0x4c,0x4f,0x50,0x4e,0x4d,0x4d,0x47,0x46,0x49,0x42,0x3e,0x39,0x3a,0x3a,0x38,0x33,\n    0x7c,0x81,0x7e,0x7f,0x7b,0x7e,0x80,0x89,0x90,0x94,0x95,0x95,0x97,0x99,0x9b,0x9f,\n    0xa1,0x9d,0x99,0x98,0x96,0x99,0x9a,0x9c,0x9d,0x9d,0x9d,0x9d,0x9e,0x9f,0x9f,0x9f,\n    0x9f,0xa1,0xa2,0xa2,0xa3,0xa4,0xa5,0xa7,0xa8,0xa9,0xac,0xad,0xaf,0xb0,0xb2,0xb2,\n    0xb3,0xaf,0xa4,0x9c,0x9a,0x9f,0xa8,0xb3,0xbc,0xc4,0xc7,0xbd,0xab,0x8e,0x6a,0x49,\n    0x42,0x3e,0x3a,0x36,0x30,0x2b,0x34,0x4e,0x5f,0x65,0x65,0x5e,0x59,0x5c,0x5e,0x5f,\n    0x5f,0x5d,0x56,0x4d,0x45,0x40,0x41,0x3f,0x3e,0x3e,0x3f,0x40,0x42,0x44,0x40,0x39,\n    0x35,0x37,0x3b,0x41,0x46,0x45,0x43,0x3d,0x3b,0x38,0x34,0x33,0x38,0x40,0x44,0x48,\n    0x4d,0x50,0x51,0x4e,0x4f,0x4f,0x4c,0x4c,0x4b,0x44,0x3f,0x3c,0x3b,0x3a,0x39,0x37,\n    0x81,0x85,0x84,0x7e,0x79,0x79,0x7c,0x83,0x88,0x8d,0x91,0x92,0x97,0x99,0x9a,0x9d,\n    0xa0,0x9f,0x9c,0x9a,0x98,0x98,0x99,0x9c,0x9e,0x9d,0x9d,0x9d,0x9f,0x9f,0x9f,0x9f,\n    0x9f,0xa0,0xa1,0xa2,0xa2,0xa3,0xa5,0xa6,0xa7,0xa8,0xaa,0xac,0xae,0xaf,0xb2,0xb3,\n    0xb3,0xaf,0xaa,0xa6,0xa1,0xa4,0xab,0xb6,0xc0,0xc8,0xc7,0xbc,0xa6,0x85,0x5e,0x41,\n    0x3f,0x3e,0x3e,0x38,0x30,0x2b,0x38,0x52,0x62,0x68,0x67,0x5e,0x59,0x5c,0x5e,0x60,\n    0x5f,0x5d,0x57,0x4e,0x47,0x45,0x45,0x43,0x42,0x43,0x45,0x42,0x41,0x42,0x41,0x3a,\n    0x32,0x32,0x36,0x39,0x3f,0x3e,0x3d,0x39,0x37,0x35,0x2f,0x2f,0x35,0x3b,0x42,0x4a,\n    0x4e,0x50,0x50,0x50,0x50,0x4f,0x49,0x49,0x49,0x43,0x3e,0x3d,0x3b,0x37,0x39,0x3b,\n    0x84,0x90,0x8e,0x85,0x7f,0x7d,0x80,0x82,0x84,0x89,0x8b,0x8e,0x94,0x97,0x99,0x9c,\n    0x9f,0x9f,0x9f,0x9c,0x99,0x97,0x97,0x99,0x9d,0x9f,0x9d,0x9d,0x9d,0x9d,0x9e,0x9f,\n    0x9f,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa7,0xa8,0xa9,0xac,0xad,0xaf,0xb1,0xb0,\n    0xb2,0xb1,0xb2,0xae,0xa8,0xa6,0xad,0xb9,0xc3,0xce,0xc9,0xb9,0xa0,0x79,0x51,0x3d,\n    0x3e,0x3d,0x3e,0x37,0x30,0x2d,0x3e,0x57,0x66,0x6b,0x68,0x5e,0x57,0x5c,0x5f,0x5f,\n    0x60,0x5b,0x53,0x4c,0x43,0x40,0x41,0x43,0x41,0x3f,0x42,0x42,0x3f,0x3d,0x3b,0x35,\n    0x2d,0x2b,0x2f,0x31,0x34,0x35,0x36,0x34,0x2e,0x2d,0x28,0x27,0x2e,0x34,0x3b,0x43,\n    0x4b,0x50,0x4f,0x51,0x52,0x4f,0x4a,0x46,0x45,0x41,0x3e,0x3b,0x3c,0x37,0x37,0x3c,\n    0x99,0x9b,0x99,0x90,0x8a,0x86,0x83,0x83,0x85,0x88,0x8b,0x8e,0x90,0x91,0x97,0x9d,\n    0x9f,0xa0,0x9e,0x9c,0x9c,0x9b,0x98,0x98,0x9c,0x9d,0x9f,0x9f,0x9d,0x9d,0x9e,0x9f,\n    0x9f,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa4,0xa7,0xa7,0xa9,0xab,0xad,0xae,0xb0,0xb2,\n    0xb6,0xbb,0xbb,0xb5,0xaf,0xac,0xb1,0xbe,0xcb,0xd2,0xcb,0xb8,0x98,0x6e,0x46,0x3d,\n    0x3c,0x3b,0x3a,0x34,0x30,0x2f,0x42,0x5c,0x6a,0x71,0x6b,0x5f,0x58,0x5c,0x5f,0x5f,\n    0x5f,0x58,0x4e,0x46,0x3e,0x3c,0x3f,0x41,0x40,0x3e,0x3d,0x40,0x3c,0x39,0x35,0x30,\n    0x29,0x28,0x29,0x29,0x2a,0x2c,0x2f,0x2a,0x26,0x25,0x24,0x23,0x2a,0x34,0x3a,0x3f,\n    0x47,0x4e,0x50,0x53,0x53,0x50,0x4b,0x47,0x42,0x3d,0x3a,0x39,0x3a,0x37,0x39,0x3b,\n    0x9d,0xa3,0xa3,0x98,0x8c,0x89,0x8a,0x8b,0x88,0x88,0x8a,0x8d,0x8d,0x8b,0x8e,0x92,\n    0x99,0x9c,0x9a,0x9c,0x9c,0x9a,0x93,0x93,0x95,0x9a,0x9e,0x9f,0x9d,0x9e,0x9e,0x9f,\n    0x9f,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa4,0xa7,0xa7,0xa8,0xab,0xac,0xae,0xb2,0xb8,\n    0xbe,0xc0,0xbe,0xba,0xb0,0xac,0xb4,0xc1,0xce,0xd1,0xca,0xb3,0x91,0x61,0x41,0x3e,\n    0x3f,0x3d,0x3a,0x32,0x2c,0x2b,0x43,0x61,0x70,0x76,0x6e,0x60,0x5a,0x5c,0x5f,0x60,\n    0x5f,0x55,0x49,0x3d,0x37,0x36,0x39,0x41,0x41,0x3c,0x35,0x35,0x33,0x32,0x2e,0x2b,\n    0x26,0x23,0x26,0x25,0x27,0x26,0x26,0x25,0x21,0x23,0x22,0x22,0x2b,0x35,0x3a,0x42,\n    0x49,0x4f,0x51,0x55,0x52,0x4e,0x4f,0x46,0x40,0x39,0x37,0x37,0x36,0x3a,0x3b,0x39,\n    0x9f,0xaa,0xa9,0x9c,0x91,0x8b,0x8b,0x8d,0x8d,0x8c,0x8c,0x8c,0x87,0x81,0x7f,0x7f,\n    0x85,0x89,0x8e,0x91,0x8d,0x84,0x7a,0x78,0x83,0x91,0x9d,0x9e,0x9e,0x9e,0x9e,0x9e,\n    0x9e,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa5,0xa6,0xa8,0xab,0xae,0xb3,0xbb,0xc0,\n    0xc4,0xc6,0xc2,0xbb,0xb4,0xb0,0xb7,0xc6,0xd2,0xd0,0xc4,0xa8,0x83,0x55,0x43,0x46,\n    0x3f,0x3d,0x39,0x30,0x27,0x27,0x45,0x67,0x77,0x7a,0x73,0x62,0x59,0x5c,0x5f,0x60,\n    0x5c,0x50,0x42,0x35,0x2f,0x32,0x36,0x39,0x3c,0x39,0x31,0x30,0x2f,0x2d,0x28,0x23,\n    0x21,0x20,0x20,0x23,0x23,0x22,0x21,0x21,0x23,0x24,0x25,0x27,0x2c,0x39,0x41,0x45,\n    0x49,0x4e,0x50,0x52,0x51,0x4e,0x4d,0x47,0x40,0x39,0x38,0x37,0x37,0x3a,0x3a,0x38,\n    0x98,0xa9,0xaa,0xa1,0x95,0x8d,0x8a,0x8a,0x8d,0x8e,0x8d,0x8a,0x83,0x76,0x6a,0x65,\n    0x6c,0x74,0x77,0x75,0x6f,0x65,0x5d,0x5c,0x6e,0x86,0x98,0x9c,0x9c,0x9e,0x9e,0x9e,\n    0x9e,0x9f,0xa0,0xa1,0xa2,0xa3,0xa3,0xa4,0xa5,0xa5,0xa8,0xad,0xb4,0xbc,0xc3,0xc6,\n    0xc8,0xc8,0xc2,0xbc,0xb7,0xb5,0xbe,0xcc,0xd0,0xc9,0xbc,0x9c,0x73,0x4e,0x4c,0x4b,\n    0x43,0x3b,0x34,0x29,0x1f,0x25,0x45,0x6b,0x7a,0x7d,0x75,0x64,0x58,0x5c,0x5f,0x5d,\n    0x5a,0x4d,0x3d,0x30,0x2a,0x2e,0x32,0x38,0x3b,0x38,0x31,0x2d,0x2a,0x26,0x22,0x1f,\n    0x20,0x1f,0x1e,0x20,0x20,0x20,0x1f,0x1f,0x22,0x23,0x26,0x27,0x2d,0x3b,0x40,0x47,\n    0x4b,0x4e,0x4e,0x4f,0x4e,0x4d,0x4b,0x45,0x3f,0x39,0x36,0x37,0x39,0x37,0x39,0x37,\n    0x92,0xa6,0xad,0xa5,0x9c,0x92,0x8e,0x8c,0x8d,0x8c,0x8c,0x8a,0x80,0x70,0x61,0x55,\n    0x56,0x5a,0x5d,0x5d,0x56,0x49,0x41,0x43,0x64,0x84,0x97,0x9d,0x9c,0x9d,0x9e,0x9e,\n    0x9e,0x9f,0xa0,0xa2,0xa3,0xa3,0xa3,0xa5,0xa7,0xac,0xb2,0xba,0xbf,0xc4,0xc7,0xca,\n    0xc8,0xc8,0xc4,0xbd,0xb9,0xbc,0xc8,0xd1,0xce,0xc3,0xae,0x8c,0x60,0x4d,0x51,0x4e,\n    0x45,0x39,0x2e,0x26,0x1d,0x25,0x46,0x6f,0x7d,0x7f,0x79,0x66,0x58,0x5d,0x5f,0x5f,\n    0x57,0x48,0x39,0x2d,0x26,0x2e,0x39,0x3d,0x3e,0x3c,0x36,0x30,0x2a,0x28,0x25,0x23,\n    0x21,0x1f,0x1e,0x1e,0x1e,0x1e,0x1c,0x1f,0x21,0x22,0x27,0x2c,0x36,0x3e,0x45,0x49,\n    0x4c,0x4e,0x4c,0x4b,0x4a,0x49,0x43,0x3f,0x3c,0x39,0x34,0x35,0x37,0x3b,0x3b,0x3c,\n    0x95,0xa8,0xaf,0xa7,0x9d,0x98,0x8d,0x8f,0x8c,0x8b,0x8b,0x8c,0x7f,0x70,0x61,0x58,\n    0x52,0x51,0x53,0x52,0x50,0x4c,0x47,0x47,0x73,0x91,0x9f,0x9f,0x9e,0x9c,0x9d,0x9e,\n    0x9e,0x9f,0xa1,0xa1,0xa3,0xa4,0xa8,0xaa,0xb2,0xbb,0xc0,0xc6,0xc8,0xc9,0xc9,0xc8,\n    0xc8,0xc8,0xc4,0xc0,0xbf,0xc6,0xd1,0xd4,0xc9,0xbc,0x9e,0x78,0x56,0x51,0x53,0x4e,\n    0x45,0x3a,0x2e,0x21,0x1a,0x22,0x47,0x72,0x81,0x83,0x7b,0x67,0x59,0x5d,0x5e,0x5d,\n    0x54,0x44,0x39,0x2e,0x29,0x32,0x3b,0x3e,0x3e,0x3c,0x38,0x34,0x30,0x2c,0x28,0x27,\n    0x24,0x1f,0x1d,0x1d,0x1e,0x1d,0x1d,0x1d,0x21,0x22,0x28,0x2f,0x38,0x3f,0x47,0x4b,\n    0x4c,0x4c,0x4a,0x49,0x44,0x41,0x3b,0x39,0x38,0x3a,0x38,0x36,0x38,0x3c,0x40,0x41,\n    0x95,0xa7,0xab,0xa8,0xa1,0x9c,0x92,0x8f,0x8c,0x89,0x8a,0x89,0x80,0x71,0x5e,0x58,\n    0x54,0x52,0x52,0x52,0x51,0x4d,0x4d,0x5f,0x8c,0xa4,0xab,0xa4,0x9e,0x9c,0x9c,0x9d,\n    0x9e,0x9e,0xa0,0xa0,0x9f,0xa7,0xb1,0xb8,0xbf,0xc7,0xcc,0xcf,0xce,0xcc,0xc9,0xc6,\n    0xc6,0xc9,0xc7,0xc4,0xc4,0xcf,0xd9,0xd8,0xcb,0xb2,0x8b,0x60,0x53,0x52,0x52,0x4d,\n    0x46,0x3c,0x2c,0x22,0x1e,0x25,0x48,0x74,0x83,0x85,0x7d,0x6b,0x5b,0x5d,0x5f,0x5b,\n    0x50,0x42,0x36,0x2d,0x2b,0x31,0x3a,0x3f,0x3d,0x39,0x38,0x34,0x32,0x30,0x2e,0x2b,\n    0x28,0x21,0x1e,0x1d,0x1b,0x19,0x1a,0x19,0x1d,0x22,0x27,0x30,0x37,0x3f,0x47,0x4b,\n    0x4d,0x4b,0x4b,0x48,0x44,0x3f,0x3a,0x35,0x36,0x37,0x37,0x38,0x40,0x42,0x45,0x4a,\n    0x93,0xa2,0xa6,0xa5,0xa1,0x9c,0x99,0x90,0x8c,0x89,0x88,0x88,0x80,0x73,0x65,0x59,\n    0x56,0x53,0x52,0x52,0x52,0x4e,0x4c,0x77,0xa3,0xb5,0xb4,0xa8,0xa0,0x9c,0x9c,0x9c,\n    0x9e,0x9d,0x9f,0xa0,0xa3,0xb0,0xbb,0xc6,0xcc,0xce,0xd2,0xd3,0xcf,0xcd,0xc8,0xc4,\n    0xc6,0xc8,0xc8,0xc6,0xcb,0xd8,0xdb,0xdb,0xc9,0xad,0x7e,0x55,0x52,0x52,0x50,0x4a,\n    0x47,0x3f,0x2d,0x25,0x21,0x26,0x4c,0x72,0x84,0x86,0x7d,0x6b,0x5d,0x5d,0x5e,0x58,\n    0x4c,0x3e,0x33,0x2b,0x2f,0x35,0x3b,0x3e,0x3e,0x3b,0x34,0x32,0x30,0x32,0x2f,0x2b,\n    0x29,0x25,0x20,0x1f,0x1c,0x1d,0x1c,0x1b,0x1e,0x23,0x27,0x2f,0x38,0x3e,0x45,0x49,\n    0x4a,0x48,0x49,0x48,0x46,0x42,0x3a,0x35,0x33,0x37,0x3a,0x3f,0x45,0x48,0x49,0x4f,\n    0xb8,0x9c,0xa1,0xa3,0xa2,0x9c,0x99,0x94,0x8e,0x8a,0x88,0x84,0x7f,0x75,0x67,0x5c,\n    0x55,0x52,0x52,0x51,0x50,0x4c,0x5c,0x96,0xb6,0xc1,0xbb,0xaf,0xa5,0x9d,0x9e,0x9e,\n    0xa2,0xa7,0xa9,0xaa,0xb0,0xbc,0xc4,0xcc,0xd0,0xd1,0xd1,0xd2,0xd0,0xcb,0xc6,0xc4,\n    0xc6,0xc8,0xc7,0xcb,0xd1,0xdb,0xde,0xd6,0xc0,0xa7,0x7a,0x58,0x50,0x4d,0x48,0x46,\n    0x44,0x3b,0x31,0x2b,0x24,0x28,0x4e,0x72,0x83,0x86,0x7d,0x69,0x5d,0x5e,0x5d,0x57,\n    0x4c,0x3f,0x34,0x2d,0x31,0x35,0x39,0x3a,0x3b,0x38,0x30,0x2e,0x2f,0x31,0x2f,0x2a,\n    0x28,0x25,0x1f,0x22,0x21,0x22,0x22,0x22,0x23,0x26,0x2b,0x31,0x3d,0x45,0x46,0x46,\n    0x45,0x45,0x47,0x4a,0x4a,0x45,0x3e,0x37,0x37,0x3a,0x3f,0x45,0x4b,0x4c,0x4f,0x55,\n    0xdd,0xb9,0xa1,0xa2,0xa1,0x9c,0x99,0x97,0x90,0x8b,0x85,0x84,0x7f,0x77,0x6a,0x5d,\n    0x53,0x51,0x51,0x4f,0x4d,0x50,0x80,0xad,0xc2,0xc9,0xc1,0xb6,0xab,0xa3,0xa5,0xad,\n    0xb2,0xb6,0xb9,0xba,0xbe,0xc5,0xcb,0xcf,0xcf,0xd1,0xd1,0xd0,0xd0,0xcb,0xc5,0xc5,\n    0xc7,0xca,0xca,0xcb,0xd2,0xda,0xda,0xcd,0xb9,0x9e,0x78,0x5c,0x51,0x4c,0x45,0x46,\n    0x45,0x3d,0x36,0x30,0x28,0x2c,0x50,0x70,0x83,0x85,0x7b,0x68,0x5d,0x5d,0x5c,0x56,\n    0x4b,0x3f,0x34,0x2e,0x32,0x36,0x38,0x37,0x34,0x32,0x32,0x30,0x30,0x30,0x2c,0x28,\n    0x25,0x25,0x23,0x22,0x25,0x23,0x24,0x26,0x28,0x2a,0x2c,0x32,0x3d,0x43,0x44,0x44,\n    0x42,0x42,0x45,0x4b,0x4d,0x49,0x44,0x3b,0x3c,0x3e,0x45,0x4a,0x4d,0x4e,0x52,0x56,\n    0xe1,0xdb,0xb6,0xa1,0xa2,0x9e,0x99,0x97,0x92,0x8e,0x86,0x85,0x81,0x79,0x6c,0x60,\n    0x55,0x50,0x50,0x4f,0x4e,0x6d,0xa0,0xbd,0xca,0xcb,0xc4,0xba,0xb5,0xb3,0xb6,0xbd,\n    0xc2,0xc4,0xc5,0xc6,0xc7,0xca,0xcc,0xcf,0xd0,0xd0,0xd0,0xd0,0xcf,0xca,0xc7,0xc8,\n    0xca,0xc9,0xc7,0xc5,0xc6,0xcc,0xce,0xc2,0xb2,0x99,0x78,0x63,0x54,0x4b,0x47,0x49,\n    0x47,0x3e,0x38,0x31,0x2a,0x2d,0x51,0x70,0x81,0x83,0x7a,0x67,0x5d,0x5c,0x5b,0x54,\n    0x49,0x3d,0x33,0x2d,0x31,0x36,0x39,0x3a,0x36,0x35,0x38,0x34,0x31,0x2f,0x29,0x25,\n    0x22,0x20,0x1e,0x21,0x25,0x24,0x25,0x28,0x2b,0x2e,0x32,0x36,0x3d,0x41,0x42,0x41,\n    0x3e,0x3c,0x40,0x47,0x4a,0x4b,0x47,0x42,0x43,0x42,0x47,0x4e,0x50,0x51,0x53,0x56,\n    0xde,0xe3,0xda,0xb5,0xa4,0xa1,0x9c,0x99,0x94,0x91,0x8a,0x87,0x82,0x7b,0x6c,0x5f,\n    0x56,0x51,0x4f,0x4d,0x5d,0x91,0xb4,0xc9,0xcd,0xcb,0xc6,0xbf,0xbd,0xc0,0xc4,0xc9,\n    0xcb,0xcc,0xcb,0xcb,0xcc,0xcd,0xcf,0xd0,0xd0,0xd0,0xd0,0xd1,0xcd,0xcb,0xca,0xc9,\n    0xc9,0xc3,0xbc,0xb6,0xb6,0xb6,0xb9,0xb0,0xa1,0x92,0x81,0x6c,0x5c,0x4f,0x48,0x46,\n    0x44,0x3c,0x36,0x2f,0x28,0x2c,0x52,0x70,0x81,0x84,0x7a,0x67,0x5d,0x5a,0x58,0x51,\n    0x47,0x3c,0x31,0x2f,0x32,0x33,0x37,0x3c,0x39,0x37,0x37,0x33,0x2e,0x2a,0x24,0x1e,\n    0x1c,0x1a,0x1a,0x1d,0x21,0x23,0x26,0x2c,0x34,0x36,0x39,0x3b,0x42,0x42,0x41,0x3d,\n    0x3a,0x37,0x39,0x43,0x49,0x4d,0x49,0x48,0x48,0x49,0x4a,0x50,0x53,0x53,0x51,0x53,\n    0xdc,0xde,0xe5,0xe0,0xb6,0xa4,0x9f,0x9d,0x99,0x95,0x8e,0x8a,0x83,0x7b,0x69,0x5d,\n    0x55,0x4e,0x4d,0x58,0x85,0xad,0xc3,0xcd,0xce,0xcb,0xc6,0xc2,0xc2,0xc6,0xc5,0xc3,\n    0xc1,0xc6,0xca,0xcb,0xcd,0xce,0xcf,0xd0,0xd1,0xd0,0xd0,0xd0,0xcf,0xcc,0xcd,0xca,\n    0xc5,0xb7,0xab,0xa4,0xa2,0xa3,0xa7,0x9e,0x9a,0x90,0x86,0x72,0x66,0x58,0x49,0x43,\n    0x3e,0x37,0x2f,0x2a,0x22,0x2b,0x51,0x73,0x82,0x84,0x7a,0x67,0x5d,0x5a,0x56,0x4e,\n    0x45,0x38,0x31,0x30,0x30,0x30,0x32,0x36,0x38,0x37,0x34,0x30,0x2b,0x27,0x20,0x1b,\n    0x17,0x17,0x17,0x1a,0x1d,0x22,0x27,0x31,0x3a,0x40,0x3f,0x3d,0x42,0x40,0x3c,0x37,\n    0x34,0x34,0x39,0x3f,0x4a,0x4e,0x4c,0x49,0x4b,0x4f,0x4d,0x51,0x55,0x51,0x51,0x53,\n    0xdf,0xdd,0xdf,0xe4,0xdf,0xbb,0xa5,0xa0,0x9b,0x98,0x93,0x8f,0x84,0x76,0x64,0x59,\n    0x51,0x4c,0x50,0x7a,0xa5,0xbd,0xcb,0xcd,0xcd,0xca,0xc6,0xc5,0xc3,0xc4,0xbc,0xaf,\n    0xa7,0xb3,0xbe,0xc8,0xcd,0xcd,0xce,0xcf,0xd0,0xcf,0xcf,0xd1,0xd0,0xcd,0xcb,0xc6,\n    0xbb,0xa9,0x96,0x8b,0x8d,0x96,0x9c,0x97,0x96,0x96,0x8b,0x79,0x70,0x60,0x48,0x41,\n    0x3a,0x31,0x28,0x21,0x1d,0x27,0x54,0x72,0x81,0x82,0x78,0x66,0x5e,0x5a,0x52,0x49,\n    0x3f,0x34,0x30,0x2e,0x2c,0x2c,0x2e,0x31,0x33,0x31,0x2e,0x2e,0x28,0x22,0x1c,0x16,\n    0x15,0x16,0x17,0x18,0x1a,0x1e,0x26,0x32,0x3e,0x44,0x44,0x42,0x41,0x3f,0x3b,0x35,\n    0x32,0x35,0x3c,0x40,0x48,0x4e,0x4f,0x4a,0x4a,0x4f,0x4c,0x4d,0x50,0x54,0x53,0x52,\n    0xdf,0xdf,0xdc,0xe0,0xe4,0xde,0xb7,0xa5,0x9e,0x9c,0x97,0x91,0x85,0x71,0x5f,0x51,\n    0x4c,0x4f,0x72,0x9b,0xb7,0xc8,0xcb,0xcb,0xcd,0xc9,0xc5,0xc4,0xc3,0xbe,0xad,0x90,\n    0x82,0x97,0xb3,0xc5,0xce,0xce,0xcd,0xcd,0xce,0xcf,0xcf,0xd0,0xcf,0xcc,0xca,0xbf,\n    0xb1,0xa1,0x8d,0x86,0x88,0x93,0x98,0x99,0x9c,0x9c,0x8f,0x83,0x78,0x65,0x4a,0x3c,\n    0x35,0x29,0x1e,0x18,0x18,0x29,0x52,0x72,0x80,0x80,0x77,0x65,0x5d,0x59,0x4f,0x45,\n    0x3b,0x31,0x2f,0x2b,0x29,0x29,0x29,0x29,0x2a,0x2a,0x27,0x23,0x1f,0x1c,0x17,0x14,\n    0x14,0x16,0x17,0x15,0x19,0x1d,0x26,0x31,0x3c,0x42,0x46,0x46,0x45,0x41,0x3a,0x35,\n    0x34,0x38,0x40,0x44,0x48,0x4d,0x4f,0x49,0x49,0x49,0x4b,0x4a,0x4e,0x56,0x56,0x53,\n    0xdf,0xdf,0xdd,0xe0,0xe0,0xe4,0xdf,0xba,0xa4,0x9f,0x9a,0x96,0x84,0x6c,0x57,0x50,\n    0x4c,0x69,0x96,0xb4,0xc3,0xc9,0xcb,0xcc,0xcc,0xc8,0xc6,0xc3,0xc5,0xbc,0x98,0x6a,\n    0x54,0x7c,0xa8,0xc0,0xcb,0xce,0xcc,0xcc,0xcb,0xcd,0xcf,0xcf,0xd0,0xcb,0xc3,0xb8,\n    0xaa,0xa1,0x96,0x92,0x93,0x96,0x97,0x98,0x9a,0x9d,0x9a,0x8e,0x82,0x6e,0x53,0x40,\n    0x37,0x2d,0x26,0x24,0x24,0x32,0x58,0x73,0x7f,0x7f,0x76,0x64,0x5b,0x55,0x4c,0x41,\n    0x38,0x32,0x2f,0x2b,0x28,0x25,0x22,0x24,0x22,0x22,0x1e,0x1c,0x17,0x16,0x13,0x12,\n    0x13,0x16,0x17,0x1a,0x1c,0x20,0x25,0x2e,0x38,0x40,0x46,0x49,0x46,0x40,0x37,0x34,\n    0x37,0x3c,0x43,0x49,0x4e,0x4f,0x4e,0x48,0x44,0x45,0x47,0x46,0x4b,0x54,0x53,0x4f,\n    0xdd,0xe0,0xdf,0xdf,0xe0,0xe2,0xe5,0xe0,0xb7,0xa1,0x9c,0x97,0x81,0x68,0x53,0x4b,\n    0x5e,0x8c,0xad,0xc1,0xc7,0xc8,0xcb,0xcd,0xca,0xc9,0xc7,0xc3,0xc3,0xb2,0x92,0x63,\n    0x4d,0x6d,0x9d,0xb9,0xc8,0xcd,0xcb,0xca,0xca,0xcc,0xce,0xcf,0xce,0xc7,0xbf,0xb4,\n    0xa8,0xa2,0x9e,0x9b,0x99,0x97,0x97,0x9a,0x9d,0x9b,0x9a,0x90,0x83,0x73,0x5d,0x49,\n    0x41,0x3c,0x37,0x36,0x36,0x40,0x61,0x77,0x7f,0x7f,0x74,0x62,0x5a,0x4e,0x45,0x3d,\n    0x38,0x30,0x2d,0x2b,0x28,0x24,0x1e,0x1e,0x1c,0x1a,0x17,0x16,0x12,0x12,0x11,0x11,\n    0x14,0x16,0x19,0x1b,0x1e,0x21,0x25,0x2a,0x34,0x3b,0x3e,0x41,0x41,0x3c,0x35,0x33,\n    0x36,0x3c,0x45,0x4b,0x4f,0x4e,0x48,0x44,0x3e,0x3d,0x3f,0x40,0x47,0x4e,0x52,0x4f,\n    0xdf,0xde,0xe2,0xdf,0xdf,0xdf,0xe4,0xe5,0xe0,0xb3,0x9d,0x94,0x7c,0x60,0x4f,0x59,\n    0x85,0xa9,0xbf,0xc9,0xc6,0xc7,0xcb,0xcf,0xcc,0xc9,0xc7,0xc4,0xc2,0xb0,0x90,0x64,\n    0x4d,0x62,0x8e,0xb0,0xc4,0xcd,0xcb,0xca,0xca,0xcc,0xce,0xcf,0xcc,0xc3,0xb8,0xb2,\n    0xaa,0xa9,0xa7,0xa5,0xa1,0x9a,0x97,0x97,0x96,0x96,0x97,0x8d,0x81,0x75,0x65,0x56,\n    0x51,0x4d,0x4c,0x4b,0x4a,0x4f,0x6c,0x7b,0x7f,0x7f,0x75,0x61,0x57,0x4a,0x42,0x38,\n    0x30,0x2d,0x2c,0x2a,0x27,0x23,0x20,0x1b,0x1c,0x18,0x14,0x13,0x12,0x10,0x10,0x12,\n    0x13,0x14,0x18,0x1b,0x1d,0x1f,0x21,0x25,0x2e,0x35,0x38,0x39,0x3b,0x3a,0x35,0x31,\n    0x35,0x3b,0x44,0x4a,0x4e,0x4b,0x42,0x3d,0x39,0x36,0x38,0x3e,0x45,0x4c,0x51,0x50,\n    0xdf,0xe1,0xe1,0xe0,0xe2,0xe5,0xe5,0xe5,0xe6,0xdf,0xae,0x8b,0x70,0x57,0x53,0x7d,\n    0xa6,0xbb,0xc5,0xc9,0xc6,0xc7,0xca,0xcd,0xcd,0xc9,0xc7,0xc4,0xbf,0xb3,0x9b,0x7b,\n    0x62,0x59,0x80,0xa4,0xbc,0xca,0xcd,0xcb,0xcd,0xce,0xcf,0xcc,0xc6,0xbc,0xb3,0xac,\n    0xad,0xae,0xab,0xab,0xa7,0x9e,0x98,0x93,0x91,0x91,0x92,0x89,0x7e,0x75,0x67,0x61,\n    0x5f,0x5b,0x59,0x59,0x55,0x58,0x70,0x7d,0x7f,0x7c,0x71,0x5e,0x51,0x47,0x3d,0x2f,\n    0x27,0x2a,0x2a,0x28,0x25,0x20,0x1c,0x1a,0x19,0x16,0x13,0x11,0x11,0x10,0x0f,0x11,\n    0x12,0x12,0x16,0x19,0x1c,0x1f,0x20,0x25,0x29,0x2c,0x30,0x32,0x34,0x35,0x32,0x2d,\n    0x2e,0x36,0x3f,0x44,0x48,0x44,0x3d,0x37,0x33,0x33,0x38,0x3e,0x44,0x4c,0x50,0x50,\n    0xdd,0xe3,0xe0,0xe5,0xde,0xde,0xe2,0xe5,0xe7,0xec,0xdd,0x8e,0x62,0x52,0x74,0xa0,\n    0xba,0xc5,0xc5,0xc9,0xc7,0xc6,0xc8,0xcc,0xcf,0xca,0xc7,0xc4,0xc1,0xbe,0xac,0x98,\n    0x7e,0x68,0x73,0x98,0xae,0xbf,0xc7,0xcf,0xd0,0xd0,0xcc,0xc8,0xbf,0xb5,0xad,0xa7,\n    0xab,0xad,0xaf,0xae,0xad,0xa5,0x9c,0x93,0x8d,0x89,0x88,0x84,0x7c,0x6f,0x6a,0x68,\n    0x69,0x67,0x66,0x64,0x5e,0x5e,0x73,0x7c,0x7c,0x7a,0x70,0x5d,0x4d,0x42,0x36,0x29,\n    0x24,0x26,0x26,0x25,0x22,0x20,0x1e,0x19,0x18,0x15,0x13,0x11,0x10,0x10,0x10,0x11,\n    0x12,0x13,0x17,0x1a,0x1c,0x1e,0x20,0x26,0x29,0x2a,0x2e,0x32,0x2f,0x2e,0x2c,0x2a,\n    0x2a,0x31,0x39,0x3b,0x3f,0x3c,0x37,0x32,0x34,0x38,0x3c,0x3f,0x45,0x4c,0x50,0x50,\n    0xde,0xdd,0xdf,0xdc,0xdb,0xe0,0xe5,0xe5,0xe5,0xe9,0xeb,0xd5,0x6d,0x6c,0x99,0xb6,\n    0xc6,0xc8,0xc6,0xc7,0xc8,0xc6,0xc7,0xc9,0xcc,0xcb,0xc6,0xc3,0xbf,0xc1,0xb8,0xaa,\n    0x95,0x7e,0x72,0x82,0x9b,0xae,0xbd,0xca,0xd0,0xcf,0xc9,0xbf,0xb6,0xac,0xa7,0xa6,\n    0xa7,0xaa,0xad,0xae,0xaf,0xa8,0xa2,0x98,0x8c,0x86,0x85,0x83,0x82,0x78,0x6d,0x66,\n    0x66,0x66,0x64,0x64,0x5f,0x5d,0x6e,0x77,0x7b,0x78,0x6e,0x58,0x4a,0x3e,0x30,0x26,\n    0x1f,0x24,0x24,0x21,0x23,0x22,0x1e,0x1b,0x18,0x14,0x12,0x0f,0x12,0x12,0x12,0x11,\n    0x10,0x15,0x18,0x1b,0x1c,0x1d,0x1d,0x27,0x2a,0x2d,0x30,0x31,0x2e,0x2a,0x28,0x28,\n    0x2c,0x2e,0x34,0x33,0x36,0x36,0x31,0x31,0x33,0x3c,0x40,0x42,0x47,0x4b,0x50,0x4e,\n    0xdf,0xde,0xe1,0xda,0xda,0xe2,0xe6,0xe8,0xe8,0xe9,0xea,0xe9,0xce,0x98,0xb4,0xc5,\n    0xc9,0xc6,0xc5,0xc6,0xc9,0xc7,0xc7,0xc9,0xcb,0xcb,0xc6,0xc3,0xbf,0xbe,0xbf,0xb8,\n    0xa9,0x94,0x85,0x7b,0x84,0x96,0xad,0xc1,0xcc,0xc9,0xc1,0xb5,0xac,0xa6,0xa5,0xa1,\n    0xa3,0xa6,0xab,0xb0,0xb2,0xaf,0xa8,0x9b,0x92,0x8c,0x8e,0x90,0x92,0x8c,0x7c,0x6d,\n    0x63,0x61,0x61,0x60,0x5b,0x59,0x6b,0x72,0x76,0x72,0x69,0x55,0x49,0x3a,0x2d,0x20,\n    0x1d,0x21,0x21,0x23,0x28,0x25,0x1f,0x1a,0x17,0x14,0x11,0x10,0x11,0x13,0x14,0x12,\n    0x13,0x17,0x1c,0x1b,0x1b,0x1c,0x1d,0x25,0x2c,0x30,0x31,0x32,0x2e,0x2a,0x29,0x2c,\n    0x2d,0x30,0x34,0x36,0x34,0x34,0x30,0x32,0x36,0x3f,0x45,0x45,0x47,0x4a,0x4f,0x4c,\n    0xdf,0xe1,0xde,0xd8,0xd9,0xe1,0xea,0xee,0xec,0xea,0xed,0xeb,0xea,0xd5,0xc4,0xc8,\n    0xc7,0xc7,0xc7,0xc7,0xca,0xc8,0xc6,0xc9,0xca,0xcb,0xc7,0xc3,0xc0,0xbf,0xc0,0xbd,\n    0xb3,0xa2,0x93,0x83,0x70,0x72,0x96,0xb3,0xbd,0xbd,0xb4,0xa9,0xa0,0x9f,0x9f,0x9f,\n    0xa0,0xa3,0xaa,0xad,0xb3,0xb1,0xab,0x9c,0x97,0x94,0x98,0x9c,0x9d,0x99,0x87,0x74,\n    0x5e,0x54,0x53,0x54,0x50,0x4e,0x60,0x6a,0x6e,0x6b,0x65,0x53,0x43,0x34,0x26,0x1b,\n    0x1a,0x1d,0x21,0x25,0x28,0x25,0x1f,0x1a,0x14,0x13,0x10,0x0f,0x0f,0x11,0x12,0x13,\n    0x15,0x1b,0x1d,0x1b,0x1b,0x1c,0x1d,0x25,0x2b,0x2f,0x2e,0x2f,0x2e,0x2c,0x2a,0x29,\n    0x2c,0x30,0x35,0x39,0x3a,0x37,0x32,0x37,0x39,0x42,0x49,0x47,0x47,0x4a,0x4b,0x4b,\n    0xdd,0xdf,0xde,0xdc,0xe0,0xe2,0xeb,0xef,0xed,0xed,0xef,0xe5,0xe9,0xeb,0xd9,0xca,\n    0xc9,0xc7,0xc7,0xc7,0xc9,0xc9,0xc6,0xc9,0xc9,0xcb,0xc8,0xc2,0xc0,0xbe,0xbf,0xbb,\n    0xb7,0xad,0x9e,0x8b,0x6d,0x5c,0x81,0xa2,0xae,0xb0,0xa5,0x9b,0x9a,0x99,0x99,0x9b,\n    0x9d,0xa0,0xa7,0xac,0xb3,0xb4,0xb1,0xa4,0x99,0x95,0x9a,0x9e,0xa0,0x9a,0x8b,0x75,\n    0x59,0x46,0x43,0x47,0x43,0x4d,0x5f,0x67,0x66,0x66,0x5f,0x4e,0x3f,0x30,0x23,0x18,\n    0x18,0x18,0x20,0x23,0x24,0x22,0x20,0x19,0x14,0x12,0x10,0x10,0x0f,0x11,0x12,0x15,\n    0x17,0x1b,0x1e,0x1c,0x1b,0x1b,0x1c,0x22,0x29,0x2f,0x2d,0x2c,0x2d,0x2a,0x2a,0x2c,\n    0x2f,0x32,0x37,0x3c,0x3d,0x3d,0x3d,0x43,0x43,0x47,0x4b,0x4a,0x49,0x49,0x48,0x46,\n    0xe0,0xe0,0xdd,0xdc,0xe2,0xe7,0xed,0xef,0xf1,0xf0,0xed,0xe1,0xe6,0xe9,0xea,0xd3,\n    0xc9,0xc7,0xc8,0xc8,0xc8,0xc9,0xc7,0xc8,0xc8,0xc9,0xc8,0xc0,0xc0,0xbc,0xbb,0xb8,\n    0xb2,0xac,0x9f,0x83,0x63,0x59,0x79,0x97,0xa3,0xa2,0x99,0x97,0x96,0x95,0x9a,0x98,\n    0x9b,0x9e,0xa5,0xac,0xb2,0xb5,0xb0,0xa7,0x97,0x8b,0x90,0x99,0x9c,0x94,0x83,0x71,\n    0x57,0x47,0x49,0x57,0x68,0x7c,0x82,0x7b,0x6f,0x63,0x56,0x49,0x3c,0x2e,0x23,0x19,\n    0x17,0x18,0x1d,0x20,0x20,0x1e,0x1c,0x18,0x13,0x0f,0x0f,0x0f,0x0e,0x10,0x11,0x15,\n    0x19,0x1c,0x1f,0x1c,0x1b,0x1a,0x1b,0x1f,0x26,0x2d,0x2e,0x2c,0x2c,0x2b,0x2d,0x30,\n    0x35,0x38,0x3c,0x40,0x3d,0x3d,0x41,0x46,0x47,0x4b,0x4e,0x4b,0x49,0x49,0x47,0x43,\n    0xe0,0xe2,0xdf,0xe1,0xe4,0xe5,0xee,0xf0,0xf0,0xeb,0xf1,0xd5,0xec,0xf0,0xf0,0xea,\n    0xd1,0xca,0xcb,0xc9,0xc8,0xc8,0xc8,0xc7,0xc7,0xc6,0xc9,0xc5,0xbf,0xbe,0xb9,0xb5,\n    0xad,0x9f,0x92,0x75,0x62,0x6c,0x87,0x93,0x9b,0x99,0x96,0x95,0x94,0x95,0x97,0x98,\n    0x97,0x9a,0x9f,0xab,0xb3,0xb6,0xb4,0xab,0x98,0x83,0x7d,0x83,0x8e,0x8e,0x88,0x80,\n    0x7f,0x80,0x89,0x99,0xa4,0xac,0xa4,0x97,0x83,0x6a,0x4e,0x42,0x38,0x2a,0x1d,0x17,\n    0x15,0x17,0x1a,0x1c,0x1d,0x1b,0x18,0x12,0x0f,0x10,0x0f,0x10,0x0f,0x10,0x11,0x15,\n    0x19,0x1a,0x1c,0x1d,0x1b,0x1a,0x18,0x1a,0x23,0x2b,0x2c,0x2c,0x2d,0x2d,0x31,0x37,\n    0x3b,0x3c,0x41,0x43,0x40,0x3d,0x41,0x43,0x46,0x4b,0x4d,0x4f,0x4b,0x47,0x46,0x42,\n    0xe3,0xe5,0xe6,0xe3,0xe5,0xdd,0xea,0xf0,0xeb,0xec,0xe5,0xd7,0xe5,0xeb,0xec,0xf0,\n    0xea,0xcf,0xc9,0xca,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc7,0xc6,0xbc,0xbd,0xb5,0xac,\n    0x9a,0x85,0x78,0x6d,0x70,0x82,0x91,0x96,0x98,0x96,0x95,0x93,0x94,0x96,0x96,0x94,\n    0x93,0x95,0x9a,0xa6,0xb2,0xb6,0xb3,0xa6,0x96,0x7d,0x72,0x7a,0x8f,0xa0,0xa7,0xac,\n    0xb1,0xb7,0xbd,0xc6,0xcd,0xce,0xc5,0xb1,0x97,0x70,0x4a,0x3e,0x34,0x26,0x1b,0x18,\n    0x15,0x15,0x17,0x18,0x18,0x16,0x13,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x11,0x11,0x15,\n    0x18,0x19,0x1a,0x18,0x19,0x18,0x18,0x1c,0x22,0x26,0x29,0x2c,0x2f,0x32,0x35,0x39,\n    0x3c,0x3f,0x40,0x3f,0x3e,0x3d,0x42,0x43,0x46,0x4a,0x4e,0x4e,0x4b,0x47,0x45,0x40,\n    0xe4,0xe6,0xeb,0xea,0xde,0xdd,0xe0,0xee,0xeb,0xed,0xe9,0xe0,0xe8,0xf0,0xee,0xf0,\n    0xe5,0xe0,0xcc,0xc9,0xc8,0xc8,0xc8,0xc9,0xc8,0xc9,0xc6,0xc5,0xb9,0xaf,0xa2,0x95,\n    0x86,0x78,0x72,0x76,0x87,0x94,0x9a,0x98,0x96,0x95,0x93,0x95,0x96,0x95,0x95,0x90,\n    0x8d,0x8c,0x93,0x9f,0xae,0xb3,0xb2,0xab,0xa3,0xa2,0xa4,0xaa,0xb5,0xc1,0xc8,0xcc,\n    0xce,0xd2,0xd8,0xdd,0xe0,0xe1,0xd6,0xc1,0xa5,0x79,0x48,0x39,0x2f,0x22,0x1a,0x18,\n    0x15,0x14,0x15,0x15,0x14,0x12,0x10,0x0e,0x0f,0x0f,0x0f,0x10,0x10,0x10,0x11,0x14,\n    0x17,0x1a,0x19,0x18,0x17,0x18,0x1a,0x1f,0x24,0x28,0x2b,0x2f,0x32,0x34,0x37,0x3b,\n    0x3f,0x40,0x3e,0x3d,0x3c,0x3e,0x42,0x46,0x4b,0x4c,0x4e,0x4f,0x4f,0x4c,0x46,0x40,\n    0xe6,0xe9,0xe9,0xed,0xea,0xe1,0xe1,0xe8,0xed,0xf0,0xe3,0xd8,0xf0,0xf1,0xef,0xe0,\n    0xe5,0xe2,0xd3,0xc9,0xca,0xc7,0xc8,0xc6,0xc5,0xc3,0xbb,0xb5,0xa3,0x9a,0x94,0x8d,\n    0x86,0x7d,0x7f,0x89,0x97,0x9c,0x9e,0x98,0x95,0x93,0x92,0x94,0x95,0x94,0x95,0x86,\n    0x7d,0x7f,0x8b,0x9a,0xaa,0xb1,0xb3,0xb4,0xb7,0xb9,0xbe,0xc6,0xce,0xd7,0xdb,0xdf,\n    0xe2,0xe4,0xe6,0xe9,0xec,0xea,0xe0,0xca,0xa9,0x7a,0x48,0x36,0x2b,0x1f,0x18,0x16,\n    0x14,0x12,0x14,0x14,0x13,0x11,0x10,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x10,0x10,0x12,\n    0x14,0x16,0x15,0x16,0x18,0x18,0x1b,0x1f,0x25,0x2a,0x2f,0x35,0x37,0x37,0x37,0x3a,\n    0x3e,0x43,0x40,0x3a,0x39,0x3d,0x41,0x45,0x49,0x4f,0x4d,0x4d,0x4f,0x4d,0x48,0x43,\n    0xdc,0xe1,0xe4,0xe9,0xeb,0xe7,0xe9,0xed,0xee,0xea,0xe3,0xdf,0xee,0xef,0xe2,0xea,\n    0xe8,0xcf,0xe6,0xd3,0xcb,0xc8,0xc2,0xbc,0xb3,0xae,0xab,0xaa,0xa4,0x9b,0x94,0x8d,\n    0x8c,0x8d,0x91,0x97,0x9d,0xa1,0x9f,0x97,0x92,0x90,0x93,0x92,0x90,0x92,0x8d,0x7d,\n    0x73,0x78,0x84,0x99,0xa9,0xb0,0xb6,0xc1,0xc6,0xce,0xd8,0xde,0xe2,0xe4,0xe7,0xe7,\n    0xe9,0xe8,0xe8,0xe9,0xe8,0xe6,0xdd,0xc6,0xaa,0x79,0x44,0x31,0x27,0x1b,0x16,0x13,\n    0x12,0x11,0x13,0x14,0x12,0x11,0x10,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x10,0x10,0x12,\n    0x13,0x13,0x13,0x15,0x16,0x18,0x1c,0x1f,0x25,0x2b,0x34,0x3b,0x3c,0x3c,0x3a,0x3a,\n    0x3c,0x3e,0x3d,0x37,0x38,0x3d,0x42,0x45,0x49,0x4e,0x50,0x4f,0x4c,0x4c,0x4d,0x47,\n    0xe1,0xdf,0xe5,0xe1,0xe5,0xe1,0xe8,0xeb,0xea,0xe9,0xe9,0xd7,0xe7,0xe5,0xeb,0xe3,\n    0xb5,0xa4,0xf0,0xe5,0xc4,0xb6,0xb1,0xad,0xac,0xae,0xae,0xac,0xa4,0x9a,0x97,0x94,\n    0x95,0x97,0x97,0x98,0xa0,0xa0,0x9e,0x95,0x8e,0x91,0x91,0x91,0x92,0x92,0x87,0x76,\n    0x73,0x79,0x86,0x9b,0xa8,0xad,0xb7,0xc7,0xd3,0xda,0xe2,0xe5,0xe9,0xe7,0xe8,0xe8,\n    0xe4,0xe4,0xe3,0xe0,0xe0,0xdd,0xd2,0xbc,0x9c,0x70,0x3f,0x2c,0x23,0x1a,0x16,0x14,\n    0x13,0x11,0x11,0x12,0x12,0x0f,0x0f,0x0f,0x0f,0x10,0x11,0x11,0x12,0x10,0x10,0x10,\n    0x10,0x13,0x13,0x13,0x15,0x17,0x1b,0x1f,0x21,0x2b,0x36,0x3d,0x3f,0x40,0x3e,0x3b,\n    0x3a,0x39,0x38,0x37,0x36,0x3c,0x44,0x48,0x4c,0x50,0x53,0x51,0x4d,0x4c,0x4d,0x4c,\n    0xdf,0xdf,0xe6,0xe1,0xe3,0xe8,0xec,0xea,0xed,0xe9,0xe4,0xda,0xe3,0xe8,0xde,0xd9,\n    0x94,0xb0,0xe6,0xdd,0xcb,0xb3,0xb2,0xb3,0xaf,0xad,0xad,0xab,0xa8,0xa7,0xa0,0x97,\n    0x94,0x93,0x95,0x98,0xa0,0x9f,0x9b,0x93,0x8d,0x8d,0x8e,0x8e,0x90,0x8f,0x83,0x77,\n    0x78,0x80,0x8b,0x9a,0xa6,0xab,0xb8,0xcd,0xda,0xe3,0xe9,0xe6,0xe8,0xe6,0xe3,0xdd,\n    0xd9,0xd6,0xd2,0xcd,0xca,0xc9,0xbb,0xa4,0x85,0x5e,0x37,0x28,0x20,0x19,0x17,0x14,\n    0x14,0x14,0x14,0x12,0x12,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x11,0x13,0x14,0x13,\n    0x13,0x12,0x12,0x12,0x14,0x15,0x19,0x1d,0x22,0x2e,0x3a,0x43,0x46,0x46,0x43,0x40,\n    0x3b,0x38,0x37,0x36,0x35,0x38,0x42,0x49,0x4e,0x51,0x55,0x54,0x52,0x50,0x51,0x50,\n    0xe1,0xdb,0xe0,0xe2,0xe2,0xe8,0xe4,0xe6,0xec,0xe2,0xea,0xe1,0xd9,0xde,0xe2,0xb9,\n    0xa2,0xbd,0xdd,0xd7,0xd6,0xbf,0xb5,0xb0,0xb2,0xb3,0xb1,0xad,0xa7,0x9a,0x92,0x90,\n    0x90,0x91,0x93,0x97,0x9f,0x9f,0x99,0x8f,0x87,0x88,0x87,0x8a,0x8f,0x8c,0x86,0x80,\n    0x81,0x8a,0x93,0x9e,0xa3,0xaa,0xbc,0xc9,0xd7,0xde,0xdf,0xdd,0xdd,0xd7,0xd2,0xcb,\n    0xc3,0xba,0xb1,0xab,0xa4,0xa1,0x93,0x7c,0x5e,0x43,0x2f,0x25,0x1d,0x17,0x16,0x14,\n    0x14,0x13,0x12,0x12,0x12,0x13,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x13,0x14,0x14,\n    0x14,0x12,0x12,0x12,0x12,0x12,0x16,0x19,0x20,0x2b,0x3a,0x47,0x4b,0x4b,0x47,0x40,\n    0x3a,0x33,0x33,0x34,0x35,0x36,0x3f,0x47,0x4b,0x50,0x55,0x56,0x54,0x54,0x52,0x4f,\n    0xe4,0xde,0xe0,0xe0,0xe9,0xe4,0xe7,0xee,0xef,0xea,0xe9,0xd9,0xd6,0xe1,0xd4,0xae,\n    0xb1,0xc0,0xdc,0xd4,0xd5,0xcc,0xbc,0xb7,0xb3,0xaa,0xa5,0xa0,0x9b,0x96,0x93,0x91,\n    0x90,0x91,0x93,0x98,0x9f,0x9d,0x98,0x89,0x81,0x81,0x84,0x8b,0x90,0x92,0x8e,0x8d,\n    0x8f,0x94,0x9c,0xa0,0xa1,0xae,0xbb,0xc7,0xd1,0xd2,0xce,0xc7,0xc2,0xb6,0xab,0xa0,\n    0x94,0x86,0x79,0x6f,0x67,0x62,0x5e,0x50,0x3f,0x2b,0x27,0x20,0x1b,0x1a,0x17,0x17,\n    0x17,0x16,0x15,0x15,0x14,0x14,0x15,0x15,0x15,0x14,0x14,0x15,0x14,0x14,0x14,0x14,\n    0x14,0x14,0x14,0x12,0x10,0x11,0x13,0x16,0x1c,0x25,0x34,0x3f,0x46,0x47,0x43,0x3c,\n    0x37,0x31,0x32,0x34,0x36,0x37,0x3e,0x46,0x4a,0x4e,0x56,0x59,0x59,0x5a,0x57,0x53,\n    0xd9,0xde,0xdd,0xe2,0xe4,0xe8,0xe5,0xe9,0xee,0xeb,0xe4,0xd1,0xd0,0xe4,0xb3,0xa9,\n    0xb2,0xbf,0xc8,0xbd,0xd7,0xd0,0xca,0xa5,0xa0,0x9f,0x9e,0x9d,0x9a,0x96,0x95,0x93,\n    0x91,0x91,0x94,0x99,0x9f,0x9b,0x92,0x82,0x7a,0x80,0x87,0x8c,0x92,0x97,0x98,0x98,\n    0x99,0x9a,0x9c,0xa0,0xa1,0xad,0xbb,0xc5,0xc9,0xc9,0xbf,0xb2,0xa9,0x99,0x87,0x72,\n    0x5f,0x52,0x42,0x39,0x31,0x30,0x2d,0x31,0x2c,0x25,0x23,0x1f,0x1d,0x1b,0x18,0x17,\n    0x17,0x15,0x15,0x16,0x15,0x14,0x15,0x15,0x15,0x15,0x14,0x14,0x15,0x15,0x15,0x15,\n    0x15,0x15,0x15,0x12,0x11,0x10,0x10,0x14,0x18,0x1f,0x2d,0x38,0x3e,0x3f,0x3a,0x36,\n    0x30,0x2c,0x30,0x35,0x38,0x3e,0x3d,0x41,0x47,0x4e,0x55,0x5c,0x5d,0x5b,0x58,0x52,\n    0xd2,0xde,0xde,0xe4,0xd8,0xe4,0xf0,0xe6,0xeb,0xef,0xe4,0xcf,0xd0,0xe5,0xae,0xa1,\n    0xaf,0x9d,0x90,0xc4,0xdb,0xd0,0xd8,0xb2,0x9f,0xa1,0xa2,0xa0,0x9c,0x99,0x95,0x92,\n    0x91,0x92,0x94,0x99,0x9f,0x9a,0x8d,0x7f,0x7a,0x84,0x8a,0x93,0x97,0x9c,0x9d,0x9e,\n    0x9f,0x9e,0x9c,0x9e,0xa8,0xb3,0xbe,0xc8,0xca,0xc5,0xb7,0xa7,0x90,0x76,0x5b,0x45,\n    0x35,0x2c,0x24,0x26,0x2c,0x2d,0x2c,0x2d,0x2c,0x26,0x25,0x21,0x1f,0x1f,0x1c,0x1b,\n    0x1b,0x1b,0x19,0x16,0x16,0x1b,0x1f,0x20,0x20,0x1b,0x18,0x17,0x18,0x18,0x18,0x17,\n    0x17,0x15,0x14,0x14,0x14,0x12,0x13,0x13,0x18,0x1e,0x29,0x31,0x36,0x33,0x30,0x2e,\n    0x2a,0x28,0x2c,0x30,0x3a,0x3e,0x3e,0x3e,0x42,0x4c,0x52,0x5a,0x5c,0x5c,0x5a,0x54,\n    0xd4,0xdf,0xe0,0xd7,0xd6,0xdd,0xed,0xed,0xed,0xea,0xbe,0xc0,0xd0,0xe8,0xb7,0xa2,\n    0x9c,0x86,0x9f,0xc2,0xda,0xd3,0xd8,0xce,0xaa,0x9e,0xa1,0x9e,0x9c,0x98,0x95,0x92,\n    0x91,0x92,0x95,0x99,0xa0,0x9a,0x8d,0x81,0x7f,0x86,0x8e,0x97,0x9c,0x9f,0xa1,0xa1,\n    0xa0,0x9d,0x9c,0xa0,0xaf,0xbb,0xc3,0xc5,0xcc,0xcb,0xc0,0xb2,0x99,0x82,0x6d,0x5a,\n    0x46,0x39,0x30,0x2c,0x32,0x31,0x2f,0x2c,0x2c,0x27,0x25,0x23,0x21,0x20,0x1f,0x1f,\n    0x1e,0x1e,0x1c,0x1b,0x1f,0x24,0x26,0x2a,0x2a,0x26,0x1d,0x1a,0x18,0x17,0x16,0x17,\n    0x18,0x15,0x14,0x13,0x14,0x12,0x13,0x16,0x1c,0x20,0x26,0x2a,0x2e,0x2b,0x2a,0x26,\n    0x22,0x26,0x2a,0x30,0x39,0x3d,0x3d,0x3d,0x3f,0x49,0x4c,0x55,0x5b,0x5b,0x5a,0x56,\n    0xd5,0xde,0xda,0xd3,0xda,0xdc,0xea,0xed,0xee,0xc2,0xa6,0xa7,0xdc,0xdc,0xbc,0xae,\n    0x9a,0xa2,0xaa,0xc5,0xd7,0xd6,0xd0,0xdb,0xc9,0xa7,0xa0,0x9f,0x9b,0x98,0x95,0x93,\n    0x92,0x92,0x95,0x98,0x9f,0x9c,0x90,0x89,0x85,0x8e,0x96,0x9c,0x9e,0xa1,0xa0,0x9f,\n    0x9e,0x9c,0x9c,0xa6,0xb9,0xc5,0xd0,0xd7,0xe1,0xe1,0xd9,0xcf,0xc1,0xad,0x9d,0x8c,\n    0x72,0x63,0x50,0x44,0x3f,0x37,0x3b,0x37,0x31,0x2b,0x2a,0x29,0x26,0x25,0x24,0x25,\n    0x22,0x22,0x22,0x20,0x24,0x29,0x2b,0x2e,0x31,0x2c,0x24,0x21,0x1a,0x19,0x17,0x17,\n    0x17,0x16,0x15,0x15,0x13,0x14,0x14,0x18,0x20,0x21,0x24,0x29,0x2c,0x29,0x26,0x22,\n    0x21,0x23,0x27,0x2d,0x39,0x3f,0x3e,0x3e,0x3e,0x44,0x48,0x4d,0x52,0x57,0x58,0x56,\n    0xd6,0xd8,0xce,0xd0,0xd1,0xe0,0xeb,0xeb,0xe8,0xc9,0xb1,0xba,0xe0,0xd0,0xc4,0xc2,\n    0x9b,0x9c,0xa6,0xaa,0xd1,0xd9,0xd0,0xdc,0xd5,0xb6,0xa0,0x9f,0x9c,0x98,0x95,0x94,\n    0x94,0x93,0x95,0x99,0xa0,0x9e,0x96,0x8e,0x8e,0x94,0x9a,0x9d,0x9d,0x9e,0x9d,0x9b,\n    0x9a,0x9b,0x9f,0xb3,0xc6,0xd5,0xde,0xe7,0xec,0xef,0xec,0xe3,0xdb,0xc5,0xbc,0xaf,\n    0x9a,0x81,0x6d,0x5b,0x4c,0x43,0x45,0x43,0x39,0x31,0x2c,0x2d,0x2a,0x29,0x29,0x29,\n    0x27,0x24,0x22,0x25,0x29,0x2c,0x2f,0x36,0x38,0x35,0x2c,0x25,0x1f,0x1a,0x18,0x18,\n    0x17,0x16,0x16,0x15,0x14,0x14,0x14,0x1b,0x1d,0x20,0x27,0x29,0x29,0x27,0x28,0x26,\n    0x21,0x1f,0x23,0x2b,0x34,0x3b,0x3d,0x3d,0x3d,0x3d,0x40,0x44,0x4d,0x52,0x55,0x54,\n    0xd4,0xcc,0xce,0xd4,0xd6,0xdc,0xee,0xea,0xe1,0xcd,0xba,0xbf,0xc2,0xcd,0xca,0xc5,\n    0xa1,0x88,0x9a,0xa4,0xbe,0xdb,0xd1,0xd9,0xda,0xcf,0xaa,0xa0,0x9c,0x98,0x95,0x95,\n    0x94,0x93,0x95,0x99,0xa0,0xa0,0x98,0x91,0x93,0x98,0x9b,0x9c,0x9c,0x9c,0x9a,0x98,\n    0x98,0x9c,0xb5,0xd8,0xe7,0xec,0xef,0xf1,0xf5,0xf4,0xf2,0xea,0xe5,0xda,0xc8,0xc1,\n    0xb3,0x97,0x7f,0x6e,0x61,0x5e,0x5a,0x53,0x48,0x3c,0x31,0x32,0x31,0x32,0x30,0x2d,\n    0x2c,0x29,0x27,0x27,0x29,0x2d,0x37,0x3d,0x3f,0x3e,0x36,0x2e,0x27,0x1f,0x19,0x18,\n    0x17,0x16,0x16,0x15,0x15,0x14,0x15,0x1b,0x20,0x23,0x28,0x2b,0x2a,0x2b,0x30,0x2e,\n    0x2b,0x25,0x22,0x27,0x2d,0x35,0x39,0x39,0x38,0x39,0x3d,0x3f,0x44,0x4a,0x50,0x51,\n    0xda,0xda,0xd5,0xd5,0xd6,0xd8,0xe7,0xe8,0xdb,0xba,0xc6,0xa7,0xad,0xc2,0xd3,0xcf,\n    0xa9,0x8b,0x8e,0x9c,0xa9,0xd6,0xd2,0xd7,0xdd,0xda,0xc0,0xa0,0x9c,0x98,0x96,0x95,\n    0x94,0x94,0x93,0x98,0x9d,0x9e,0x9e,0x9c,0x99,0x9a,0x9b,0x9b,0x9b,0x9a,0x98,0x97,\n    0x9e,0xb3,0xd2,0xed,0xf4,0xf3,0xf5,0xf4,0xf4,0xf3,0xf1,0xec,0xe2,0xd8,0xcd,0xc5,\n    0xbd,0xaa,0x9f,0x91,0x88,0x7f,0x76,0x67,0x57,0x47,0x37,0x38,0x37,0x36,0x36,0x34,\n    0x30,0x2e,0x2c,0x28,0x2a,0x2f,0x39,0x41,0x40,0x40,0x3a,0x34,0x29,0x22,0x1d,0x1a,\n    0x18,0x17,0x17,0x15,0x14,0x15,0x17,0x1d,0x22,0x26,0x29,0x2c,0x2c,0x2e,0x35,0x36,\n    0x35,0x2f,0x27,0x24,0x28,0x30,0x33,0x34,0x35,0x34,0x34,0x38,0x3c,0x42,0x49,0x4c,\n    0xcd,0xcf,0xd1,0xd6,0xd4,0xd9,0xe7,0xe1,0xdb,0xae,0xb0,0xb1,0xbf,0xc8,0xe1,0xd1,\n    0xa0,0x8b,0x87,0x90,0xa0,0xcc,0xd6,0xd1,0xe0,0xd7,0xd5,0xa7,0x9b,0x97,0x96,0x95,\n    0x94,0x95,0x92,0x98,0x9e,0xa3,0xa7,0xa5,0xa0,0x9c,0x9a,0x9b,0x9c,0x9a,0x9a,0x9b,\n    0xa6,0xc3,0xe4,0xf1,0xf6,0xf8,0xf5,0xf2,0xf1,0xef,0xe8,0xe1,0xdb,0xd2,0xd0,0xcc,\n    0xcc,0xc8,0xbc,0xaf,0xa8,0xa0,0x8d,0x7d,0x6a,0x50,0x39,0x3a,0x3a,0x38,0x3a,0x3c,\n    0x38,0x34,0x32,0x2d,0x2e,0x31,0x37,0x3b,0x3f,0x3f,0x3a,0x33,0x2c,0x26,0x20,0x1c,\n    0x1c,0x1a,0x19,0x16,0x17,0x19,0x1a,0x1e,0x23,0x25,0x27,0x2b,0x2f,0x3a,0x39,0x3c,\n    0x3c,0x35,0x2b,0x23,0x22,0x27,0x2d,0x30,0x31,0x33,0x32,0x34,0x37,0x3b,0x3e,0x43,\n    0xc7,0xca,0xd0,0xd8,0xd6,0xda,0xdf,0xd9,0xdd,0xad,0xaf,0xd5,0xcf,0xd7,0xe9,0xd5,\n    0x8f,0x8e,0x8a,0x7d,0x91,0xcd,0xd9,0xcd,0xe1,0xd5,0xdb,0xbb,0x9c,0x99,0x96,0x96,\n    0x95,0x94,0x92,0x98,0xa0,0xa8,0xa9,0xa9,0xa7,0x9f,0x9d,0x9c,0x9d,0x9d,0x9d,0xa1,\n    0xad,0xc4,0xe5,0xed,0xf4,0xf5,0xef,0xe9,0xe3,0xe1,0xde,0xdb,0xd3,0xd2,0xd3,0xd4,\n    0xd1,0xcf,0xc9,0xc0,0xb9,0xb3,0xa2,0x8e,0x77,0x52,0x39,0x3c,0x37,0x37,0x3d,0x40,\n    0x40,0x3d,0x37,0x31,0x30,0x33,0x36,0x3a,0x40,0x40,0x3b,0x34,0x2f,0x2b,0x25,0x20,\n    0x1d,0x1d,0x1b,0x18,0x18,0x1c,0x1f,0x20,0x22,0x23,0x2a,0x2d,0x32,0x3a,0x40,0x40,\n    0x3f,0x38,0x2b,0x20,0x1e,0x21,0x24,0x2a,0x2e,0x30,0x2f,0x30,0x32,0x35,0x37,0x3c,\n    0xc6,0xc8,0xcc,0xd1,0xd8,0xdb,0xdd,0xd9,0xdc,0xab,0xbc,0xca,0xc8,0xe1,0xe1,0xc8,\n    0x80,0x8f,0x8d,0x71,0x98,0xc4,0xdc,0xcf,0xdb,0xd6,0xde,0xcf,0xaa,0x99,0x98,0x98,\n    0x96,0x96,0x94,0x98,0xa0,0xab,0xad,0xac,0xa8,0xa0,0x9d,0x9f,0xa1,0xa1,0xa1,0xa2,\n    0xaf,0xbd,0xd8,0xe9,0xec,0xea,0xe5,0xd7,0xd7,0xd1,0xd3,0xd2,0xce,0xd1,0xd4,0xd8,\n    0xd7,0xd7,0xd5,0xce,0xc9,0xc1,0xb0,0x9d,0x7e,0x57,0x3d,0x3a,0x38,0x39,0x40,0x45,\n    0x45,0x3f,0x3b,0x37,0x32,0x34,0x36,0x3c,0x41,0x44,0x3e,0x37,0x30,0x2e,0x28,0x25,\n    0x22,0x21,0x1e,0x1b,0x1b,0x1e,0x22,0x27,0x2b,0x30,0x35,0x34,0x37,0x3f,0x46,0x49,\n    0x43,0x3a,0x2f,0x22,0x1c,0x1f,0x25,0x29,0x2e,0x31,0x31,0x33,0x34,0x33,0x33,0x37,\n    0xcb,0xcd,0xd2,0xce,0xe3,0xde,0xcb,0xb7,0xd8,0xb1,0xd3,0xd0,0xdc,0xdb,0xcb,0xad,\n    0x87,0x8c,0xa3,0x6f,0x9e,0xb6,0xdf,0xd3,0xd8,0xdb,0xda,0xd4,0xbd,0x9b,0x99,0x98,\n    0x96,0x95,0x93,0x97,0x9c,0xa5,0xa9,0xa9,0xa5,0x9f,0xa2,0xa3,0xa5,0xa4,0xa0,0x9f,\n    0xa3,0xb2,0xbf,0xcd,0xd3,0xcf,0xc6,0xbe,0xc4,0xc9,0xcd,0xce,0xd1,0xd4,0xd7,0xdb,\n    0xdd,0xde,0xdb,0xd8,0xd3,0xc7,0xb6,0xa2,0x83,0x5b,0x3c,0x36,0x37,0x3d,0x43,0x45,\n    0x44,0x41,0x3f,0x3a,0x36,0x36,0x3b,0x41,0x43,0x42,0x3e,0x39,0x32,0x2d,0x28,0x28,\n    0x26,0x23,0x20,0x1f,0x1e,0x22,0x2a,0x33,0x3b,0x3f,0x44,0x42,0x41,0x45,0x4d,0x49,\n    0x46,0x3d,0x32,0x25,0x21,0x24,0x29,0x2d,0x33,0x36,0x36,0x35,0x34,0x32,0x34,0x38,\n    0xc7,0xc6,0xc9,0xcb,0xd9,0xe1,0xbe,0xac,0xcf,0xbf,0xcd,0xc9,0xc9,0xc9,0xbe,0xad,\n    0x93,0x78,0xb6,0x6e,0x8a,0xb5,0xd8,0xd3,0xd4,0xdb,0xda,0xd5,0xcf,0xa6,0x98,0x98,\n    0x97,0x95,0x93,0x97,0x9b,0xa1,0xa3,0xa2,0x9f,0xa2,0xa7,0xaa,0xa9,0xa6,0xa6,0xa7,\n    0xa9,0xb0,0xb2,0xb5,0xb8,0xba,0xb7,0xbb,0xc2,0xc9,0xcf,0xd2,0xd6,0xda,0xdc,0xdf,\n    0xdf,0xde,0xdb,0xd6,0xd0,0xc9,0xbb,0xa4,0x87,0x64,0x40,0x38,0x3b,0x3f,0x43,0x45,\n    0x45,0x47,0x42,0x3d,0x3a,0x3b,0x45,0x48,0x48,0x46,0x40,0x3b,0x33,0x30,0x2d,0x2d,\n    0x2a,0x29,0x26,0x27,0x26,0x2d,0x37,0x40,0x49,0x4c,0x4f,0x50,0x4f,0x4e,0x4e,0x47,\n    0x45,0x3d,0x35,0x2e,0x2b,0x30,0x32,0x37,0x3c,0x3c,0x3a,0x39,0x36,0x33,0x36,0x39,\n    0xc2,0xbc,0xc2,0xc8,0xcd,0xdf,0xd4,0xcb,0xc5,0xc2,0xbe,0xb2,0xc4,0xc9,0xcc,0xb1,\n    0x98,0x83,0xab,0x7b,0x80,0xb7,0xc9,0xd9,0xd0,0xde,0xd7,0xd4,0xd5,0xbf,0x98,0x99,\n    0x97,0x95,0x94,0x98,0x9c,0x9f,0x9f,0xa0,0xa1,0xa7,0xac,0xb1,0xb1,0xb0,0xaf,0xab,\n    0xac,0xad,0xaf,0xb1,0xb4,0xb7,0xbc,0xc3,0xcb,0xd0,0xd4,0xd9,0xdc,0xdc,0xdd,0xdd,\n    0xdd,0xdb,0xd8,0xd4,0xcf,0xcb,0xbe,0xab,0x90,0x6f,0x50,0x40,0x43,0x46,0x48,0x4a,\n    0x48,0x48,0x44,0x40,0x3c,0x41,0x4e,0x51,0x51,0x4e,0x47,0x3e,0x38,0x37,0x35,0x35,\n    0x33,0x31,0x30,0x30,0x31,0x39,0x43,0x4c,0x54,0x54,0x58,0x58,0x58,0x53,0x4b,0x45,\n    0x40,0x39,0x36,0x33,0x31,0x35,0x38,0x3d,0x3f,0x40,0x3e,0x3d,0x3a,0x3a,0x3a,0x3d,\n    0x67,0x94,0xc4,0xca,0xcf,0xd3,0xde,0xd6,0xcc,0xcc,0xcb,0xc8,0xcd,0xd7,0xd6,0xc4,\n    0x8f,0x84,0x98,0x81,0x7d,0xa0,0xc7,0xdc,0xd2,0xdf,0xd3,0xd8,0xd1,0xce,0xa7,0x97,\n    0x97,0x95,0x95,0x97,0x9b,0x9e,0x9e,0xa2,0xa6,0xab,0xb2,0xb7,0xb7,0xb7,0xb6,0xb1,\n    0xaf,0xb0,0xb3,0xb4,0xb8,0xbc,0xc3,0xcb,0xcf,0xd2,0xd5,0xd6,0xd8,0xd8,0xd9,0xdb,\n    0xdb,0xdb,0xd9,0xd4,0xd0,0xca,0xc1,0xae,0x97,0x79,0x5d,0x4e,0x50,0x4f,0x4e,0x4f,\n    0x4e,0x4a,0x45,0x44,0x47,0x4d,0x58,0x59,0x58,0x55,0x4d,0x44,0x3c,0x3d,0x3d,0x3b,\n    0x3d,0x40,0x3e,0x3d,0x3d,0x43,0x4a,0x4f,0x56,0x59,0x5c,0x59,0x55,0x4d,0x47,0x44,\n    0x41,0x3c,0x38,0x35,0x32,0x36,0x3a,0x40,0x42,0x45,0x45,0x44,0x43,0x40,0x40,0x40,\n    0x54,0x3d,0x57,0x7f,0xb6,0xc3,0xd2,0xdc,0xd3,0xca,0xbf,0xcf,0xb4,0xbc,0xda,0xd3,\n    0x91,0x78,0x85,0x76,0x7a,0xa7,0xc6,0xd9,0xd4,0xdf,0xda,0xdc,0xd3,0xd7,0xbd,0x97,\n    0x96,0x95,0x93,0x96,0x9a,0xa0,0xa2,0xa6,0xa7,0xad,0xb4,0xb9,0xb9,0xba,0xbc,0xb7,\n    0xb6,0xb8,0xb7,0xb9,0xbb,0xc2,0xc4,0xc9,0xce,0xd0,0xd2,0xd4,0xd7,0xda,0xdb,0xdd,\n    0xdb,0xdb,0xd7,0xd3,0xcf,0xcc,0xc4,0xb3,0xa0,0x86,0x6e,0x5e,0x5c,0x59,0x57,0x57,\n    0x53,0x4f,0x4a,0x4d,0x54,0x5d,0x61,0x63,0x63,0x5d,0x54,0x4c,0x43,0x46,0x47,0x47,\n    0x4a,0x4f,0x4e,0x4a,0x47,0x48,0x4e,0x51,0x53,0x59,0x59,0x54,0x4f,0x49,0x44,0x44,\n    0x3e,0x3c,0x3b,0x38,0x34,0x33,0x38,0x3c,0x41,0x46,0x48,0x4a,0x4b,0x47,0x45,0x46,\n    0x9b,0x40,0x3c,0x40,0x4a,0x68,0x98,0xc3,0xcd,0xb2,0x8a,0x7c,0x76,0xa1,0xe7,0xdd,\n    0x9c,0x71,0x77,0x78,0xaa,0xa4,0xba,0xd3,0xd6,0xdc,0xdc,0xdc,0xd7,0xd6,0xcb,0xa2,\n    0x97,0x95,0x93,0x97,0x9c,0xa0,0xa2,0xa3,0xa5,0xaa,0xb2,0xb6,0xb9,0xbb,0xbe,0xbd,\n    0xbc,0xb9,0xb9,0xbb,0xbc,0xc1,0xc7,0xcd,0xd1,0xd3,0xd5,0xd5,0xd8,0xda,0xdb,0xdd,\n    0xdc,0xdb,0xd9,0xd5,0xd1,0xcd,0xc6,0xb9,0xa7,0x92,0x7b,0x67,0x63,0x64,0x60,0x5f,\n    0x5c,0x55,0x53,0x57,0x5d,0x65,0x6c,0x6b,0x69,0x63,0x58,0x50,0x50,0x52,0x55,0x58,\n    0x5b,0x5d,0x5c,0x56,0x51,0x4f,0x50,0x51,0x4f,0x4d,0x4b,0x45,0x41,0x41,0x3f,0x3f,\n    0x3b,0x3c,0x3f,0x3c,0x37,0x33,0x35,0x37,0x3d,0x44,0x49,0x4f,0x51,0x4b,0x49,0x49,\n    0xb7,0x85,0x43,0x36,0x3b,0x3b,0x41,0x54,0xa1,0x7a,0x5d,0x62,0x93,0xca,0xe6,0xd2,\n    0xb1,0x8d,0x7d,0x84,0xae,0xa6,0xb1,0xca,0xe2,0xdb,0xde,0xdc,0xd5,0xdc,0xcf,0xb9,\n    0x98,0x97,0x94,0x98,0x9e,0xa1,0xa0,0x9e,0xa0,0xa4,0xaa,0xb0,0xb5,0xb9,0xb8,0xb4,\n    0xb3,0xb3,0xb8,0xbf,0xc7,0xcd,0xce,0xd3,0xd4,0xd5,0xd7,0xd6,0xd8,0xda,0xdc,0xdd,\n    0xdb,0xdb,0xd9,0xd7,0xd3,0xcd,0xc8,0xbd,0xaf,0x9b,0x86,0x70,0x6a,0x68,0x65,0x65,\n    0x63,0x5f,0x5b,0x61,0x66,0x6b,0x71,0x71,0x6d,0x67,0x5e,0x5a,0x57,0x5b,0x62,0x66,\n    0x68,0x6a,0x68,0x62,0x59,0x53,0x52,0x4f,0x49,0x45,0x40,0x39,0x34,0x35,0x37,0x3a,\n    0x3a,0x3e,0x40,0x40,0x39,0x35,0x31,0x35,0x3c,0x41,0x49,0x52,0x55,0x51,0x4f,0x4a,\n    0xb4,0xb3,0x9d,0x8a,0x71,0x49,0x36,0x44,0x86,0x95,0x63,0x5d,0xb0,0xc5,0xda,0xcc,\n    0xaf,0xbb,0x7c,0x7a,0xb1,0xaa,0xad,0xcc,0xde,0xd4,0xe1,0xdc,0xd3,0xdc,0xce,0xc6,\n    0xa0,0x98,0x96,0x98,0x9f,0x9e,0x9c,0x98,0x9a,0x9c,0xa0,0xa6,0xac,0xb1,0xb0,0xaf,\n    0xb1,0xb4,0xb9,0xc1,0xcb,0xd3,0xd4,0xd7,0xd8,0xd5,0xd5,0xd8,0xd7,0xdb,0xdd,0xdc,\n    0xdd,0xdb,0xda,0xd7,0xd5,0xcf,0xca,0xc0,0xb3,0xa3,0x8d,0x77,0x6e,0x6c,0x68,0x65,\n    0x65,0x63,0x65,0x67,0x6c,0x72,0x74,0x73,0x6a,0x67,0x60,0x5c,0x58,0x5e,0x67,0x6c,\n    0x6d,0x6e,0x6b,0x65,0x5b,0x55,0x4f,0x4b,0x46,0x3e,0x38,0x32,0x2d,0x2f,0x33,0x3a,\n    0x3c,0x40,0x42,0x3f,0x3c,0x37,0x33,0x35,0x39,0x3e,0x44,0x50,0x51,0x4f,0x4e,0x49,\n    0xc4,0xb1,0xb3,0xba,0xcb,0xbf,0x98,0x65,0x8a,0xb4,0x73,0x61,0x71,0xb4,0xb2,0xad,\n    0xac,0xdb,0x84,0x7e,0xa1,0xb9,0xb8,0xb9,0xe0,0xd7,0xdc,0xdc,0xd4,0xdb,0xd1,0xcd,\n    0xb0,0x98,0x98,0x9a,0x9f,0x9b,0x96,0x91,0x93,0x97,0x9b,0xa1,0xa8,0xa9,0xa6,0xa7,\n    0xad,0xb2,0xb8,0xc2,0xcc,0xd4,0xd5,0xd8,0xd8,0xd5,0xd4,0xd6,0xd8,0xdb,0xdd,0xdc,\n    0xdd,0xdc,0xdc,0xd9,0xd6,0xd2,0xcd,0xc4,0xb8,0xaa,0x98,0x7f,0x75,0x6e,0x6a,0x68,\n    0x67,0x68,0x69,0x6c,0x70,0x75,0x77,0x71,0x68,0x62,0x5c,0x58,0x57,0x5f,0x68,0x6c,\n    0x6e,0x6b,0x67,0x63,0x59,0x54,0x50,0x4e,0x46,0x3c,0x32,0x2b,0x28,0x2c,0x30,0x3e,\n    0x45,0x47,0x48,0x47,0x45,0x40,0x3b,0x38,0x3b,0x3c,0x42,0x4b,0x4e,0x4d,0x4b,0x4a,\n    0xc8,0xc0,0xac,0xa5,0xa3,0xc6,0xd5,0xba,0x92,0xae,0xa0,0x62,0x5f,0x93,0xaf,0xaf,\n    0xb8,0xe1,0x9d,0x72,0x9b,0xb7,0xaa,0x99,0xe6,0xe1,0xd5,0xdb,0xd6,0xd7,0xd3,0xce,\n    0xc1,0x9e,0x99,0x9b,0xa0,0x99,0x94,0x8e,0x8f,0x99,0xa0,0xa1,0xa1,0x9f,0x9c,0x97,\n    0x9d,0xab,0xb5,0xc0,0xc8,0xce,0xd0,0xd1,0xce,0xcf,0xd0,0xd2,0xd7,0xd9,0xdc,0xdd,\n    0xdd,0xdc,0xdd,0xdc,0xd8,0xd5,0xcf,0xc8,0xbc,0xaf,0x9e,0x8e,0x79,0x6e,0x69,0x6d,\n    0x6a,0x6b,0x6a,0x69,0x6b,0x6f,0x6e,0x67,0x5f,0x58,0x52,0x4c,0x50,0x56,0x5f,0x66,\n    0x6a,0x68,0x60,0x58,0x54,0x56,0x55,0x53,0x4a,0x40,0x35,0x2c,0x28,0x2c,0x31,0x3b,\n    0x47,0x4b,0x4d,0x51,0x50,0x4b,0x46,0x3f,0x3d,0x3b,0x40,0x47,0x49,0x4d,0x4c,0x4e,\n    0xb7,0xca,0xb5,0xb2,0xa1,0xa1,0xbc,0xcf,0x9b,0x99,0xca,0x62,0x5f,0x72,0xaa,0xa8,\n    0x8e,0xc5,0xe7,0x83,0x93,0xc0,0x9a,0x93,0xe7,0xe7,0xd5,0xd8,0xd6,0xd4,0xd3,0xcf,\n    0xcc,0xac,0x9a,0x9b,0x9f,0x99,0x93,0x8c,0x8e,0x9d,0xa2,0x9d,0x9a,0x97,0x94,0x90,\n    0x97,0x9b,0xa9,0xb4,0xbd,0xc4,0xc7,0xc7,0xc8,0xc8,0xca,0xcd,0xd1,0xd7,0xdb,0xdd,\n    0xdf,0xdd,0xde,0xdc,0xda,0xd7,0xd3,0xcc,0xc3,0xb6,0xa6,0x96,0x80,0x70,0x6b,0x69,\n    0x6b,0x68,0x68,0x68,0x65,0x67,0x62,0x5a,0x51,0x4c,0x43,0x3f,0x49,0x4e,0x54,0x59,\n    0x60,0x60,0x58,0x52,0x50,0x54,0x57,0x55,0x4f,0x46,0x3a,0x2e,0x28,0x2b,0x33,0x39,\n    0x42,0x49,0x4d,0x56,0x56,0x53,0x4e,0x4b,0x43,0x3c,0x41,0x42,0x44,0x4a,0x4d,0x50,\n    0xbb,0xbb,0xcc,0xb7,0xad,0xa0,0x93,0x8d,0xa7,0xcd,0xd3,0x63,0x5e,0x5e,0x82,0x94,\n    0x81,0xac,0xfd,0xae,0x8a,0xc7,0x7f,0x9c,0xe0,0xe7,0xd6,0xd6,0xd5,0xd1,0xd4,0xd0,\n    0xce,0xbe,0x9c,0x9b,0xa1,0x9b,0x93,0x8b,0x8e,0x9b,0x9f,0x9a,0x97,0x96,0x95,0x95,\n    0x9c,0xa7,0xb0,0xb2,0xb8,0xba,0xc0,0xbf,0xbb,0xbb,0xc1,0xc5,0xca,0xd1,0xd7,0xd9,\n    0xdc,0xde,0xde,0xde,0xdc,0xd8,0xd5,0xce,0xc8,0xbd,0xb0,0x9f,0x8a,0x74,0x6b,0x64,\n    0x65,0x64,0x64,0x62,0x60,0x5e,0x57,0x4b,0x45,0x41,0x37,0x35,0x3d,0x45,0x4a,0x4d,\n    0x54,0x58,0x51,0x4f,0x52,0x54,0x59,0x5b,0x56,0x4c,0x3f,0x32,0x2c,0x2d,0x34,0x38,\n    0x40,0x44,0x4c,0x53,0x56,0x54,0x55,0x52,0x46,0x40,0x3e,0x3e,0x41,0x49,0x4f,0x54,\n    0xc6,0xb9,0xc6,0xc4,0xaf,0xa8,0x97,0x9b,0xab,0xcb,0xd5,0x62,0x5e,0x5e,0x67,0x7e,\n    0x7d,0x9e,0xf8,0xd1,0x9d,0xc2,0x85,0x9b,0xde,0xe4,0xdf,0xd2,0xd3,0xcf,0xd4,0xcd,\n    0xcd,0xca,0xa5,0x9f,0xa1,0x9b,0x93,0x8b,0x8c,0x98,0x9b,0x98,0x94,0x94,0x93,0x9c,\n    0xb0,0xbf,0xc7,0xc9,0xc8,0xce,0xcd,0xcb,0xc6,0xb7,0xb6,0xba,0xc2,0xca,0xce,0xd4,\n    0xd6,0xd9,0xda,0xdd,0xde,0xdb,0xd9,0xd1,0xcb,0xc2,0xb5,0xa8,0x95,0x7c,0x6b,0x5e,\n    0x5e,0x5c,0x59,0x56,0x54,0x51,0x49,0x3f,0x3c,0x39,0x2f,0x2b,0x33,0x3e,0x47,0x49,\n    0x50,0x54,0x53,0x52,0x58,0x5e,0x63,0x63,0x5e,0x52,0x44,0x38,0x32,0x34,0x39,0x3d,\n    0x41,0x41,0x48,0x4e,0x51,0x54,0x57,0x52,0x48,0x43,0x3d,0x3f,0x44,0x4d,0x59,0x61,\n    0xc6,0xc4,0xbc,0xcc,0xba,0xb0,0xa3,0x9c,0x90,0xa3,0xc3,0x9e,0x5d,0x60,0x61,0x67,\n    0x73,0x8b,0xea,0xee,0xca,0xbb,0x84,0x8f,0xe3,0xde,0xe2,0xd0,0xd1,0xcd,0xd2,0xcd,\n    0xcd,0xcc,0xb3,0x9e,0xa3,0x9c,0x94,0x8c,0x8c,0x95,0x98,0x95,0x92,0x94,0x94,0xab,\n    0xc2,0xd1,0xd8,0xdb,0xdc,0xdf,0xdb,0xd7,0xd4,0xce,0xc2,0xc8,0xca,0xcc,0xc9,0xcc,\n    0xd0,0xd3,0xd5,0xd7,0xd8,0xdb,0xd7,0xd3,0xcd,0xc6,0xbc,0xae,0x9b,0x7f,0x6a,0x57,\n    0x56,0x53,0x50,0x48,0x43,0x3f,0x39,0x36,0x36,0x37,0x2e,0x2c,0x33,0x3b,0x44,0x4c,\n    0x53,0x55,0x56,0x59,0x62,0x69,0x6c,0x6b,0x64,0x5a,0x4f,0x43,0x40,0x3e,0x3f,0x42,\n    0x43,0x40,0x43,0x49,0x4c,0x51,0x53,0x4e,0x44,0x41,0x3f,0x3f,0x44,0x4f,0x5a,0x66,\n    0xc4,0xc4,0xc6,0xcc,0xca,0xb5,0xae,0xa8,0x9a,0x95,0xb5,0xe0,0x7e,0x5f,0x5e,0x5f,\n    0x63,0x78,0xcc,0xfc,0xf3,0xc0,0xa8,0xa3,0xda,0xda,0xde,0xd1,0xd1,0xcc,0xd0,0xcd,\n    0xcc,0xcd,0xc0,0xa1,0xa3,0x9c,0x94,0x8b,0x8c,0x96,0x97,0x92,0x90,0x95,0xa2,0xbf,\n    0xd3,0xdc,0xe3,0xe6,0xe9,0xea,0xe7,0xe7,0xe7,0xe0,0xdd,0xdb,0xd2,0xcf,0xcf,0xc9,\n    0xcf,0xd2,0xd3,0xd3,0xd4,0xd7,0xd5,0xd3,0xd0,0xca,0xc2,0xb5,0xa2,0x8a,0x6a,0x4f,\n    0x4a,0x48,0x41,0x3b,0x36,0x31,0x30,0x33,0x35,0x33,0x30,0x30,0x35,0x3b,0x45,0x50,\n    0x57,0x59,0x5b,0x60,0x69,0x72,0x75,0x73,0x6b,0x61,0x59,0x51,0x4e,0x4a,0x47,0x45,\n    0x44,0x42,0x42,0x45,0x44,0x48,0x4a,0x45,0x40,0x40,0x42,0x43,0x48,0x4f,0x55,0x63,\n    0xbd,0xc3,0xc8,0xcc,0xd1,0xc6,0xb2,0xaf,0xa4,0x9d,0x90,0xa2,0x7f,0x65,0x5c,0x5d,\n    0x5c,0x67,0x95,0xee,0xf8,0xe3,0xc0,0xb1,0xc6,0xd9,0xe2,0xd4,0xd1,0xce,0xce,0xcd,\n    0xcc,0xcc,0xca,0xa9,0xa2,0x9e,0x95,0x8d,0x8f,0x98,0x99,0x94,0x8f,0x95,0xab,0xc7,\n    0xdc,0xe5,0xeb,0xee,0xf0,0xf0,0xef,0xef,0xee,0xea,0xec,0xe6,0xdd,0xd6,0xd3,0xcf,\n    0xd2,0xd5,0xd4,0xd2,0xd1,0xd0,0xd0,0xcf,0xce,0xc9,0xc7,0xbc,0xa9,0x90,0x6c,0x4e,\n    0x40,0x3a,0x34,0x32,0x2e,0x2a,0x2d,0x31,0x32,0x32,0x33,0x37,0x38,0x3a,0x42,0x4d,\n    0x54,0x56,0x5b,0x63,0x6e,0x78,0x7b,0x7b,0x74,0x6b,0x64,0x5e,0x5b,0x5a,0x56,0x4f,\n    0x4a,0x47,0x44,0x43,0x42,0x41,0x41,0x40,0x3f,0x43,0x44,0x45,0x4a,0x50,0x55,0x61,\n    0xb4,0xb8,0xc1,0xcb,0xd0,0xd1,0xc3,0xb1,0xab,0xa2,0x9d,0x93,0x79,0x71,0x78,0x5e,\n    0x5d,0x5f,0x83,0xda,0xf6,0xf2,0xd9,0xcc,0xbb,0xd2,0xe5,0xdf,0xd2,0xcd,0xcc,0xce,\n    0xcd,0xcc,0xcd,0xb4,0xa0,0x9d,0x95,0x90,0x91,0x99,0x98,0x93,0x8f,0x99,0xb1,0xca,\n    0xe0,0xe9,0xf0,0xf0,0xf1,0xf5,0xf6,0xf6,0xf5,0xf3,0xf5,0xef,0xe6,0xdd,0xdb,0xd4,\n    0xd9,0xdb,0xd6,0xd1,0xcd,0xca,0xc7,0xc8,0xca,0xc9,0xc6,0xc3,0xb2,0x98,0x72,0x50,\n    0x39,0x30,0x2b,0x29,0x26,0x26,0x2c,0x32,0x33,0x35,0x36,0x39,0x36,0x37,0x3d,0x48,\n    0x4c,0x50,0x57,0x65,0x6e,0x76,0x7f,0x80,0x78,0x70,0x6b,0x62,0x62,0x63,0x63,0x5d,\n    0x59,0x55,0x4d,0x46,0x40,0x3c,0x3b,0x3f,0x43,0x4b,0x49,0x48,0x4e,0x54,0x56,0x5f,\n    0xad,0xb1,0xb5,0xc5,0xcc,0xd1,0xd5,0xb9,0xae,0xa8,0xa1,0xa6,0x94,0x95,0xaa,0x71,\n    0x63,0x5f,0x6d,0xb9,0xeb,0xf8,0xeb,0xd0,0xcd,0xad,0xe3,0xe3,0xd8,0xcb,0xcb,0xcc,\n    0xcd,0xcc,0xce,0xbf,0xa1,0x9b,0x96,0x90,0x91,0x98,0x98,0x92,0x90,0x9b,0xb2,0xcc,\n    0xe1,0xeb,0xef,0xf0,0xf1,0xf1,0xf2,0xf6,0xf7,0xf4,0xf6,0xf4,0xea,0xe4,0xde,0xda,\n    0xe0,0xe2,0xd9,0xd2,0xca,0xc1,0xbd,0xbe,0xbf,0xc2,0xc2,0xc0,0xb2,0x9b,0x75,0x50,\n    0x36,0x2d,0x29,0x29,0x26,0x27,0x2c,0x2f,0x31,0x34,0x37,0x38,0x36,0x36,0x3b,0x41,\n    0x42,0x46,0x4e,0x5c,0x64,0x6f,0x76,0x7a,0x74,0x70,0x6a,0x67,0x64,0x68,0x67,0x67,\n    0x65,0x5e,0x56,0x4d,0x47,0x43,0x3f,0x43,0x4c,0x51,0x51,0x4f,0x4e,0x51,0x53,0x5d,\n    0xaf,0xae,0xb7,0xb9,0xc9,0xd2,0xd5,0xce,0xb6,0xac,0xa8,0xa4,0xa4,0xa3,0x98,0x92,\n    0x76,0x64,0x6a,0x7e,0xd1,0xf5,0xef,0xdb,0xe2,0xb8,0xe6,0xea,0xd9,0xcc,0xcb,0xcb,\n    0xcc,0xcd,0xcb,0xc8,0xa3,0x9a,0x95,0x93,0x92,0x97,0x96,0x91,0x8f,0x9a,0xb3,0xcc,\n    0xe0,0xea,0xef,0xf0,0xf1,0xf1,0xf4,0xf7,0xf6,0xf8,0xf7,0xf2,0xe9,0xe0,0xda,0xdd,\n    0xe3,0xe7,0xe0,0xd4,0xc8,0xba,0xb3,0xb3,0xb5,0xb8,0xba,0xba,0xad,0x99,0x79,0x52,\n    0x36,0x30,0x2c,0x2d,0x2a,0x2b,0x2e,0x33,0x32,0x32,0x33,0x31,0x33,0x32,0x39,0x3e,\n    0x3a,0x39,0x40,0x4f,0x5a,0x63,0x6b,0x6c,0x68,0x67,0x66,0x68,0x66,0x69,0x69,0x6a,\n    0x68,0x60,0x5b,0x56,0x4f,0x47,0x46,0x4a,0x50,0x56,0x57,0x59,0x57,0x55,0x56,0x5e,\n    0xb1,0xac,0xaf,0xb4,0xb9,0xc3,0xcc,0xd3,0xc8,0xb4,0xab,0xa8,0x9d,0xa1,0x9a,0x99,\n    0x94,0x70,0x60,0x64,0x86,0xdc,0xf5,0xed,0xe6,0xce,0xe4,0xec,0xda,0xcc,0xcb,0xcc,\n    0xcc,0xcb,0xcc,0xcb,0xaa,0x96,0x94,0x94,0x92,0x94,0x93,0x8d,0x8c,0x99,0xb5,0xcd,\n    0xe0,0xe9,0xee,0xf0,0xf0,0xf0,0xf2,0xf4,0xf5,0xf7,0xf7,0xf3,0xe7,0xdf,0xdb,0xdc,\n    0xe4,0xe8,0xe0,0xd6,0xc6,0xb6,0xa8,0xa5,0xa5,0xa9,0xad,0xaf,0xa5,0x94,0x77,0x54,\n    0x37,0x2e,0x2d,0x2d,0x2c,0x2c,0x2e,0x31,0x30,0x30,0x2d,0x2b,0x2c,0x2b,0x31,0x36,\n    0x2f,0x2c,0x30,0x3f,0x45,0x51,0x5a,0x5f,0x5c,0x5b,0x5e,0x64,0x65,0x66,0x67,0x67,\n    0x63,0x5d,0x5b,0x57,0x52,0x4a,0x4b,0x4d,0x50,0x58,0x5c,0x5e,0x5c,0x5c,0x5c,0x60,\n    0xb1,0xae,0xae,0xae,0xb0,0xb8,0xc5,0xc6,0xd3,0xc4,0xb2,0xab,0xa7,0xa2,0x9f,0x9c,\n    0x89,0x85,0x7a,0x63,0x66,0x9d,0xf4,0xf4,0xee,0xe0,0xe2,0xec,0xdd,0xcd,0xcb,0xcb,\n    0xcb,0xcb,0xcc,0xcd,0xb7,0x99,0x96,0x91,0x93,0x92,0x90,0x89,0x89,0x99,0xb3,0xcb,\n    0xdf,0xe8,0xee,0xef,0xf0,0xef,0xf1,0xf4,0xf5,0xf6,0xf7,0xf2,0xe7,0xde,0xd8,0xd9,\n    0xe1,0xe6,0xdf,0xd4,0xc3,0xb0,0xa1,0x9b,0x95,0x96,0x9d,0xa4,0x9c,0x89,0x74,0x57,\n    0x3c,0x31,0x31,0x2f,0x2e,0x2d,0x2d,0x2e,0x2e,0x2d,0x2b,0x29,0x29,0x27,0x29,0x2d,\n    0x2b,0x28,0x2b,0x32,0x36,0x3f,0x4a,0x50,0x51,0x51,0x53,0x58,0x5d,0x5f,0x5f,0x60,\n    0x5b,0x57,0x55,0x56,0x51,0x4d,0x4e,0x50,0x51,0x56,0x5c,0x62,0x64,0x65,0x66,0x6a,\n    0xb8,0xab,0xac,0xae,0xac,0xaf,0xb1,0xbc,0xc6,0xcc,0xc1,0xb2,0xa9,0xac,0xa4,0x9f,\n    0xa0,0x9b,0x95,0x80,0x6b,0x6d,0xcd,0xf6,0xf2,0xda,0xd0,0xe8,0xe1,0xcd,0xcc,0xcb,\n    0xcb,0xcb,0xcc,0xcc,0xc0,0x9c,0x95,0x8f,0x90,0x90,0x8e,0x89,0x88,0x96,0xb2,0xca,\n    0xdd,0xe6,0xee,0xee,0xf0,0xf0,0xf1,0xf3,0xf4,0xf5,0xf5,0xf1,0xe7,0xdb,0xd3,0xd6,\n    0xdf,0xe3,0xdd,0xd1,0xc0,0xaa,0x9d,0x95,0x8c,0x86,0x89,0x94,0x8f,0x82,0x6e,0x57,\n    0x3d,0x34,0x31,0x30,0x2b,0x29,0x28,0x2b,0x2b,0x2b,0x2a,0x29,0x28,0x27,0x28,0x2b,\n    0x2b,0x28,0x27,0x29,0x2c,0x2e,0x36,0x3d,0x40,0x43,0x47,0x4d,0x53,0x55,0x56,0x57,\n    0x55,0x52,0x54,0x53,0x50,0x4f,0x51,0x4f,0x4e,0x54,0x59,0x60,0x65,0x6b,0x6f,0x72,\n    0xe2,0xcf,0xd1,0xc8,0xc4,0xcb,0xc2,0xb9,0xbf,0xc6,0xc7,0xc1,0xb1,0xac,0xa9,0xa3,\n    0x9b,0xa2,0xaa,0x88,0x7f,0x74,0x95,0xf6,0xf9,0xdb,0xd5,0xe4,0xe3,0xcc,0xcb,0xcb,\n    0xca,0xca,0xcc,0xcc,0xc7,0x9c,0x8d,0x89,0x8b,0x8d,0x8b,0x86,0x86,0x95,0xb1,0xc9,\n    0xdc,0xe7,0xec,0xec,0xef,0xef,0xf0,0xf2,0xf3,0xf5,0xf5,0xef,0xe3,0xd7,0xcc,0xd3,\n    0xdc,0xe1,0xda,0xce,0xbc,0xa6,0x95,0x8d,0x85,0x7e,0x7e,0x88,0x8b,0x80,0x6f,0x5c,\n    0x41,0x37,0x33,0x30,0x2c,0x2b,0x2b,0x2e,0x2d,0x2b,0x29,0x29,0x28,0x28,0x28,0x2b,\n    0x29,0x25,0x23,0x23,0x25,0x28,0x2b,0x31,0x38,0x3f,0x44,0x48,0x4d,0x4d,0x4e,0x4e,\n    0x4f,0x4e,0x4f,0x50,0x50,0x52,0x4d,0x4c,0x4c,0x4f,0x55,0x5e,0x68,0x70,0x74,0x77,\n    0xf0,0xeb,0xef,0xf0,0xe6,0xec,0xef,0xe3,0xe2,0xe2,0xdf,0xdd,0xd5,0xcb,0xc3,0xb7,\n    0xa8,0xa1,0x9e,0xa2,0x97,0x8f,0x89,0xe0,0xf5,0xec,0xe8,0xe5,0xde,0xce,0xcc,0xcb,\n    0xca,0xca,0xca,0xcb,0xcb,0x9c,0x80,0x80,0x85,0x8a,0x89,0x83,0x83,0x92,0xae,0xc6,\n    0xda,0xe5,0xeb,0xec,0xed,0xed,0xee,0xf0,0xf0,0xf3,0xf2,0xec,0xdd,0xcf,0xc8,0xce,\n    0xd8,0xdf,0xd8,0xcb,0xb8,0xa0,0x8f,0x87,0x7f,0x7b,0x7c,0x88,0x89,0x80,0x70,0x5c,\n    0x43,0x37,0x33,0x2e,0x2b,0x2c,0x2e,0x32,0x31,0x2d,0x2a,0x29,0x28,0x28,0x28,0x28,\n    0x25,0x24,0x22,0x22,0x22,0x27,0x2d,0x32,0x36,0x3b,0x3e,0x42,0x48,0x49,0x4a,0x4b,\n    0x4b,0x4c,0x4c,0x4e,0x4c,0x4b,0x4b,0x4b,0x4c,0x50,0x56,0x5d,0x68,0x6e,0x72,0x75,\n    0xed,0xeb,0xef,0xef,0xe5,0xe6,0xe5,0xdf,0xe0,0xe5,0xe6,0xe4,0xe4,0xe4,0xe4,0xe7,\n    0xe6,0xde,0xda,0xd3,0xc7,0xbb,0xd6,0xe9,0xf6,0xf5,0xf2,0xed,0xdd,0xcf,0xcc,0xcb,\n    0xca,0xcb,0xca,0xc9,0xca,0xa2,0x6d,0x72,0x7c,0x84,0x83,0x80,0x7f,0x8f,0xa9,0xc2,\n    0xd5,0xe0,0xe6,0xe7,0xea,0xea,0xeb,0xeb,0xed,0xee,0xee,0xe5,0xd5,0xc8,0xc4,0xcb,\n    0xd5,0xdd,0xd6,0xc8,0xb5,0x9e,0x8c,0x83,0x7d,0x7d,0x83,0x90,0x8f,0x86,0x75,0x5f,\n    0x47,0x3a,0x33,0x30,0x2f,0x32,0x34,0x35,0x34,0x2e,0x2b,0x29,0x28,0x28,0x28,0x28,\n    0x27,0x27,0x25,0x27,0x27,0x29,0x2f,0x36,0x3a,0x3e,0x41,0x44,0x49,0x4a,0x4c,0x4e,\n    0x4f,0x50,0x4d,0x4c,0x4e,0x4f,0x4e,0x4c,0x4b,0x50,0x58,0x5e,0x68,0x6d,0x72,0x76,\n    0xf0,0xec,0xe8,0xef,0xe9,0xe4,0xea,0xdf,0xe3,0xe7,0xe4,0xe4,0xe1,0xe0,0xe0,0xe1,\n    0xe0,0xde,0xe3,0xe2,0xe8,0xe7,0xe9,0xeb,0xee,0xf4,0xf2,0xf0,0xe2,0xd2,0xcb,0xcd,\n    0xcc,0xca,0xc9,0xca,0xca,0xb3,0x68,0x6a,0x71,0x78,0x7a,0x79,0x7a,0x87,0x9f,0xb7,\n    0xcb,0xd7,0xdc,0xdc,0xe1,0xe0,0xe0,0xe0,0xe3,0xe6,0xe1,0xd8,0xc7,0xbf,0xbe,0xc6,\n    0xd4,0xda,0xd1,0xc0,0xaf,0x9a,0x86,0x7f,0x7e,0x85,0x8e,0x98,0x96,0x8b,0x78,0x5f,\n    0x47,0x3b,0x34,0x32,0x35,0x38,0x37,0x36,0x37,0x31,0x2d,0x2a,0x29,0x28,0x27,0x2b,\n    0x2c,0x2d,0x2c,0x2c,0x2c,0x2d,0x37,0x3c,0x3e,0x43,0x45,0x47,0x4a,0x4c,0x4f,0x54,\n    0x54,0x53,0x50,0x4f,0x4f,0x50,0x4e,0x4b,0x4b,0x4f,0x5c,0x5f,0x66,0x6b,0x71,0x75,\n    0xec,0xef,0xe9,0xeb,0xee,0xe5,0xeb,0xe3,0xe7,0xe5,0xe2,0xe3,0xe0,0xe0,0xe0,0xde,\n    0xe3,0xe2,0xe6,0xe0,0xe9,0xe0,0xe7,0xe7,0xe9,0xea,0xed,0xef,0xee,0xe1,0xd9,0xd2,\n    0xcc,0xca,0xc8,0xc8,0xc9,0xc0,0x70,0x67,0x6f,0x6f,0x6e,0x6f,0x74,0x7f,0x91,0xa8,\n    0xb9,0xc3,0xca,0xce,0xce,0xcd,0xce,0xce,0xd0,0xd1,0xcc,0xc3,0xb5,0xb1,0xb2,0xbd,\n    0xc7,0xcd,0xc4,0xb6,0xa7,0x93,0x84,0x85,0x8a,0x91,0x9a,0x9e,0x9b,0x90,0x76,0x5b,\n    0x45,0x3c,0x35,0x37,0x3d,0x3e,0x3d,0x3b,0x3b,0x36,0x30,0x2c,0x27,0x27,0x2a,0x2f,\n    0x2f,0x30,0x34,0x37,0x36,0x3a,0x3e,0x43,0x47,0x4c,0x4b,0x4b,0x4f,0x51,0x52,0x58,\n    0x57,0x54,0x4f,0x4f,0x4c,0x48,0x4a,0x49,0x4c,0x55,0x62,0x64,0x67,0x6b,0x6f,0x72,\n    0xe7,0xed,0xeb,0xe7,0xec,0xea,0xe7,0xe4,0xe0,0xe6,0xe4,0xe8,0xe1,0xde,0xde,0xde,\n    0xe2,0xe5,0xe3,0xeb,0xe2,0xe3,0xe8,0xe9,0xea,0xec,0xf0,0xf0,0xed,0xea,0xea,0xe9,\n    0xe4,0xd9,0xcf,0xca,0xc9,0xc3,0x78,0x63,0x65,0x66,0x64,0x65,0x69,0x75,0x86,0x9b,\n    0xa4,0xae,0xb2,0xb3,0xb6,0xb5,0xb5,0xb5,0xb3,0xb3,0xb0,0xa7,0x9c,0x9e,0xa4,0xaf,\n    0xb9,0xbe,0xb2,0xa7,0x98,0x91,0x8c,0x90,0x95,0x9b,0xa2,0xa5,0x9c,0x8d,0x6f,0x52,\n    0x40,0x3b,0x36,0x3b,0x40,0x3f,0x41,0x40,0x3c,0x37,0x2d,0x2a,0x29,0x28,0x2b,0x30,\n    0x33,0x38,0x3c,0x3f,0x3f,0x41,0x44,0x4a,0x50,0x51,0x4c,0x49,0x4d,0x50,0x50,0x54,\n    0x56,0x54,0x4e,0x4b,0x45,0x42,0x45,0x48,0x52,0x5d,0x64,0x69,0x6d,0x6e,0x6f,0x6e,\n    0xeb,0xe9,0xeb,0xed,0xe6,0xea,0xe9,0xe8,0xe4,0xe2,0xe7,0xe5,0xe5,0xe1,0xe0,0xde,\n    0xde,0xe3,0xdf,0xe6,0xe2,0xe6,0xe8,0xea,0xec,0xed,0xec,0xec,0xed,0xeb,0xeb,0xec,\n    0xec,0xec,0xe9,0xde,0xcf,0xa3,0x64,0x6a,0x68,0x64,0x60,0x61,0x64,0x71,0x82,0x93,\n    0x9e,0xa2,0xa1,0xa2,0xa0,0x9d,0x9c,0x9d,0x9a,0x97,0x92,0x8f,0x87,0x8b,0x94,0x9f,\n    0xa4,0xa6,0x9f,0x9a,0x97,0x96,0x99,0x9e,0xa3,0xa6,0xa9,0xa8,0x9a,0x85,0x68,0x4a,\n    0x3b,0x39,0x3a,0x3d,0x3f,0x42,0x42,0x40,0x3d,0x34,0x2e,0x2c,0x2c,0x2c,0x2f,0x34,\n    0x3c,0x3f,0x45,0x49,0x49,0x4a,0x4b,0x4f,0x52,0x50,0x4d,0x4a,0x4d,0x4e,0x4e,0x52,\n    0x53,0x53,0x4d,0x4a,0x42,0x3d,0x3f,0x49,0x53,0x5b,0x64,0x69,0x6d,0x6f,0x6e,0x6b,\n    0xee,0xef,0xec,0xed,0xe8,0xe9,0xe9,0xe6,0xe5,0xe6,0xe3,0xe8,0xe7,0xe3,0xe1,0xe2,\n    0xe0,0xe0,0xe1,0xe0,0xe7,0xe7,0xec,0xec,0xec,0xeb,0xe9,0xea,0xe7,0xe5,0xe7,0xe6,\n    0xe4,0xe2,0xdb,0xd1,0xb9,0x72,0x65,0x75,0x6e,0x67,0x65,0x60,0x63,0x71,0x7f,0x8d,\n    0x9c,0xa3,0xa2,0x9f,0x9c,0x9b,0x9b,0x9b,0x9c,0x9b,0x96,0x8d,0x87,0x83,0x89,0x8f,\n    0x92,0x91,0x96,0x98,0x9d,0xa3,0xa6,0xa8,0xab,0xae,0xaf,0xa6,0x93,0x78,0x5f,0x44,\n    0x38,0x39,0x3c,0x40,0x44,0x45,0x44,0x43,0x3c,0x36,0x31,0x31,0x30,0x30,0x33,0x38,\n    0x40,0x45,0x4a,0x4b,0x4d,0x4d,0x4c,0x4f,0x4e,0x4d,0x49,0x49,0x4a,0x4b,0x4c,0x4f,\n    0x51,0x51,0x4c,0x48,0x43,0x3f,0x3f,0x44,0x4e,0x55,0x5f,0x64,0x68,0x63,0x64,0x65,\n    0xb2,0xd4,0xe3,0xe8,0xe5,0xe7,0xe6,0xe6,0xe7,0xe6,0xe6,0xe4,0xe5,0xe7,0xe8,0xe5,\n    0xe7,0xe8,0xe7,0xe2,0xe5,0xe5,0xe1,0xdc,0xd3,0xd4,0xc9,0xbc,0xb4,0xb5,0xb1,0xae,\n    0xa9,0x9a,0x8d,0x91,0x8e,0x6e,0x73,0x7b,0x73,0x71,0x6d,0x68,0x68,0x72,0x7c,0x8b,\n    0x99,0xa5,0xac,0xae,0xab,0xa9,0xa9,0xab,0xaa,0xa9,0xa5,0x9f,0x99,0x93,0x92,0x93,\n    0x93,0x96,0x9d,0xa4,0xac,0xaf,0xb2,0xb3,0xb4,0xb1,0xac,0xa1,0x8d,0x72,0x56,0x43,\n    0x3a,0x3d,0x42,0x45,0x47,0x49,0x48,0x44,0x41,0x3d,0x3d,0x3a,0x36,0x35,0x38,0x3e,\n    0x44,0x46,0x49,0x4e,0x4e,0x4e,0x4c,0x4d,0x4b,0x49,0x46,0x48,0x47,0x47,0x4b,0x50,\n    0x4e,0x4d,0x4b,0x49,0x45,0x40,0x3e,0x41,0x49,0x52,0x58,0x5f,0x5e,0x59,0x5b,0x58,\n    0x3d,0x48,0x63,0x7f,0x82,0x87,0x8f,0x99,0x9f,0xa3,0xa1,0x9d,0xa2,0x9a,0x96,0x9a,\n    0xa2,0x9c,0x87,0x88,0x86,0x85,0x7f,0x7c,0x84,0x8c,0x96,0x99,0x95,0x92,0x94,0x92,\n    0x91,0x7f,0x7c,0x80,0x7c,0x60,0x6b,0x75,0x74,0x72,0x72,0x6e,0x6a,0x6f,0x7c,0x89,\n    0x9a,0xa8,0xb1,0xb6,0xba,0xb8,0xb6,0xb5,0xb6,0xb5,0xb1,0xac,0xa9,0xa2,0xa1,0xa4,\n    0xa2,0xa7,0xab,0xb1,0xb7,0xba,0xbb,0xb8,0xb6,0xb2,0xaa,0x9a,0x85,0x68,0x4f,0x40,\n    0x3c,0x43,0x46,0x48,0x48,0x48,0x47,0x45,0x40,0x3f,0x3f,0x3c,0x3a,0x38,0x3c,0x41,\n    0x44,0x45,0x4b,0x4e,0x4e,0x4e,0x4b,0x4a,0x46,0x45,0x46,0x49,0x48,0x48,0x4c,0x50,\n    0x4e,0x4c,0x4c,0x4a,0x45,0x40,0x41,0x3f,0x46,0x4c,0x4f,0x52,0x51,0x4b,0x4f,0x4b,\n    0x4b,0x4b,0x5b,0x58,0x55,0x5a,0x68,0x68,0x6e,0x7a,0x68,0x5b,0x6a,0x70,0x76,0x7b,\n    0x7f,0x87,0x82,0x7e,0x79,0x70,0x7a,0x8c,0x84,0x7b,0x81,0x87,0x8a,0x8c,0x94,0x88,\n    0x6c,0x5f,0x69,0x6f,0x6e,0x5c,0x6d,0x74,0x73,0x74,0x74,0x74,0x70,0x71,0x76,0x81,\n    0x91,0xa0,0xad,0xb3,0xbc,0xc0,0xc0,0xc0,0xc1,0xc1,0xba,0xb6,0xb2,0xb0,0xb0,0xb1,\n    0xb2,0xb5,0xba,0xbd,0xbf,0xc2,0xbf,0xba,0xb5,0xae,0xa5,0x94,0x7b,0x63,0x4e,0x42,\n    0x43,0x47,0x48,0x4a,0x4a,0x49,0x48,0x48,0x43,0x42,0x43,0x40,0x3c,0x3d,0x44,0x45,\n    0x47,0x49,0x4e,0x50,0x4e,0x4d,0x4b,0x4a,0x47,0x44,0x48,0x4a,0x4b,0x4c,0x4f,0x4e,\n    0x4f,0x50,0x4e,0x4d,0x47,0x41,0x42,0x3f,0x40,0x43,0x43,0x46,0x45,0x41,0x44,0x42,\n    0x76,0x59,0x4d,0x61,0x64,0x53,0x5c,0x7b,0x84,0x7a,0x6c,0x5d,0x5b,0x55,0x5e,0x79,\n    0x82,0x85,0x84,0x7f,0x79,0x41,0x63,0x8c,0x7f,0x7d,0x79,0x6c,0x76,0x80,0x6b,0x59,\n    0x61,0x6c,0x6e,0x73,0x64,0x5f,0x7e,0x74,0x73,0x74,0x74,0x74,0x73,0x73,0x6f,0x72,\n    0x7d,0x90,0xa2,0xab,0xb4,0xba,0xbf,0xc1,0xc3,0xc3,0xbf,0xbc,0xba,0xb9,0xba,0xba,\n    0xbd,0xc0,0xc1,0xc2,0xc3,0xc3,0xbe,0xb8,0xb3,0xab,0x9f,0x8e,0x76,0x60,0x50,0x49,\n    0x45,0x48,0x49,0x4a,0x4a,0x48,0x48,0x49,0x44,0x41,0x42,0x41,0x40,0x41,0x43,0x45,\n    0x47,0x4a,0x50,0x50,0x4f,0x4e,0x4e,0x4b,0x46,0x43,0x4a,0x4c,0x50,0x52,0x51,0x4d,\n    0x4d,0x4d,0x4c,0x4c,0x48,0x45,0x42,0x3f,0x3c,0x39,0x38,0x39,0x3b,0x39,0x3a,0x3a,\n    0x86,0x7e,0x71,0x70,0x7d,0x74,0x5e,0x5f,0x71,0x83,0x8a,0x88,0x83,0x7e,0x7e,0x7f,\n    0x82,0x86,0x85,0x81,0x7f,0x4e,0x2a,0x74,0x80,0x7d,0x65,0x68,0x5f,0x5a,0x54,0x55,\n    0x5e,0x74,0x6d,0x7c,0x5b,0x73,0x92,0x74,0x74,0x73,0x73,0x73,0x76,0x77,0x75,0x71,\n    0x71,0x78,0x89,0x98,0xa5,0xab,0xb4,0xb9,0xbd,0xbe,0xbc,0xbd,0xbd,0xbe,0xbe,0xbf,\n    0xbf,0xbf,0xc2,0xc2,0xc2,0xc0,0xbd,0xb7,0xb0,0xa7,0x9c,0x88,0x72,0x5f,0x53,0x4f,\n    0x50,0x4d,0x4f,0x4e,0x4b,0x47,0x49,0x49,0x47,0x44,0x42,0x41,0x40,0x42,0x44,0x47,\n    0x4b,0x4e,0x51,0x51,0x53,0x51,0x4e,0x4b,0x45,0x49,0x48,0x4c,0x51,0x54,0x52,0x4e,\n    0x4e,0x4c,0x4b,0x49,0x47,0x45,0x3e,0x3b,0x39,0x36,0x38,0x39,0x37,0x37,0x36,0x32,\n    0x73,0x7f,0x85,0x8b,0x84,0x88,0x7e,0x6a,0x64,0x74,0x84,0x8c,0x91,0x8f,0x8d,0x8a,\n    0x89,0x86,0x85,0x82,0x7f,0x67,0x1d,0x48,0x84,0x82,0x63,0x59,0x54,0x55,0x53,0x57,\n    0x55,0x66,0x70,0x82,0x59,0x7f,0x92,0x72,0x73,0x73,0x74,0x74,0x74,0x74,0x74,0x73,\n    0x73,0x72,0x77,0x85,0x93,0x9f,0xa8,0xaf,0xb4,0xb9,0xbc,0xbb,0xbc,0xbc,0xbc,0xbd,\n    0xbe,0xbf,0xc0,0xc0,0xc1,0xbf,0xbc,0xb4,0xac,0xa4,0x94,0x81,0x6e,0x60,0x54,0x55,\n    0x54,0x54,0x52,0x51,0x4f,0x4b,0x4b,0x4c,0x4b,0x47,0x41,0x41,0x40,0x42,0x46,0x4b,\n    0x4b,0x4d,0x50,0x51,0x52,0x51,0x4c,0x48,0x45,0x48,0x46,0x47,0x4c,0x51,0x50,0x4e,\n    0x4f,0x4c,0x49,0x48,0x44,0x3f,0x39,0x39,0x36,0x34,0x35,0x36,0x37,0x39,0x37,0x2f,\n    0x51,0x6d,0x86,0x89,0x86,0x88,0x87,0x84,0x80,0x7e,0x87,0x8c,0x8c,0x8d,0x8c,0x88,\n    0x86,0x86,0x85,0x83,0x7e,0x74,0x2d,0x1e,0x6f,0x81,0x63,0x58,0x5d,0x60,0x5e,0x56,\n    0x5d,0x76,0x89,0x73,0x64,0x91,0x93,0x72,0x74,0x73,0x74,0x74,0x74,0x74,0x74,0x75,\n    0x75,0x76,0x74,0x77,0x7e,0x8a,0x95,0x9f,0xa7,0xaf,0xb3,0xb6,0xb9,0xb9,0xba,0xbc,\n    0xbd,0xbd,0xbf,0xbf,0xbd,0xbd,0xba,0xb1,0xa7,0x9d,0x8c,0x79,0x6a,0x5d,0x56,0x58,\n    0x56,0x54,0x52,0x51,0x4f,0x50,0x51,0x51,0x4d,0x4b,0x44,0x40,0x42,0x43,0x46,0x4a,\n    0x4a,0x4c,0x4f,0x50,0x50,0x4e,0x4a,0x46,0x41,0x42,0x42,0x43,0x48,0x4d,0x4c,0x4e,\n    0x50,0x4f,0x4c,0x4a,0x46,0x3e,0x36,0x35,0x31,0x31,0x33,0x34,0x35,0x36,0x35,0x2e,\n    0x5a,0x61,0x84,0x85,0x88,0x89,0x86,0x83,0x86,0x87,0x86,0x87,0x8a,0x8a,0x86,0x85,\n    0x84,0x84,0x84,0x81,0x7e,0x7c,0x47,0x16,0x3c,0x7d,0x70,0x5a,0x66,0x5f,0x71,0x58,\n    0x68,0x8b,0x7c,0x6e,0x71,0xa2,0x93,0x71,0x73,0x74,0x74,0x75,0x75,0x75,0x75,0x75,\n    0x75,0x75,0x76,0x75,0x79,0x7e,0x86,0x91,0x9b,0xa4,0xad,0xb3,0xb6,0xb7,0xb9,0xbb,\n    0xbb,0xbc,0xbe,0xbf,0xbc,0xba,0xb7,0xad,0xa2,0x94,0x82,0x70,0x63,0x5c,0x58,0x59,\n    0x56,0x54,0x52,0x51,0x53,0x57,0x57,0x54,0x53,0x4d,0x48,0x45,0x45,0x45,0x47,0x49,\n    0x49,0x4c,0x4e,0x4e,0x4d,0x4b,0x48,0x43,0x3e,0x3f,0x3e,0x3d,0x43,0x48,0x4b,0x4d,\n    0x4f,0x50,0x4e,0x4e,0x48,0x40,0x36,0x33,0x30,0x2d,0x2f,0x31,0x30,0x2e,0x2d,0x2a,\n    0x78,0x72,0x6f,0x7a,0x81,0x85,0x85,0x81,0x84,0x84,0x85,0x84,0x83,0x83,0x82,0x83,\n    0x81,0x81,0x82,0x80,0x7d,0x7e,0x67,0x1e,0x18,0x6c,0x7d,0x5c,0x5b,0x5e,0x6f,0x6a,\n    0x68,0x71,0x65,0x64,0x74,0xb9,0x92,0x72,0x74,0x75,0x76,0x76,0x75,0x75,0x75,0x75,\n    0x75,0x75,0x77,0x77,0x78,0x79,0x7c,0x85,0x8e,0x9b,0xa6,0xad,0xb4,0xb5,0xb6,0xb8,\n    0xba,0xbc,0xbc,0xbc,0xba,0xb7,0xb2,0xa5,0x99,0x89,0x76,0x67,0x5b,0x5b,0x5a,0x59,\n    0x57,0x56,0x55,0x56,0x58,0x5d,0x5b,0x5c,0x59,0x54,0x4e,0x4a,0x47,0x46,0x46,0x48,\n    0x48,0x4a,0x4d,0x4c,0x4b,0x49,0x44,0x3e,0x39,0x38,0x38,0x39,0x3f,0x46,0x4b,0x50,\n    0x52,0x52,0x4e,0x4f,0x49,0x42,0x38,0x31,0x2d,0x2a,0x2b,0x2e,0x2c,0x2b,0x26,0x24,\n    0x7f,0x7f,0x7c,0x7d,0x83,0x85,0x83,0x82,0x83,0x83,0x85,0x83,0x82,0x81,0x7f,0x84,\n    0x82,0x82,0x82,0x82,0x81,0x84,0x7c,0x23,0x14,0x39,0x85,0x72,0x53,0x54,0x60,0x63,\n    0x5e,0x63,0x58,0x67,0x7e,0xc7,0x89,0x72,0x74,0x74,0x75,0x75,0x74,0x75,0x75,0x75,\n    0x75,0x75,0x79,0x78,0x7a,0x7a,0x7b,0x7c,0x84,0x94,0xa0,0xab,0xb0,0xb3,0xb6,0xb8,\n    0xb8,0xba,0xba,0xba,0xb9,0xb4,0xac,0x9c,0x8b,0x7a,0x67,0x5d,0x59,0x57,0x55,0x55,\n    0x56,0x55,0x57,0x59,0x5c,0x61,0x61,0x5f,0x5e,0x59,0x52,0x4e,0x4a,0x47,0x48,0x49,\n    0x4c,0x4d,0x4b,0x48,0x49,0x47,0x40,0x3a,0x35,0x33,0x32,0x35,0x38,0x43,0x45,0x4d,\n    0x4e,0x4f,0x4e,0x4d,0x4b,0x43,0x3b,0x31,0x2d,0x29,0x29,0x2a,0x29,0x28,0x24,0x21,\n    0x7d,0x7e,0x7e,0x7d,0x81,0x82,0x82,0x84,0x84,0x85,0x81,0x81,0x80,0x81,0x82,0x81,\n    0x82,0x82,0x85,0x85,0x89,0x8c,0x85,0x29,0x13,0x14,0x6b,0x85,0x5b,0x55,0x5c,0x60,\n    0x60,0x5f,0x59,0x73,0x84,0xd4,0x82,0x75,0x74,0x76,0x76,0x75,0x75,0x75,0x75,0x75,\n    0x76,0x76,0x77,0x77,0x7a,0x79,0x7a,0x7f,0x88,0x93,0x9d,0xa3,0xaf,0xb1,0xb4,0xb5,\n    0xb8,0xb9,0xb9,0xb8,0xb8,0xb1,0xa1,0x8e,0x7c,0x6b,0x5b,0x55,0x57,0x55,0x53,0x51,\n    0x53,0x55,0x57,0x59,0x5f,0x63,0x63,0x62,0x61,0x5d,0x55,0x4f,0x4e,0x4d,0x4d,0x4c,\n    0x4d,0x50,0x4f,0x4a,0x49,0x45,0x3c,0x38,0x35,0x31,0x2f,0x32,0x3b,0x41,0x42,0x47,\n    0x4a,0x49,0x4d,0x4d,0x49,0x44,0x3d,0x36,0x2f,0x2a,0x29,0x25,0x26,0x24,0x21,0x1f,\n    0x7e,0x7e,0x7e,0x7e,0x7f,0x7d,0x80,0x81,0x82,0x83,0x82,0x81,0x80,0x80,0x7f,0x80,\n    0x82,0x84,0x85,0x8a,0x8f,0x93,0x89,0x24,0x12,0x0d,0x3a,0x88,0x72,0x5e,0x5c,0x5d,\n    0x5e,0x5a,0x61,0x84,0x99,0xd9,0x7c,0x75,0x73,0x75,0x76,0x76,0x76,0x76,0x75,0x75,\n    0x75,0x75,0x76,0x77,0x76,0x76,0x79,0x82,0x8b,0x93,0xa0,0xa6,0xaa,0xae,0xb1,0xb2,\n    0xb6,0xb7,0xb8,0xb8,0xb4,0xaa,0x98,0x82,0x6d,0x5e,0x53,0x52,0x53,0x52,0x53,0x52,\n    0x54,0x56,0x57,0x59,0x62,0x64,0x62,0x63,0x63,0x5f,0x57,0x54,0x55,0x54,0x54,0x52,\n    0x51,0x54,0x51,0x4e,0x4a,0x44,0x3e,0x39,0x33,0x30,0x30,0x36,0x3e,0x40,0x41,0x44,\n    0x44,0x46,0x48,0x49,0x49,0x46,0x40,0x3a,0x35,0x2e,0x28,0x25,0x24,0x23,0x21,0x21,\n    0x7f,0x7e,0x7f,0x7e,0x7e,0x7e,0x80,0x81,0x81,0x82,0x80,0x7f,0x7f,0x80,0x81,0x81,\n    0x84,0x87,0x8d,0x92,0x97,0x98,0x62,0x18,0x11,0x0c,0x1a,0x71,0x87,0x5f,0x64,0x60,\n    0x5d,0x58,0x78,0x8d,0xb6,0xd8,0x78,0x77,0x77,0x77,0x77,0x76,0x76,0x76,0x75,0x75,\n    0x76,0x76,0x77,0x76,0x74,0x75,0x7b,0x88,0x90,0x99,0xa3,0xa9,0xab,0xad,0xb0,0xb1,\n    0xb4,0xb5,0xb6,0xb7,0xb0,0xa3,0x8c,0x75,0x60,0x56,0x55,0x56,0x57,0x55,0x54,0x55,\n    0x56,0x58,0x5b,0x5e,0x63,0x67,0x67,0x65,0x65,0x62,0x5f,0x5c,0x5b,0x59,0x59,0x58,\n    0x5a,0x5a,0x56,0x54,0x4e,0x46,0x3d,0x37,0x33,0x33,0x34,0x3b,0x40,0x41,0x42,0x3f,\n    0x42,0x46,0x47,0x49,0x46,0x42,0x44,0x39,0x37,0x31,0x2b,0x27,0x25,0x24,0x21,0x20,\n    0x7f,0x82,0x84,0x82,0x82,0x83,0x7f,0x80,0x80,0x80,0x7f,0x7e,0x7f,0x7f,0x82,0x83,\n    0x87,0x8e,0x97,0x99,0x9c,0x6a,0x14,0x10,0x0d,0x0a,0x0f,0x3b,0x87,0x66,0x5f,0x5f,\n    0x5e,0x5e,0x8a,0x90,0xd2,0xcd,0x77,0x77,0x77,0x77,0x76,0x77,0x77,0x76,0x75,0x75,\n    0x75,0x77,0x76,0x75,0x72,0x76,0x81,0x8f,0x95,0x9f,0xa6,0xa8,0xa8,0xad,0xb0,0xb1,\n    0xb2,0xb4,0xb4,0xb4,0xac,0x9b,0x81,0x6b,0x58,0x53,0x57,0x58,0x59,0x57,0x57,0x57,\n    0x56,0x56,0x5b,0x60,0x63,0x65,0x67,0x6c,0x6c,0x69,0x64,0x63,0x5f,0x5d,0x5d,0x5f,\n    0x61,0x62,0x5d,0x58,0x4c,0x43,0x3d,0x39,0x37,0x3b,0x3d,0x43,0x46,0x46,0x42,0x41,\n    0x41,0x40,0x43,0x46,0x46,0x46,0x43,0x3c,0x38,0x33,0x2e,0x27,0x25,0x24,0x23,0x22,\n    0x80,0x83,0x84,0x81,0x81,0x82,0x7f,0x81,0x7e,0x7f,0x7e,0x7e,0x7d,0x82,0x85,0x89,\n    0x8e,0x97,0x9b,0x9e,0x8e,0x56,0x30,0x18,0x15,0x0b,0x0e,0x16,0x6c,0x7a,0x5a,0x5f,\n    0x62,0x6c,0x8a,0x96,0xe4,0xbc,0x77,0x77,0x77,0x77,0x79,0x79,0x77,0x76,0x77,0x77,\n    0x76,0x76,0x74,0x72,0x72,0x7b,0x86,0x95,0x9d,0xa3,0xa7,0xa8,0xa8,0xad,0xaf,0xb0,\n    0xb1,0xb3,0xb3,0xb1,0xa8,0x97,0x7d,0x69,0x57,0x54,0x55,0x58,0x5b,0x58,0x57,0x57,\n    0x58,0x57,0x5c,0x61,0x63,0x67,0x67,0x6c,0x6c,0x6b,0x68,0x65,0x61,0x61,0x62,0x63,\n    0x67,0x68,0x61,0x55,0x49,0x43,0x3f,0x3a,0x3c,0x40,0x45,0x49,0x48,0x47,0x43,0x42,\n    0x41,0x41,0x44,0x45,0x46,0x47,0x44,0x41,0x3c,0x37,0x34,0x2b,0x28,0x26,0x24,0x21,\n    0x82,0x84,0x84,0x82,0x81,0x7f,0x7f,0x80,0x7f,0x7d,0x7d,0x7e,0x7f,0x82,0x89,0x8e,\n    0x99,0x9f,0xa0,0x93,0x7b,0x73,0x62,0x27,0x24,0x14,0x0f,0x12,0x3d,0x82,0x64,0x57,\n    0x5d,0x7a,0x88,0xa9,0xea,0xa6,0x77,0x76,0x78,0x78,0x78,0x77,0x77,0x77,0x75,0x75,\n    0x74,0x72,0x71,0x6e,0x74,0x7f,0x8b,0x97,0xa3,0xa4,0xa5,0xa8,0xa9,0xac,0xac,0xae,\n    0xb0,0xb1,0xb2,0xb0,0xa5,0x90,0x7b,0x6c,0x5b,0x59,0x58,0x5a,0x57,0x54,0x55,0x55,\n    0x58,0x58,0x5d,0x60,0x64,0x69,0x68,0x6c,0x6b,0x6c,0x69,0x64,0x5f,0x61,0x62,0x65,\n    0x6a,0x66,0x5f,0x55,0x4e,0x44,0x3c,0x39,0x3d,0x42,0x48,0x4a,0x49,0x47,0x43,0x44,\n    0x43,0x43,0x43,0x45,0x43,0x44,0x46,0x44,0x42,0x40,0x39,0x31,0x2d,0x26,0x27,0x22,\n    0x85,0x84,0x7f,0x7f,0x7f,0x81,0x7e,0x7e,0x7d,0x7d,0x7e,0x80,0x82,0x89,0x91,0x98,\n    0x9e,0xa2,0x95,0x7d,0x78,0x77,0x6f,0x28,0x19,0x1a,0x18,0x0f,0x18,0x69,0x76,0x58,\n    0x65,0x82,0x85,0xc7,0xe9,0x91,0x75,0x75,0x77,0x78,0x78,0x77,0x77,0x77,0x77,0x74,\n    0x72,0x6e,0x6a,0x6b,0x76,0x84,0x91,0x9c,0xa4,0xa4,0xa6,0xa7,0xa8,0xa8,0xa9,0xab,\n    0xac,0xad,0xaf,0xac,0xa0,0x8f,0x7e,0x6e,0x61,0x5e,0x5b,0x5c,0x58,0x56,0x56,0x58,\n    0x5a,0x5a,0x5e,0x61,0x66,0x69,0x69,0x6c,0x6c,0x6a,0x66,0x60,0x5c,0x5c,0x5d,0x60,\n    0x64,0x5f,0x58,0x54,0x4a,0x3f,0x39,0x36,0x38,0x40,0x48,0x4b,0x48,0x47,0x43,0x42,\n    0x43,0x44,0x46,0x48,0x47,0x48,0x48,0x48,0x49,0x45,0x3d,0x38,0x32,0x2b,0x27,0x25,\n    0x7b,0x7d,0x7e,0x7f,0x81,0x80,0x7e,0x7e,0x7e,0x7e,0x7f,0x82,0x89,0x93,0x9a,0x9e,\n    0xa0,0x93,0x80,0x7d,0x7a,0x7a,0x71,0x2f,0x15,0x10,0x16,0x16,0x14,0x3e,0x76,0x64,\n    0x73,0x89,0x97,0xe4,0xda,0x79,0x71,0x71,0x75,0x75,0x77,0x77,0x77,0x77,0x77,0x73,\n    0x6f,0x68,0x67,0x6e,0x7c,0x8a,0x96,0x9f,0xa2,0xa2,0xa2,0xa2,0xa2,0xa3,0xa5,0xa7,\n    0xa9,0xab,0xac,0xa7,0x9e,0x90,0x80,0x6f,0x66,0x62,0x60,0x5e,0x58,0x58,0x58,0x5a,\n    0x5e,0x61,0x64,0x65,0x68,0x69,0x6b,0x6c,0x6c,0x68,0x62,0x5c,0x56,0x56,0x56,0x58,\n    0x59,0x55,0x51,0x4a,0x40,0x38,0x34,0x33,0x31,0x3b,0x42,0x48,0x47,0x45,0x42,0x41,\n    0x43,0x46,0x46,0x47,0x48,0x49,0x48,0x4b,0x4a,0x44,0x40,0x3c,0x38,0x2e,0x2c,0x28,\n    0x7d,0x81,0x81,0x7f,0x7a,0x7d,0x7c,0x7d,0x7f,0x7e,0x83,0x89,0x93,0x9b,0x9f,0xa1,\n    0x91,0x82,0x7d,0x7f,0x7e,0x7a,0x72,0x2e,0x18,0x0e,0x13,0x10,0x0f,0x1e,0x63,0x72,\n    0x84,0x8a,0xb6,0xeb,0xc0,0x6e,0x70,0x70,0x72,0x73,0x74,0x76,0x75,0x76,0x73,0x6e,\n    0x6a,0x65,0x64,0x6f,0x81,0x8d,0x99,0x9d,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0xa0,0xa3,\n    0xa5,0xa8,0xa8,0xa3,0x9a,0x8f,0x81,0x72,0x67,0x63,0x5e,0x59,0x55,0x53,0x56,0x5c,\n    0x5e,0x61,0x64,0x69,0x6a,0x6a,0x6b,0x6d,0x6a,0x61,0x5b,0x56,0x51,0x4f,0x4f,0x4e,\n    0x4f,0x49,0x45,0x3c,0x34,0x2c,0x2b,0x2d,0x2d,0x32,0x39,0x3f,0x43,0x44,0x41,0x42,\n    0x45,0x47,0x48,0x4a,0x4a,0x4b,0x4a,0x49,0x47,0x43,0x42,0x3e,0x39,0x32,0x2f,0x2a,\n    0x80,0x7f,0x7d,0x7b,0x7b,0x7b,0x7c,0x7f,0x81,0x83,0x8c,0x96,0x9b,0x9e,0x9e,0x91,\n    0x82,0x81,0x7f,0x7e,0x7e,0x7b,0x75,0x34,0x16,0x10,0x12,0x0d,0x0d,0x10,0x49,0x6a,\n    0x8a,0x92,0xd8,0xeb,0x9d,0x6b,0x6f,0x6f,0x70,0x70,0x72,0x74,0x74,0x72,0x6f,0x68,\n    0x63,0x5f,0x65,0x74,0x83,0x90,0x98,0x99,0x99,0x99,0x99,0x9a,0x9b,0x9d,0x9f,0xa1,\n    0xa2,0xa5,0xa5,0x9f,0x99,0x8d,0x82,0x78,0x72,0x6a,0x65,0x5b,0x58,0x56,0x57,0x58,\n    0x5c,0x64,0x65,0x6b,0x6d,0x6a,0x67,0x66,0x62,0x5a,0x57,0x52,0x4c,0x47,0x45,0x42,\n    0x40,0x3e,0x37,0x2f,0x2a,0x26,0x27,0x26,0x26,0x2b,0x33,0x3a,0x3f,0x43,0x43,0x46,\n    0x49,0x4a,0x4d,0x4d,0x4d,0x4d,0x4a,0x47,0x46,0x43,0x42,0x3f,0x3b,0x33,0x31,0x2f,\n    0x7a,0x7a,0x7a,0x7a,0x7a,0x7c,0x7e,0x80,0x83,0x8c,0x98,0x9c,0xa1,0xa0,0x92,0x85,\n    0x83,0x83,0x80,0x7f,0x7f,0x7c,0x76,0x37,0x18,0x0f,0x11,0x0f,0x0f,0x0d,0x33,0x72,\n    0x8c,0xa9,0xe6,0xe1,0x7e,0x6b,0x6e,0x6e,0x6e,0x70,0x71,0x73,0x71,0x70,0x69,0x62,\n    0x5e,0x5d,0x68,0x74,0x83,0x8f,0x94,0x95,0x94,0x95,0x98,0x99,0x9b,0x9d,0xa0,0xa2,\n    0xa6,0xa2,0xb7,0xdd,0xc7,0xcf,0xd4,0xd7,0xdb,0xd5,0xd1,0xcd,0xca,0xc6,0xc0,0xb9,\n    0xae,0xa5,0x9e,0x98,0x91,0x8a,0x82,0x7a,0x75,0x6f,0x68,0x60,0x56,0x50,0x48,0x3f,\n    0x2f,0x2e,0x2b,0x24,0x25,0x24,0x24,0x22,0x21,0x27,0x31,0x3a,0x41,0x44,0x46,0x49,\n    0x4b,0x4d,0x51,0x54,0x52,0x4f,0x4a,0x48,0x45,0x41,0x40,0x3e,0x3b,0x35,0x34,0x31,\n    0x7a,0x7a,0x7a,0x7a,0x7b,0x7d,0x7f,0x87,0x90,0x9b,0x9e,0xa1,0x9b,0x90,0x86,0x85,\n    0x85,0x84,0x81,0x80,0x7e,0x7c,0x76,0x3a,0x19,0x0f,0x10,0x0f,0x0f,0x12,0x3f,0x84,\n    0x91,0xd3,0xeb,0xcc,0x6e,0x6d,0x6c,0x6c,0x6d,0x6e,0x70,0x71,0x71,0x6b,0x65,0x5d,\n    0x5a,0x5c,0x69,0x77,0x83,0x8c,0x91,0x92,0x94,0x95,0x99,0x9b,0x9d,0xa1,0xa3,0xa5,\n    0xa3,0x9f,0x91,0x2b,0x28,0x27,0x27,0x2a,0x2e,0x2f,0x34,0x41,0x49,0x53,0x5f,0x63,\n    0x69,0x77,0x8a,0x95,0x9a,0xa5,0xab,0xb1,0xb4,0xba,0xc0,0xc3,0xcb,0xd4,0xd6,0xcb,\n    0xb1,0x62,0x27,0x24,0x23,0x23,0x21,0x22,0x24,0x29,0x33,0x3c,0x3f,0x41,0x45,0x48,\n    0x4b,0x4d,0x53,0x58,0x56,0x52,0x4d,0x46,0x44,0x3f,0x3f,0x3e,0x3b,0x38,0x36,0x37,\n    0x7a,0x7a,0x79,0x7b,0x7c,0x7e,0x85,0x93,0x9b,0x9f,0xa0,0x98,0x8c,0x86,0x85,0x85,\n    0x84,0x83,0x83,0x81,0x80,0x7f,0x7a,0x3e,0x19,0x10,0x0e,0x0f,0x11,0x19,0x61,0x8a,\n    0xac,0xe5,0xea,0xac,0x6d,0x6c,0x6a,0x6b,0x6b,0x6d,0x6e,0x70,0x6e,0x67,0x60,0x59,\n    0x58,0x5e,0x6c,0x79,0x82,0x89,0x90,0x92,0x92,0x95,0x9a,0x9e,0xa0,0xa4,0xa5,0xa8,\n    0x96,0xc5,0x3a,0x39,0x6b,0x6b,0x61,0x5a,0x52,0x47,0x43,0x3b,0x37,0x33,0x30,0x2d,\n    0x2f,0x2f,0x30,0x32,0x34,0x35,0x32,0x39,0x37,0x3a,0x3c,0x3e,0x40,0x41,0x43,0x43,\n    0x41,0x53,0x78,0x27,0x26,0x24,0x24,0x24,0x25,0x2b,0x31,0x3a,0x3a,0x3d,0x3f,0x44,\n    0x48,0x49,0x52,0x57,0x55,0x52,0x4d,0x47,0x44,0x3f,0x40,0x40,0x3e,0x3b,0x39,0x36,\n    0x79,0x7a,0x7a,0x7c,0x7c,0x85,0x95,0x9e,0x9b,0xa1,0x98,0x8b,0x87,0x86,0x87,0x85,\n    0x85,0x85,0x83,0x83,0x82,0x80,0x7c,0x41,0x18,0x11,0x0d,0x0d,0x12,0x3d,0x7f,0x8d,\n    0xd3,0xe8,0xe2,0x88,0x6b,0x6a,0x6a,0x6a,0x6a,0x6b,0x6e,0x6f,0x6c,0x63,0x5d,0x57,\n    0x58,0x65,0x71,0x7d,0x85,0x8b,0x8e,0x92,0x95,0x97,0x9d,0xa0,0xa3,0xa6,0xa7,0xa6,\n    0x8c,0xc2,0x37,0x4a,0xc9,0xd0,0xd1,0xdc,0xdd,0xdc,0xdf,0xde,0xdf,0xdd,0xd8,0xd5,\n    0xce,0xc7,0xc0,0xbb,0xb1,0xaa,0xa2,0x99,0x96,0x8e,0x88,0x83,0x7c,0x78,0x72,0x69,\n    0x3c,0x2a,0x8b,0x2a,0x2e,0x2b,0x29,0x28,0x29,0x2b,0x31,0x36,0x37,0x38,0x3c,0x40,\n    0x41,0x48,0x4e,0x50,0x53,0x54,0x52,0x4b,0x48,0x43,0x41,0x41,0x40,0x3e,0x3e,0x39,\n    0x7b,0x7c,0x7b,0x7c,0x84,0x93,0x9d,0x9f,0x9c,0x96,0x8b,0x89,0x87,0x86,0x86,0x86,\n    0x87,0x88,0x84,0x84,0x81,0x81,0x7b,0x44,0x19,0x12,0x0d,0x0d,0x21,0x6b,0x82,0xad,\n    0xe8,0xe7,0xcb,0x6f,0x6a,0x68,0x69,0x69,0x69,0x6b,0x6d,0x6e,0x6a,0x62,0x5b,0x58,\n    0x5c,0x69,0x76,0x80,0x88,0x8e,0x91,0x94,0x96,0x98,0x9e,0xa1,0xa4,0xa4,0xa5,0xa5,\n    0x7f,0xc1,0x3a,0x49,0xc1,0xca,0xcc,0xcc,0xd1,0xd4,0xd2,0xd3,0xd3,0xd4,0xd5,0xd5,\n    0xd5,0xd6,0xd5,0xd6,0xd4,0xd5,0xd6,0xd6,0xd5,0xd7,0xd6,0xd7,0xd4,0xd3,0xd4,0xdc,\n    0x3e,0x2f,0x8c,0x3b,0x39,0x35,0x33,0x2f,0x2f,0x2e,0x30,0x34,0x35,0x36,0x36,0x39,\n    0x3c,0x42,0x46,0x49,0x51,0x54,0x51,0x4b,0x49,0x45,0x43,0x41,0x41,0x41,0x3f,0x3b,\n    0x7c,0x7e,0x7f,0x86,0x98,0x9c,0x9b,0x99,0x90,0x89,0x89,0x88,0x86,0x86,0x87,0x89,\n    0x88,0x88,0x84,0x85,0x82,0x7f,0x7d,0x48,0x18,0x12,0x0d,0x12,0x47,0x7f,0x92,0xd8,\n    0xe8,0xe5,0x9f,0x6a,0x6b,0x6a,0x69,0x69,0x68,0x6a,0x6c,0x6c,0x67,0x60,0x5a,0x58,\n    0x61,0x71,0x7e,0x87,0x8e,0x91,0x94,0x95,0x95,0x9e,0xa7,0xa8,0xa8,0xa7,0xac,0xaa,\n    0x73,0x6f,0x37,0x4c,0xbf,0xcb,0xcf,0xce,0xd0,0xd2,0xd3,0xd4,0xd5,0xd5,0xd5,0xd4,\n    0xd5,0xd6,0xd6,0xd5,0xd6,0xd5,0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xd7,0xd6,0xd5,0xe1,\n    0x44,0x33,0x8c,0x43,0x46,0x40,0x3c,0x38,0x35,0x34,0x33,0x32,0x32,0x33,0x33,0x34,\n    0x38,0x3b,0x3e,0x44,0x4a,0x4f,0x4c,0x4b,0x4d,0x4a,0x46,0x45,0x43,0x42,0x40,0x3c,\n    0x7d,0x80,0x87,0x99,0x9b,0x9d,0x97,0x8e,0x89,0x89,0x87,0x87,0x88,0x88,0x88,0x86,\n    0x87,0x87,0x85,0x85,0x81,0x7f,0x77,0x4b,0x19,0x11,0x0c,0x23,0x6b,0x89,0xb5,0xe6,\n    0xe6,0xd8,0x7e,0x70,0x6d,0x6c,0x6a,0x68,0x67,0x68,0x69,0x69,0x65,0x5e,0x59,0x57,\n    0x69,0x79,0x83,0x8c,0x92,0x94,0x93,0x93,0x9e,0xad,0xb1,0xaf,0xae,0xb1,0xb6,0xb6,\n    0x55,0x1f,0x2f,0x50,0xc7,0xd1,0xce,0xd1,0xd3,0xd4,0xd3,0xd4,0xd4,0xd4,0xd4,0xd3,\n    0xd4,0xd4,0xd4,0xd0,0xd5,0xd5,0xd6,0xd7,0xd7,0xd6,0xd6,0xd6,0xd7,0xd6,0xd5,0xd5,\n    0x35,0x2c,0x87,0x54,0x51,0x4b,0x48,0x42,0x3c,0x38,0x36,0x35,0x33,0x34,0x36,0x36,\n    0x37,0x39,0x3b,0x3e,0x42,0x48,0x47,0x48,0x4a,0x48,0x45,0x43,0x42,0x40,0x40,0x3f,\n    0x86,0x94,0xa2,0xa3,0xa3,0x9d,0x93,0x90,0x91,0x90,0x90,0x92,0x91,0x90,0x8f,0x8e,\n    0x8d,0x8c,0x89,0x8c,0x87,0x83,0x7d,0x53,0x14,0x0a,0x0f,0x4c,0x85,0x9e,0xe2,0xf0,\n    0xf0,0xba,0x75,0x72,0x74,0x72,0x6f,0x6e,0x67,0x6a,0x6b,0x68,0x63,0x5c,0x5b,0x5f,\n    0x70,0x80,0x8b,0x91,0x94,0x95,0x93,0x9d,0xb1,0xbb,0xbb,0xb9,0xb6,0xc5,0xce,0xc4,\n    0x30,0x1f,0x2c,0x51,0xc9,0xcc,0xd1,0xd1,0xd2,0xd4,0xd2,0xd3,0xd4,0xd5,0xd5,0xd6,\n    0xd5,0xd4,0xd5,0xd6,0xd5,0xd6,0xd5,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd5,0xd6,0xcf,\n    0x38,0x26,0x15,0x60,0x5c,0x56,0x52,0x4a,0x42,0x3d,0x3a,0x37,0x36,0x36,0x39,0x3a,\n    0x39,0x3b,0x3c,0x3a,0x3f,0x43,0x44,0x46,0x45,0x44,0x44,0x41,0x3f,0x3b,0x3b,0x3c,\n    0x36,0x38,0x33,0x3a,0x37,0x3b,0x3e,0x3e,0x3d,0x40,0x41,0x41,0x45,0x47,0x46,0x4c,\n    0x4b,0x4a,0x4c,0x4b,0x4d,0x51,0x50,0x4f,0x40,0x3d,0x3d,0x51,0x5a,0x6f,0x7f,0x81,\n    0x83,0x68,0x5b,0x5a,0x59,0x5d,0x65,0x62,0x64,0x5d,0x65,0x60,0x5d,0x56,0x57,0x5b,\n    0x66,0x70,0x7a,0x7e,0x80,0x82,0x8b,0x99,0xa9,0xa9,0xa4,0x98,0x97,0x76,0x26,0x01,\n    0x11,0x21,0x26,0x51,0xc9,0xcf,0xcc,0xcf,0xd1,0xd2,0xd3,0xd2,0xd2,0xd4,0xd4,0xd5,\n    0xd5,0xd4,0xd3,0xd3,0xd3,0xd4,0xd6,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xe1,\n    0x34,0x19,0x13,0x6a,0x62,0x5e,0x58,0x54,0x4c,0x41,0x3d,0x38,0x35,0x39,0x3b,0x3c,\n    0x3c,0x3f,0x3e,0x3c,0x3f,0x42,0x45,0x44,0x43,0x42,0x41,0x40,0x3c,0x36,0x36,0x36,\n    0x60,0x60,0x5e,0x5f,0x5f,0x61,0x6a,0x5f,0x61,0x64,0x60,0x5e,0x58,0x5a,0x5a,0x5c,\n    0x5e,0x61,0x5e,0x5d,0x59,0x61,0x62,0x64,0x5e,0x5b,0x63,0x5d,0x5c,0x5b,0x56,0x51,\n    0x50,0x51,0x57,0x4e,0x5d,0x6f,0xc4,0xd0,0xbe,0xce,0xc7,0x7a,0x59,0x58,0x58,0x54,\n    0x50,0x52,0x4e,0x47,0x3a,0x39,0x3a,0x3c,0x3a,0x1f,0x12,0x14,0x12,0x13,0x12,0x12,\n    0x0d,0x18,0x21,0x51,0xcc,0xcf,0xcd,0xce,0xd0,0xd2,0xd0,0xd1,0xd3,0xd5,0xd5,0xd5,\n    0xd4,0xd4,0xd4,0xd4,0xd5,0xd4,0xd6,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd4,0xe1,\n    0x29,0x15,0x14,0x6c,0x68,0x63,0x5e,0x59,0x51,0x49,0x41,0x3d,0x3a,0x3d,0x3e,0x40,\n    0x44,0x47,0x44,0x42,0x43,0x43,0x43,0x43,0x46,0x44,0x3f,0x3b,0x38,0x34,0x33,0x33,\n    0x9a,0x9f,0x93,0x9f,0x8d,0x9e,0x8c,0x96,0x93,0x8d,0x99,0x95,0x94,0x91,0x94,0x99,\n    0x95,0x9a,0x97,0x9b,0x9c,0x9f,0xa1,0x9e,0xa3,0xa3,0xa2,0xa4,0xa1,0x9e,0x93,0x95,\n    0x96,0x91,0x94,0x8f,0x99,0xa9,0xfa,0xf7,0xf6,0xf6,0xf9,0xb6,0x9b,0x9c,0x9c,0x99,\n    0x97,0x78,0x71,0x52,0x4f,0x49,0x49,0x50,0x4f,0x1b,0x16,0x14,0x12,0x15,0x16,0x10,\n    0x32,0x8b,0x2f,0x4f,0xc6,0xcd,0xcf,0xd0,0xd1,0xd0,0xd3,0xd3,0xd3,0xd4,0xd1,0xd1,\n    0xd5,0xd4,0xd4,0xd4,0xd6,0xd6,0xd6,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xe1,\n    0x31,0x15,0x12,0x6c,0x68,0x67,0x61,0x5a,0x53,0x49,0x46,0x40,0x3d,0x3f,0x43,0x46,\n    0x4b,0x4d,0x4c,0x49,0x48,0x47,0x43,0x44,0x44,0x43,0x3e,0x3b,0x37,0x33,0x31,0x31,\n    0x8a,0x8b,0x94,0x8f,0x92,0x9b,0x94,0x95,0x93,0x94,0x96,0x98,0x9f,0xa4,0xa1,0xa6,\n    0xa8,0xa5,0xa2,0xad,0xb3,0xb2,0xab,0xad,0xae,0xb2,0xb0,0xab,0xb0,0xac,0xb2,0xb6,\n    0xb2,0xb4,0xb4,0xb4,0xb7,0xd0,0xfb,0xf8,0xf9,0xfc,0xff,0xc7,0xbf,0xba,0xab,0x86,\n    0x5f,0x56,0x54,0x5e,0x67,0x5d,0x52,0x56,0x5a,0x43,0x15,0x13,0x1f,0x1e,0x12,0x1d,\n    0x45,0xbb,0x39,0x4e,0xca,0xcf,0xcf,0xd1,0xd2,0xd3,0xd4,0xd4,0xd4,0xd3,0xd4,0xd4,\n    0xd4,0xd4,0xd4,0xd4,0xd2,0xd2,0xd6,0xd5,0xd5,0xd5,0xd5,0xd5,0xd2,0xd4,0xd5,0xe0,\n    0x38,0x1c,0x3e,0x68,0x6a,0x68,0x62,0x5c,0x54,0x4e,0x48,0x44,0x41,0x43,0x47,0x4c,\n    0x50,0x53,0x54,0x54,0x52,0x4d,0x4c,0x49,0x47,0x43,0x3f,0x3b,0x38,0x36,0x31,0x32,\n    0x8c,0x89,0x88,0x88,0x89,0x87,0x89,0x8b,0x84,0x86,0x89,0x85,0x86,0x84,0x83,0x82,\n    0x84,0x84,0x82,0x82,0x82,0x8a,0x85,0x83,0x64,0x7a,0xa8,0xc5,0xc6,0xc6,0xbe,0x90,\n    0x87,0x8b,0x8a,0x89,0x91,0xa9,0xc8,0xc9,0xc9,0xc4,0xbf,0x87,0x6b,0x5e,0x5e,0x64,\n    0x6b,0x70,0x7a,0x7f,0x81,0x89,0x8d,0x89,0x88,0x79,0x59,0x55,0x5c,0x54,0x4a,0x52,\n    0x57,0xbf,0x38,0x50,0xcd,0xce,0xce,0xce,0xd1,0xd1,0xd3,0xd4,0xd5,0xd4,0xd4,0xd4,\n    0xd4,0xd4,0xd3,0xd3,0xd3,0xd4,0xd4,0xd5,0xd5,0xd5,0xd5,0xd5,0xd6,0xd5,0xd4,0xe0,\n    0x46,0x32,0x85,0x6b,0x6a,0x67,0x64,0x5e,0x55,0x50,0x49,0x48,0x48,0x49,0x4d,0x50,\n    0x56,0x58,0x59,0x5b,0x58,0x55,0x51,0x4e,0x4b,0x47,0x42,0x3e,0x3b,0x38,0x36,0x33,\n    0x8b,0x8a,0x8e,0x8b,0x8c,0x8d,0x8d,0x8d,0x8b,0x89,0x87,0x87,0x88,0x86,0x83,0x82,\n    0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x80,0x76,0x7a,0x9c,0xde,0xe4,0xe5,0xe4,0xba,0x7e,\n    0x7f,0x7f,0x7f,0x7f,0x7e,0x80,0x7e,0x80,0x81,0x7e,0x7c,0x76,0x6f,0x6d,0x73,0x84,\n    0x93,0xa0,0xaf,0xc0,0xcd,0xd8,0xd9,0xd6,0xd1,0xcf,0xce,0xd6,0xde,0xe7,0xed,0xe8,\n    0x9f,0xbe,0x39,0x50,0xcd,0xce,0xcc,0xd3,0xd4,0xd4,0xd4,0xd5,0xd5,0xd4,0xd4,0xd4,\n    0xd4,0xd4,0xd5,0xd5,0xd4,0xd4,0xd4,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd4,0xd4,0xdf,\n    0x44,0x32,0x7e,0x68,0x68,0x65,0x60,0x5d,0x57,0x53,0x50,0x51,0x51,0x52,0x54,0x58,\n    0x5d,0x5f,0x5e,0x5e,0x5c,0x5b,0x56,0x52,0x52,0x4d,0x4a,0x45,0x43,0x42,0x3e,0x3b,\n    0x88,0x89,0x8b,0x8f,0x8d,0x8b,0x8b,0x8b,0x8c,0x88,0x87,0x87,0x87,0x84,0x82,0x81,\n    0x81,0x80,0x7e,0x7e,0x7f,0x81,0x75,0x71,0x96,0xd3,0xe5,0xe5,0xe6,0xd7,0x8e,0x7e,\n    0x7f,0x7e,0x7e,0x7f,0x7f,0x7e,0x7f,0x7e,0x7d,0x7b,0x79,0x72,0x6c,0x6d,0x79,0x89,\n    0x9d,0xaa,0xba,0xcb,0xd6,0xdb,0xd9,0xcd,0xc0,0xb8,0xbb,0xc5,0xd7,0xe3,0xed,0xf0,\n    0xa3,0xbd,0x39,0x53,0xcc,0xc7,0xcd,0xd0,0xd1,0xd4,0xd4,0xd5,0xd5,0xd3,0xd2,0xd4,\n    0xd5,0xd4,0xd5,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd5,0xd3,0xd4,0xd4,0xdf,\n    0x46,0x32,0x83,0x66,0x64,0x60,0x5d,0x5c,0x5a,0x58,0x56,0x57,0x58,0x5a,0x5e,0x63,\n    0x67,0x67,0x65,0x64,0x62,0x5f,0x5b,0x59,0x56,0x54,0x4f,0x4d,0x4b,0x49,0x45,0x44,\n    0x88,0x8a,0x8f,0x8e,0x8d,0x8b,0x8b,0x8a,0x8c,0x87,0x86,0x86,0x86,0x84,0x81,0x7f,\n    0x80,0x7f,0x82,0x80,0x7b,0x79,0x69,0x90,0xd0,0xe2,0xe4,0xe3,0xe1,0xa9,0x7f,0x81,\n    0x82,0x82,0x82,0x81,0x7e,0x7f,0x7d,0x7d,0x7d,0x7b,0x76,0x6f,0x6a,0x6f,0x7f,0x97,\n    0xa4,0xb1,0xc3,0xd1,0xd7,0xdb,0xd5,0xc0,0xa4,0x91,0x96,0xb1,0xca,0xdd,0xea,0xef,\n    0xa7,0xba,0x3c,0x4d,0xca,0xce,0xd3,0xd0,0xd2,0xd4,0xd4,0xd5,0xd5,0xd3,0xd3,0xd4,\n    0xd6,0xd4,0xd5,0xd5,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd5,0xd4,0xd4,0xdf,\n    0x47,0x31,0x81,0x64,0x61,0x61,0x5e,0x5e,0x5c,0x5d,0x5b,0x5d,0x5c,0x5f,0x65,0x6a,\n    0x6a,0x6b,0x6b,0x6b,0x69,0x62,0x61,0x61,0x60,0x59,0x54,0x54,0x53,0x50,0x4f,0x50,\n    0x8c,0x8d,0x8f,0x8e,0x8d,0x8c,0x8b,0x89,0x88,0x86,0x86,0x85,0x85,0x83,0x81,0x81,\n    0x81,0x81,0x7d,0x6c,0x78,0x61,0x80,0xca,0xe5,0xe5,0xe4,0xe5,0xc2,0x83,0x80,0x81,\n    0x82,0x81,0x7f,0x7f,0x7f,0x7f,0x7f,0x7b,0x7a,0x79,0x74,0x6c,0x6a,0x73,0x89,0x9e,\n    0xa7,0xb3,0xc4,0xce,0xd5,0xd6,0xcf,0xb7,0x96,0x74,0x72,0x95,0xb6,0xd4,0xe4,0xeb,\n    0xa8,0xb9,0x3b,0x53,0xd1,0xcf,0xd0,0xd1,0xd2,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd4,\n    0xd4,0xd4,0xd4,0xd3,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xdf,\n    0x48,0x32,0x7f,0x60,0x62,0x62,0x60,0x5f,0x5e,0x5e,0x5f,0x5f,0x61,0x65,0x68,0x6b,\n    0x6b,0x6c,0x6d,0x6a,0x67,0x66,0x65,0x64,0x60,0x58,0x56,0x56,0x58,0x58,0x58,0x58,\n    0x8d,0x8e,0x8f,0x8f,0x8d,0x8d,0x8a,0x88,0x87,0x85,0x85,0x84,0x83,0x82,0x81,0x81,\n    0x81,0x7c,0x5c,0x60,0x5e,0x7b,0xbd,0xeb,0xea,0xec,0xe8,0xdb,0x9b,0x78,0x7b,0x7f,\n    0x82,0x82,0x81,0x80,0x7e,0x7d,0x7c,0x79,0x78,0x76,0x71,0x68,0x6a,0x7c,0x92,0xa0,\n    0xac,0xb8,0xc6,0xcb,0xcf,0xd0,0xc5,0xad,0x90,0x75,0x6a,0x89,0xaf,0xca,0xde,0xe6,\n    0xa4,0xbc,0x39,0x56,0xd1,0xd0,0xd1,0xd2,0xd1,0xd2,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,\n    0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xe0,\n    0x48,0x31,0x86,0x63,0x62,0x61,0x60,0x61,0x61,0x64,0x63,0x63,0x66,0x6a,0x6e,0x6e,\n    0x6f,0x6e,0x6c,0x67,0x68,0x69,0x66,0x62,0x5f,0x5b,0x5a,0x5b,0x5c,0x5e,0x5e,0x5e,\n    0x8b,0x8f,0x8e,0x8d,0x8b,0x8a,0x87,0x87,0x85,0x84,0x84,0x84,0x82,0x82,0x7f,0x7f,\n    0x85,0x63,0x52,0x55,0x71,0xc3,0xe5,0xee,0xef,0xf5,0xee,0xce,0xa4,0x7c,0x72,0x79,\n    0x7c,0x81,0x80,0x7f,0x7d,0x7b,0x79,0x78,0x76,0x73,0x6f,0x68,0x6d,0x81,0x92,0xa6,\n    0xb4,0xbb,0xc3,0xc7,0xcd,0xcc,0xbc,0xa5,0x96,0x8e,0x8e,0x9c,0xb1,0xc8,0xd8,0xe1,\n    0xa0,0xbd,0x3b,0x55,0xd0,0xcd,0xd2,0xd1,0xd2,0xd2,0xd3,0xd3,0xd4,0xe1,0xdf,0xde,\n    0xda,0xdc,0xd7,0xd4,0xd4,0xd6,0xd2,0xd3,0xd1,0xd4,0xd0,0xd5,0xd4,0xd4,0xd4,0xdf,\n    0x48,0x31,0x7f,0x69,0x63,0x63,0x62,0x64,0x65,0x66,0x66,0x65,0x6a,0x6a,0x6b,0x6c,\n    0x6e,0x6e,0x6a,0x66,0x66,0x67,0x65,0x61,0x5e,0x5c,0x5b,0x59,0x59,0x5d,0x5e,0x5c,\n    0x8c,0x8e,0x8d,0x8b,0x8a,0x89,0x87,0x86,0x84,0x84,0x84,0x84,0x83,0x83,0x73,0x77,\n    0x71,0x4d,0x51,0x5c,0xc1,0xe4,0xee,0xef,0xf7,0xf7,0xe3,0xc2,0xb1,0x97,0x75,0x6f,\n    0x75,0x79,0x7e,0x7c,0x7b,0x78,0x76,0x75,0x73,0x70,0x6e,0x68,0x6e,0x80,0x95,0xad,\n    0xbb,0xbd,0xc1,0xc5,0xcb,0xc7,0xb9,0xb1,0xac,0xa9,0xad,0xb8,0xbd,0xc3,0xcd,0xd5,\n    0x9e,0xb9,0x3b,0x59,0xd0,0xd0,0xd1,0xd1,0xd2,0xd2,0xd2,0xd3,0xcf,0x3e,0x3b,0x46,\n    0x4e,0x5c,0x65,0x71,0x7d,0x88,0x92,0x99,0xa1,0xa3,0xca,0xd3,0xd4,0xd3,0xd2,0xdf,\n    0x48,0x33,0x81,0x6b,0x65,0x67,0x67,0x68,0x6a,0x69,0x68,0x68,0x65,0x69,0x6b,0x6a,\n    0x6c,0x6d,0x69,0x64,0x64,0x64,0x64,0x5f,0x5f,0x5b,0x59,0x55,0x53,0x57,0x59,0x57,\n    0x8c,0x8d,0x8c,0x8b,0x89,0x88,0x85,0x85,0x84,0x86,0x86,0x83,0x82,0x79,0x6d,0x77,\n    0x51,0x4b,0x4f,0xba,0xe2,0xee,0xee,0xf6,0xfa,0xec,0xbe,0xb8,0xad,0x9d,0x87,0x6f,\n    0x6b,0x70,0x76,0x79,0x77,0x74,0x74,0x72,0x71,0x6e,0x6a,0x66,0x6e,0x81,0x9c,0xb5,\n    0xbe,0xbf,0xc3,0xc7,0xcb,0xc7,0xc2,0xbf,0xbd,0xbc,0xc3,0xc9,0xc8,0xc2,0xc6,0xd0,\n    0x9b,0xb5,0x3a,0x53,0xcc,0xce,0xd2,0xd1,0xd1,0xcf,0xd0,0xd2,0xce,0x2c,0x13,0x10,\n    0x0b,0x0b,0x0f,0x18,0x15,0x10,0x15,0x17,0x15,0x0e,0x9a,0xd6,0xd1,0xd3,0xd4,0xdf,\n    0x48,0x33,0x7d,0x6a,0x66,0x65,0x68,0x69,0x6a,0x6a,0x68,0x69,0x65,0x68,0x69,0x68,\n    0x69,0x6a,0x68,0x65,0x65,0x65,0x62,0x62,0x5f,0x5b,0x55,0x52,0x4d,0x50,0x52,0x52,\n    0x8c,0x8d,0x8c,0x89,0x89,0x87,0x86,0x85,0x86,0x88,0x86,0x84,0x79,0x5d,0x70,0x5f,\n    0x4c,0x56,0xad,0xea,0xef,0xef,0xf3,0xfc,0xf0,0x8e,0x83,0xa4,0xa7,0x95,0x83,0x70,\n    0x5d,0x64,0x6a,0x72,0x72,0x74,0x72,0x71,0x70,0x6d,0x69,0x65,0x70,0x8a,0xa8,0xb9,\n    0xc1,0xc6,0xca,0xce,0xcd,0xcb,0xca,0xca,0xcb,0xcb,0xcc,0xce,0xd0,0xce,0xc9,0xcd,\n    0x97,0xb5,0x39,0x54,0xcc,0xd0,0xd1,0xd1,0xd2,0xd3,0xd3,0xd3,0xd3,0xdd,0xdb,0xd5,\n    0xcf,0xc8,0x98,0x13,0x46,0xa8,0x99,0x8e,0x86,0x79,0xb8,0xd5,0xd4,0xd3,0xd3,0xde,\n    0x47,0x31,0x7c,0x67,0x63,0x62,0x66,0x68,0x6c,0x6e,0x6d,0x6b,0x67,0x69,0x69,0x6b,\n    0x6b,0x6b,0x68,0x66,0x66,0x66,0x66,0x64,0x60,0x58,0x53,0x50,0x4b,0x47,0x48,0x4d,\n    0x8b,0x8c,0x8b,0x88,0x88,0x87,0x84,0x86,0x87,0x86,0x84,0x81,0x5f,0x5c,0x6a,0x4d,\n    0x55,0x9b,0xe4,0xed,0xee,0xf0,0xf7,0xf9,0x9a,0x23,0x3e,0x72,0x8f,0x88,0x7a,0x61,\n    0x4e,0x56,0x5d,0x67,0x70,0x72,0x71,0x6f,0x6e,0x6a,0x68,0x64,0x75,0x94,0xad,0xbf,\n    0xc6,0xcc,0xd0,0xd0,0xd1,0xd2,0xd3,0xd3,0xd2,0xcc,0xce,0xd2,0xd3,0xd1,0xce,0xcc,\n    0x99,0xb1,0x3d,0x58,0xce,0xcc,0xcc,0xd2,0xd2,0xd1,0xd2,0xd2,0xd2,0xd2,0xd3,0xd1,\n    0xd3,0xd4,0xa7,0x0f,0x52,0xdc,0xd6,0xd4,0xd2,0xd3,0xd3,0xd4,0xd4,0xd2,0xd3,0xdd,\n    0x49,0x32,0x7f,0x64,0x5d,0x5e,0x5f,0x66,0x6d,0x6d,0x6a,0x68,0x67,0x68,0x6a,0x6d,\n    0x6c,0x6d,0x68,0x67,0x68,0x67,0x66,0x65,0x61,0x56,0x51,0x4d,0x48,0x43,0x48,0x4c,\n    0x8d,0x8c,0x8b,0x89,0x88,0x86,0x84,0x87,0x8a,0x85,0x84,0x69,0x4e,0x69,0x52,0x57,\n    0x8f,0xe5,0xed,0xed,0xf0,0xf8,0xf8,0xae,0x1b,0x20,0x2d,0x3f,0x64,0x6e,0x66,0x53,\n    0x3a,0x3f,0x4c,0x5d,0x6a,0x6f,0x6f,0x6e,0x6b,0x6c,0x6a,0x68,0x82,0xa1,0xb7,0xc8,\n    0xce,0xd2,0xd4,0xd4,0xd5,0xd8,0xd5,0xd1,0xcd,0xd1,0xd0,0xd3,0xd6,0xd8,0xd9,0xd5,\n    0x95,0xb3,0x3c,0x5d,0xd3,0xd0,0xd1,0xd2,0xd3,0xd2,0xd1,0xd2,0xd2,0xd2,0xd1,0xd3,\n    0xd2,0xd2,0xa1,0x11,0x51,0xde,0xd4,0xd4,0xd3,0xd4,0xd2,0xd4,0xd3,0xd4,0xd3,0xde,\n    0x4a,0x34,0x80,0x64,0x5d,0x5d,0x5a,0x61,0x67,0x67,0x67,0x68,0x68,0x68,0x69,0x6a,\n    0x6b,0x6e,0x68,0x67,0x69,0x67,0x66,0x62,0x5a,0x4f,0x4c,0x4c,0x49,0x46,0x4a,0x4f,\n    0x8c,0x8a,0x89,0x89,0x86,0x83,0x82,0x8c,0x8a,0x83,0x79,0x49,0x53,0x5e,0x4b,0x75,\n    0xcf,0xe9,0xf1,0xed,0xf8,0xfa,0xc9,0x2f,0x1c,0x24,0x30,0x38,0x42,0x4f,0x4f,0x40,\n    0x2e,0x27,0x3a,0x51,0x62,0x6e,0x6f,0x6d,0x6b,0x6e,0x6c,0x6e,0x8a,0xa9,0xbf,0xcf,\n    0xd5,0xd6,0xd6,0xd6,0xd6,0xd3,0xd0,0xce,0xce,0xd1,0xd2,0xd6,0xd9,0xdd,0xe1,0xe0,\n    0x91,0xb3,0x3b,0x5e,0xd0,0xd1,0xd3,0xd1,0xd1,0xd1,0xd1,0xd2,0xd0,0xbc,0xc2,0xc8,\n    0xc9,0xcb,0xa2,0x0d,0x4e,0xd6,0xcb,0xcf,0xce,0xcd,0xd5,0xd3,0xd3,0xd3,0xd3,0xde,\n    0x49,0x33,0x7f,0x64,0x5d,0x5c,0x59,0x5c,0x5e,0x5e,0x61,0x64,0x66,0x68,0x64,0x63,\n    0x62,0x63,0x60,0x5f,0x63,0x61,0x5f,0x5a,0x54,0x4b,0x4a,0x47,0x44,0x46,0x4c,0x4f,\n    0x8b,0x87,0x87,0x87,0x85,0x83,0x84,0x8e,0x87,0x82,0x5c,0x41,0x5d,0x46,0x64,0xb4,\n    0xe0,0xec,0xf2,0xf7,0xfa,0xcc,0x38,0x1d,0x1f,0x23,0x28,0x31,0x3d,0x50,0x53,0x45,\n    0x33,0x1e,0x2d,0x46,0x5a,0x6a,0x6d,0x6c,0x6c,0x6e,0x6f,0x71,0x90,0xad,0xc4,0xd3,\n    0xd8,0xd8,0xd5,0xd4,0xd0,0xce,0xcd,0xce,0xcf,0xd2,0xd5,0xd9,0xdd,0xe4,0xe6,0xe3,\n    0x96,0xaf,0x3a,0x5d,0xd2,0xcf,0xd0,0xd2,0xd1,0xd1,0xd0,0xd1,0xcc,0x21,0x0f,0x14,\n    0x18,0x1d,0x1e,0x19,0x1d,0x2e,0x33,0x36,0x3a,0x36,0xa9,0xd4,0xd4,0xd2,0xd1,0xde,\n    0x49,0x34,0x7c,0x69,0x5f,0x5b,0x55,0x57,0x58,0x57,0x5b,0x60,0x62,0x60,0x5e,0x5c,\n    0x59,0x55,0x50,0x52,0x58,0x56,0x53,0x51,0x4a,0x43,0x41,0x3e,0x3d,0x42,0x49,0x4a,\n    0x89,0x88,0x89,0x85,0x84,0x83,0x84,0x86,0x7e,0x70,0x41,0x51,0x52,0x5a,0x93,0xd0,\n    0xe1,0xee,0xf4,0xf9,0xdc,0x4c,0x24,0x23,0x22,0x23,0x23,0x2b,0x49,0x6c,0x74,0x68,\n    0x4f,0x2e,0x2a,0x3f,0x53,0x64,0x6a,0x6b,0x6c,0x6f,0x72,0x73,0x91,0xae,0xc5,0xd5,\n    0xd8,0xd3,0xd1,0xcd,0xcf,0xcf,0xcf,0xd0,0xd2,0xd6,0xd9,0xdd,0xe3,0xe4,0xe5,0xe2,\n    0x99,0xab,0x3c,0x5f,0xd1,0xce,0xd0,0xd1,0xd1,0xd0,0xd1,0xd1,0xd0,0x7b,0x66,0x5a,\n    0x4f,0x45,0x3b,0x37,0x31,0x30,0x2b,0x2a,0x26,0x1e,0x9e,0xd5,0xd3,0xd3,0xd3,0xdd,\n    0x4a,0x34,0x7a,0x66,0x5d,0x57,0x50,0x52,0x52,0x52,0x5a,0x5b,0x5d,0x5b,0x59,0x52,\n    0x4c,0x46,0x44,0x44,0x4a,0x49,0x48,0x46,0x40,0x38,0x38,0x35,0x35,0x3b,0x42,0x42,\n    0x89,0x89,0x87,0x84,0x83,0x83,0x87,0x78,0x77,0x52,0x3d,0x5b,0x5a,0x89,0xc8,0xde,\n    0xe6,0xf3,0xfb,0xe3,0x62,0x35,0x33,0x31,0x2b,0x2d,0x2b,0x35,0x55,0x80,0x99,0x97,\n    0x7e,0x57,0x33,0x3b,0x4e,0x5e,0x66,0x6c,0x6d,0x71,0x75,0x76,0x8c,0xae,0xc2,0xcf,\n    0xd0,0xcf,0xcd,0xcf,0xd0,0xd1,0xd2,0xd4,0xd7,0xdb,0xdf,0xe2,0xe2,0xe4,0xe6,0xe3,\n    0x99,0xa8,0x3a,0x61,0xd1,0xce,0xd0,0xd0,0xd1,0xd2,0xd1,0xd1,0xd1,0xd7,0xd3,0xe5,\n    0xdc,0xd5,0xd5,0xd3,0xd0,0xce,0xc9,0xca,0xc8,0xc6,0xcd,0xd2,0xd2,0xd2,0xd2,0xdd,\n    0x4a,0x33,0x7e,0x62,0x58,0x50,0x4b,0x4a,0x4c,0x50,0x59,0x5f,0x5c,0x5a,0x55,0x4e,\n    0x42,0x3b,0x38,0x3b,0x3c,0x3a,0x39,0x3a,0x36,0x30,0x2f,0x2d,0x2c,0x2f,0x35,0x3a,\n    0x89,0x87,0x83,0x82,0x82,0x85,0x81,0x67,0x6b,0x36,0x4c,0x5f,0x78,0xc4,0xdd,0xe2,\n    0xf1,0xfa,0xea,0x9b,0x6c,0x60,0x50,0x3a,0x33,0x34,0x32,0x41,0x68,0x8f,0xad,0xb5,\n    0xac,0x8e,0x69,0x4f,0x52,0x59,0x64,0x6b,0x6f,0x73,0x77,0x78,0x89,0xa5,0xb8,0xc3,\n    0xce,0xcf,0xcf,0xd0,0xd3,0xd5,0xd7,0xd9,0xdd,0xde,0xe0,0xe1,0xe1,0xe1,0xe3,0xe0,\n    0x99,0xa9,0x3b,0x63,0xd2,0xcf,0xd0,0xd1,0xd1,0xd0,0xd1,0xd1,0xd2,0xc9,0x77,0x3d,\n    0x53,0x9f,0xd2,0xc8,0xaa,0xd2,0xd3,0xd3,0xd3,0xd3,0xd4,0xd1,0xd2,0xd1,0xd2,0xde,\n    0x4a,0x31,0x7e,0x57,0x4e,0x4a,0x48,0x46,0x4d,0x50,0x58,0x5e,0x5b,0x5a,0x55,0x4e,\n    0x40,0x36,0x30,0x2d,0x2f,0x2e,0x31,0x33,0x2f,0x2c,0x29,0x26,0x23,0x21,0x27,0x2f,\n    0x87,0x83,0x7c,0x7e,0x85,0x83,0x6d,0x63,0x50,0x33,0x60,0x68,0xb2,0xde,0xdf,0xe9,\n    0xf9,0xee,0xc2,0xb8,0xb8,0xae,0x8d,0x5d,0x3c,0x3c,0x49,0x5e,0x83,0xa4,0xba,0xc3,\n    0xc5,0xbc,0xa9,0x85,0x6e,0x5f,0x63,0x6c,0x71,0x76,0x7a,0x7a,0x84,0x99,0xae,0xbe,\n    0xcb,0xcf,0xd1,0xd3,0xd6,0xda,0xdf,0xdf,0xde,0xdf,0xe0,0xe0,0xe0,0xe0,0xe0,0xdf,\n    0x96,0xa8,0x3d,0x63,0xd4,0xd0,0xd0,0xd0,0xd0,0xcc,0xd0,0xd0,0xd1,0x40,0x17,0x0e,\n    0x12,0x18,0x8b,0xc3,0x1c,0x3d,0xce,0xd2,0xd3,0xd2,0xd2,0xd1,0xd1,0xd2,0xd2,0xdd,\n    0x4a,0x32,0x7e,0x4c,0x41,0x45,0x45,0x47,0x4d,0x4e,0x55,0x59,0x5c,0x5c,0x57,0x4f,\n    0x3f,0x35,0x2e,0x26,0x28,0x28,0x2d,0x31,0x31,0x2b,0x26,0x20,0x1a,0x1d,0x23,0x2a,\n    0x86,0x7f,0x71,0x7f,0x86,0x7f,0x5a,0x59,0x35,0x4d,0x6e,0xaa,0xd8,0xde,0xe5,0xf4,\n    0xec,0xd1,0xd0,0xdb,0xdf,0xd0,0xad,0x7f,0x51,0x4e,0x69,0x8c,0xa5,0xb1,0xbd,0xc5,\n    0xcd,0xd2,0xcc,0xb3,0x8f,0x70,0x68,0x6e,0x74,0x79,0x7d,0x7c,0x7f,0x8f,0xa3,0xb8,\n    0xc6,0xcf,0xd6,0xd8,0xdc,0xde,0xdf,0xde,0xdd,0xdd,0xdf,0xde,0xde,0xde,0xde,0xdd,\n    0x92,0xa6,0x3d,0x66,0xd5,0xd0,0xd0,0xd0,0xd0,0xd1,0xd0,0xcf,0xc3,0x23,0x29,0xcb,\n    0xa3,0x16,0x46,0xd2,0x52,0x0f,0x8f,0xd5,0xd2,0xd3,0xd2,0xd2,0xd0,0xd1,0xd2,0xdd,\n    0x4b,0x34,0x7e,0x41,0x38,0x3e,0x40,0x46,0x4b,0x4e,0x53,0x56,0x5b,0x58,0x54,0x4e,\n    0x43,0x38,0x2f,0x26,0x23,0x28,0x2c,0x2c,0x2d,0x29,0x26,0x1f,0x19,0x20,0x28,0x31,\n    0x84,0x71,0x6f,0x84,0x86,0x6d,0x50,0x41,0x3f,0x5e,0xa7,0xda,0xdc,0xde,0xee,0xe6,\n    0xc7,0xd3,0xe7,0xee,0xef,0xe4,0xc3,0x93,0x5f,0x5b,0x88,0xb3,0xc9,0xc0,0xbd,0xbd,\n    0xc6,0xd5,0xd5,0xc3,0xa7,0x83,0x70,0x74,0x75,0x7b,0x7e,0x7f,0x7e,0x83,0x98,0xac,\n    0xc0,0xcc,0xda,0xdb,0xdc,0xde,0xdd,0xdd,0xdc,0xdc,0xdc,0xdd,0xdc,0xdd,0xde,0xdd,\n    0x94,0xa2,0x3f,0x69,0xd3,0xcf,0xd0,0xd1,0xd0,0xd0,0xd0,0xd0,0xc7,0x27,0x37,0xce,\n    0xc2,0x11,0x37,0xdf,0xd1,0x0b,0x38,0xe0,0xd0,0xd2,0xd2,0xd2,0xd2,0xd1,0xd2,0xdc,\n    0x4c,0x34,0x7a,0x3f,0x34,0x3c,0x41,0x46,0x49,0x49,0x4b,0x51,0x55,0x54,0x53,0x4a,\n    0x43,0x39,0x2b,0x22,0x24,0x26,0x29,0x29,0x2a,0x28,0x26,0x21,0x21,0x28,0x2f,0x37,\n    0x82,0x65,0x79,0x87,0x7d,0x57,0x4b,0x3c,0x3d,0xa1,0xdd,0xdd,0xde,0xe3,0xd8,0xb4,\n    0xbc,0xdc,0xef,0xf5,0xf4,0xe9,0xc7,0x95,0x66,0x6b,0x9b,0xc6,0xdb,0xd2,0xba,0xa9,\n    0xa8,0xc3,0xc6,0xbc,0xa9,0x87,0x73,0x77,0x7b,0x80,0x82,0x80,0x82,0x80,0x8c,0xa3,\n    0xb7,0xc8,0xd4,0xdb,0xdc,0xdc,0xdb,0xdc,0xda,0xda,0xdb,0xdc,0xdb,0xdc,0xdd,0xdc,\n    0x91,0xa2,0x3f,0x6b,0xd1,0xcf,0xcf,0xd0,0xd0,0xd0,0xd0,0xd0,0xd1,0x75,0x13,0x7f,\n    0xd0,0x29,0x22,0xd7,0xb6,0x0c,0x47,0xde,0xd2,0xd2,0xd2,0xd2,0xd1,0xd1,0xd2,0xdd,\n    0x4c,0x35,0x7d,0x41,0x3a,0x40,0x45,0x49,0x48,0x49,0x48,0x4a,0x4e,0x4e,0x4c,0x48,\n    0x40,0x35,0x27,0x21,0x24,0x25,0x27,0x29,0x29,0x2a,0x26,0x25,0x29,0x2f,0x34,0x39,\n    0x70,0x64,0x80,0x86,0x73,0x44,0x34,0x2a,0x7a,0xd7,0xe0,0xdd,0xdc,0xce,0xb1,0xa9,\n    0xc5,0xe3,0xf0,0xf6,0xf1,0xe0,0xba,0x84,0x5c,0x7b,0xaf,0xd4,0xe4,0xdd,0xbe,0x8b,\n    0x6b,0x8f,0xa2,0x9f,0x92,0x7a,0x72,0x79,0x82,0x84,0x84,0x83,0x84,0x83,0x83,0x93,\n    0xa8,0xbd,0xca,0xd5,0xd9,0xd9,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xdb,0xda,\n    0x91,0xa0,0x3d,0x6d,0xd2,0xce,0xcf,0xd0,0xd0,0xd0,0xd0,0xcf,0xca,0x23,0x19,0x14,\n    0x0b,0x16,0x17,0x0f,0x14,0x17,0xaf,0xd1,0xd2,0xd2,0xd2,0xd2,0xd0,0xd2,0xd0,0xdd,\n    0x4d,0x35,0x7b,0x46,0x41,0x43,0x49,0x4e,0x4f,0x4f,0x4a,0x49,0x4b,0x49,0x48,0x44,\n    0x3c,0x34,0x29,0x24,0x25,0x27,0x2a,0x2d,0x2d,0x2c,0x2c,0x2f,0x31,0x37,0x3b,0x3f,\n    0x63,0x6a,0x7f,0x81,0x62,0x22,0x25,0x6e,0xd8,0xe1,0xe1,0xd9,0xc5,0xb5,0xab,0xa8,\n    0xc3,0xe1,0xf0,0xf4,0xeb,0xd4,0xa7,0x6a,0x63,0x92,0xc0,0xde,0xe8,0xdc,0xbf,0x7a,\n    0x30,0x3b,0x60,0x6d,0x6a,0x66,0x72,0x7b,0x81,0x86,0x86,0x85,0x85,0x84,0x84,0x86,\n    0x94,0xaa,0xbc,0xc9,0xd4,0xd7,0xd8,0xd8,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xdb,0xd7,\n    0x8c,0x9b,0x3c,0x6e,0xd2,0xce,0xcf,0xcf,0xd0,0xd0,0xd0,0xcf,0xcd,0x7b,0x61,0x55,\n    0x48,0x3b,0x2f,0x26,0x46,0xa5,0xd2,0xd1,0xd1,0xd2,0xd1,0xd1,0xd1,0xd1,0xd1,0xdb,\n    0x4f,0x35,0x75,0x47,0x40,0x45,0x4d,0x52,0x52,0x51,0x4b,0x4a,0x46,0x48,0x46,0x3f,\n    0x38,0x33,0x2f,0x28,0x2a,0x2b,0x2c,0x31,0x30,0x32,0x32,0x38,0x3d,0x42,0x45,0x49,\n    0x5e,0x75,0x7e,0x7a,0x42,0x2a,0x4c,0xd5,0xee,0xe5,0xd4,0xbf,0xb4,0xb1,0xaa,0xa7,\n    0xba,0xd3,0xe1,0xe5,0xdb,0xbe,0x8d,0x57,0x79,0xa5,0xcb,0xe0,0xe6,0xdb,0xb9,0x70,\n    0x23,0x1a,0x29,0x40,0x52,0x64,0x72,0x7b,0x81,0x87,0x87,0x86,0x86,0x85,0x85,0x85,\n    0x87,0x9a,0xaf,0xbe,0xca,0xd3,0xd6,0xd7,0xd8,0xd8,0xd8,0xd7,0xd7,0xd6,0xd6,0xcb,\n    0x88,0x99,0x3b,0x6f,0xd1,0xce,0xcf,0xcf,0xcf,0xcf,0xcf,0xd0,0xd1,0xd2,0xd6,0xdd,\n    0xe0,0xe1,0xe4,0xe0,0xda,0xce,0xd2,0xd1,0xd1,0xd1,0xd1,0xd2,0xd1,0xd1,0xd1,0xda,\n    0x4e,0x35,0x73,0x4c,0x43,0x4a,0x4f,0x54,0x55,0x50,0x4c,0x48,0x45,0x46,0x44,0x3f,\n    0x3a,0x36,0x34,0x30,0x30,0x32,0x34,0x37,0x38,0x3c,0x3e,0x42,0x48,0x4c,0x4c,0x4a,\n    0x61,0x7d,0x80,0x60,0x39,0x3f,0xca,0xed,0xec,0xd8,0xb7,0xab,0xb2,0xb2,0xaa,0xa2,\n    0xac,0xbd,0xca,0xcc,0xc2,0xa2,0x6a,0x5a,0x8a,0xb2,0xd2,0xe5,0xe8,0xdd,0xb5,0x71,\n    0x1e,0x1e,0x2a,0x3c,0x51,0x64,0x72,0x7c,0x82,0x86,0x87,0x87,0x86,0x85,0x86,0x86,\n    0x87,0x8e,0xa0,0xb3,0xc2,0xcf,0xd5,0xd6,0xd6,0xd5,0xd7,0xd5,0xd3,0xcd,0xc5,0xb8,\n    0x81,0x95,0x3a,0x71,0xd1,0xcd,0xcd,0xd0,0xd0,0xcf,0xce,0xd0,0xd1,0xcd,0xcc,0x68,\n    0x4a,0x54,0x61,0x79,0xca,0xd4,0xd4,0xd2,0xd0,0xd1,0xd1,0xd1,0xd1,0xd1,0xd0,0xdc,\n    0x4e,0x37,0x74,0x4f,0x45,0x49,0x4b,0x51,0x50,0x4c,0x47,0x46,0x45,0x45,0x46,0x41,\n    0x3b,0x35,0x37,0x37,0x3c,0x3c,0x3f,0x40,0x43,0x46,0x4a,0x4b,0x4f,0x50,0x4d,0x4a,\n    0x6d,0x80,0x5e,0x35,0x31,0xa6,0xee,0xef,0xdb,0xb8,0xaa,0xab,0xb1,0xb2,0xac,0xa3,\n    0x8e,0x93,0xa5,0xa8,0x9c,0x80,0x5c,0x63,0x91,0xb9,0xd9,0xe9,0xe7,0xd9,0xb1,0x6d,\n    0x22,0x24,0x33,0x44,0x56,0x67,0x75,0x7e,0x83,0x86,0x87,0x87,0x86,0x85,0x86,0x87,\n    0x88,0x8a,0x92,0xa5,0xb6,0xc6,0xcf,0xd4,0xd5,0xd3,0xd2,0xce,0xc4,0xb8,0xaa,0x9a,\n    0x7a,0x94,0x3b,0x73,0xd2,0xcd,0xce,0xd1,0xd0,0xcf,0xcf,0xcf,0xd1,0xa4,0x15,0x0c,\n    0x16,0x12,0x0e,0x0c,0x0a,0x79,0xce,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd0,0xdc,\n    0x4e,0x36,0x74,0x4b,0x3e,0x41,0x43,0x46,0x46,0x46,0x43,0x47,0x49,0x46,0x44,0x42,\n    0x3d,0x38,0x39,0x3e,0x47,0x47,0x45,0x46,0x4a,0x4d,0x4f,0x52,0x55,0x54,0x50,0x4a,\n    0x77,0x93,0x5f,0x1e,0x99,0xe7,0xe1,0xc6,0xb2,0xb0,0xad,0xaa,0xaf,0xb0,0xae,0xa4,\n    0x89,0x7a,0x7b,0x7a,0x77,0x6a,0x5e,0x67,0x8e,0xb8,0xd8,0xe8,0xe5,0xd5,0xab,0x67,\n    0x2c,0x2f,0x3c,0x4b,0x5d,0x6d,0x7a,0x80,0x83,0x85,0x86,0x86,0x86,0x85,0x86,0x86,\n    0x88,0x8a,0x8c,0x99,0xac,0xbe,0xc9,0xd3,0xd3,0xd0,0xc8,0xbc,0xae,0x9b,0x86,0x6c,\n    0x73,0x90,0x3b,0x73,0xd0,0xcd,0xcf,0xcf,0xcf,0xce,0xcf,0xce,0xc8,0x31,0x15,0x8f,\n    0xce,0xc6,0xc5,0xaa,0x29,0x14,0xa7,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd0,0xdc,\n    0x4e,0x34,0x78,0x4a,0x3b,0x3b,0x3b,0x3c,0x3c,0x3d,0x40,0x48,0x48,0x45,0x43,0x45,\n    0x41,0x3d,0x3e,0x47,0x4e,0x4a,0x4d,0x4e,0x4f,0x51,0x52,0x52,0x56,0x56,0x50,0x4a,\n    0x85,0xa7,0x3b,0x67,0xdc,0xcd,0xad,0xa2,0xab,0xad,0xab,0xab,0xae,0xad,0xa8,0xa1,\n    0x95,0x8c,0x81,0x6c,0x6a,0x65,0x59,0x60,0x8a,0xb6,0xd6,0xe3,0xdf,0xce,0xa0,0x64,\n    0x35,0x3c,0x47,0x56,0x65,0x71,0x7a,0x81,0x85,0x84,0x85,0x85,0x85,0x83,0x84,0x85,\n    0x87,0x8b,0x8d,0x90,0xa0,0xb4,0xc3,0xcb,0xca,0xc1,0xb1,0xa2,0x8a,0x6f,0x53,0x36,\n    0x6b,0x91,0x3e,0x74,0xd0,0xce,0xce,0xcf,0xce,0xcc,0xce,0xcd,0xbe,0x21,0x38,0xce,\n    0xcf,0xd0,0xd2,0xd0,0xaf,0x07,0x4e,0xdd,0xd1,0xd2,0xd1,0xd1,0xd0,0xd0,0xd0,0xd9,\n    0x4e,0x35,0x78,0x4b,0x3b,0x3a,0x37,0x39,0x3b,0x3c,0x40,0x47,0x49,0x47,0x47,0x46,\n    0x45,0x42,0x46,0x4c,0x4f,0x50,0x52,0x51,0x51,0x4f,0x52,0x51,0x55,0x53,0x4e,0x4b,\n    0xbe,0xc3,0x85,0xc4,0xbe,0x95,0x95,0xa1,0xaa,0xa9,0xa9,0xa9,0xac,0xac,0xa6,0xa0,\n    0x93,0x7e,0x77,0x69,0x61,0x5a,0x53,0x66,0x8e,0xab,0xc6,0xd2,0xd0,0xbc,0x90,0x57,\n    0x44,0x48,0x4f,0x57,0x61,0x69,0x74,0x7d,0x83,0x84,0x86,0x84,0x84,0x85,0x83,0x84,\n    0x86,0x8a,0x8d,0x8e,0x98,0xaa,0xb6,0xbb,0xb5,0xab,0x97,0x81,0x62,0x40,0x26,0x18,\n    0x6a,0x8d,0x3d,0x78,0xcf,0xcd,0xcf,0xd0,0xcf,0xcf,0xd0,0xd1,0xc5,0x2b,0x1f,0xc6,\n    0xcf,0xd0,0xcf,0xd1,0x9f,0x0b,0x4e,0xda,0xd2,0xd1,0xd1,0xd1,0xcf,0xce,0xd0,0xda,\n    0x4f,0x35,0x75,0x4d,0x3a,0x38,0x37,0x37,0x3d,0x41,0x43,0x47,0x4b,0x4d,0x4a,0x47,\n    0x45,0x43,0x47,0x4d,0x51,0x54,0x53,0x50,0x4e,0x4e,0x4f,0x4e,0x4f,0x4d,0x49,0x48,\n    0xcf,0xd5,0xcd,0xaa,0x8b,0x8b,0x97,0xa0,0xa7,0xaa,0xaa,0xaa,0xab,0xaa,0xa5,0x9c,\n    0x90,0x74,0x5f,0x57,0x45,0x42,0x54,0x73,0x93,0xa4,0xba,0xbf,0xb1,0x98,0x72,0x48,\n    0x46,0x46,0x48,0x4a,0x50,0x5b,0x6d,0x77,0x81,0x83,0x85,0x85,0x85,0x8a,0x8a,0x89,\n    0x87,0x89,0x8c,0x8e,0x93,0x9f,0xa7,0xaa,0xa6,0x99,0x81,0x68,0x47,0x2e,0x1d,0x14,\n    0x6a,0x8c,0x3c,0x78,0xd0,0xce,0xce,0xce,0xce,0xce,0xcf,0xcf,0xd1,0x8e,0x0b,0x12,\n    0xb7,0xd0,0xd0,0xa2,0x18,0x13,0xac,0xd1,0xd1,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xda,\n    0x51,0x35,0x71,0x4e,0x3a,0x3b,0x3a,0x3b,0x3f,0x41,0x43,0x45,0x4a,0x4d,0x4d,0x49,\n    0x45,0x45,0x48,0x4b,0x4d,0x52,0x54,0x4f,0x4b,0x4e,0x4e,0x4d,0x4c,0x4a,0x43,0x42,\n    0xc8,0xb5,0x97,0x8d,0x8c,0x8f,0x99,0xa1,0xa8,0xab,0xab,0xac,0xad,0xaa,0xa2,0x97,\n    0x87,0x79,0x60,0x43,0x39,0x44,0x61,0x85,0x9e,0xb8,0xb7,0xae,0x96,0x6d,0x50,0x3f,\n    0x3f,0x3d,0x3c,0x39,0x3d,0x4e,0x63,0x72,0x7c,0x82,0x85,0x84,0x89,0x93,0x93,0x93,\n    0x8e,0x89,0x8c,0x8f,0x92,0x9a,0x9f,0x9e,0x9c,0x8e,0x7a,0x6a,0x55,0x3e,0x2b,0x17,\n    0x6d,0x88,0x3c,0x7a,0xd0,0xce,0xce,0xce,0xce,0xce,0xcf,0xcf,0xcf,0xd4,0xa4,0x21,\n    0xaf,0xcd,0xd3,0x95,0x18,0x87,0xd3,0xd2,0xd2,0xd1,0xd0,0xd0,0xd0,0xd0,0xd0,0xda,\n    0x53,0x36,0x74,0x50,0x3d,0x40,0x41,0x3c,0x3c,0x3c,0x3e,0x40,0x46,0x4a,0x4a,0x48,\n    0x49,0x48,0x47,0x48,0x4a,0x50,0x53,0x4e,0x4f,0x4f,0x4f,0x4d,0x4f,0x4e,0x48,0x45,\n    0x94,0x7d,0x80,0x8a,0x91,0x9b,0xa1,0xa3,0xa9,0xaa,0xaa,0xac,0xac,0xaa,0xa3,0x97,\n    0x83,0x6e,0x55,0x3f,0x3d,0x48,0x68,0x8c,0xb2,0xca,0xbe,0xa3,0x7d,0x4f,0x37,0x32,\n    0x31,0x2e,0x2b,0x24,0x28,0x40,0x5a,0x70,0x7f,0x83,0x84,0x85,0x8c,0x96,0x97,0x99,\n    0x94,0x8b,0x8d,0x91,0x93,0x98,0x98,0x99,0x97,0x91,0x8b,0x82,0x71,0x5c,0x40,0x25,\n    0x72,0x85,0x3b,0x7d,0xcf,0xcc,0xce,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xd2,0xd0,\n    0xcc,0xce,0xcd,0xc8,0xc3,0xd4,0xcc,0xd0,0xd1,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd9,\n    0x51,0x37,0x74,0x4f,0x3e,0x40,0x3f,0x3a,0x39,0x38,0x3a,0x3c,0x41,0x46,0x4a,0x4a,\n    0x47,0x46,0x44,0x45,0x4a,0x51,0x53,0x4f,0x51,0x4f,0x4f,0x4f,0x52,0x50,0x4d,0x47,\n    0x6c,0x75,0x7e,0x8b,0x9d,0xab,0xaa,0xa9,0xa7,0xa6,0xa7,0xa9,0xac,0xa8,0xa4,0x9a,\n    0x8a,0x74,0x5d,0x4a,0x43,0x4b,0x6c,0x9c,0xc7,0xd6,0xc9,0xa6,0x79,0x3a,0x21,0x22,\n    0x1f,0x1d,0x1b,0x1a,0x22,0x40,0x5d,0x74,0x82,0x85,0x83,0x84,0x8c,0x99,0x9b,0x9b,\n    0x95,0x8d,0x8d,0x8f,0x93,0x97,0x9b,0x9c,0x9f,0x9f,0xa3,0x9c,0x8b,0x74,0x57,0x35,\n    0x73,0x82,0x3d,0x7b,0xcd,0xcc,0xcd,0xcf,0xce,0xce,0xcf,0xce,0xc9,0x91,0x92,0x9c,\n    0xa7,0xac,0xb2,0xb1,0xbb,0xbb,0xbe,0xc1,0xc2,0xc3,0xcf,0xd1,0xd1,0xd0,0xcf,0xda,\n    0x54,0x37,0x73,0x52,0x3c,0x3d,0x3b,0x38,0x37,0x35,0x35,0x36,0x3d,0x47,0x4a,0x4a,\n    0x48,0x44,0x41,0x44,0x48,0x4f,0x54,0x54,0x51,0x51,0x52,0x53,0x52,0x56,0x53,0x4c,\n    0x72,0x75,0x7e,0x87,0xa2,0xb4,0xb4,0xb0,0xa5,0xa2,0xa4,0xa4,0xa6,0xa5,0xa1,0x98,\n    0x8c,0x7b,0x67,0x52,0x4b,0x53,0x76,0xaf,0xcd,0xd5,0xc2,0xa4,0x68,0x23,0x1a,0x1b,\n    0x1a,0x1a,0x1a,0x19,0x1f,0x3d,0x5c,0x74,0x83,0x84,0x83,0x82,0x88,0x93,0x97,0x97,\n    0x92,0x8d,0x8b,0x8f,0x93,0x98,0x9c,0xa0,0xa5,0xa9,0xae,0xad,0x9f,0x8b,0x6c,0x48,\n    0x75,0x7f,0x3b,0x82,0xcd,0xcc,0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xb8,0x1b,0x12,0x16,\n    0x18,0x17,0x16,0x1b,0x1a,0x1e,0x20,0x21,0x21,0x1b,0x9e,0xd2,0xd0,0xcf,0xcf,0xd9,\n    0x53,0x37,0x71,0x4d,0x38,0x3c,0x3a,0x36,0x34,0x32,0x32,0x35,0x3c,0x46,0x4a,0x4a,\n    0x46,0x41,0x3f,0x41,0x46,0x4e,0x54,0x55,0x52,0x53,0x55,0x56,0x55,0x57,0x54,0x4e,\n    0x75,0x79,0x7c,0x84,0xa0,0xb6,0xb9,0xb6,0xa6,0xa1,0xa2,0xa1,0xa4,0xa4,0x9e,0x96,\n    0x83,0x6e,0x5b,0x4b,0x4b,0x53,0x76,0xa1,0xbd,0xc0,0xb1,0x8a,0x42,0x1b,0x1a,0x1b,\n    0x1a,0x19,0x19,0x19,0x1d,0x38,0x58,0x72,0x82,0x86,0x85,0x83,0x85,0x89,0x8d,0x8e,\n    0x8c,0x8b,0x8c,0x8e,0x92,0x97,0x9c,0xa3,0xa7,0xab,0xb0,0xb2,0xaa,0x99,0x7c,0x55,\n    0x77,0x7e,0x3b,0x86,0xcf,0xcc,0xcd,0xcb,0xcc,0xcd,0xce,0xce,0xca,0x97,0x89,0x4e,\n    0x12,0x16,0x2f,0x5e,0x52,0x4c,0x44,0x41,0x3b,0x2e,0xa9,0xd1,0xd0,0xcf,0xce,0xd9,\n    0x53,0x37,0x6f,0x4a,0x36,0x3a,0x36,0x35,0x34,0x34,0x36,0x3b,0x41,0x46,0x49,0x49,\n    0x42,0x3e,0x3f,0x41,0x46,0x4e,0x57,0x56,0x52,0x53,0x55,0x53,0x57,0x58,0x55,0x51,\n    0x76,0x7a,0x7e,0x82,0x98,0xb0,0xb4,0xb5,0xa9,0xa4,0xa4,0xa3,0xa2,0xa2,0x9c,0x91,\n    0x7c,0x64,0x55,0x4b,0x4b,0x4d,0x67,0x8d,0xa4,0xa9,0x94,0x5e,0x2c,0x26,0x29,0x27,\n    0x25,0x22,0x20,0x1f,0x1d,0x2f,0x54,0x6f,0x80,0x86,0x87,0x86,0x86,0x86,0x86,0x87,\n    0x88,0x89,0x8d,0x8d,0x91,0x96,0x9d,0xa2,0xa7,0xab,0xae,0xb2,0xae,0xa0,0x85,0x62,\n    0x78,0x7a,0x3c,0x88,0xcf,0xcc,0xcd,0xcd,0xce,0xcd,0xcd,0xcd,0xce,0xd1,0xcb,0xcd,\n    0x83,0x13,0x15,0x58,0xce,0xce,0xce,0xca,0xcc,0xcb,0xcc,0xd2,0xcf,0xcf,0xcf,0xd9,\n    0x54,0x36,0x71,0x4b,0x35,0x36,0x36,0x38,0x38,0x3a,0x3e,0x44,0x49,0x4d,0x4b,0x47,\n    0x43,0x41,0x41,0x41,0x47,0x4e,0x54,0x52,0x50,0x50,0x4e,0x4c,0x4f,0x4f,0x4e,0x4d,\n    0x7b,0x7f,0x82,0x86,0x8e,0xa2,0xab,0xb1,0xaa,0xa7,0xa5,0xa3,0xa1,0xa1,0x9a,0x8e,\n    0x7a,0x63,0x4f,0x4b,0x48,0x4a,0x56,0x71,0x81,0x7c,0x67,0x4e,0x49,0x54,0x61,0x5f,\n    0x5d,0x59,0x51,0x47,0x36,0x3a,0x53,0x6f,0x81,0x8a,0x8b,0x89,0x88,0x85,0x85,0x86,\n    0x87,0x8a,0x8d,0x8e,0x91,0x97,0x9c,0xa1,0xa6,0xaa,0xae,0xb1,0xaf,0xa6,0x90,0x74,\n    0x7d,0x77,0x3a,0x89,0xcd,0xcc,0xcd,0xcd,0xcd,0xcb,0xcd,0xcd,0xcd,0xcf,0xd6,0x9a,\n    0x50,0x16,0x0f,0x12,0x45,0xbe,0xcf,0xce,0xce,0xce,0xce,0xcf,0xcf,0xcf,0xcf,0xd9,\n    0x54,0x34,0x73,0x49,0x2f,0x32,0x35,0x3d,0x41,0x45,0x49,0x4d,0x4c,0x50,0x4e,0x4b,\n    0x48,0x46,0x46,0x44,0x49,0x50,0x53,0x52,0x4f,0x4c,0x49,0x47,0x48,0x46,0x44,0x46,\n    0x7f,0x82,0x86,0x88,0x86,0x97,0xa4,0xa9,0xa9,0xa7,0xa3,0xa2,0xa2,0xa1,0x99,0x92,\n    0x7c,0x61,0x46,0x3c,0x40,0x42,0x47,0x4b,0x57,0x5c,0x4e,0x50,0x5d,0x69,0x75,0x78,\n    0x79,0x73,0x6d,0x62,0x56,0x55,0x61,0x75,0x82,0x8b,0x8c,0x8a,0x89,0x88,0x89,0x87,\n    0x88,0x8a,0x8e,0x8f,0x92,0x97,0x9b,0xa1,0xa3,0xaa,0xb2,0xb6,0xb6,0xab,0x98,0x81,\n    0x7e,0x76,0x39,0x8a,0xce,0xcc,0xcc,0xcc,0xcd,0xca,0xce,0xcd,0xcd,0x9c,0x23,0x16,\n    0x17,0x19,0x81,0x28,0x18,0x1d,0xb6,0xd0,0xcf,0xce,0xce,0xcf,0xcf,0xce,0xcf,0xd7,\n    0x53,0x33,0x70,0x47,0x2a,0x31,0x39,0x3e,0x45,0x49,0x4d,0x52,0x51,0x52,0x4e,0x4d,\n    0x4b,0x48,0x4a,0x4a,0x4e,0x50,0x51,0x51,0x4d,0x48,0x46,0x44,0x43,0x40,0x3f,0x40,\n    0x81,0x84,0x87,0x8c,0x87,0x8e,0x97,0xa0,0xa4,0xa3,0xa3,0xa1,0xa2,0xa0,0x9c,0x95,\n    0x85,0x6c,0x4a,0x35,0x34,0x35,0x3e,0x46,0x51,0x54,0x4d,0x58,0x6a,0x7c,0x8a,0x8d,\n    0x8e,0x8a,0x87,0x7f,0x77,0x7f,0x8a,0x92,0x93,0x91,0x8f,0x8e,0x8d,0x8c,0x8b,0x8b,\n    0x8c,0x8d,0x90,0x91,0x93,0x96,0x9b,0xa1,0xa6,0xaf,0xb7,0xbd,0xbf,0xbb,0xa6,0x91,\n    0x80,0x72,0x3a,0x8d,0xce,0xcc,0xcc,0xcc,0xcd,0xce,0xcd,0xcd,0xc1,0x1f,0x11,0x3f,\n    0x92,0xca,0xd3,0xcb,0x62,0x07,0x7f,0xd2,0xce,0xce,0xce,0xce,0xcf,0xce,0xce,0xd8,\n    0x53,0x37,0x6d,0x48,0x2f,0x37,0x3c,0x41,0x48,0x4f,0x51,0x56,0x56,0x53,0x53,0x51,\n    0x4f,0x4f,0x52,0x55,0x54,0x56,0x55,0x4f,0x4d,0x48,0x46,0x41,0x3b,0x3a,0x38,0x35,\n    0x82,0x83,0x88,0x8c,0x8d,0x9f,0xa7,0xa5,0xa4,0xa5,0xa1,0xa0,0xa0,0x9f,0x9d,0x98,\n    0x8b,0x73,0x57,0x2a,0x18,0x1c,0x2b,0x40,0x44,0x44,0x42,0x4c,0x63,0x76,0x85,0x89,\n    0x89,0x88,0x89,0x86,0x93,0x9e,0xa7,0xaf,0xaf,0xa5,0x9c,0x93,0x90,0x8d,0x8e,0x8e,\n    0x8f,0x90,0x91,0x91,0x93,0x96,0x9d,0xa1,0xa6,0xb2,0xbc,0xc4,0xc7,0xc3,0xb7,0xa1,\n    0x83,0x72,0x38,0x91,0xce,0xcb,0xcb,0xcc,0xcc,0xcd,0xcb,0xcc,0xbe,0x3c,0xa4,0xd5,\n    0xcd,0xce,0xcc,0xce,0xd3,0x91,0x86,0xd2,0xce,0xcf,0xcf,0xcd,0xce,0xcd,0xce,0xd8,\n    0x53,0x34,0x6a,0x4a,0x35,0x3c,0x3f,0x46,0x4e,0x50,0x51,0x54,0x53,0x55,0x56,0x57,\n    0x56,0x58,0x58,0x57,0x56,0x59,0x56,0x51,0x4e,0x49,0x47,0x3e,0x3a,0x38,0x35,0x33,\n    0x83,0x82,0x82,0x8b,0x9c,0xb7,0xb8,0xb1,0xa5,0xa3,0xa2,0xa0,0x9f,0x9f,0x9c,0x9a,\n    0x91,0x7e,0x62,0x48,0x20,0x1f,0x30,0x37,0x39,0x36,0x34,0x3f,0x4e,0x65,0x76,0x7b,\n    0x7a,0x7c,0x7a,0x7f,0x95,0xad,0xb9,0xbf,0xc1,0xba,0xb2,0xae,0xaa,0xa2,0x96,0x91,\n    0x93,0x93,0x93,0x94,0x94,0x98,0x9d,0xa1,0xa5,0xb5,0xc3,0xcc,0xd1,0xcc,0xc4,0xb8,\n    0x85,0x6e,0x39,0x93,0xcd,0xcb,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xce,0xda,0xdf,0xdc,\n    0xdc,0xd6,0xd5,0xd3,0xd0,0xd1,0xc6,0xcd,0xcd,0xcd,0xcc,0xce,0xce,0xce,0xce,0xd8,\n    0x53,0x36,0x69,0x4c,0x36,0x3d,0x42,0x47,0x4d,0x4d,0x4f,0x53,0x55,0x54,0x58,0x5d,\n    0x5e,0x5e,0x5e,0x5d,0x5c,0x59,0x58,0x52,0x51,0x4f,0x4b,0x45,0x3d,0x39,0x35,0x32,\n    0x84,0x80,0x7e,0x86,0xa5,0xc4,0xc5,0xbe,0xaa,0xa2,0xa2,0xa2,0x9f,0x9c,0x9b,0x93,\n    0x91,0x83,0x6a,0x59,0x50,0x3b,0x34,0x36,0x34,0x2f,0x27,0x2d,0x40,0x5b,0x6b,0x74,\n    0x76,0x76,0x79,0x88,0x9e,0xb8,0xca,0xd1,0xd4,0xd0,0xd1,0xcf,0xc8,0xb8,0xa8,0x99,\n    0x92,0x95,0x95,0x95,0x94,0x95,0x9a,0x9e,0xa0,0xb4,0xc8,0xd3,0xd9,0xd5,0xcb,0xc5,\n    0x84,0x6d,0x39,0x92,0xcc,0xca,0xca,0xca,0xcb,0xcb,0xcc,0xca,0xbd,0x27,0x20,0x2a,\n    0x37,0x47,0x56,0x5f,0x70,0x7a,0xb1,0xd0,0xac,0xa1,0xc9,0xcc,0xcd,0xcd,0xcd,0xd8,\n    0x53,0x36,0x6a,0x4f,0x37,0x3c,0x3f,0x42,0x45,0x47,0x4d,0x53,0x55,0x55,0x59,0x5e,\n    0x5f,0x5f,0x60,0x61,0x5f,0x5b,0x58,0x55,0x54,0x50,0x4e,0x47,0x41,0x3a,0x36,0x33,\n    0x86,0x83,0x80,0x84,0xa0,0xcc,0xcd,0xc5,0xaa,0xa1,0xa3,0xa2,0x9e,0x9b,0x98,0x90,\n    0x7d,0x7b,0x70,0x67,0x66,0x5e,0x45,0x3a,0x32,0x27,0x1f,0x1f,0x31,0x4a,0x5d,0x6b,\n    0x71,0x79,0x8f,0xab,0xc2,0xd1,0xdd,0xe1,0xe2,0xe1,0xe2,0xe4,0xdc,0xd2,0xbc,0xa1,\n    0x8f,0x8e,0x8e,0x8b,0x87,0x8f,0x97,0x97,0x9b,0xb1,0xc5,0xd2,0xdc,0xd9,0xd1,0xd1,\n    0x86,0x6a,0x38,0x91,0xcb,0xc9,0xca,0xca,0xcb,0xcb,0xcb,0xca,0xbf,0x25,0x15,0x0e,\n    0x09,0x06,0x08,0x0a,0x08,0x06,0x80,0xd6,0x51,0x06,0xa9,0xcf,0xcd,0xcd,0xcd,0xd6,\n    0x54,0x34,0x6b,0x52,0x37,0x3b,0x3b,0x3c,0x3f,0x41,0x48,0x4f,0x52,0x55,0x5a,0x5e,\n    0x5d,0x5e,0x62,0x60,0x5f,0x5c,0x58,0x54,0x53,0x4e,0x4b,0x44,0x40,0x39,0x38,0x36,\n    0x88,0x87,0x8a,0x87,0x9c,0xc5,0xc9,0xc1,0xa4,0x9e,0xa3,0xa2,0x9e,0x9c,0x96,0x8d,\n    0x78,0x62,0x70,0x73,0x6f,0x72,0x69,0x48,0x2a,0x1d,0x1c,0x1c,0x20,0x38,0x49,0x5a,\n    0x64,0x73,0xa2,0xc6,0xda,0xe5,0xe8,0xea,0xea,0xe9,0xe9,0xeb,0xea,0xdf,0xc7,0xa7,\n    0x84,0x7f,0x82,0x82,0x82,0x89,0x8d,0x8c,0x94,0xad,0xc3,0xd2,0xda,0xdb,0xd6,0xd8,\n    0x89,0x66,0x39,0x92,0xca,0xc9,0xcb,0xcc,0xcc,0xcc,0xcb,0xcb,0xcd,0xdd,0xdb,0xd6,\n    0xce,0xc8,0xbb,0xae,0xa5,0x9a,0xb4,0xd0,0x95,0x69,0xbb,0xce,0xcd,0xcd,0xcd,0xd6,\n    0x55,0x37,0x68,0x50,0x33,0x32,0x32,0x35,0x38,0x3f,0x43,0x44,0x4a,0x51,0x55,0x58,\n    0x58,0x57,0x5b,0x5b,0x5b,0x5c,0x59,0x55,0x51,0x4c,0x47,0x42,0x40,0x39,0x38,0x39,\n    0x86,0x8a,0x8e,0x8a,0x92,0xb1,0xb8,0xb6,0xa4,0x9f,0xa3,0xa2,0x9d,0x9b,0x94,0x8c,\n    0x7d,0x66,0x59,0x66,0x77,0x79,0x6e,0x61,0x3f,0x21,0x1d,0x18,0x19,0x23,0x33,0x45,\n    0x54,0x6d,0xae,0xd4,0xe8,0xf1,0xf0,0xef,0xee,0xec,0xec,0xee,0xec,0xe1,0xcb,0xaa,\n    0x86,0x7a,0x7d,0x7f,0x82,0x83,0x82,0x82,0x90,0xa9,0xc0,0xd0,0xd7,0xda,0xd9,0xdd,\n    0x8e,0x62,0x39,0x97,0xcb,0xc9,0xca,0xca,0xca,0xca,0xcb,0xcb,0xc0,0x7a,0x84,0x96,\n    0xa6,0xb3,0xc0,0xc8,0xcf,0xd1,0xd0,0xcd,0xcb,0xcd,0xcb,0xcd,0xcd,0xcd,0xcd,0xd4,\n    0x56,0x38,0x67,0x4f,0x2d,0x2b,0x2d,0x2a,0x2f,0x37,0x3a,0x3d,0x42,0x47,0x4c,0x4d,\n    0x4e,0x4e,0x54,0x55,0x5b,0x59,0x57,0x51,0x4d,0x49,0x41,0x40,0x3e,0x38,0x39,0x3d,\n    0x84,0x8a,0x8d,0x88,0x85,0x9b,0xa8,0xab,0x9f,0x9f,0xa1,0xa0,0x9c,0x98,0x92,0x89,\n    0x7f,0x6d,0x5b,0x50,0x65,0x77,0x70,0x64,0x5a,0x3c,0x1b,0x18,0x1a,0x24,0x33,0x41,\n    0x4a,0x63,0xb1,0xdb,0xeb,0xf3,0xf3,0xf0,0xec,0xea,0xea,0xed,0xec,0xe1,0xcd,0xac,\n    0x85,0x78,0x7d,0x81,0x84,0x82,0x7d,0x7a,0x8b,0xa5,0xbc,0xcb,0xd4,0xd7,0xd7,0xe0,\n    0x90,0x5c,0x38,0x98,0xc9,0xc9,0xca,0xca,0xcb,0xcc,0xca,0xc9,0xb9,0x11,0x04,0x04,\n    0x04,0x06,0x07,0x0c,0x0d,0x13,0x85,0xcf,0xcc,0xcc,0xce,0xcc,0xcd,0xcc,0xcd,0xd5,\n    0x55,0x37,0x64,0x4f,0x27,0x27,0x23,0x22,0x26,0x2e,0x34,0x38,0x3c,0x3e,0x40,0x40,\n    0x43,0x44,0x4d,0x52,0x56,0x53,0x50,0x4b,0x48,0x41,0x3c,0x3b,0x3b,0x3a,0x39,0x3f,\n    0x88,0x8c,0x8e,0x8a,0x80,0x86,0x8f,0x9c,0x9e,0xa3,0xa5,0xa4,0x9e,0x9a,0x94,0x8b,\n    0x82,0x70,0x5b,0x4a,0x41,0x57,0x6f,0x6f,0x61,0x55,0x3c,0x1d,0x26,0x35,0x3c,0x41,\n    0x4c,0x69,0xb1,0xdb,0xec,0xf2,0xf1,0xee,0xec,0xe9,0xea,0xed,0xec,0xe1,0xd0,0xae,\n    0x8b,0x85,0x8a,0x8e,0x8f,0x88,0x7f,0x79,0x88,0xa2,0xb8,0xc7,0xd0,0xd3,0xd4,0xe0,\n    0x94,0x5c,0x37,0x9b,0xca,0xc9,0xca,0xca,0xcb,0xc9,0xcb,0xc9,0xc7,0xa6,0x94,0x82,\n    0x74,0x66,0x54,0x30,0x1c,0x16,0x8c,0xcc,0xcb,0xcd,0xcc,0xcc,0xcb,0xcc,0xcc,0xd5,\n    0x55,0x36,0x63,0x51,0x26,0x24,0x1f,0x20,0x24,0x27,0x2d,0x33,0x38,0x36,0x35,0x35,\n    0x37,0x3f,0x4a,0x4e,0x4f,0x4d,0x48,0x43,0x40,0x3e,0x39,0x39,0x3a,0x3b,0x3f,0x46,\n    0x8c,0x8e,0x8e,0x8e,0x84,0x8e,0x97,0x9b,0x9e,0xa4,0xa7,0xa6,0xa0,0x99,0x94,0x8f,\n    0x84,0x6d,0x52,0x3c,0x31,0x34,0x4e,0x6b,0x6c,0x60,0x51,0x45,0x3c,0x4c,0x58,0x5d,\n    0x60,0x7c,0xb8,0xdc,0xee,0xf2,0xf2,0xed,0xeb,0xe9,0xea,0xee,0xec,0xe0,0xcc,0xac,\n    0x90,0x8e,0x90,0x8e,0x8d,0x84,0x79,0x76,0x83,0x9c,0xb3,0xc1,0xca,0xcf,0xd3,0xe0,\n    0x93,0x5c,0x38,0x9e,0xcb,0xc9,0xca,0xca,0xca,0xca,0xca,0xcb,0xcb,0xcd,0xca,0xd0,\n    0xd0,0xd3,0xd4,0xd1,0x66,0x17,0xa6,0xcd,0xcb,0xcc,0xcb,0xcd,0xcb,0xcc,0xcd,0xd5,\n    0x56,0x35,0x63,0x53,0x26,0x21,0x20,0x23,0x24,0x26,0x2b,0x31,0x35,0x31,0x2f,0x2e,\n    0x2f,0x38,0x41,0x45,0x46,0x45,0x41,0x3b,0x38,0x38,0x34,0x34,0x34,0x39,0x3f,0x4a,\n    0x92,0x91,0x93,0x8f,0x90,0xa5,0xaa,0xa6,0x9f,0xa2,0xa5,0xa8,0xa3,0x9c,0x98,0x91,\n    0x83,0x66,0x47,0x2d,0x23,0x28,0x2c,0x49,0x6b,0x67,0x5b,0x5b,0x66,0x73,0x7a,0x7a,\n    0x6c,0x7e,0xbc,0xde,0xec,0xef,0xed,0xec,0xeb,0xeb,0xed,0xf1,0xe9,0xde,0xc6,0xa4,\n    0x8c,0x8e,0x8f,0x8c,0x87,0x7e,0x75,0x71,0x82,0x99,0xad,0xbd,0xc6,0xce,0xd3,0xdd,\n    0x91,0x5a,0x38,0xa0,0xcb,0xc9,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xc9,0xcd,0xcc,\n    0xcc,0xcb,0xca,0xca,0x9a,0x0b,0x5a,0xd5,0xcb,0xcc,0xcb,0xcc,0xcb,0xcc,0xce,0xd5,\n    0x56,0x34,0x67,0x54,0x29,0x23,0x20,0x24,0x26,0x27,0x2c,0x31,0x33,0x31,0x2f,0x2b,\n    0x2c,0x33,0x39,0x3a,0x3c,0x38,0x33,0x2e,0x2d,0x2f,0x2f,0x2d,0x2d,0x37,0x3f,0x4b,\n    0x93,0x91,0x90,0x8d,0x96,0xbb,0xc0,0xb8,0xa6,0xa0,0xa7,0xa9,0xa4,0x9e,0x9a,0x92,\n    0x7f,0x63,0x3d,0x20,0x17,0x1a,0x24,0x30,0x50,0x69,0x69,0x71,0x7d,0x84,0x83,0x7b,\n    0x71,0x7f,0xbd,0xda,0xe4,0xe6,0xe4,0xe1,0xe3,0xe5,0xea,0xee,0xe7,0xdb,0xbf,0x9b,\n    0x8b,0x8e,0x8c,0x87,0x83,0x7a,0x71,0x6e,0x81,0x9a,0xac,0xbd,0xc9,0xcf,0xd1,0xd5,\n    0x8a,0x56,0x38,0xa0,0xc9,0xc8,0xc9,0xc9,0xc9,0xc9,0xc8,0xc8,0xc1,0x68,0x6b,0x77,\n    0x89,0x95,0xa4,0x98,0x30,0x11,0x75,0xd1,0xcb,0xcc,0xcb,0xca,0xcb,0xcb,0xcc,0xd5,\n    0x56,0x35,0x66,0x57,0x2a,0x28,0x25,0x26,0x27,0x29,0x2c,0x30,0x32,0x2f,0x2b,0x29,\n    0x2a,0x2e,0x2f,0x2f,0x2f,0x29,0x24,0x23,0x26,0x29,0x2a,0x29,0x2a,0x32,0x3d,0x45,\n    0x95,0x90,0x8f,0x8c,0x99,0xc6,0xce,0xc7,0xab,0x9a,0xa4,0xa5,0xa2,0x9c,0x98,0x91,\n    0x7f,0x61,0x3a,0x1a,0x10,0x13,0x1c,0x2d,0x40,0x5b,0x6b,0x76,0x86,0x8f,0x8d,0x7c,\n    0x6f,0x86,0xbc,0xd4,0xe1,0xdc,0xcf,0xc7,0xc7,0xd2,0xe3,0xe8,0xe6,0xd8,0xba,0x94,\n    0x8a,0x88,0x89,0x83,0x7f,0x7a,0x72,0x71,0x89,0xa2,0xb4,0xc0,0xcb,0xce,0xc8,0xc8,\n    0x89,0x53,0x37,0xa4,0xc8,0xc9,0xc8,0xc9,0xc9,0xc9,0xca,0xc8,0xba,0x1b,0x0f,0x0c,\n    0x09,0x08,0x06,0x0d,0x0f,0x31,0xc0,0xcb,0xcc,0xcb,0xcb,0xcc,0xcb,0xcb,0xcb,0xd5,\n    0x57,0x37,0x64,0x54,0x2d,0x2e,0x2b,0x29,0x2b,0x2b,0x2e,0x2f,0x2f,0x2c,0x29,0x25,\n    0x23,0x26,0x29,0x28,0x23,0x1d,0x1d,0x1f,0x1f,0x21,0x22,0x23,0x28,0x30,0x3c,0x45,\n    0x92,0x93,0x91,0x8e,0x97,0xc3,0xcd,0xc5,0xad,0x98,0x9d,0xa0,0x9e,0x98,0x94,0x91,\n    0x80,0x60,0x3b,0x1b,0x10,0x0e,0x14,0x26,0x3d,0x4d,0x5a,0x75,0x7b,0x7e,0x83,0x6b,\n    0x51,0x79,0xad,0xc0,0xc8,0xc3,0xa6,0x8f,0x96,0xb5,0xd6,0xe5,0xe4,0xd8,0xbb,0x94,\n    0x87,0x86,0x82,0x82,0x7f,0x79,0x71,0x7e,0x95,0xab,0xbc,0xc7,0xca,0xc4,0xba,0xb3,\n    0x88,0x4f,0x36,0xa6,0xc9,0xc8,0xc9,0xc8,0xc9,0xc9,0xc9,0xca,0xc4,0xb1,0xa8,0x9d,\n    0x90,0x83,0x71,0x67,0x91,0xc5,0xca,0xca,0xca,0xca,0xcb,0xcb,0xcb,0xcb,0xcb,0xd5,\n    0x56,0x38,0x61,0x56,0x2c,0x2f,0x2e,0x2d,0x2e,0x2d,0x2f,0x31,0x33,0x2e,0x28,0x23,\n    0x1e,0x1b,0x1c,0x1b,0x18,0x12,0x15,0x19,0x19,0x18,0x1a,0x1d,0x21,0x2a,0x38,0x40,\n    0x94,0x92,0x92,0x8e,0x91,0xb1,0xbb,0xb8,0xa4,0x93,0x96,0x99,0x9a,0x93,0x92,0x8f,\n    0x7e,0x5f,0x3c,0x1e,0x12,0x11,0x16,0x27,0x39,0x45,0x47,0x5d,0x64,0x5d,0x5f,0x50,\n    0x3a,0x57,0x93,0xa8,0xaa,0x9b,0x71,0x51,0x54,0x95,0xc9,0xde,0xde,0xd3,0xb8,0x9e,\n    0x8d,0x88,0x84,0x83,0x81,0x7c,0x7e,0x93,0xa3,0xb3,0xc2,0xc8,0xc2,0xb8,0xa7,0x97,\n    0x87,0x4e,0x33,0xa8,0xc8,0xc8,0xc9,0xc8,0xc7,0xc7,0xc8,0xd0,0xc8,0xc9,0xca,0xd0,\n    0xd2,0xd1,0xd5,0xd0,0xcc,0xc9,0xcb,0xca,0xc9,0xca,0xca,0xcb,0xcb,0xcb,0xcb,0xd5,\n    0x56,0x36,0x5e,0x58,0x2c,0x30,0x31,0x32,0x32,0x32,0x33,0x34,0x35,0x30,0x2a,0x24,\n    0x1c,0x17,0x14,0x13,0x13,0x10,0x13,0x15,0x16,0x15,0x1a,0x20,0x20,0x2a,0x32,0x3b,\n    0x96,0x91,0x90,0x8c,0x89,0x94,0xa6,0xa5,0x96,0x8d,0x90,0x95,0x98,0x94,0x91,0x8c,\n    0x7b,0x60,0x40,0x24,0x15,0x18,0x1f,0x28,0x31,0x3b,0x34,0x36,0x42,0x46,0x46,0x3f,\n    0x37,0x34,0x57,0x79,0x83,0x75,0x56,0x41,0x4d,0x90,0xb9,0xcf,0xd8,0xcd,0xb8,0x9f,\n    0x8d,0x8a,0x87,0x86,0x85,0x87,0x94,0xa2,0xac,0xb9,0xc0,0xc0,0xb4,0xa4,0x8f,0x79,\n    0x8d,0x4b,0x34,0xa9,0xc8,0xc8,0xc8,0xc7,0xc8,0xce,0xad,0x37,0xda,0xc9,0xa4,0x4e,\n    0x4e,0x5e,0x6c,0x7e,0xbe,0xcc,0xca,0xc9,0xc9,0xc9,0xc9,0xca,0xca,0xca,0xca,0xd4,\n    0x56,0x35,0x64,0x55,0x2b,0x2f,0x34,0x38,0x37,0x34,0x33,0x36,0x37,0x35,0x2c,0x24,\n    0x1d,0x16,0x12,0x10,0x11,0x0f,0x11,0x12,0x14,0x15,0x1a,0x23,0x27,0x2c,0x31,0x37,\n    0x9b,0x93,0x8d,0x8c,0x89,0x89,0x91,0x94,0x8d,0x8d,0x91,0x99,0x9d,0x9f,0x99,0x91,\n    0x7b,0x5e,0x3c,0x21,0x1a,0x21,0x2c,0x34,0x34,0x30,0x27,0x1d,0x24,0x31,0x33,0x3a,\n    0x39,0x35,0x2f,0x34,0x3a,0x35,0x3d,0x48,0x5e,0x8e,0xad,0xc0,0xc6,0xbc,0xa7,0x91,\n    0x8b,0x8a,0x89,0x88,0x8d,0x96,0xa2,0xac,0xb4,0xb6,0xb6,0xad,0x9d,0x87,0x6e,0x57,\n    0x91,0x4a,0x34,0xab,0xc7,0xc8,0xc7,0xc8,0xc7,0x7e,0x0f,0x12,0xd6,0x5d,0x0c,0x0b,\n    0x0a,0x06,0x03,0x08,0x0d,0x5e,0xc7,0xc9,0xc9,0xc9,0xc9,0xca,0xca,0xca,0xca,0xd3,\n    0x55,0x34,0x64,0x53,0x27,0x2e,0x32,0x37,0x37,0x36,0x37,0x38,0x36,0x32,0x2a,0x24,\n    0x1c,0x14,0x11,0x12,0x10,0x11,0x10,0x10,0x11,0x14,0x1b,0x24,0x2d,0x32,0x34,0x35,\n    0x9d,0x94,0x8c,0x8d,0x8d,0x97,0xa0,0x9d,0x94,0x90,0x93,0x9d,0xa4,0xa3,0x9f,0x94,\n    0x7b,0x5d,0x37,0x21,0x22,0x2f,0x3d,0x41,0x3e,0x30,0x21,0x1c,0x22,0x27,0x33,0x4e,\n    0x52,0x48,0x3e,0x2c,0x30,0x55,0x67,0x6c,0x6b,0x7b,0x8f,0x9b,0xa3,0x97,0x89,0x86,\n    0x8a,0x8a,0x88,0x8d,0x96,0x9d,0xa6,0xaf,0xb0,0xae,0xa6,0x94,0x7c,0x66,0x4c,0x46,\n    0x92,0x47,0x31,0xad,0xc8,0xc6,0xc7,0xc8,0xc9,0x29,0x15,0x98,0xaf,0x1a,0x18,0x8b,\n    0xbf,0xb2,0xa4,0x81,0x1b,0x15,0x9a,0xca,0xc8,0xca,0xc9,0xc8,0xca,0xca,0xcb,0xd3,\n    0x53,0x36,0x65,0x51,0x26,0x2d,0x32,0x35,0x36,0x39,0x36,0x33,0x31,0x2c,0x28,0x21,\n    0x1c,0x13,0x10,0x10,0x10,0x10,0x0f,0x0f,0x12,0x13,0x1c,0x23,0x2d,0x33,0x37,0x35,\n    0x98,0x97,0x8e,0x90,0x98,0xb2,0xbb,0xb2,0x9d,0x92,0x97,0xa0,0xa8,0xa9,0xa6,0x99,\n    0x79,0x5a,0x36,0x23,0x28,0x39,0x46,0x47,0x42,0x32,0x21,0x1e,0x27,0x41,0x53,0x68,\n    0x5b,0x56,0x59,0x43,0x52,0x5d,0x63,0x68,0x68,0x65,0x69,0x76,0x75,0x73,0x79,0x80,\n    0x83,0x83,0x87,0x8c,0x96,0x9f,0xaa,0xad,0xa5,0x9c,0x8c,0x74,0x58,0x42,0x37,0x48,\n    0x92,0x46,0x31,0xaf,0xc8,0xc7,0xc7,0xc8,0xc8,0x12,0x23,0xca,0xac,0x19,0x45,0xc9,\n    0xc9,0xc8,0xc9,0xcf,0x90,0x0b,0x56,0xd1,0xc8,0xc8,0xc8,0xca,0xc9,0xca,0xc9,0xd3,\n    0x54,0x31,0x61,0x54,0x25,0x2b,0x31,0x33,0x32,0x34,0x31,0x2e,0x2b,0x29,0x25,0x1e,\n    0x1b,0x14,0x13,0x12,0x12,0x12,0x10,0x10,0x11,0x12,0x1a,0x23,0x2d,0x33,0x37,0x33,\n    0x93,0x96,0x90,0x93,0xa0,0xc7,0xcf,0xc6,0xaf,0x92,0x98,0xa2,0xaa,0xaa,0xa6,0x98,\n    0x79,0x56,0x33,0x20,0x2a,0x39,0x44,0x45,0x40,0x31,0x1f,0x22,0x36,0x5a,0x75,0x89,\n    0x7e,0x66,0x52,0x44,0x4e,0x5a,0x60,0x65,0x65,0x56,0x55,0x56,0x5a,0x64,0x70,0x7b,\n    0x7f,0x82,0x87,0x8d,0x9c,0xa8,0xa9,0xa3,0x98,0x88,0x70,0x53,0x3a,0x33,0x34,0x4e,\n    0x94,0x43,0x32,0xaf,0xc5,0xc5,0xc6,0xc6,0xc6,0x32,0x17,0xa0,0xb8,0x29,0x34,0xbb,\n    0xcb,0xca,0xcc,0xc7,0x8d,0x0d,0x82,0xcc,0xc7,0xc7,0xc8,0xc9,0xc9,0xc5,0xc9,0xd2,\n    0x54,0x33,0x5e,0x50,0x21,0x28,0x2d,0x30,0x2e,0x2f,0x2c,0x2a,0x26,0x25,0x1f,0x19,\n    0x16,0x14,0x14,0x13,0x13,0x13,0x11,0x11,0x11,0x13,0x1b,0x22,0x2a,0x30,0x32,0x2e,\n    0x93,0x95,0x90,0x90,0x9f,0xcf,0xde,0xd3,0xb8,0x94,0x98,0xa3,0xa9,0xaa,0xa4,0x93,\n    0x77,0x54,0x30,0x1e,0x22,0x30,0x3c,0x3d,0x34,0x2c,0x1e,0x20,0x3a,0x6a,0x7e,0x7d,\n    0x7c,0x68,0x4d,0x3e,0x44,0x49,0x4a,0x4b,0x3b,0x3a,0x43,0x4e,0x5d,0x6d,0x7a,0x7f,\n    0x81,0x86,0x90,0x98,0xa4,0xaa,0xa3,0x9e,0x96,0x83,0x63,0x4b,0x3b,0x37,0x36,0x53,\n    0x94,0x44,0x31,0xb2,0xc5,0xc5,0xc6,0xc6,0xc6,0x8c,0x09,0x1b,0x31,0x20,0x13,0x2b,\n    0x44,0x50,0x5b,0x56,0x22,0x22,0xaf,0xc9,0xc9,0xc8,0xc7,0xc7,0xc9,0xc7,0xc9,0xd3,\n    0x56,0x33,0x5f,0x50,0x20,0x27,0x2e,0x30,0x2f,0x30,0x2c,0x27,0x24,0x21,0x1a,0x16,\n    0x16,0x17,0x15,0x15,0x14,0x14,0x14,0x13,0x12,0x13,0x1a,0x21,0x29,0x2d,0x2e,0x2d,\n    0x95,0x92,0x8e,0x8c,0x9f,0xc9,0xd6,0xd3,0xb9,0x99,0x9c,0xa4,0xa7,0xa5,0xa0,0x92,\n    0x77,0x54,0x2f,0x1c,0x1d,0x24,0x2d,0x31,0x36,0x33,0x2c,0x29,0x34,0x65,0x83,0x7c,\n    0x6b,0x54,0x3d,0x37,0x33,0x2c,0x22,0x1f,0x2e,0x3e,0x4d,0x5c,0x6d,0x79,0x7e,0x82,\n    0x88,0x90,0x9b,0xa1,0xac,0xae,0xab,0xaa,0xa3,0x83,0x64,0x57,0x4c,0x3e,0x37,0x56,\n    0x96,0x40,0x2f,0xb4,0xc5,0xc5,0xc6,0xc6,0xc6,0xcb,0x97,0x3e,0x27,0x22,0x1b,0x1b,\n    0x17,0x12,0x11,0x10,0x0e,0x07,0x86,0xcc,0xc9,0xc8,0xc9,0xca,0xca,0xca,0xc9,0xd2,\n    0x57,0x34,0x60,0x54,0x22,0x28,0x2f,0x32,0x32,0x31,0x2e,0x29,0x24,0x21,0x1b,0x17,\n    0x16,0x15,0x16,0x14,0x15,0x15,0x14,0x14,0x13,0x15,0x1b,0x22,0x28,0x2b,0x2d,0x2c,\n    0x98,0x92,0x8b,0x85,0x91,0xb4,0xc4,0xc2,0xaf,0x99,0x9f,0xa2,0xa6,0xa3,0x9e,0x93,\n    0x7c,0x59,0x38,0x20,0x1b,0x1d,0x23,0x35,0x49,0x46,0x3c,0x32,0x31,0x4d,0x69,0x74,\n    0x62,0x3d,0x27,0x22,0x1f,0x1f,0x21,0x2e,0x3e,0x4c,0x5d,0x6d,0x79,0x7c,0x82,0x87,\n    0x91,0x9b,0xa5,0xaa,0xb3,0xb7,0xba,0xb6,0xa3,0x85,0x6d,0x65,0x59,0x44,0x40,0x5a,\n    0x95,0x3f,0x2e,0xb5,0xc5,0xc5,0xc5,0xc5,0xc6,0xc6,0xc7,0xc5,0xc0,0xbe,0xbe,0xba,\n    0xb9,0xb4,0xac,0xa3,0x97,0x8c,0xad,0xc9,0xc8,0xc7,0xc4,0xc9,0xca,0xca,0xca,0xd1,\n    0x57,0x34,0x60,0x57,0x24,0x2a,0x2f,0x31,0x32,0x33,0x30,0x29,0x23,0x20,0x1b,0x17,\n    0x14,0x13,0x13,0x14,0x15,0x15,0x15,0x14,0x15,0x17,0x1c,0x21,0x28,0x2c,0x2b,0x29,\n    0x9b,0x92,0x8a,0x89,0x8c,0x9f,0xaa,0xab,0x9c,0x94,0x9e,0xa1,0xa5,0xa2,0x9d,0x92,\n    0x7e,0x5f,0x3e,0x26,0x1d,0x1e,0x2c,0x40,0x4d,0x50,0x47,0x3c,0x3c,0x47,0x4e,0x4c,\n    0x3f,0x27,0x1e,0x20,0x21,0x23,0x32,0x3e,0x4d,0x5d,0x6b,0x78,0x7d,0x81,0x85,0x8e,\n    0x98,0xa1,0xab,0xb0,0xb8,0xbe,0xbc,0xb1,0xa3,0x8c,0x7b,0x6e,0x59,0x47,0x46,0x61,\n    0x95,0x3d,0x2d,0xb6,0xc5,0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc4,0xc5,0xc5,0xc6,\n    0xc5,0xc5,0xc7,0xc6,0xc8,0xc8,0xc8,0xc7,0xc7,0xc8,0xc7,0xca,0xc8,0xc9,0xc8,0xd1,\n    0x57,0x35,0x5e,0x5c,0x28,0x2e,0x30,0x31,0x31,0x33,0x31,0x2a,0x24,0x20,0x1b,0x15,\n    0x13,0x13,0x13,0x13,0x14,0x15,0x15,0x14,0x16,0x19,0x1c,0x1f,0x25,0x29,0x28,0x27,\n    0x96,0x8c,0x87,0x88,0x8c,0x93,0x96,0x94,0x8e,0x8f,0x98,0xa1,0xa5,0xa3,0x9d,0x93,\n    0x7e,0x63,0x42,0x2b,0x23,0x23,0x2f,0x3f,0x4c,0x48,0x48,0x3b,0x37,0x46,0x52,0x51,\n    0x3d,0x26,0x1f,0x1f,0x21,0x32,0x3f,0x4c,0x5c,0x6d,0x77,0x7c,0x80,0x85,0x8d,0x95,\n    0x9e,0xa6,0xae,0xb4,0xb8,0xba,0xb3,0xa8,0x9c,0x89,0x7a,0x5f,0x4b,0x47,0x47,0x5f,\n    0x97,0x3a,0x2c,0xb6,0xc5,0xc4,0xc4,0xc4,0xc5,0xc5,0xc4,0xc5,0xc6,0xc5,0xc5,0xc5,\n    0xc7,0xc6,0xc6,0xc5,0xc7,0xc8,0xc7,0xc8,0xc7,0xc8,0xc9,0xc8,0xc8,0xc8,0xc8,0xd1,\n    0x56,0x34,0x5a,0x5d,0x2a,0x2f,0x30,0x31,0x30,0x2e,0x2e,0x29,0x22,0x1d,0x19,0x14,\n    0x12,0x12,0x12,0x13,0x14,0x14,0x14,0x15,0x15,0x19,0x19,0x1d,0x21,0x24,0x25,0x23,\n    0x94,0x8a,0x84,0x85,0x8f,0xa3,0xac,0xa3,0x92,0x8e,0x98,0xa0,0xa5,0xa5,0x9f,0x94,\n    0x7e,0x61,0x45,0x30,0x27,0x27,0x2a,0x34,0x3d,0x3d,0x32,0x2b,0x37,0x4e,0x56,0x50,\n    0x3c,0x2a,0x21,0x23,0x32,0x3e,0x4a,0x59,0x6b,0x76,0x78,0x7f,0x84,0x8a,0x94,0x9e,\n    0xa4,0xab,0xaf,0xb3,0xb5,0xb2,0xaa,0x9f,0x8f,0x79,0x5e,0x47,0x42,0x42,0x41,0x5a,\n    0x9b,0x3c,0x2e,0xb7,0xc4,0xc4,0xc5,0xc4,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc7,\n    0xc7,0xc7,0xc7,0xc7,0xc7,0xc8,0xc8,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc8,0xd0,\n    0x55,0x33,0x5b,0x60,0x2a,0x2d,0x2d,0x2d,0x2a,0x29,0x29,0x25,0x21,0x1b,0x18,0x13,\n    0x11,0x11,0x12,0x13,0x14,0x14,0x14,0x15,0x16,0x17,0x1a,0x1b,0x1e,0x20,0x22,0x22,\n    0x91,0x86,0x80,0x87,0x92,0xb0,0xbb,0xb3,0xa1,0x8e,0x96,0xa0,0xa7,0xa8,0x9f,0x94,\n    0x7e,0x61,0x46,0x30,0x24,0x23,0x26,0x29,0x28,0x27,0x20,0x25,0x39,0x52,0x58,0x4e,\n    0x3e,0x2e,0x28,0x35,0x3f,0x4a,0x59,0x67,0x74,0x7a,0x7e,0x83,0x87,0x8f,0x98,0xa2,\n    0xa9,0xad,0xb0,0xb0,0xaf,0xad,0xa6,0x96,0x7c,0x60,0x4a,0x44,0x46,0x44,0x42,0x56,\n    0x97,0x3c,0x2e,0xb9,0xc5,0xc4,0xc5,0xc4,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc4,\n    0xc5,0xc7,0xc7,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xd0,\n    0x55,0x31,0x5a,0x5e,0x2a,0x2c,0x2d,0x2d,0x2a,0x29,0x27,0x24,0x1f,0x1a,0x18,0x13,\n    0x11,0x11,0x14,0x14,0x17,0x16,0x17,0x17,0x15,0x13,0x16,0x17,0x19,0x1b,0x20,0x21,\n    0x8a,0x82,0x80,0x84,0x92,0xb6,0xc7,0xc2,0xb0,0x8e,0x94,0x9e,0xa8,0xa7,0x9e,0x92,\n    0x7e,0x61,0x44,0x2f,0x23,0x20,0x22,0x23,0x1f,0x1b,0x1a,0x26,0x3d,0x50,0x55,0x4f,\n    0x40,0x30,0x33,0x3f,0x4b,0x59,0x67,0x72,0x77,0x7d,0x82,0x84,0x84,0x8e,0x9d,0xa8,\n    0xaf,0xaf,0xaf,0xaf,0xb0,0xae,0xa4,0x94,0x7a,0x57,0x4c,0x4d,0x4c,0x4b,0x4b,0x5b,\n    0x97,0x3b,0x2f,0xba,0xc4,0xc4,0xc5,0xc4,0xc4,0xc5,0xc5,0xc5,0xc5,0xc6,0xc5,0xc7,\n    0xc5,0xc4,0xc9,0xc7,0xc7,0xc6,0xc7,0xc6,0xc7,0xc7,0xc8,0xc7,0xc6,0xc7,0xc7,0xd0,\n    0x57,0x32,0x5b,0x60,0x2a,0x2c,0x2c,0x2f,0x2a,0x28,0x27,0x23,0x1e,0x1b,0x1a,0x15,\n    0x13,0x13,0x13,0x15,0x1b,0x1c,0x1c,0x1a,0x17,0x14,0x15,0x14,0x16,0x1c,0x20,0x21,\n    0x81,0x82,0x83,0x8b,0x91,0xb3,0xcd,0xc5,0xb3,0x8e,0x92,0x9e,0xa4,0xa3,0x9a,0x8e,\n    0x7a,0x62,0x44,0x2b,0x20,0x1a,0x1a,0x1b,0x1b,0x1a,0x1a,0x24,0x38,0x49,0x51,0x4b,\n    0x3e,0x37,0x45,0x52,0x5c,0x67,0x73,0x78,0x7e,0x82,0x85,0x82,0x80,0x8b,0x9d,0xa7,\n    0xaf,0xaf,0xaf,0xaf,0xb2,0xaf,0xa6,0x95,0x7f,0x6a,0x55,0x4e,0x4c,0x4b,0x49,0x59,\n    0x97,0x39,0x30,0xbb,0xc4,0xc3,0xc4,0xc4,0xc4,0xc0,0xc4,0xc4,0xc4,0xc5,0xc5,0xc0,\n    0xc6,0xbb,0x9b,0xc2,0xc5,0xc6,0xc6,0xc6,0xc7,0xc7,0xc8,0xc7,0xc7,0xc7,0xc7,0xcf,\n    0x57,0x33,0x58,0x61,0x29,0x2c,0x2f,0x2f,0x2a,0x28,0x26,0x22,0x1e,0x1d,0x19,0x16,\n    0x14,0x13,0x16,0x1d,0x23,0x24,0x24,0x1f,0x1d,0x18,0x16,0x16,0x18,0x1d,0x21,0x22,\n    0x7d,0x80,0x82,0x84,0x8b,0xa8,0xbd,0xba,0xae,0x8e,0x90,0x9b,0xa3,0xa0,0x96,0x8b,\n    0x7b,0x64,0x4c,0x2f,0x21,0x1a,0x18,0x18,0x19,0x18,0x18,0x1e,0x2f,0x41,0x46,0x46,\n    0x43,0x44,0x50,0x5c,0x6a,0x76,0x78,0x7e,0x82,0x85,0x87,0x85,0x83,0x8d,0x9a,0xa4,\n    0xad,0xaf,0xaf,0xb0,0xb3,0xb2,0xaa,0x9d,0x8c,0x79,0x6c,0x5d,0x5a,0x59,0x59,0x5b,\n    0x95,0x39,0x31,0xc0,0xc2,0xc3,0xc4,0xc3,0xc5,0xc5,0xc5,0xc5,0xc5,0xc4,0xc5,0xc5,\n    0x9b,0x26,0x17,0x7c,0xc8,0xc5,0xc5,0xc5,0xc6,0xc6,0xc8,0xc8,0xc4,0xc4,0xc8,0xcf,\n    0x58,0x33,0x56,0x5c,0x25,0x2a,0x2c,0x2f,0x30,0x2c,0x29,0x26,0x20,0x1d,0x19,0x16,\n    0x15,0x16,0x1b,0x21,0x26,0x28,0x27,0x22,0x21,0x1b,0x19,0x1a,0x1d,0x20,0x23,0x23,\n    0x7c,0x7e,0x7d,0x82,0x84,0x94,0xa9,0xa7,0x9c,0x88,0x8f,0x98,0xa2,0x9f,0x97,0x8c,\n    0x79,0x67,0x50,0x37,0x24,0x1a,0x18,0x18,0x18,0x17,0x16,0x18,0x26,0x35,0x3b,0x46,\n    0x4b,0x50,0x5c,0x69,0x73,0x7e,0x7d,0x83,0x83,0x82,0x84,0x87,0x89,0x91,0x9e,0xa6,\n    0xae,0xae,0xaf,0xae,0xaf,0xae,0xad,0xa5,0x93,0x84,0x78,0x71,0x61,0x5e,0x6b,0x66,\n    0x95,0x3a,0x33,0xbf,0xc4,0xc3,0xc4,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc4,0xc5,0x8c,\n    0x17,0x17,0x16,0x14,0x80,0xca,0xc6,0xc5,0xc6,0xc6,0xc7,0xc6,0xc6,0xc7,0xc7,0xcd,\n    0x59,0x33,0x52,0x5c,0x24,0x29,0x2b,0x2f,0x30,0x2e,0x2b,0x28,0x25,0x20,0x1c,0x17,\n    0x16,0x1a,0x1e,0x21,0x2a,0x2b,0x2b,0x28,0x25,0x22,0x1f,0x20,0x21,0x21,0x22,0x23,\n    0x7f,0x7d,0x78,0x7a,0x80,0x81,0x8f,0x91,0x84,0x7d,0x88,0x97,0xa1,0x9f,0x99,0x8c,\n    0x7c,0x6b,0x54,0x3b,0x29,0x1b,0x18,0x17,0x17,0x16,0x15,0x14,0x19,0x2a,0x3d,0x48,\n    0x53,0x59,0x68,0x73,0x7a,0x82,0x83,0x87,0x88,0x87,0x87,0x87,0x8c,0x98,0xa7,0xaf,\n    0xaf,0xb1,0xaf,0xad,0xac,0xa7,0xa4,0xa6,0x9d,0x8c,0x88,0x81,0x7b,0x81,0x8c,0x78,\n    0x98,0x38,0x31,0xc0,0xc3,0xc3,0xc4,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc9,0x73,0x1c,\n    0x16,0x16,0x16,0x16,0x15,0x5f,0xc6,0xc5,0xc6,0xc6,0xc7,0xc6,0xc6,0xc6,0xc7,0xce,\n    0x59,0x35,0x57,0x5c,0x21,0x28,0x2c,0x2e,0x30,0x2d,0x2b,0x28,0x27,0x23,0x20,0x1d,\n    0x1a,0x1c,0x1f,0x26,0x2d,0x2f,0x2e,0x2d,0x29,0x26,0x25,0x24,0x23,0x21,0x21,0x22,\n    0x80,0x7d,0x77,0x7b,0x7f,0x86,0x89,0x8a,0x7f,0x7d,0x88,0x95,0x9e,0x9d,0x96,0x8e,\n    0x7d,0x6f,0x58,0x41,0x2d,0x1c,0x16,0x13,0x14,0x15,0x15,0x16,0x15,0x1e,0x36,0x48,\n    0x59,0x62,0x69,0x72,0x78,0x7e,0x85,0x8a,0x8a,0x87,0x8d,0x92,0x91,0x9a,0xaa,0xb3,\n    0xb1,0xb2,0xaf,0xab,0xa8,0xa2,0x9b,0x9b,0x9f,0x96,0x96,0x9c,0xa2,0xa5,0xa0,0x7b,\n    0x99,0x35,0x31,0xbf,0xc2,0xc3,0xc4,0xc3,0xc2,0xc3,0xc3,0xc2,0xc3,0x5d,0x0d,0x15,\n    0x17,0x14,0x15,0x17,0x15,0x18,0x66,0xc8,0xc5,0xc5,0xc7,0xc7,0xc6,0xc6,0xc5,0xce,\n    0x59,0x36,0x5a,0x5e,0x21,0x27,0x2c,0x2f,0x2e,0x2c,0x2c,0x2b,0x2b,0x2a,0x2a,0x25,\n    0x22,0x1f,0x22,0x27,0x2d,0x2f,0x2e,0x2d,0x2b,0x2a,0x2a,0x2a,0x27,0x23,0x22,0x22,\n    0x80,0x7f,0x7c,0x7f,0x85,0x90,0xa0,0x9e,0x92,0x88,0x8c,0x97,0x9c,0x9c,0x96,0x8f,\n    0x7e,0x70,0x5b,0x41,0x2e,0x1c,0x12,0x0e,0x11,0x15,0x16,0x16,0x18,0x18,0x2d,0x4b,\n    0x63,0x71,0x74,0x78,0x7b,0x7b,0x7d,0x88,0x90,0x8e,0x8b,0x8d,0x9a,0xa3,0xaa,0xb4,\n    0xb4,0xb3,0xaf,0xa9,0xa3,0x9f,0x97,0x94,0x99,0xa1,0xa9,0xb2,0xbb,0xc3,0xbb,0x85,\n    0x99,0x33,0x2f,0xc1,0xc2,0xc2,0xc2,0xc2,0xc3,0xc1,0xc1,0xc4,0x31,0x16,0x17,0x16,\n    0x16,0x15,0x15,0x17,0x1a,0x16,0x14,0x4c,0xc1,0xc6,0xc5,0xc6,0xc6,0xc5,0xc5,0xcc,\n    0x5a,0x34,0x59,0x62,0x22,0x29,0x2d,0x2e,0x2e,0x2e,0x2e,0x31,0x33,0x32,0x2f,0x2b,\n    0x29,0x25,0x27,0x29,0x2c,0x2d,0x2d,0x2d,0x2b,0x2e,0x2e,0x2e,0x2b,0x28,0x25,0x25,\n    0x81,0x84,0x81,0x81,0x85,0x94,0xae,0xaf,0xa5,0x93,0x92,0x9a,0x9b,0x9c,0x98,0x8d,\n    0x81,0x71,0x5f,0x45,0x2d,0x1c,0x12,0x0f,0x12,0x16,0x19,0x19,0x18,0x18,0x2b,0x4b,\n    0x64,0x74,0x79,0x7a,0x75,0x76,0x74,0x79,0x87,0x94,0x94,0x8e,0x91,0xa3,0xaf,0xb2,\n    0xb5,0xb5,0xad,0xa6,0xa1,0x9c,0x96,0x93,0x96,0xa3,0xb3,0xbd,0xc9,0xcd,0xc7,0x84,\n    0x9a,0x33,0x31,0xc2,0xc2,0xc1,0xc1,0xc1,0xc0,0xc7,0xa6,0x29,0x14,0x16,0x18,0x16,\n    0x16,0x15,0x16,0x17,0x16,0x15,0x15,0x12,0x49,0xc2,0xc5,0xc5,0xc5,0xc5,0xc6,0xcb,\n    0x59,0x33,0x58,0x65,0x24,0x2a,0x2d,0x2e,0x2e,0x2f,0x2f,0x35,0x39,0x37,0x35,0x30,\n    0x2c,0x26,0x27,0x28,0x29,0x2b,0x2c,0x2c,0x2d,0x2e,0x2e,0x2d,0x2a,0x27,0x26,0x24,\n    0x81,0x84,0x85,0x84,0x84,0x95,0xbb,0xbc,0xb4,0x9c,0x94,0x9a,0x9e,0x9e,0x9a,0x91,\n    0x84,0x71,0x5e,0x46,0x30,0x20,0x16,0x13,0x19,0x22,0x26,0x24,0x1e,0x16,0x28,0x49,\n    0x62,0x74,0x79,0x77,0x79,0x78,0x73,0x71,0x6e,0x78,0x87,0x95,0x96,0xa3,0xb0,0xb6,\n    0xb5,0xb5,0xad,0xa6,0x9f,0x98,0x94,0x95,0x96,0xa1,0xb4,0xc6,0xd1,0xd1,0xcb,0x81,\n    0x98,0x35,0x31,0xc2,0xc0,0xc0,0xc0,0xc3,0xc2,0x7d,0x10,0x17,0x17,0x16,0x15,0x17,\n    0x15,0x15,0x16,0x16,0x16,0x16,0x14,0x15,0x15,0x3f,0xc6,0xc4,0xc3,0xc6,0xc5,0xca,\n    0x59,0x32,0x54,0x65,0x26,0x29,0x2c,0x2e,0x2e,0x2d,0x2f,0x37,0x3d,0x3a,0x38,0x33,\n    0x2d,0x25,0x27,0x29,0x28,0x27,0x29,0x27,0x2a,0x2f,0x2d,0x2d,0x2a,0x25,0x23,0x20,\n    0x80,0x83,0x87,0x84,0x84,0x8e,0xb7,0xbb,0xb9,0xa2,0x92,0x98,0x9f,0xa0,0x9d,0x94,\n    0x85,0x71,0x59,0x43,0x30,0x1f,0x17,0x19,0x27,0x36,0x3d,0x38,0x2c,0x1d,0x22,0x43,\n    0x5c,0x6b,0x73,0x73,0x78,0x7e,0x7e,0x79,0x70,0x67,0x64,0x7c,0x94,0xa2,0xb2,0xbc,\n    0xb9,0xb5,0xad,0xa3,0x9b,0x96,0x93,0x94,0x95,0xa0,0xb6,0xc9,0xd3,0xd2,0xc4,0x73,\n    0x99,0x31,0x32,0xc4,0xbf,0xbf,0xc0,0xc0,0x4c,0x17,0x16,0x15,0x19,0x17,0x16,0x15,\n    0x15,0x15,0x15,0x15,0x15,0x15,0x16,0x14,0x16,0x11,0x2e,0xb8,0xc4,0xc3,0xc4,0xc9,\n    0x58,0x32,0x50,0x63,0x23,0x29,0x2a,0x2d,0x2e,0x2d,0x33,0x39,0x38,0x37,0x32,0x2d,\n    0x27,0x25,0x25,0x27,0x26,0x26,0x27,0x26,0x2c,0x2d,0x2e,0x29,0x27,0x22,0x1f,0x1d,\n    0x7e,0x7e,0x82,0x84,0x88,0x8a,0xa6,0xb2,0xb0,0xa1,0x93,0x95,0x9b,0x9e,0x9e,0x99,\n    0x86,0x73,0x5d,0x47,0x33,0x20,0x1a,0x2a,0x3b,0x4f,0x5b,0x55,0x47,0x33,0x2b,0x3c,\n    0x52,0x5e,0x68,0x6b,0x70,0x7f,0x87,0x87,0x7e,0x6f,0x62,0x64,0x82,0x9c,0xb2,0xbf,\n    0xbd,0xb6,0xad,0xa3,0x9a,0x96,0x97,0x96,0x97,0xa8,0xbb,0xcb,0xd4,0xcf,0xbc,0x63,\n    0x9a,0x31,0x32,0xc5,0xbf,0xbf,0xba,0x41,0x13,0x13,0x16,0x15,0x15,0x16,0x15,0x16,\n    0x15,0x14,0x15,0x15,0x14,0x15,0x16,0x17,0x18,0x14,0x16,0x2d,0xbd,0xc5,0xc4,0xc9,\n    0x58,0x34,0x52,0x64,0x21,0x28,0x2a,0x2d,0x2f,0x30,0x35,0x38,0x35,0x32,0x2b,0x24,\n    0x1c,0x1d,0x21,0x24,0x25,0x26,0x28,0x2a,0x2f,0x2d,0x2b,0x25,0x22,0x1e,0x1a,0x1c,\n    0x7c,0x7a,0x7e,0x81,0x88,0x85,0x91,0x9d,0x9f,0x98,0x94,0x93,0x96,0x9a,0x9a,0x94,\n    0x86,0x75,0x5e,0x47,0x35,0x24,0x28,0x39,0x4e,0x61,0x70,0x6e,0x5e,0x44,0x39,0x3b,\n    0x4b,0x59,0x5a,0x57,0x68,0x7c,0x87,0x87,0x84,0x7f,0x6e,0x5e,0x75,0x93,0xad,0xbb,\n    0xbf,0xb6,0xad,0xa2,0x9a,0x97,0x96,0x95,0x9d,0xb1,0xc3,0xcf,0xd5,0xcc,0xb6,0x5a,\n    0x99,0x32,0x32,0xc8,0xbd,0xaf,0x2a,0x14,0x16,0x15,0x16,0x15,0x14,0x14,0x15,0x15,\n    0x15,0x15,0x15,0x14,0x14,0x14,0x16,0x14,0x14,0x14,0x14,0x12,0x29,0xb4,0xc1,0xcb,\n    0x59,0x34,0x52,0x65,0x21,0x28,0x2a,0x2d,0x30,0x30,0x37,0x37,0x34,0x2d,0x28,0x20,\n    0x1a,0x1a,0x1e,0x24,0x26,0x29,0x2b,0x2e,0x30,0x2c,0x28,0x21,0x1e,0x1d,0x1e,0x20,\n    0x7d,0x7a,0x7d,0x81,0x87,0x87,0x88,0x8d,0x91,0x90,0x90,0x91,0x90,0x95,0x92,0x90,\n    0x83,0x72,0x5e,0x49,0x39,0x31,0x3a,0x4e,0x61,0x70,0x78,0x77,0x6a,0x51,0x44,0x43,\n    0x48,0x51,0x55,0x52,0x5b,0x6a,0x7f,0x8a,0x87,0x7d,0x74,0x6f,0x72,0x8e,0xab,0xbd,\n    0xc1,0xba,0xae,0xa2,0x99,0x96,0x98,0x9d,0xac,0xbd,0xcb,0xd6,0xd7,0xca,0xaf,0x55,\n    0x9a,0x32,0x34,0xc2,0x93,0x19,0x12,0x16,0x14,0x15,0x15,0x15,0x16,0x1c,0x17,0x17,\n    0x17,0x17,0x18,0x17,0x16,0x15,0x17,0x13,0x13,0x13,0x14,0x16,0x14,0x1d,0xad,0xca,\n    0x5b,0x36,0x51,0x69,0x23,0x29,0x2b,0x2f,0x32,0x33,0x36,0x33,0x2f,0x27,0x1f,0x1b,\n    0x18,0x1c,0x20,0x26,0x2a,0x2f,0x30,0x32,0x33,0x2d,0x27,0x21,0x1e,0x20,0x25,0x25,\n    0x7e,0x7e,0x7f,0x7e,0x86,0x85,0x87,0x8e,0x8c,0x8d,0x8d,0x8f,0x8b,0x8c,0x8b,0x8a,\n    0x82,0x75,0x69,0x58,0x4a,0x47,0x4f,0x5f,0x6d,0x75,0x74,0x70,0x67,0x57,0x4a,0x45,\n    0x46,0x4c,0x4e,0x4e,0x56,0x5e,0x66,0x77,0x7f,0x7a,0x71,0x70,0x78,0x93,0xae,0xbf,\n    0xc0,0xbe,0xaf,0xa1,0x97,0x97,0x9a,0xa5,0xb4,0xc5,0xcf,0xd9,0xda,0xc7,0xa7,0x4d,\n    0x97,0x32,0x35,0xc3,0x51,0x12,0x15,0x14,0x19,0x13,0x14,0x16,0x1b,0x15,0x15,0x15,\n    0x14,0x14,0x14,0x15,0x15,0x16,0x16,0x13,0x14,0x14,0x13,0x15,0x15,0x13,0x1a,0xb2,\n    0x5b,0x33,0x51,0x6c,0x25,0x2b,0x2c,0x2e,0x34,0x34,0x35,0x31,0x2b,0x24,0x1e,0x1c,\n    0x1d,0x20,0x24,0x29,0x2d,0x32,0x32,0x32,0x2f,0x29,0x24,0x1f,0x20,0x21,0x28,0x27,\n    0x80,0x85,0x84,0x82,0x85,0x86,0x8e,0x94,0x92,0x8f,0x8b,0x8b,0x89,0x87,0x8a,0x89,\n    0x85,0x7f,0x75,0x67,0x5c,0x57,0x61,0x6a,0x70,0x6f,0x69,0x60,0x57,0x51,0x47,0x45,\n    0x40,0x42,0x43,0x42,0x49,0x56,0x60,0x5f,0x61,0x65,0x62,0x68,0x75,0x93,0xb2,0xc4,\n    0xc5,0xc0,0xb3,0xa2,0x9a,0x9c,0x9f,0xa8,0xb9,0xca,0xd7,0xdd,0xda,0xc3,0x9f,0x46,\n    0x96,0x31,0x35,0xc7,0xc6,0x57,0x10,0x17,0x13,0x10,0x30,0x35,0x12,0x14,0x14,0x14,\n    0x13,0x13,0x13,0x13,0x13,0x14,0x14,0x14,0x15,0x13,0x13,0x15,0x14,0x14,0x16,0x18,\n    0x43,0x34,0x4f,0x71,0x2b,0x30,0x30,0x31,0x34,0x32,0x32,0x2f,0x2a,0x23,0x1d,0x1f,\n    0x20,0x24,0x28,0x2d,0x30,0x33,0x32,0x31,0x2d,0x24,0x1f,0x1d,0x20,0x25,0x2b,0x2c,\n    0x7e,0x86,0x85,0x81,0x7f,0x83,0x8f,0x97,0x95,0x91,0x89,0x8b,0x8e,0x8c,0x8a,0x8a,\n    0x86,0x84,0x7b,0x70,0x67,0x61,0x60,0x62,0x63,0x5c,0x52,0x4a,0x45,0x40,0x3b,0x3a,\n    0x39,0x35,0x35,0x34,0x35,0x3d,0x4c,0x51,0x4a,0x40,0x45,0x4f,0x5d,0x77,0x9e,0xb5,\n    0xb8,0xb6,0xad,0x9d,0x94,0x92,0x98,0xa9,0xba,0xc8,0xd4,0xd9,0xd0,0xb5,0x8f,0x3c,\n    0x96,0x2f,0x36,0xc7,0xbe,0xc0,0x61,0x11,0x17,0x40,0xc3,0x49,0x14,0x14,0x14,0x15,\n    0x14,0x14,0x10,0x13,0x13,0x15,0x16,0x14,0x13,0x17,0x14,0x18,0x13,0x14,0x13,0x12,\n    0x11,0x2a,0x50,0x72,0x31,0x35,0x34,0x32,0x32,0x31,0x2e,0x2c,0x27,0x22,0x20,0x20,\n    0x22,0x28,0x2b,0x30,0x31,0x32,0x31,0x2d,0x27,0x22,0x1c,0x1e,0x21,0x26,0x29,0x29,\n    0x80,0x8b,0x85,0x7e,0x7a,0x7f,0x88,0x91,0x93,0x92,0x8d,0x8f,0x91,0x93,0x8f,0x8b,\n    0x87,0x7d,0x77,0x6d,0x64,0x5b,0x52,0x50,0x4c,0x44,0x3d,0x36,0x35,0x34,0x34,0x30,\n    0x31,0x2b,0x29,0x26,0x29,0x2a,0x2f,0x33,0x31,0x2c,0x2a,0x2d,0x40,0x58,0x79,0x91,\n    0x97,0x96,0x8d,0x85,0x7c,0x7c,0x83,0x96,0xa3,0xaf,0xb9,0xc0,0xb7,0xa1,0x87,0x44,\n    0x95,0x2f,0x36,0xc6,0xbd,0xbc,0xc6,0x7a,0x64,0xbe,0xbd,0x45,0x13,0x14,0x15,0x15,\n    0x14,0x12,0x16,0x13,0x14,0x15,0x14,0x15,0x14,0x38,0x99,0x17,0x17,0x16,0x15,0x12,\n    0x17,0x30,0x51,0x76,0x37,0x39,0x36,0x35,0x35,0x35,0x30,0x2b,0x25,0x21,0x1f,0x20,\n    0x24,0x28,0x2c,0x2f,0x32,0x33,0x2e,0x28,0x25,0x1e,0x1b,0x1c,0x21,0x26,0x28,0x24,\n    0x83,0x87,0x82,0x7c,0x7b,0x81,0x82,0x8a,0x90,0x8e,0x8e,0x90,0x93,0x95,0x90,0x8d,\n    0x84,0x77,0x6e,0x63,0x59,0x4f,0x45,0x3c,0x36,0x31,0x2d,0x2f,0x2e,0x2c,0x2d,0x2b,\n    0x29,0x25,0x21,0x1e,0x1f,0x21,0x25,0x25,0x23,0x21,0x20,0x26,0x2d,0x3e,0x4a,0x5b,\n    0x64,0x63,0x65,0x62,0x65,0x69,0x64,0x6c,0x77,0x83,0x8f,0x98,0x9a,0x99,0x94,0x59,\n    0x92,0x2f,0x35,0xc6,0xbc,0xbd,0xbc,0xbf,0xbf,0xbe,0xb9,0x3e,0x14,0x14,0x14,0x14,\n    0x13,0x13,0x14,0x13,0x14,0x14,0x15,0x14,0x14,0x40,0xc4,0x9a,0x16,0x12,0x16,0x36,\n    0x5a,0x31,0x4a,0x7a,0x3b,0x3c,0x38,0x36,0x36,0x37,0x31,0x2b,0x24,0x20,0x1d,0x1d,\n    0x21,0x27,0x2a,0x2f,0x32,0x32,0x2c,0x28,0x23,0x1d,0x1a,0x1a,0x1d,0x21,0x20,0x1f,\n    0x7f,0x85,0x7f,0x7c,0x7f,0x83,0x84,0x85,0x87,0x89,0x8c,0x8d,0x90,0x91,0x8f,0x8a,\n    0x81,0x75,0x68,0x5e,0x59,0x52,0x44,0x37,0x2d,0x2d,0x2f,0x2f,0x30,0x31,0x31,0x2f,\n    0x2c,0x27,0x1f,0x1a,0x1b,0x1b,0x1d,0x21,0x1f,0x21,0x27,0x33,0x38,0x40,0x3d,0x36,\n    0x3d,0x47,0x51,0x63,0x67,0x62,0x58,0x4b,0x44,0x47,0x51,0x69,0x8a,0x9e,0xac,0x60,\n    0x90,0x2f,0x36,0xc6,0xbc,0xbc,0xbd,0xbc,0xbd,0xbd,0xb6,0x1e,0x15,0x14,0x13,0x13,\n    0x13,0x13,0x13,0x13,0x13,0x17,0x13,0x14,0x14,0x4f,0xbf,0xc3,0xa7,0x1a,0x44,0xc6,\n    0x58,0x31,0x48,0x79,0x3a,0x3c,0x37,0x39,0x37,0x37,0x31,0x2c,0x27,0x24,0x24,0x2a,\n    0x31,0x3b,0x43,0x47,0x46,0x3f,0x30,0x26,0x20,0x1a,0x18,0x19,0x1a,0x1c,0x1b,0x1a,\n    0x77,0x7f,0x79,0x7a,0x7d,0x85,0x83,0x82,0x81,0x88,0x8a,0x87,0x8d,0x8c,0x8b,0x89,\n    0x7f,0x74,0x6a,0x61,0x60,0x5a,0x4a,0x3b,0x33,0x32,0x34,0x34,0x35,0x36,0x38,0x39,\n    0x31,0x29,0x21,0x1b,0x1b,0x19,0x1a,0x1c,0x20,0x23,0x31,0x3f,0x44,0x49,0x48,0x3c,\n    0x42,0x56,0x70,0x85,0x8a,0x81,0x6f,0x59,0x44,0x33,0x35,0x61,0x8d,0xa8,0xba,0x63,\n    0x8e,0x30,0x36,0xc5,0xbd,0xbc,0xbc,0xbc,0xbc,0xbc,0xb6,0x26,0x13,0x14,0x13,0x13,\n    0x13,0x13,0x13,0x13,0x13,0x16,0x14,0x14,0x13,0x57,0xbf,0xc3,0xc1,0xaa,0xc6,0xc1,\n    0x59,0x31,0x49,0x77,0x37,0x3a,0x3a,0x39,0x39,0x37,0x36,0x36,0x39,0x41,0x4e,0x62,\n    0x6e,0x76,0x7d,0x7d,0x72,0x5e,0x40,0x27,0x1e,0x19,0x19,0x18,0x19,0x19,0x18,0x17,\n    0x77,0x7c,0x79,0x76,0x7c,0x7f,0x80,0x7d,0x7d,0x82,0x87,0x89,0x8a,0x8a,0x8b,0x8a,\n    0x81,0x78,0x6f,0x69,0x6a,0x65,0x53,0x41,0x37,0x39,0x3c,0x3e,0x3c,0x39,0x39,0x37,\n    0x35,0x31,0x28,0x22,0x21,0x22,0x25,0x2a,0x2e,0x32,0x3e,0x4b,0x51,0x52,0x51,0x43,\n    0x4b,0x64,0x86,0x9f,0xa6,0xa0,0x92,0x7b,0x64,0x48,0x3e,0x5f,0x91,0xae,0xc1,0x60,\n    0x92,0x2f,0x38,0xc4,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xb7,0x3a,0x13,0x15,0x15,0x13,\n    0x13,0x13,0x13,0x13,0x13,0x14,0x15,0x14,0x15,0x62,0xc0,0xc3,0xc2,0xc4,0xc0,0xc4,\n    0x58,0x2f,0x48,0x7f,0x48,0x4a,0x4a,0x4b,0x4f,0x53,0x55,0x52,0x5f,0x6f,0x7a,0x8a,\n    0x94,0x96,0x96,0x8c,0x7c,0x63,0x48,0x2c,0x20,0x19,0x18,0x18,0x1a,0x19,0x17,0x17,\n    0x76,0x7a,0x79,0x76,0x78,0x7c,0x7c,0x7f,0x7f,0x82,0x83,0x88,0x8a,0x8a,0x8b,0x8b,\n    0x84,0x7f,0x73,0x6c,0x6a,0x60,0x4d,0x3f,0x37,0x36,0x3d,0x41,0x3c,0x38,0x38,0x37,\n    0x39,0x37,0x36,0x32,0x30,0x37,0x3e,0x44,0x48,0x4a,0x4f,0x5a,0x5d,0x5f,0x59,0x50,\n    0x58,0x72,0x96,0xa9,0xb4,0xb7,0xad,0x9b,0x87,0x68,0x57,0x66,0x91,0xaf,0xc5,0x60,\n    0x72,0x31,0x39,0xc5,0xba,0xbc,0xbc,0xbc,0xbd,0xb8,0xb9,0x37,0x15,0x14,0x13,0x13,\n    0x13,0x13,0x14,0x12,0x13,0x14,0x13,0x15,0x15,0x6a,0xc0,0xc1,0xc0,0xc1,0xc2,0xc6,\n    0x5b,0x2f,0x35,0x6d,0x51,0x53,0x54,0x55,0x58,0x5d,0x5c,0x56,0x65,0x77,0x81,0x8f,\n    0x94,0x95,0x91,0x84,0x75,0x58,0x39,0x26,0x1f,0x19,0x18,0x17,0x18,0x18,0x18,0x17,\n    0x76,0x7c,0x7b,0x75,0x75,0x79,0x7c,0x83,0x80,0x81,0x82,0x86,0x8a,0x8c,0x8c,0x8b,\n    0x86,0x89,0x8a,0x88,0x7f,0x6a,0x53,0x42,0x3a,0x3e,0x49,0x52,0x50,0x52,0x52,0x49,\n    0x48,0x44,0x42,0x43,0x44,0x4c,0x59,0x5e,0x66,0x68,0x6c,0x70,0x6e,0x70,0x6f,0x66,\n    0x66,0x80,0xa0,0xb7,0xc4,0xc7,0xc0,0xb6,0xa6,0x8e,0x76,0x7d,0x9a,0xb4,0xcf,0x5f,\n    0x11,0x31,0x39,0xc5,0xba,0xbc,0xbc,0xbc,0xbc,0xbd,0xb9,0x34,0x14,0x13,0x13,0x12,\n    0x13,0x12,0x10,0x17,0x14,0x14,0x13,0x16,0x14,0x75,0xbf,0xbf,0xbe,0xbe,0xc3,0xc6,\n    0x5a,0x2f,0x14,0x35,0x53,0x53,0x53,0x53,0x55,0x59,0x58,0x53,0x57,0x60,0x6a,0x6f,\n    0x6c,0x68,0x64,0x5c,0x4b,0x37,0x27,0x20,0x1d,0x18,0x17,0x17,0x16,0x16,0x15,0x14,\n    0x78,0x7b,0x7b,0x7a,0x76,0x78,0x80,0x87,0x86,0x86,0x85,0x86,0x8a,0x8e,0x8d,0x89,\n    0x86,0x94,0x9c,0x9d,0x9c,0x8b,0x73,0x63,0x5a,0x60,0x6a,0x73,0x7c,0x86,0x80,0x6f,\n    0x67,0x5c,0x52,0x52,0x56,0x5d,0x6b,0x71,0x7b,0x7a,0x7e,0x80,0x83,0x7c,0x7f,0x75,\n    0x70,0x8d,0xac,0xc3,0xd1,0xd3,0xce,0xc4,0xbd,0xae,0x9b,0x97,0xa4,0xbf,0xd5,0x40,\n    0x13,0x34,0x38,0xc5,0xbb,0xbb,0xbb,0xbb,0xbc,0xbd,0xb8,0x32,0x13,0x13,0x13,0x10,\n    0x1d,0x29,0x2a,0x16,0x12,0x13,0x12,0x13,0x15,0x80,0xc0,0xbf,0xbf,0xc0,0xc1,0xc5,\n    0x5a,0x2e,0x15,0x2d,0x40,0x3e,0x40,0x3f,0x3d,0x3b,0x39,0x32,0x28,0x25,0x29,0x2a,\n    0x25,0x21,0x1f,0x1f,0x1f,0x20,0x1d,0x1a,0x18,0x15,0x16,0x15,0x14,0x14,0x12,0x12,\n    0x7b,0x7b,0x7d,0x79,0x77,0x77,0x7e,0x83,0x87,0x87,0x85,0x84,0x87,0x89,0x8c,0x88,\n    0x84,0x8f,0x9d,0xa2,0xa4,0x99,0x85,0x78,0x72,0x7a,0x81,0x8d,0x97,0x9e,0x9c,0x8d,\n    0x7d,0x70,0x61,0x62,0x65,0x68,0x6e,0x74,0x7a,0x7e,0x7f,0x86,0x87,0x82,0x83,0x7f,\n    0x7c,0x93,0xb0,0xc5,0xd1,0xd6,0xd2,0xcc,0xcb,0xc4,0xbc,0xb3,0xb4,0xc3,0xcf,0x19,\n    0x14,0x34,0x38,0xc3,0xba,0xba,0xbb,0xbb,0xbb,0xbc,0xb8,0x32,0x13,0x13,0x12,0x37,\n    0x1a,0x13,0x15,0x11,0x14,0x13,0x13,0x14,0x14,0x8d,0xbf,0xbf,0xbf,0xc0,0xc1,0xc4,\n    0x57,0x2c,0x15,0x24,0x27,0x28,0x28,0x28,0x25,0x22,0x1d,0x1b,0x16,0x15,0x13,0x12,\n    0x13,0x16,0x17,0x18,0x19,0x18,0x16,0x16,0x14,0x14,0x13,0x12,0x13,0x13,0x12,0x11,\n    0x59,0x5b,0x5d,0x59,0x59,0x5a,0x5e,0x62,0x67,0x68,0x67,0x68,0x6c,0x6e,0x71,0x70,\n    0x6d,0x6b,0x73,0x81,0x89,0x81,0x75,0x72,0x73,0x7c,0x88,0x92,0x99,0x9c,0x9b,0x94,\n    0x87,0x7a,0x72,0x73,0x75,0x7a,0x80,0x7c,0x79,0x7a,0x7c,0x81,0x83,0x83,0x86,0x89,\n    0x82,0x8c,0xa7,0xb4,0xc0,0xc7,0xc6,0xc5,0xc8,0xcc,0xcd,0xcc,0xc8,0xcd,0xb0,0x0d,\n    0x17,0x33,0x36,0xc5,0xba,0xba,0xbb,0xbb,0xbb,0xbc,0xb8,0x2f,0x11,0x13,0x13,0x11,\n    0x13,0x12,0x13,0x12,0x13,0x13,0x13,0x14,0x11,0x97,0xbd,0xbf,0xbf,0xc0,0xc0,0xc4,\n    0x58,0x2a,0x14,0x20,0x26,0x26,0x24,0x26,0x26,0x24,0x1d,0x1a,0x18,0x18,0x17,0x15,\n    0x14,0x14,0x14,0x16,0x17,0x15,0x13,0x12,0x12,0x11,0x10,0x11,0x11,0x11,0x11,0x10,\n    0x3b,0x3c,0x3c,0x3a,0x38,0x3c,0x38,0x3b,0x3a,0x37,0x35,0x34,0x33,0x33,0x32,0x35,\n    0x30,0x35,0x34,0x30,0x2e,0x2f,0x32,0x2f,0x2e,0x2e,0x2d,0x2e,0x2d,0x2d,0x2c,0x31,\n    0x32,0x32,0x39,0x38,0x33,0x35,0x39,0x3c,0x3d,0x3b,0x3e,0x40,0x3e,0x45,0x44,0x44,\n    0x43,0x41,0x44,0x42,0x45,0x46,0x49,0x51,0x54,0x47,0x24,0x33,0x40,0x2e,0x18,0x10,\n    0x15,0x33,0x36,0xc5,0xba,0xba,0xbb,0xbb,0xbb,0xbb,0xb7,0x2e,0x14,0x13,0x13,0x13,\n    0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x14,0x0f,0xa0,0xbd,0xbf,0xbe,0xbf,0xc0,0xc4,\n    0x58,0x26,0x12,0x1f,0x2b,0x28,0x28,0x26,0x26,0x24,0x20,0x1c,0x1b,0x1b,0x1a,0x19,\n    0x17,0x17,0x17,0x17,0x17,0x16,0x15,0x13,0x11,0x12,0x13,0x13,0x13,0x13,0x11,0x11,\n    0x69,0x65,0x62,0x68,0x6b,0x66,0x6e,0x69,0x64,0x65,0x66,0x6d,0x6a,0x6e,0x6d,0x69,\n    0x67,0x68,0x68,0x68,0x63,0x67,0x6c,0x62,0x60,0x68,0x69,0x63,0x65,0x66,0x67,0x67,\n    0x67,0x61,0x62,0x5d,0x5a,0x5d,0x5f,0x5c,0x5d,0x5b,0x5c,0x5a,0x57,0x5b,0x59,0x56,\n    0x54,0x55,0x52,0x4e,0x4b,0x4c,0x3d,0x3d,0x39,0x3c,0x10,0x0f,0x0e,0x0f,0x0f,0x10,\n    0x13,0x31,0x36,0xc4,0xb9,0xb9,0xba,0xbb,0xbb,0xbb,0xb8,0x2b,0x13,0x13,0x13,0x13,\n    0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0b,0xad,0xbe,0xbe,0xbd,0xbe,0xbf,0xc3,\n    0x57,0x26,0x11,0x23,0x28,0x28,0x29,0x26,0x23,0x22,0x22,0x1e,0x1e,0x1e,0x1c,0x1c,\n    0x1c,0x1c,0x1c,0x1c,0x1b,0x1a,0x18,0x16,0x16,0x15,0x15,0x16,0x16,0x15,0x13,0x11,\n    0x7e,0x77,0x7d,0x76,0x7f,0x8c,0x7b,0x86,0x84,0x87,0x85,0x8d,0x88,0x8c,0x86,0x8e,\n    0x8e,0x8d,0x8d,0x8e,0x90,0x90,0x90,0x93,0x8f,0x91,0x8c,0x8f,0x92,0x93,0x93,0x93,\n    0x90,0x8e,0x8a,0x87,0x8d,0x8b,0x8e,0x8e,0x8a,0x86,0x87,0x85,0x84,0x82,0x85,0x86,\n    0x83,0x83,0x87,0x88,0x7f,0x81,0x7b,0x4c,0x43,0x41,0x39,0x17,0x0e,0x0c,0x0c,0x10,\n    0x14,0x31,0x39,0xc3,0xb9,0xb9,0xba,0xba,0xba,0xba,0xb8,0x26,0x13,0x13,0x13,0x13,\n    0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0b,0xbb,0xbf,0xbd,0xbd,0xbc,0xbc,0xc3,\n    0x56,0x2a,0x10,0x23,0x29,0x28,0x27,0x25,0x21,0x20,0x22,0x1e,0x1e,0x1e,0x1f,0x1f,\n    0x20,0x21,0x21,0x22,0x20,0x1c,0x1c,0x1b,0x19,0x18,0x18,0x19,0x19,0x18,0x15,0x14,\n    0x85,0x88,0x87,0x86,0x8a,0x87,0x8a,0x92,0x8c,0x8e,0x89,0x88,0x8b,0x80,0x7f,0x7c,\n    0x81,0x81,0x84,0x8a,0x8d,0x89,0x8f,0x93,0x94,0x98,0x99,0x91,0x8e,0x8d,0x88,0x94,\n    0x8f,0x8a,0x8a,0x85,0x89,0x8d,0x90,0x94,0x92,0x94,0x93,0x93,0x97,0x9a,0x94,0x9a,\n    0x94,0x91,0x92,0x93,0x94,0x93,0x95,0x7b,0x4f,0x53,0x4f,0x53,0x23,0x0d,0x0d,0x0e,\n    0x13,0x34,0x3b,0xc3,0xb9,0xb9,0xb9,0xb9,0xba,0xb9,0xb3,0x24,0x13,0x12,0x15,0x13,\n    0x16,0x14,0x15,0x12,0x12,0x12,0x13,0x14,0x12,0xbe,0xbe,0xbc,0xbd,0xbd,0xbd,0xc2,\n    0x55,0x29,0x12,0x1f,0x28,0x27,0x25,0x24,0x20,0x1f,0x20,0x1d,0x1e,0x1f,0x1f,0x20,\n    0x22,0x24,0x25,0x27,0x25,0x22,0x1f,0x20,0x1e,0x1d,0x1e,0x1e,0x1e,0x1c,0x19,0x17,\n    0x73,0x6f,0x74,0x76,0x75,0x78,0x7d,0x8a,0x91,0x90,0x88,0x82,0x7f,0x82,0x84,0x7f,\n    0x79,0x72,0x6a,0x6b,0x6e,0x64,0x52,0x3e,0x38,0x47,0x56,0x61,0x67,0x6a,0x6d,0x76,\n    0x79,0x7b,0x7b,0x7e,0x81,0x83,0x83,0x84,0x84,0x86,0x8b,0x8a,0x87,0x84,0x82,0x81,\n    0x79,0x75,0x77,0x72,0x75,0x73,0x78,0x79,0x5e,0x5f,0x59,0x44,0x3f,0x32,0x2e,0x10,\n    0x14,0x28,0x3d,0xc3,0xb8,0xb9,0xb9,0xb9,0xb8,0xb8,0xb8,0x6d,0x5b,0x54,0x48,0x1a,\n    0x13,0x0f,0x0c,0x11,0x12,0x12,0x11,0x0d,0x14,0xc5,0xbe,0xbc,0xbd,0xbd,0xbd,0xc1,\n    0x54,0x29,0x10,0x1f,0x25,0x26,0x24,0x22,0x1e,0x1c,0x1b,0x1b,0x1b,0x1c,0x1e,0x1f,\n    0x22,0x24,0x26,0x29,0x2a,0x27,0x25,0x24,0x21,0x22,0x22,0x20,0x1e,0x1d,0x1c,0x19,\n    0x72,0x72,0x73,0x72,0x70,0x70,0x77,0x85,0x8f,0x8b,0x88,0x81,0x7d,0x80,0x86,0x84,\n    0x7b,0x6f,0x6a,0x6d,0x74,0x6b,0x56,0x42,0x3c,0x45,0x54,0x5e,0x63,0x69,0x6f,0x75,\n    0x7b,0x7e,0x81,0x83,0x85,0x86,0x88,0x8a,0x8d,0x8f,0x91,0x92,0x94,0x8f,0x87,0x7b,\n    0x70,0x63,0x59,0x59,0x66,0x73,0x80,0x8c,0x94,0x96,0x9a,0x9e,0x99,0x8f,0x7d,0x14,\n    0x13,0x17,0x42,0xbf,0xb7,0xb6,0xb6,0xb8,0xb7,0xb5,0xb8,0xba,0xb7,0xba,0xb8,0xb1,\n    0xaf,0x9d,0x79,0x81,0xae,0xac,0xaa,0x9f,0x9c,0xc0,0xbd,0xbc,0xbc,0xbe,0xbc,0xc1,\n    0x55,0x29,0x15,0x1e,0x27,0x27,0x25,0x23,0x1e,0x1c,0x18,0x19,0x1a,0x1b,0x1b,0x1d,\n    0x21,0x27,0x2a,0x30,0x2f,0x31,0x2b,0x28,0x26,0x24,0x23,0x22,0x21,0x1e,0x1b,0x1a,\n    0x71,0x6f,0x6e,0x67,0x69,0x6a,0x70,0x7a,0x82,0x84,0x82,0x7f,0x81,0x84,0x86,0x85,\n    0x7b,0x6f,0x69,0x6c,0x72,0x6c,0x59,0x43,0x3d,0x44,0x51,0x5d,0x63,0x68,0x6d,0x72,\n    0x77,0x7d,0x80,0x83,0x86,0x89,0x8b,0x8d,0x8f,0x91,0x93,0x94,0x95,0x91,0x8a,0x81,\n    0x7b,0x75,0x6c,0x69,0x73,0x80,0x8a,0x98,0xa2,0xa6,0xab,0xae,0xa9,0x9e,0x90,0x19,\n    0x2b,0x20,0x3a,0xc4,0xbc,0xbe,0xbf,0xc0,0xbd,0xbc,0xbc,0xb9,0xba,0xba,0xb9,0xb8,\n    0xb7,0xba,0xbc,0xbe,0xba,0xbb,0xbe,0xbc,0xbd,0xbb,0xbd,0xbc,0xbb,0xbc,0xbb,0xc2,\n    0x56,0x29,0x14,0x1e,0x29,0x2b,0x27,0x23,0x1f,0x1d,0x1a,0x16,0x17,0x18,0x1a,0x1d,\n    0x24,0x2d,0x30,0x33,0x37,0x36,0x32,0x2f,0x2a,0x25,0x24,0x20,0x20,0x1e,0x1a,0x1a,\n    0x73,0x6e,0x6c,0x66,0x66,0x68,0x6e,0x71,0x75,0x75,0x79,0x7a,0x80,0x85,0x86,0x80,\n    0x77,0x6b,0x69,0x6f,0x72,0x6a,0x53,0x41,0x3a,0x43,0x4f,0x5c,0x63,0x68,0x6b,0x70,\n    0x74,0x79,0x81,0x86,0x88,0x8c,0x8f,0x92,0x91,0x93,0x94,0x95,0x94,0x90,0x8a,0x84,\n    0x7f,0x80,0x7b,0x78,0x7c,0x89,0x95,0x9d,0xa3,0xab,0xb1,0xb4,0xb2,0xaf,0xa2,0x1e,\n    0x85,0x2a,0x2c,0x31,0x3a,0x41,0x4c,0x54,0x61,0x75,0x7f,0x8e,0x9d,0xa5,0xaf,0xb6,\n    0xba,0xbe,0xb9,0xba,0xb9,0xbb,0xba,0xba,0xba,0xb9,0xbc,0xbb,0xbc,0xbb,0xbc,0xc1,\n    0x55,0x28,0x14,0x21,0x2a,0x2e,0x28,0x22,0x1e,0x1b,0x16,0x14,0x16,0x17,0x1a,0x1e,\n    0x27,0x2f,0x36,0x3e,0x3e,0x3c,0x39,0x34,0x30,0x2a,0x27,0x24,0x20,0x1d,0x1a,0x19,\n    0x70,0x6d,0x69,0x62,0x66,0x6b,0x71,0x71,0x72,0x71,0x71,0x73,0x7b,0x83,0x86,0x7f,\n    0x76,0x6d,0x6b,0x70,0x70,0x64,0x4d,0x3b,0x38,0x43,0x50,0x5b,0x64,0x69,0x6c,0x6e,\n    0x72,0x77,0x7e,0x84,0x88,0x8c,0x8e,0x91,0x92,0x94,0x95,0x94,0x91,0x8d,0x87,0x81,\n    0x7e,0x7e,0x80,0x80,0x81,0x84,0x90,0x9a,0x9e,0xa6,0xb0,0xb0,0xb2,0xb7,0xb9,0x44,\n    0x63,0x70,0x26,0x1e,0x20,0x20,0x21,0x22,0x25,0x22,0x22,0x24,0x25,0x26,0x26,0x2b,\n    0x2f,0x32,0x3a,0x3e,0x46,0x4c,0x53,0x58,0x5f,0x65,0x6c,0x74,0x7c,0x86,0x8f,0x9b,\n    0x43,0x24,0x17,0x29,0x2e,0x2b,0x29,0x21,0x1d,0x19,0x14,0x16,0x16,0x18,0x1a,0x21,\n    0x28,0x31,0x39,0x3f,0x3f,0x3f,0x3b,0x39,0x36,0x32,0x2a,0x29,0x25,0x1e,0x1c,0x1b,\n    0x6d,0x6d,0x65,0x62,0x68,0x69,0x70,0x71,0x71,0x6e,0x71,0x73,0x78,0x7c,0x80,0x7a,\n    0x73,0x6d,0x6a,0x6f,0x71,0x63,0x4d,0x3c,0x3c,0x44,0x50,0x5b,0x64,0x69,0x6c,0x6e,\n    0x70,0x76,0x7c,0x81,0x85,0x89,0x8d,0x90,0x91,0x91,0x91,0x8e,0x8a,0x88,0x81,0x7c,\n    0x7a,0x7a,0x7c,0x80,0x84,0x84,0x83,0x8b,0x92,0x9a,0xa5,0xa8,0xa9,0xb5,0xba,0x9f,\n    0x46,0x8b,0xa0,0x8d,0x81,0x77,0x6d,0x5a,0x4a,0x47,0x3f,0x36,0x30,0x2c,0x25,0x25,\n    0x26,0x29,0x27,0x29,0x29,0x29,0x28,0x29,0x2b,0x2e,0x2a,0x2c,0x2d,0x28,0x28,0x29,\n    0x26,0x1d,0x70,0x5e,0x2d,0x2c,0x27,0x21,0x1f,0x1a,0x15,0x16,0x17,0x18,0x1c,0x24,\n    0x2b,0x33,0x3b,0x3d,0x3d,0x3e,0x3d,0x3c,0x38,0x33,0x2e,0x29,0x24,0x20,0x1d,0x1c,\n    0x6f,0x6c,0x67,0x65,0x62,0x66,0x6d,0x6f,0x72,0x74,0x74,0x74,0x74,0x72,0x77,0x77,\n    0x71,0x6e,0x6a,0x6e,0x6e,0x61,0x4c,0x3b,0x3d,0x44,0x52,0x5f,0x64,0x69,0x6c,0x6e,\n    0x71,0x74,0x79,0x7d,0x81,0x85,0x86,0x89,0x88,0x88,0x85,0x84,0x81,0x7e,0x7a,0x78,\n    0x77,0x77,0x7b,0x7d,0x7e,0x80,0x82,0x84,0x87,0x88,0x8e,0x97,0x9c,0xa7,0xb3,0xb1,\n    0x8d,0x8e,0xb8,0xb8,0xd5,0xd5,0xdb,0xc8,0xc5,0xc6,0xc2,0xbb,0xb6,0xb6,0xb5,0xb1,\n    0xae,0xae,0xa5,0x9c,0x91,0x88,0x7d,0x75,0x6c,0x62,0x55,0x48,0x3d,0x37,0x33,0x26,\n    0x26,0x6e,0xcb,0x2b,0x2f,0x2b,0x25,0x22,0x22,0x1e,0x19,0x17,0x17,0x19,0x1e,0x23,\n    0x29,0x2e,0x33,0x36,0x37,0x39,0x3a,0x3a,0x37,0x35,0x34,0x2d,0x2a,0x26,0x22,0x20,\n    0x6f,0x6d,0x6b,0x6b,0x65,0x64,0x69,0x6c,0x76,0x79,0x77,0x75,0x73,0x6d,0x6f,0x74,\n    0x72,0x6f,0x6c,0x6a,0x6a,0x5d,0x49,0x3c,0x3e,0x45,0x54,0x5e,0x64,0x69,0x6c,0x6e,\n    0x70,0x73,0x77,0x79,0x7d,0x7e,0x7d,0x7c,0x7b,0x7c,0x7a,0x7a,0x79,0x77,0x73,0x73,\n    0x73,0x78,0x7d,0x81,0x82,0x7f,0x7e,0x7e,0x7d,0x80,0x81,0x80,0x80,0x8c,0x9d,0xaa,\n    0xa8,0xa7,0xa9,0xb7,0xc0,0xc6,0xcd,0xd4,0xd9,0xd8,0xdb,0xda,0xd3,0xd6,0xd5,0xd1,\n    0xd4,0xd4,0xcf,0xd3,0xd6,0xd3,0xcf,0xce,0xcb,0xd1,0xd4,0xd2,0xcd,0xcc,0xd2,0xca,\n    0xdd,0xf5,0xa1,0x2d,0x30,0x30,0x2d,0x2a,0x28,0x23,0x1c,0x18,0x17,0x18,0x1d,0x22,\n    0x24,0x25,0x27,0x2b,0x2d,0x2f,0x33,0x33,0x35,0x36,0x38,0x35,0x31,0x2e,0x29,0x23,\n    0x6d,0x71,0x73,0x71,0x6c,0x69,0x6a,0x6e,0x73,0x76,0x76,0x77,0x77,0x71,0x72,0x74,\n    0x70,0x70,0x6b,0x6b,0x6a,0x5a,0x46,0x3b,0x3a,0x47,0x56,0x5e,0x66,0x6c,0x6d,0x6e,\n    0x70,0x70,0x73,0x74,0x75,0x75,0x72,0x6f,0x6d,0x6f,0x70,0x71,0x71,0x71,0x71,0x6f,\n    0x71,0x74,0x7e,0x84,0x87,0x86,0x82,0x7f,0x7a,0x78,0x79,0x7a,0x77,0x76,0x88,0x9b,\n    0xa3,0xa3,0xa4,0xa5,0xab,0xba,0xcc,0xd8,0xdd,0xdd,0xdf,0xde,0xd4,0xc7,0xc4,0xce,\n    0xca,0xb8,0xa5,0x80,0x58,0x64,0x76,0x88,0xa2,0xb5,0xc7,0xd7,0xdd,0xde,0xe4,0xea,\n    0xf3,0xa4,0x38,0x33,0x34,0x37,0x34,0x30,0x2b,0x26,0x1e,0x18,0x17,0x16,0x1a,0x1e,\n    0x21,0x21,0x21,0x22,0x25,0x25,0x2b,0x2e,0x30,0x34,0x36,0x35,0x32,0x2f,0x29,0x25,\n    0x6b,0x70,0x72,0x72,0x6e,0x6c,0x6b,0x6f,0x73,0x73,0x73,0x76,0x76,0x77,0x78,0x74,\n    0x72,0x70,0x6b,0x68,0x66,0x56,0x40,0x39,0x36,0x47,0x59,0x62,0x67,0x6c,0x6c,0x6e,\n    0x6f,0x6e,0x6f,0x70,0x6f,0x6d,0x69,0x64,0x62,0x63,0x68,0x6f,0x6e,0x6f,0x6c,0x6c,\n    0x6f,0x75,0x7d,0x83,0x87,0x88,0x86,0x82,0x80,0x7d,0x7a,0x78,0x77,0x77,0x7c,0x8c,\n    0x98,0xa2,0xa7,0xb6,0xc6,0xd6,0xdd,0xde,0xdc,0xd8,0xd4,0xca,0xbd,0xbc,0xbd,0xc9,\n    0xbe,0xaf,0x90,0x55,0x1e,0x21,0x20,0x1f,0x1a,0x19,0x19,0x1e,0x27,0x34,0x44,0x4a,\n    0x38,0x32,0x3a,0x37,0x38,0x3b,0x38,0x33,0x2f,0x27,0x1d,0x18,0x15,0x15,0x1a,0x1a,\n    0x1b,0x1b,0x1c,0x1b,0x1d,0x23,0x25,0x2b,0x2c,0x32,0x35,0x35,0x33,0x2f,0x2c,0x27,\n    0x65,0x6b,0x6f,0x70,0x6c,0x6c,0x6a,0x6d,0x6c,0x6b,0x69,0x6c,0x76,0x7a,0x7d,0x76,\n    0x73,0x6c,0x65,0x66,0x62,0x50,0x3d,0x35,0x37,0x4a,0x5b,0x64,0x6b,0x6c,0x6b,0x6c,\n    0x6d,0x6b,0x6b,0x6b,0x69,0x66,0x62,0x5b,0x59,0x5c,0x63,0x6b,0x68,0x68,0x6a,0x6a,\n    0x6f,0x76,0x7c,0x82,0x86,0x87,0x86,0x82,0x80,0x80,0x7f,0x7d,0x78,0x77,0x82,0x8b,\n    0x90,0x9f,0xb4,0xc4,0xd1,0xda,0xd8,0xd3,0xcc,0xbe,0xae,0xa4,0xaa,0xb1,0xb3,0xc0,\n    0xb7,0xa3,0x80,0x38,0x1f,0x22,0x24,0x25,0x29,0x2e,0x2e,0x31,0x34,0x35,0x39,0x3a,\n    0x3a,0x3a,0x38,0x39,0x39,0x3a,0x39,0x36,0x32,0x29,0x20,0x1c,0x16,0x13,0x16,0x17,\n    0x17,0x18,0x18,0x18,0x1a,0x1d,0x1f,0x23,0x26,0x2f,0x30,0x31,0x31,0x2d,0x28,0x28,\n    0x64,0x69,0x6d,0x6c,0x68,0x64,0x67,0x69,0x68,0x67,0x66,0x68,0x72,0x79,0x7e,0x7b,\n    0x71,0x6c,0x65,0x64,0x61,0x4d,0x38,0x31,0x39,0x4d,0x5e,0x67,0x6c,0x6c,0x6c,0x6b,\n    0x6a,0x69,0x68,0x68,0x67,0x62,0x5c,0x56,0x52,0x53,0x5c,0x60,0x66,0x6e,0x6c,0x6e,\n    0x73,0x7a,0x7e,0x82,0x86,0x87,0x86,0x82,0x82,0x82,0x82,0x82,0x82,0x80,0x86,0x93,\n    0x95,0xa3,0xb5,0xc1,0xc6,0xcc,0xc6,0xb7,0x9a,0x7c,0x7a,0x8c,0x9a,0xa1,0xb4,0xb9,\n    0xb1,0x9a,0x6e,0x2c,0x20,0x23,0x24,0x29,0x2a,0x2e,0x33,0x36,0x38,0x38,0x39,0x3c,\n    0x38,0x36,0x39,0x3b,0x3b,0x3b,0x3a,0x3b,0x36,0x2d,0x27,0x24,0x1d,0x18,0x15,0x14,\n    0x15,0x16,0x17,0x18,0x19,0x18,0x18,0x1b,0x20,0x28,0x28,0x28,0x2a,0x29,0x29,0x2c,\n    0x67,0x69,0x69,0x69,0x69,0x63,0x63,0x63,0x62,0x60,0x5f,0x63,0x6c,0x76,0x79,0x7a,\n    0x70,0x6a,0x68,0x68,0x60,0x4e,0x38,0x32,0x3b,0x50,0x60,0x68,0x6b,0x6a,0x69,0x68,\n    0x67,0x67,0x67,0x66,0x64,0x60,0x5b,0x56,0x49,0x44,0x4e,0x58,0x65,0x71,0x70,0x74,\n    0x78,0x7c,0x7f,0x83,0x86,0x86,0x85,0x83,0x82,0x81,0x80,0x82,0x84,0x86,0x89,0x94,\n    0x99,0x9b,0xa6,0xac,0xaf,0xa6,0x92,0x72,0x50,0x48,0x5a,0x6e,0x7f,0x8f,0xaf,0xb7,\n    0xab,0x93,0x61,0x24,0x23,0x24,0x25,0x2a,0x2c,0x2d,0x2d,0x30,0x32,0x35,0x38,0x3a,\n    0x37,0x37,0x37,0x38,0x3a,0x3c,0x3c,0x3a,0x37,0x32,0x2e,0x29,0x26,0x1c,0x16,0x15,\n    0x13,0x13,0x13,0x15,0x15,0x15,0x17,0x18,0x1b,0x24,0x27,0x26,0x28,0x2b,0x2c,0x32,\n    0x6f,0x69,0x65,0x67,0x68,0x62,0x5e,0x5e,0x5f,0x60,0x60,0x61,0x6a,0x74,0x77,0x79,\n    0x72,0x6e,0x6a,0x69,0x64,0x50,0x39,0x35,0x3f,0x54,0x63,0x69,0x6a,0x67,0x66,0x65,\n    0x64,0x66,0x66,0x66,0x65,0x61,0x59,0x53,0x48,0x41,0x4b,0x58,0x66,0x73,0x78,0x7a,\n    0x7c,0x7c,0x7e,0x81,0x84,0x85,0x85,0x83,0x81,0x81,0x80,0x82,0x84,0x87,0x8d,0x94,\n    0x99,0x9c,0x95,0x8e,0x81,0x68,0x51,0x42,0x44,0x44,0x47,0x54,0x66,0x80,0xa3,0xa7,\n    0x9c,0x86,0x53,0x20,0x23,0x23,0x24,0x25,0x27,0x28,0x28,0x2a,0x2d,0x2e,0x30,0x32,\n    0x33,0x34,0x34,0x38,0x3c,0x3c,0x3b,0x3b,0x3e,0x3a,0x38,0x33,0x2c,0x20,0x18,0x15,\n    0x12,0x11,0x11,0x12,0x12,0x12,0x15,0x18,0x1e,0x24,0x27,0x2b,0x2e,0x30,0x34,0x3a,\n    0x70,0x6a,0x64,0x66,0x65,0x62,0x5f,0x58,0x5e,0x64,0x64,0x67,0x6b,0x72,0x75,0x78,\n    0x73,0x70,0x6a,0x69,0x61,0x4d,0x3c,0x37,0x43,0x56,0x66,0x67,0x64,0x64,0x65,0x65,\n    0x65,0x66,0x64,0x65,0x63,0x5e,0x57,0x54,0x52,0x4c,0x55,0x60,0x6c,0x74,0x7c,0x7b,\n    0x7a,0x7b,0x7c,0x7f,0x84,0x84,0x86,0x81,0x80,0x7e,0x7d,0x82,0x82,0x84,0x8c,0x93,\n    0x96,0x9b,0x92,0x81,0x6c,0x53,0x45,0x43,0x42,0x42,0x42,0x45,0x4f,0x67,0x8b,0x90,\n    0x83,0x6b,0x3c,0x22,0x1f,0x21,0x21,0x20,0x1f,0x21,0x23,0x25,0x25,0x28,0x2a,0x31,\n    0x32,0x33,0x36,0x39,0x3b,0x3a,0x3a,0x39,0x3b,0x3a,0x39,0x36,0x2d,0x22,0x19,0x13,\n    0x11,0x0e,0x0f,0x10,0x10,0x11,0x15,0x1b,0x26,0x27,0x2a,0x2e,0x34,0x35,0x38,0x3d,\n    0x6e,0x68,0x67,0x6a,0x68,0x66,0x60,0x5b,0x5f,0x6c,0x6d,0x72,0x71,0x74,0x76,0x79,\n    0x74,0x70,0x68,0x65,0x5f,0x4b,0x3e,0x3d,0x47,0x59,0x64,0x61,0x61,0x63,0x63,0x64,\n    0x65,0x65,0x64,0x65,0x61,0x59,0x59,0x56,0x57,0x5b,0x61,0x6c,0x75,0x7a,0x7e,0x7d,\n    0x7c,0x7a,0x7b,0x7e,0x82,0x84,0x84,0x81,0x7f,0x7e,0x7d,0x7f,0x82,0x84,0x8a,0x92,\n    0x96,0x99,0x92,0x7f,0x69,0x53,0x46,0x41,0x40,0x3f,0x40,0x41,0x48,0x55,0x6d,0x70,\n    0x66,0x4b,0x27,0x1e,0x1f,0x1e,0x1f,0x1e,0x1d,0x1f,0x20,0x1f,0x21,0x23,0x2a,0x2b,\n    0x2f,0x35,0x37,0x3a,0x3a,0x39,0x36,0x36,0x35,0x3a,0x37,0x33,0x2a,0x22,0x17,0x10,\n    0x0d,0x0d,0x0e,0x0f,0x11,0x12,0x17,0x1e,0x26,0x28,0x2b,0x31,0x36,0x39,0x3c,0x3d,\n};\n"
  },
  {
    "path": "partitions_example.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild\nnvs,      data, nvs,     0x9000,  0x6000,\nphy_init, data, phy,     0xf000,  0x1000,\nfactory,  app,  factory, 0x10000, 1M,\nstorage,  data, spiffs,  0x180000, 1M, \n"
  },
  {
    "path": "sdkconfig.defaults",
    "content": "CONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions_example.csv\"\nCONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000\nCONFIG_PARTITION_TABLE_FILENAME=\"partitions_example.csv\"\nCONFIG_APP_OFFSET=0x10000\nCONFIG_ESP32_PANIC_PRINT_HALT=y\nCONFIG_ESP32_DEFAULT_CPU_FREQ_240=y\nCONFIG_FREERTOS_HZ=1000\nCONFIG_MAIN_TASK_STACK_SIZE=8192\nCONFIG_TASK_WDT_TIMEOUT_S=20\n"
  }
]